diff --git a/.github/workflows/run_integration_tests.yml b/.github/workflows/run_integration_tests.yml index 22cec5d48bb3dc..0c4ba61a8a45e1 100644 --- a/.github/workflows/run_integration_tests.yml +++ b/.github/workflows/run_integration_tests.yml @@ -63,7 +63,6 @@ jobs: tools/build/build --ci dm -DCIBUILDING -DANSICOLORS -WError -NWTG0001 - name: Run Tests run: | - cp libbyond_sleeping_procs.so ~/.byond/bin/libbyond_sleeping_procs.so source $HOME/BYOND/byond/bin/byondsetup bash tools/ci/run_server.sh ${{ inputs.map }} - name: Upload screenshot tests diff --git a/.gitignore b/.gitignore index f8688c913d8f39..1c74dfcdf37590 100644 --- a/.gitignore +++ b/.gitignore @@ -24,9 +24,6 @@ # Ignore compiled linux libs in the root folder, e.g. librust_g.so /*.so -# Remove when removing byond_status -!/libbyond_sleeping_procs.so - #Ignore compiled files and other files generated during compilation. *.mdme *.mdme.* diff --git a/_maps/RandomRuins/LavaRuins/lavaland_battle_site.dmm b/_maps/RandomRuins/LavaRuins/lavaland_battle_site.dmm new file mode 100644 index 00000000000000..7dbc17d40f969a --- /dev/null +++ b/_maps/RandomRuins/LavaRuins/lavaland_battle_site.dmm @@ -0,0 +1,464 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/closed/mineral/strong/wasteland, +/area/lavaland/surface/outdoors) +"f" = ( +/obj/effect/mob_spawn/corpse/human/skeleton, +/obj/item/clothing/head/costume/crown{ + pixel_x = 15; + pixel_y = 6; + desc = "A crown that was fit for a king, looks like it didn't get them very far."; + name = "dented crown" + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"g" = ( +/obj/structure/water_source/puddle, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"h" = ( +/obj/effect/mob_spawn/corpse/human/skeleton, +/obj/item/shield/buckler, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"j" = ( +/turf/template_noop, +/area/template_noop) +"m" = ( +/obj/effect/decal/cleanable/shreds, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"n" = ( +/obj/structure/stone_tile/block/burnt, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"o" = ( +/obj/structure/stone_tile/burnt{ + dir = 1 + }, +/obj/structure/stone_tile/burnt{ + dir = 8 + }, +/obj/effect/decal/cleanable/blood/drip, +/mob/living/basic/mining/goliath, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"p" = ( +/obj/item/stack/rods{ + pixel_x = 10 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"q" = ( +/obj/structure/flora/rock, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"s" = ( +/mob/living/basic/mining/goliath, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"t" = ( +/obj/effect/decal/cleanable/blood/gibs/old, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"u" = ( +/obj/effect/decal/cleanable/blood/old, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"x" = ( +/obj/effect/decal/cleanable/blood/drip, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"D" = ( +/obj/structure/statue/bone/rib{ + name = "colossal tailbone" + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"F" = ( +/obj/effect/decal/cleanable/blood/drip, +/obj/structure/stone_tile/cracked{ + dir = 1 + }, +/obj/structure/statue/bone/rib, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"G" = ( +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"H" = ( +/obj/structure/firepit, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"I" = ( +/obj/structure/closet/crate/wooden, +/obj/item/stack/sheet/animalhide/goliath_hide, +/obj/item/flashlight/flare/torch, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"J" = ( +/obj/structure/flora/ash/cap_shroom, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"K" = ( +/obj/structure/closet/crate/wooden, +/obj/item/stack/sheet/sinew, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"L" = ( +/obj/effect/decal/cleanable/blood/hitsplatter{ + dir = 4 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"M" = ( +/obj/structure/statue/bone/skull, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"O" = ( +/obj/structure/statue/bone/rib{ + dir = 1 + }, +/obj/structure/stone_tile/cracked{ + dir = 4 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"P" = ( +/obj/effect/mob_spawn/corpse/human/skeleton, +/obj/item/shovel/spade, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"S" = ( +/obj/structure/chair/wood/wings{ + color = "#ffff00" + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"T" = ( +/obj/effect/mob_spawn/corpse/human/skeleton, +/obj/item/spear/bonespear{ + pixel_x = 13; + pixel_y = 12 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"U" = ( +/obj/structure/statue/bone/rib, +/obj/structure/stone_tile/cracked{ + dir = 1 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"V" = ( +/obj/effect/mob_spawn/corpse/human/skeleton, +/obj/item/stack/rods{ + pixel_x = -1; + pixel_y = -7 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"X" = ( +/obj/structure/stone_tile/burnt, +/obj/structure/stone_tile/burnt{ + dir = 4 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) +"Y" = ( +/obj/effect/mob_spawn/corpse/human/skeleton, +/obj/item/stack/rods{ + pixel_y = -12; + pixel_x = 2 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) + +(1,1,1) = {" +j +j +j +j +j +j +j +j +j +j +j +j +j +j +j +j +"} +(2,1,1) = {" +j +j +a +j +j +j +j +j +j +j +j +j +a +j +j +j +"} +(3,1,1) = {" +j +a +a +a +j +j +J +G +G +G +j +j +a +a +a +j +"} +(4,1,1) = {" +j +j +a +a +G +K +G +u +T +x +J +a +a +a +j +j +"} +(5,1,1) = {" +j +j +j +J +I +G +G +q +L +G +s +g +a +G +j +j +"} +(6,1,1) = {" +j +j +j +G +s +x +x +G +x +G +x +G +G +D +j +j +"} +(7,1,1) = {" +j +j +V +q +G +p +t +J +G +q +J +O +q +G +j +j +"} +(8,1,1) = {" +j +j +m +u +G +q +f +O +J +O +G +n +J +x +j +j +"} +(9,1,1) = {" +j +j +G +x +G +M +S +n +o +n +X +F +u +G +j +j +"} +(10,1,1) = {" +j +j +J +G +G +u +J +U +G +U +J +G +G +G +j +j +"} +(11,1,1) = {" +j +j +j +q +h +G +G +G +q +G +G +J +m +q +j +j +"} +(12,1,1) = {" +j +j +j +G +G +x +H +x +G +G +q +Y +G +a +j +j +"} +(13,1,1) = {" +j +j +a +G +J +G +G +P +G +u +G +a +a +a +a +j +"} +(14,1,1) = {" +j +a +a +a +j +j +G +G +q +G +j +j +a +a +j +j +"} +(15,1,1) = {" +j +a +a +j +j +j +j +j +j +j +j +a +a +a +j +j +"} +(16,1,1) = {" +j +j +j +j +j +j +j +j +j +j +j +j +j +j +j +j +"} diff --git a/_maps/RandomRuins/SpaceRuins/anomaly_research.dmm b/_maps/RandomRuins/SpaceRuins/anomaly_research.dmm index 50a3ba98cba3b4..e3015469bcea4a 100644 --- a/_maps/RandomRuins/SpaceRuins/anomaly_research.dmm +++ b/_maps/RandomRuins/SpaceRuins/anomaly_research.dmm @@ -32,7 +32,7 @@ /obj/effect/spawner/structure/window, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/white, +/turf/open/floor/plating, /area/misc/anomaly_research) "bP" = ( /obj/structure/table/wood, @@ -54,10 +54,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/smooth, /area/misc/anomaly_research) -"cA" = ( -/obj/effect/spawner/structure/window/reinforced, -/turf/open/floor/iron/white, -/area/misc/anomaly_research) "cD" = ( /obj/effect/turf_decal/stripes/line, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -217,10 +213,6 @@ }, /turf/open/floor/iron/white, /area/misc/anomaly_research) -"hh" = ( -/obj/effect/spawner/structure/window/plasma, -/turf/open/floor/wood, -/area/misc/anomaly_research) "hl" = ( /obj/effect/turf_decal/stripes/line{ dir = 6 @@ -268,8 +260,7 @@ /area/misc/anomaly_research) "ii" = ( /obj/effect/spawner/structure/window/reinforced, -/obj/effect/spawner/structure/window/reinforced, -/turf/open/floor/iron/white, +/turf/open/floor/plating, /area/misc/anomaly_research) "ip" = ( /obj/effect/turf_decal/tile/neutral{ @@ -947,7 +938,7 @@ /area/misc/anomaly_research) "yR" = ( /obj/effect/spawner/structure/window, -/turf/open/floor/iron/white, +/turf/open/floor/plating, /area/misc/anomaly_research) "yS" = ( /obj/effect/turf_decal/tile/purple/opposingcorners, @@ -1028,7 +1019,7 @@ /area/misc/anomaly_research) "Cl" = ( /obj/effect/spawner/structure/window/plasma, -/turf/open/floor/engine, +/turf/open/floor/plating, /area/misc/anomaly_research) "CI" = ( /turf/open/floor/engine, @@ -1217,7 +1208,7 @@ "GG" = ( /obj/effect/spawner/structure/window, /obj/machinery/duct, -/turf/open/floor/iron/white, +/turf/open/floor/plating, /area/misc/anomaly_research) "GI" = ( /obj/effect/turf_decal/stripes/white/line, @@ -1308,7 +1299,7 @@ /area/misc/anomaly_research) "IC" = ( /obj/effect/spawner/structure/window/reinforced/plasma, -/turf/open/floor/iron/dark/textured, +/turf/open/floor/plating, /area/misc/anomaly_research) "IH" = ( /obj/effect/spawner/random/big_anomaly, @@ -1658,11 +1649,6 @@ /obj/effect/turf_decal/siding/white, /turf/open/floor/iron/dark, /area/misc/anomaly_research) -"Ss" = ( -/obj/effect/spawner/structure/window/reinforced/plasma, -/obj/effect/spawner/structure/window/reinforced/plasma, -/turf/open/floor/iron/dark/textured, -/area/misc/anomaly_research) "SQ" = ( /obj/structure/table/reinforced, /obj/effect/turf_decal/stripes/white/line, @@ -2176,11 +2162,11 @@ dr xE xE AV -Ss -Ss -Ss -Ss -Ss +IC +IC +IC +IC +IC AV AV AV @@ -3312,9 +3298,9 @@ AV AV Xo AV -cA -cA -cA +ii +ii +ii eW QP HT @@ -3390,7 +3376,7 @@ sF Gr mC nh -cA +ii tG ZL Ng @@ -3428,7 +3414,7 @@ kt En dy Gg -cA +ii Ls Iw Ff @@ -3504,7 +3490,7 @@ uN vG lz ut -cA +ii Cf sE tG @@ -3580,7 +3566,7 @@ bP FE PY CP -hh +Cl xE xE xE @@ -3618,7 +3604,7 @@ UC LZ Tt PY -hh +Cl xE xE xE @@ -3656,7 +3642,7 @@ TF ev Tt tf -hh +Cl xE xE xE diff --git a/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm b/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm index bae9001b061afe..a1b7d571679565 100644 --- a/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm +++ b/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm @@ -98,7 +98,7 @@ /turf/open/floor/iron/white, /area/ruin/space/has_grav/dangerous_research/medical) "aZ" = ( -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/structure/table, /turf/open/floor/plating/rust, /area/ruin/space/has_grav/dangerous_research/medical) diff --git a/_maps/RandomRuins/SpaceRuins/derelict9.dmm b/_maps/RandomRuins/SpaceRuins/derelict9.dmm new file mode 100644 index 00000000000000..2fa948a60fae32 --- /dev/null +++ b/_maps/RandomRuins/SpaceRuins/derelict9.dmm @@ -0,0 +1,900 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/closed/mineral/random, +/area/ruin/space) +"b" = ( +/turf/closed/indestructible/riveted, +/area/ruin/space/has_grav) +"c" = ( +/obj/item/storage/toolbox/mechanical/old, +/obj/structure/rack, +/obj/effect/decal/cleanable/dirt, +/obj/effect/spawner/random/maintenance/three, +/turf/open/floor/plating/airless, +/area/ruin/space) +"h" = ( +/obj/structure/closet/crate, +/obj/item/weldingtool, +/obj/item/clothing/glasses/welding, +/turf/open/misc/asteroid/airless, +/area/ruin/space) +"j" = ( +/obj/structure/closet/crate/secure/loot, +/turf/open/floor/pod/dark, +/area/ruin/space/has_grav) +"l" = ( +/turf/template_noop, +/area/template_noop) +"m" = ( +/turf/closed/wall/rock, +/area/ruin/space) +"q" = ( +/obj/effect/mob_spawn/corpse/human/pirate/melee/space, +/obj/effect/decal/cleanable/blood, +/turf/open/misc/asteroid/airless, +/area/ruin/space) +"r" = ( +/obj/effect/decal/cleanable/blood, +/turf/open/misc/asteroid/airless, +/area/ruin/space) +"s" = ( +/obj/effect/mapping_helpers/bombable_wall, +/turf/closed/indestructible/riveted, +/area/ruin/space/has_grav) +"t" = ( +/obj/effect/gibspawner/human/bodypartless, +/obj/effect/mob_spawn/corpse/human/charredskeleton, +/turf/open/misc/asteroid/airless, +/area/ruin/space) +"u" = ( +/obj/structure/rack, +/obj/effect/spawner/random/clothing/beret_or_rabbitears, +/obj/effect/spawner/random/clothing/mafia_outfit, +/turf/open/floor/pod/dark, +/area/ruin/space/has_grav) +"x" = ( +/turf/open/floor/pod, +/area/ruin/space/has_grav) +"B" = ( +/obj/structure/rack, +/obj/effect/spawner/random/clothing/funny_hats, +/obj/effect/spawner/random/clothing/gloves, +/turf/open/floor/pod/dark, +/area/ruin/space/has_grav) +"C" = ( +/obj/structure/rack, +/obj/effect/spawner/random/clothing/mafia_outfit, +/obj/effect/spawner/random/clothing/pirate_or_bandana, +/turf/open/floor/pod/dark, +/area/ruin/space/has_grav) +"E" = ( +/obj/structure/mineral_door/wood, +/turf/open/misc/asteroid/airless, +/area/ruin/space) +"G" = ( +/obj/structure/safe, +/obj/item/clothing/head/collectable/petehat, +/turf/open/floor/pod/light, +/area/ruin/space/has_grav) +"I" = ( +/obj/machinery/porta_turret/syndicate/pod, +/turf/closed/wall/r_wall, +/area/ruin/space) +"J" = ( +/obj/item/gun/energy/laser/musket, +/obj/effect/decal/cleanable/blood, +/turf/open/misc/asteroid/airless, +/area/ruin/space) +"K" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating/airless, +/area/ruin/space) +"M" = ( +/obj/structure/reagent_dispensers/fueltank, +/turf/open/misc/asteroid/airless, +/area/ruin/space) +"O" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/spawner/random/maintenance, +/turf/open/floor/plating/airless, +/area/ruin/space) +"Q" = ( +/turf/open/floor/pod/light, +/area/ruin/space/has_grav) +"S" = ( +/obj/item/flashlight/lantern, +/turf/open/misc/asteroid/airless, +/area/ruin/space) +"T" = ( +/turf/open/misc/asteroid/airless, +/area/ruin/space) +"U" = ( +/obj/structure/rack, +/obj/effect/spawner/random/clothing/kittyears_or_rabbitears, +/obj/effect/spawner/random/clothing/lizardboots, +/turf/open/floor/pod/dark, +/area/ruin/space/has_grav) +"X" = ( +/obj/structure/rack, +/obj/effect/spawner/random/clothing/twentyfive_percent_cyborg_mask, +/obj/effect/spawner/random/clothing/costume, +/turf/open/floor/pod/dark, +/area/ruin/space/has_grav) +"Y" = ( +/obj/machinery/light/dim/directional/north, +/turf/open/floor/pod, +/area/ruin/space/has_grav) +"Z" = ( +/turf/closed/indestructible/fakedoor, +/area/ruin/space/has_grav) + +(1,1,1) = {" +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +a +a +a +l +l +l +l +"} +(2,1,1) = {" +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +T +l +l +a +l +"} +(3,1,1) = {" +l +l +l +l +l +l +l +a +l +l +l +l +l +l +l +l +l +l +l +l +l +l +a +a +l +l +l +l +l +l +l +l +l +"} +(4,1,1) = {" +l +l +l +l +T +a +a +a +T +l +l +I +l +l +l +l +l +l +l +l +l +l +T +l +l +l +l +l +l +l +l +l +a +"} +(5,1,1) = {" +T +T +T +T +T +a +a +m +r +T +r +a +l +a +l +l +l +l +l +l +l +l +l +l +l +l +l +T +a +a +l +l +T +"} +(6,1,1) = {" +l +T +T +a +a +a +a +T +q +T +m +a +a +a +a +l +l +l +l +l +l +l +l +l +l +l +T +a +a +T +l +l +l +"} +(7,1,1) = {" +l +T +a +a +a +a +a +J +a +a +a +a +a +a +a +a +a +a +l +l +l +l +l +l +l +l +l +a +a +T +l +l +l +"} +(8,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +O +m +a +a +a +a +a +T +T +T +T +l +l +l +a +r +l +l +l +l +"} +(9,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +T +T +K +K +T +O +a +a +a +a +T +T +T +T +T +l +l +l +l +l +l +l +"} +(10,1,1) = {" +a +a +a +a +a +a +a +a +b +b +b +s +b +b +r +T +T +K +a +a +a +a +T +T +T +l +l +l +l +l +l +T +T +"} +(11,1,1) = {" +l +a +a +a +a +a +a +a +b +j +B +X +U +b +T +t +T +m +a +a +a +a +T +T +T +l +l +l +l +l +l +a +a +"} +(12,1,1) = {" +l +l +a +a +a +a +a +a +b +x +x +x +x +b +K +T +T +a +a +a +a +a +a +T +T +l +l +l +l +l +l +l +l +"} +(13,1,1) = {" +l +T +T +a +a +a +a +a +b +Y +G +Q +x +Z +K +K +r +a +a +a +a +a +a +T +T +l +l +l +l +l +l +l +l +"} +(14,1,1) = {" +l +l +T +T +a +a +a +a +b +x +x +x +x +b +c +T +S +m +a +a +a +a +T +T +l +l +l +l +l +T +l +l +l +"} +(15,1,1) = {" +l +l +l +l +l +a +a +a +b +u +j +C +j +b +r +r +T +T +r +m +a +a +T +l +l +l +l +T +T +T +l +l +l +"} +(16,1,1) = {" +l +l +l +l +a +a +a +a +b +b +b +b +b +b +K +r +m +a +r +E +T +T +T +l +l +T +T +T +T +T +a +l +l +"} +(17,1,1) = {" +l +l +l +l +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +m +T +r +T +T +T +a +T +T +a +a +a +l +l +"} +(18,1,1) = {" +l +l +l +l +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +M +h +a +a +a +a +a +a +a +a +l +l +"} +(19,1,1) = {" +l +l +l +l +l +a +a +a +a +a +a +T +T +T +T +T +T +a +a +a +a +a +a +a +a +a +a +a +a +a +a +T +l +"} +(20,1,1) = {" +l +l +l +l +l +l +T +T +a +a +T +T +l +l +l +T +T +T +a +a +a +a +a +a +a +a +a +a +a +a +l +l +l +"} +(21,1,1) = {" +l +l +l +l +l +l +l +l +T +T +T +l +l +l +l +l +l +T +T +a +a +a +a +a +a +a +a +T +T +T +l +l +l +"} +(22,1,1) = {" +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +l +a +a +T +T +T +l +l +l +l +"} diff --git a/_maps/RandomRuins/SpaceRuins/interdyne.dmm b/_maps/RandomRuins/SpaceRuins/interdyne.dmm index e2a49a71d1afe5..bd0ba4cc2ff7f0 100644 --- a/_maps/RandomRuins/SpaceRuins/interdyne.dmm +++ b/_maps/RandomRuins/SpaceRuins/interdyne.dmm @@ -1020,7 +1020,7 @@ /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/interdyne) "PD" = ( -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/structure/table/reinforced/rglass, /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/interdyne) diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/cargodiselost.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/cargodiselost.dmm index 67bd69b7664213..269476f1c11589 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/cargodiselost.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/cargodiselost.dmm @@ -51,6 +51,7 @@ dir = 8 }, /obj/item/kirbyplants/random, +/obj/machinery/light_switch/directional/west, /turf/open/floor/iron/dark, /area/ruin/space/has_grav/cargodise_freighter/bridge) "aN" = ( @@ -331,6 +332,7 @@ /obj/effect/turf_decal/tile/blue/anticorner/contrasted{ dir = 8 }, +/obj/machinery/light_switch/directional/west, /turf/open/floor/iron/white, /area/ruin/space/has_grav/cargodise_freighter/trauma) "eC" = ( @@ -481,6 +483,7 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 }, +/obj/machinery/light_switch/directional/north, /turf/open/floor/wood/parquet, /area/ruin/space/has_grav/cargodise_freighter/bridge) "hr" = ( @@ -673,6 +676,11 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/ruin/space/has_grav/cargodise_freighter/cargo) +"kn" = ( +/obj/item/kirbyplants/random, +/obj/machinery/light_switch/directional/north, +/turf/open/floor/wood/parquet, +/area/ruin/space/has_grav/cargodise_freighter/quarters) "kt" = ( /obj/machinery/seed_extractor, /turf/open/floor/wood/tile, @@ -907,6 +915,9 @@ /obj/machinery/airalarm/directional/east, /obj/effect/mapping_helpers/airalarm/all_access, /obj/machinery/light/cold/directional/east, +/obj/structure/closet/crate, +/obj/item/mod/core, +/obj/item/mod/core, /turf/open/floor/iron/smooth, /area/ruin/space/has_grav/cargodise_freighter/utility) "oz" = ( @@ -929,6 +940,7 @@ /obj/effect/turf_decal/tile/brown/half/contrasted{ dir = 8 }, +/obj/structure/tank_dispenser/oxygen, /turf/open/floor/iron/dark, /area/ruin/space/has_grav/cargodise_freighter/mining) "oY" = ( @@ -1107,6 +1119,7 @@ /obj/effect/turf_decal/tile/yellow/anticorner/contrasted{ dir = 1 }, +/obj/machinery/light_switch/directional/north, /turf/open/floor/iron/dark, /area/ruin/space/has_grav/cargodise_freighter/cargo) "sJ" = ( @@ -1155,6 +1168,7 @@ /obj/item/circuitboard/machine/rtg/advanced, /obj/item/folded_navigation_gigabeacon, /obj/structure/cable, +/obj/item/circuitboard/computer/powermonitor, /turf/open/floor/plating, /area/ruin/space/has_grav/cargodise_freighter/utility) "ty" = ( @@ -1338,6 +1352,12 @@ amount = 25 }, /obj/item/stack/sheet/mineral/plasma/thirty, +/obj/item/stack/sheet/plastic/fifty, +/obj/item/stack/sheet/mineral/silver, +/obj/item/stack/sheet/mineral/silver, +/obj/item/stack/sheet/mineral/silver, +/obj/item/stack/sheet/mineral/silver, +/obj/item/stack/sheet/mineral/silver, /turf/open/floor/plating, /area/ruin/space/has_grav/cargodise_freighter/utility) "wT" = ( @@ -1384,6 +1404,16 @@ /obj/machinery/light/cold/directional/west, /turf/open/floor/wood/parquet, /area/ruin/space/has_grav/cargodise_freighter/kitchen) +"xy" = ( +/obj/effect/turf_decal/tile/yellow/anticorner{ + dir = 4 + }, +/obj/item/kirbyplants/random, +/obj/machinery/light/directional/east, +/turf/open/floor/iron/dark/smooth_corner{ + dir = 8 + }, +/area/ruin/space/has_grav/cargodise_freighter/primaryhall) "xC" = ( /obj/structure/bed/double, /obj/item/bedsheet/qm/double, @@ -1584,6 +1614,13 @@ }, /turf/open/floor/iron/white, /area/ruin/space/has_grav/cargodise_freighter/trauma) +"Au" = ( +/obj/effect/turf_decal/tile/brown/half/contrasted{ + dir = 8 + }, +/obj/machinery/light_switch/directional/west, +/turf/open/floor/iron/dark, +/area/ruin/space/has_grav/cargodise_freighter/mining) "Ay" = ( /obj/structure/table/wood, /obj/item/toy/cards/deck, @@ -1812,6 +1849,7 @@ "Et" = ( /obj/structure/cable, /obj/machinery/light/cold/directional/south, +/obj/machinery/light_switch/directional/west, /turf/open/floor/plating, /area/ruin/space/has_grav/cargodise_freighter/utility) "Ew" = ( @@ -2311,7 +2349,6 @@ /obj/structure/closet/crate/goldcrate, /obj/item/stack/sheet/mineral/plasma/five, /obj/item/stack/sheet/plasteel/twenty, -/obj/item/stack/sheet/plastic/five, /obj/item/stack/sheet/mineral/diamond, /obj/effect/spawner/random/entertainment/money_large, /obj/effect/spawner/random/entertainment/money_large, @@ -2380,6 +2417,11 @@ /obj/item/clothing/glasses/hud/security/sunglasses/gars/giga, /turf/open/floor/iron/dark, /area/ruin/space/has_grav/cargodise_freighter/cargo) +"Mu" = ( +/obj/structure/cable, +/obj/structure/reagent_dispensers/fueltank/large, +/turf/open/floor/plating, +/area/ruin/space/has_grav/cargodise_freighter/utility) "ME" = ( /turf/closed/wall/r_wall/syndicate, /area/ruin/space/has_grav/cargodise_freighter/hydroponics) @@ -2405,7 +2447,7 @@ /area/ruin/space/has_grav/cargodise_freighter/vault) "MZ" = ( /obj/structure/extinguisher_cabinet/directional/east, -/obj/machinery/light/cold/directional/east, +/obj/structure/sink/kitchen/directional/west, /turf/open/floor/iron/kitchen, /area/ruin/space/has_grav/cargodise_freighter/kitchen) "Ni" = ( @@ -2451,6 +2493,7 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 }, +/obj/machinery/light/directional/west, /turf/open/floor/iron/dark/smooth_half{ dir = 1 }, @@ -2662,7 +2705,7 @@ /obj/item/storage/organbox{ pixel_y = 6 }, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/effect/turf_decal/tile/blue/half/contrasted{ dir = 8 }, @@ -2830,6 +2873,7 @@ /area/ruin/space/has_grav/cargodise_freighter/primaryhall) "UD" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden, +/obj/structure/reagent_dispensers/watertank/high, /turf/open/floor/wood/tile, /area/ruin/space/has_grav/cargodise_freighter/hydroponics) "UH" = ( @@ -2887,6 +2931,7 @@ dir = 4 }, /mob/living/simple_animal/hostile/looter, +/obj/machinery/light_switch/directional/east, /turf/open/floor/iron/dark/smooth_half{ dir = 1 }, @@ -2991,6 +3036,7 @@ id = "freighterkitchen"; name = "Kitchen Shutters" }, +/obj/machinery/light/directional/south, /turf/open/floor/iron/kitchen, /area/ruin/space/has_grav/cargodise_freighter/kitchen) "WE" = ( @@ -3210,6 +3256,7 @@ /obj/effect/turf_decal/tile/yellow/anticorner{ dir = 8 }, +/obj/machinery/light/directional/west, /turf/open/floor/iron/dark/smooth_corner{ dir = 4 }, @@ -3224,6 +3271,7 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 }, +/obj/machinery/light_switch/directional/north, /turf/open/floor/iron/dark, /area/ruin/space/has_grav/cargodise_freighter/kitchen) "Zz" = ( @@ -3615,7 +3663,7 @@ SZ VL Ai is -hM +Mu NE Ar QU @@ -4398,7 +4446,7 @@ sc Sd pp cd -oV +Au oV tY Hv @@ -4840,7 +4888,7 @@ vh Jy vh vh -Zz +xy PW tV gm @@ -5215,7 +5263,7 @@ Do tN aK kX -Kt +kn qG St kz diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon2.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon2.dmm index f07ef7cd0ecc89..1897f962201ace 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon2.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon2.dmm @@ -144,7 +144,7 @@ dir = 8 }, /obj/structure/table/rolling, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/clothing/gloves/latex{ pixel_y = 10 }, @@ -7102,7 +7102,7 @@ dir = 4 }, /obj/structure/table/rolling, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/clothing/gloves/latex{ pixel_y = 10 }, diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon3.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon3.dmm index 6a60c4b19419c9..ae5484c9891da9 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon3.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon3.dmm @@ -118,7 +118,7 @@ dir = 8 }, /obj/structure/table/rolling, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/effect/decal/cleanable/dirt, /obj/item/clothing/gloves/latex{ pixel_y = 10 @@ -6734,7 +6734,7 @@ dir = 4 }, /obj/structure/table/rolling, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/effect/decal/cleanable/dirt, /obj/item/clothing/gloves/latex{ pixel_y = 10 diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon4.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon4.dmm index fc02dd8b824c62..6e42ed738cdc29 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon4.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon4.dmm @@ -98,7 +98,7 @@ dir = 8 }, /obj/structure/table/rolling, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/clothing/gloves/latex{ pixel_y = 10 }, @@ -5903,7 +5903,7 @@ dir = 4 }, /obj/structure/table/rolling, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/clothing/gloves/latex{ pixel_y = 10 }, diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon5.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon5.dmm index 3cf8398c5edb58..eef26fbf6d9b78 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon5.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon/defcon5.dmm @@ -114,7 +114,7 @@ dir = 8 }, /obj/structure/table/rolling, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/clothing/gloves/latex{ pixel_y = 10 }, @@ -6448,7 +6448,7 @@ dir = 4 }, /obj/structure/table/rolling, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/clothing/gloves/latex{ pixel_y = 10 }, diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/scrapheap.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/scrapheap.dmm index b85062c50a0539..3f65766b5affa8 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/scrapheap.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/scrapheap.dmm @@ -1125,7 +1125,7 @@ /area/ruin/space/has_grav/powered/skyrat/scrapheap) "Ej" = ( /obj/structure/rack/shelf, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /turf/open/floor/iron/white, /area/ruin/space/has_grav/powered/skyrat/scrapheap) "El" = ( diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/wreckedhomestead.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/wreckedhomestead.dmm index a93290fea46329..ceb070858fa0ba 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/wreckedhomestead.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/wreckedhomestead.dmm @@ -76,7 +76,7 @@ /area/ruin/unpowered) "mP" = ( /obj/structure/table/reinforced, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/reagent_containers/cup/beaker/cryoxadone, /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/hidden{ dir = 5 diff --git a/_maps/RandomRuins/SpaceRuins/spacehotel_skyrat.dmm b/_maps/RandomRuins/SpaceRuins/spacehotel_skyrat.dmm index 91193428a6ba7a..43334c57b9b3a5 100644 --- a/_maps/RandomRuins/SpaceRuins/spacehotel_skyrat.dmm +++ b/_maps/RandomRuins/SpaceRuins/spacehotel_skyrat.dmm @@ -6958,7 +6958,7 @@ /area/ruin/space/has_grav/hotel) "Ps" = ( /obj/structure/table, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /turf/open/floor/iron/showroomfloor, /area/ruin/space/has_grav/hotel) "Pw" = ( @@ -7837,7 +7837,9 @@ dir = 4; id = "garbage" }, -/obj/machinery/recycler, +/obj/machinery/recycler{ + dir = 8 + }, /turf/open/floor/plating, /area/ruin/space/has_grav/hotel/workroom) "VQ" = ( diff --git a/_maps/RandomRuins/SpaceRuins/the_outlet.dmm b/_maps/RandomRuins/SpaceRuins/the_outlet.dmm index 8f91cc3fee2f16..6b0f009dcc6fe9 100644 --- a/_maps/RandomRuins/SpaceRuins/the_outlet.dmm +++ b/_maps/RandomRuins/SpaceRuins/the_outlet.dmm @@ -704,7 +704,7 @@ /area/ruin/space/has_grav/the_outlet/employeesection) "rF" = ( /obj/structure/table/reinforced/rglass, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/reagent_containers/syringe/lethal/execution, /turf/open/floor/iron/freezer, /area/ruin/space/has_grav/the_outlet/researchrooms) diff --git a/_maps/RandomZLevels/blackmesa.dmm b/_maps/RandomZLevels/blackmesa.dmm index 122770f8cf78a4..b9887279a16d02 100644 --- a/_maps/RandomZLevels/blackmesa.dmm +++ b/_maps/RandomZLevels/blackmesa.dmm @@ -14741,7 +14741,7 @@ /area/awaymission/black_mesa/resonant_chamber) "vEa" = ( /obj/structure/table, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /turf/open/floor/iron/smooth_large, /area/awaymission/black_mesa/deep_sci_medbay) "vEe" = ( diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index 01ecb68c703c39..90ca0b048802db 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -916,6 +916,16 @@ /obj/machinery/door/firedoor, /turf/open/floor/iron/textured_half, /area/station/service/cafeteria) +"asZ" = ( +/obj/structure/disposalpipe/trunk, +/obj/structure/disposaloutlet{ + dir = 1 + }, +/obj/structure/window/reinforced/spawner/directional/south, +/obj/structure/window/reinforced/spawner/directional/east, +/obj/effect/turf_decal/stripes/box, +/turf/open/floor/plating, +/area/station/service/janitor) "ata" = ( /obj/structure/flora/bush/flowers_yw/style_random, /obj/machinery/light/small/directional/west, @@ -1683,7 +1693,6 @@ dir = 4 }, /obj/effect/mapping_helpers/airlock/access/any/science/maintenance, -/obj/effect/mapping_helpers/airlock/access/any/science/maintenance, /obj/effect/mapping_helpers/airlock/unres{ dir = 4 }, @@ -3201,19 +3210,11 @@ /turf/open/floor/iron/white, /area/station/science/robotics/augments) "boX" = ( -/obj/structure/table, -/obj/item/clothing/gloves/color/orange{ - pixel_x = 4; - pixel_y = -2 - }, -/obj/item/stack/tile/iron/base{ - pixel_y = 18 - }, -/obj/item/key/janitor{ - pixel_x = -3; - pixel_y = 6 +/obj/machinery/conveyor{ + dir = 4; + id = "garbage" }, -/turf/open/floor/iron/white/small, +/turf/open/floor/plating, /area/station/service/janitor) "boY" = ( /obj/machinery/atmospherics/pipe/smart/simple/purple/visible, @@ -3730,10 +3731,11 @@ "bzn" = ( /obj/structure/cable, /obj/effect/turf_decal/tile/yellow/opposingcorners, -/obj/item/stack/sheet/plasteel/fifty, /obj/machinery/firealarm/directional/east, /obj/structure/rack, -/obj/item/stock_parts/cell/emproof, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/signlang_radio, +/obj/item/mod/module/thermal_regulator, /turf/open/floor/iron, /area/station/engineering/atmospherics_engine) "bzs" = ( @@ -5933,6 +5935,16 @@ /obj/machinery/air_sensor/incinerator_tank, /turf/open/floor/engine, /area/station/maintenance/disposal/incinerator) +"cqS" = ( +/obj/machinery/conveyor{ + dir = 4; + id = "garbage" + }, +/obj/effect/spawner/random/trash/garbage{ + spawn_loot_count = 3 + }, +/turf/open/floor/plating, +/area/station/service/janitor) "crm" = ( /obj/machinery/atmospherics/pipe/smart/simple/dark/visible{ dir = 4 @@ -7676,7 +7688,11 @@ /obj/item/reagent_containers/cup/bucket, /obj/item/mop, /obj/structure/sink/kitchen/directional/east, -/obj/machinery/airalarm/directional/west, +/obj/machinery/airalarm/directional/south, +/obj/machinery/button/door/directional/west{ + pixel_y = 8; + id = "custodialshutters" + }, /turf/open/floor/iron/white/small, /area/station/service/janitor) "cZM" = ( @@ -9534,14 +9550,14 @@ name = "Privacy Bolts"; normaldoorcontrol = 1; pixel_x = -32; - pixel_y = 26; + pixel_y = 35; specialfunctions = 4 }, /obj/machinery/button/door/directional/north{ id = "com_guest2"; name = "Privacy Shutters"; pixel_x = -32; - pixel_y = 35 + pixel_y = 26 }, /turf/open/floor/wood/large, /area/station/command/corporate_suite) @@ -10277,6 +10293,13 @@ dir = 9 }, /area/station/engineering/atmos) +"dXO" = ( +/obj/effect/spawner/structure/window/reinforced/tinted, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/service/janitor) "dXT" = ( /obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ dir = 4 @@ -12243,7 +12266,6 @@ }, /obj/effect/turf_decal/tile/neutral, /obj/effect/landmark/navigate_destination/eva, -/obj/machinery/status_display/ai/directional/east, /turf/open/floor/iron, /area/station/hallway/primary/fore) "eFV" = ( @@ -13526,6 +13548,13 @@ /obj/effect/turf_decal/sand/plating, /turf/open/floor/plating/airless, /area/space/nearstation) +"ffD" = ( +/obj/machinery/conveyor/inverted{ + dir = 10; + id = "garbage" + }, +/turf/open/floor/plating, +/area/station/service/janitor) "ffO" = ( /obj/machinery/atmospherics/pipe/smart/simple/green/visible, /turf/open/floor/plating/airless, @@ -13767,6 +13796,7 @@ /obj/item/mod/module/thermal_regulator, /obj/effect/turf_decal/bot_white, /obj/machinery/status_display/ai/directional/south, +/obj/item/mod/module/signlang_radio, /turf/open/floor/iron/small, /area/station/medical/storage) "fkt" = ( @@ -16643,16 +16673,10 @@ /turf/open/floor/circuit/green, /area/station/ai_monitored/command/nuke_storage) "ghW" = ( -/obj/structure/disposalpipe/trunk{ - dir = 8 - }, -/obj/structure/window/reinforced/spawner/directional/east, -/obj/machinery/disposal/bin, -/obj/effect/turf_decal/bot, -/obj/effect/turf_decal/stripes/end{ - dir = 4 +/obj/machinery/mineral/stacking_machine{ + input_dir = 2 }, -/turf/open/floor/iron/white/small, +/turf/open/floor/plating, /area/station/service/janitor) "gic" = ( /obj/effect/turf_decal/siding/blue{ @@ -19665,6 +19689,10 @@ pixel_x = 20; pixel_y = 11 }, +/obj/item/mod/module/signlang_radio{ + pixel_y = 2; + pixel_x = -2 + }, /turf/open/floor/iron/small, /area/station/security/office) "hiV" = ( @@ -21655,19 +21683,12 @@ /turf/open/floor/iron, /area/station/hallway/primary/fore) "hTW" = ( +/obj/structure/window/reinforced/spawner/directional/north, +/obj/vehicle/ridden/janicart, /obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/machinery/conveyor{ - dir = 1; - id = "garbage"; - name = "trash belt" + dir = 1 }, -/obj/machinery/recycler, -/turf/open/floor/plating, +/turf/open/floor/iron/white/small, /area/station/service/janitor) "hTZ" = ( /obj/structure/chair/sofa/bench/left{ @@ -23346,11 +23367,14 @@ "ixP" = ( /obj/structure/table, /obj/machinery/firealarm/directional/south, +/obj/item/restraints/legcuffs/beartrap, +/obj/item/stack/tile/iron/base{ + pixel_y = 18 + }, /obj/item/grenade/chem_grenade/cleaner{ pixel_x = -7; pixel_y = 12 }, -/obj/item/restraints/legcuffs/beartrap, /turf/open/floor/iron, /area/station/service/janitor) "ixU" = ( @@ -24774,7 +24798,7 @@ /obj/structure/railing{ dir = 5 }, -/obj/machinery/atmospherics/components/unary/passive_vent/layer2{ +/obj/machinery/atmospherics/components/unary/outlet_injector/layer2{ dir = 8 }, /turf/open/space/basic, @@ -25861,6 +25885,9 @@ }, /obj/structure/table, /obj/effect/decal/cleanable/dirt, +/obj/item/stack/package_wrap{ + pixel_y = 5 + }, /obj/item/storage/box/matches, /turf/open/floor/iron, /area/station/cargo/sorting) @@ -27132,7 +27159,8 @@ /area/station/cargo/warehouse) "jPq" = ( /obj/structure/disposalpipe/segment, -/turf/closed/wall, +/obj/effect/spawner/structure/window/reinforced/tinted, +/turf/open/floor/plating, /area/station/maintenance/fore/greater) "jQo" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -27606,10 +27634,7 @@ /turf/open/floor/plating, /area/station/maintenance/department/prison) "jZK" = ( -/obj/structure/disposalpipe/segment{ - dir = 10 - }, -/obj/effect/decal/cleanable/dirt, +/obj/structure/disposalpipe/junction/yjunction, /turf/open/floor/iron, /area/station/maintenance/hallway/abandoned_command) "jZL" = ( @@ -27636,16 +27661,16 @@ /turf/open/floor/plating, /area/station/maintenance/department/engine) "kam" = ( -/obj/structure/cable, -/obj/structure/table, -/obj/machinery/power/apc/auto_name/directional/north, -/obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/cobweb, -/obj/item/storage/box/mousetraps{ - pixel_x = -3; - pixel_y = 8 +/obj/machinery/disposal/delivery_chute{ + dir = 4 }, -/turf/open/floor/iron/white/small, +/obj/structure/window/reinforced/spawner/directional/south, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/box, +/turf/open/floor/plating, /area/station/service/janitor) "kar" = ( /obj/structure/disposalpipe/segment, @@ -27686,11 +27711,8 @@ /obj/structure/disposalpipe/trunk{ dir = 1 }, -/obj/effect/turf_decal/stripes/end{ - dir = 1 - }, /obj/machinery/disposal/delivery_chute, -/obj/structure/sign/poster/official/random/directional/north, +/obj/effect/turf_decal/stripes/box, /turf/open/floor/plating, /area/station/service/janitor) "kaI" = ( @@ -27723,22 +27745,6 @@ /obj/structure/broken_flooring/corner/directional/south, /turf/open/floor/plating, /area/station/maintenance/hallway/abandoned_recreation) -"kbc" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/machinery/door/window/left/directional/east{ - name = "Trash Chute"; - req_access = list("janitor") - }, -/obj/machinery/conveyor_switch/oneway{ - dir = 4; - id = "garbage"; - name = "trash chute" - }, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/white/small, -/area/station/service/janitor) "kbE" = ( /obj/effect/decal/cleanable/blood/gibs/body, /obj/machinery/light/small/broken/directional/north, @@ -28106,10 +28112,8 @@ "kjh" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/stripes/corner, +/obj/effect/mapping_helpers/broken_floor, /turf/open/floor/iron, /area/station/maintenance/hallway/abandoned_command) "kjl" = ( @@ -28217,9 +28221,8 @@ "kkD" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/light/small/directional/east, /obj/effect/mapping_helpers/broken_floor, -/obj/effect/turf_decal/stripes/corner, -/obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/maintenance/hallway/abandoned_command) "kkL" = ( @@ -29162,16 +29165,24 @@ /turf/open/floor/plating, /area/station/maintenance/fore/lesser) "kCN" = ( -/obj/machinery/holopad, /obj/effect/decal/cleanable/dirt, +/obj/machinery/door/window/left/directional/north{ + name = "Trash Chute" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 9 + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron/white/small, /area/station/service/janitor) "kCP" = ( /obj/effect/turf_decal/stripes/line{ - dir = 5 + dir = 1 }, -/obj/structure/window/reinforced/spawner/directional/east, /obj/structure/mop_bucket/janitorialcart, +/obj/machinery/door/window/left/directional/north{ + name = "Trash Chute" + }, /turf/open/floor/iron/white/small, /area/station/service/janitor) "kCT" = ( @@ -30554,27 +30565,25 @@ /turf/open/floor/iron/small, /area/station/engineering/atmos) "lcW" = ( -/obj/structure/disposalpipe/segment{ - dir = 6 +/obj/structure/disposalpipe/sorting/mail{ + dir = 1 }, +/obj/effect/mapping_helpers/mail_sorting/service/janitor_closet, +/obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/white/small, /area/station/service/janitor) "lde" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 6 +/obj/item/radio/intercom/directional/south, +/obj/structure/disposalpipe/trunk{ + dir = 8 }, -/obj/effect/turf_decal/stripes/corner{ +/obj/structure/disposaloutlet{ dir = 1 }, -/obj/machinery/conveyor{ - dir = 1; - id = "garbage"; - name = "trash belt" - }, -/obj/item/radio/intercom/directional/south, -/turf/open/floor/plating, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/stripes/box, +/turf/open/floor/iron/white/small, /area/station/service/janitor) "ldo" = ( /obj/structure/chair/comfy/brown{ @@ -31881,6 +31890,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/curtain/cloth, /obj/effect/decal/cleanable/dirt, +/obj/structure/cable, /turf/open/floor/iron/textured_half, /area/station/service/janitor) "lyQ" = ( @@ -33940,14 +33950,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/department/medical/central) -"mhW" = ( -/obj/structure/cable, -/obj/machinery/door/airlock{ - name = "Custodial Closet Maintenance" - }, -/obj/effect/mapping_helpers/airlock/access/any/service/janitor, -/turf/open/floor/plating, -/area/station/maintenance/fore/greater) "mhY" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -35119,15 +35121,15 @@ /turf/open/floor/iron/dark/smooth_corner, /area/station/maintenance/starboard/greater) "mEy" = ( -/obj/structure/disposalpipe/segment{ - dir = 6 +/obj/machinery/conveyor{ + dir = 8; + id = "garbage" }, -/obj/structure/cable, -/obj/effect/turf_decal/stripes/line{ - dir = 1 +/obj/machinery/light/cold/directional/north, +/obj/machinery/mineral/stacking_unit_console{ + pixel_y = 27 }, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/white/small, +/turf/open/floor/plating, /area/station/service/janitor) "mEB" = ( /obj/effect/spawner/structure/window, @@ -36375,9 +36377,12 @@ /turf/open/floor/wood, /area/station/maintenance/starboard/greater) "ncf" = ( -/obj/structure/disposalpipe/segment, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/white/small, +/obj/machinery/recycler, +/obj/machinery/conveyor{ + dir = 4; + id = "garbage" + }, +/turf/open/floor/plating, /area/station/service/janitor) "ncl" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -37895,20 +37900,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white, /area/station/science/cytology) -"nEJ" = ( -/obj/effect/turf_decal/delivery, -/obj/machinery/door/poddoor/shutters{ - dir = 8; - id = "custodialshutters"; - name = "Custodial Closet Shutters" - }, -/obj/machinery/button/door/directional/north{ - id = "custodialshutters"; - name = "shutters control"; - pixel_x = 8 - }, -/turf/open/floor/iron/large, -/area/station/service/janitor) "nEY" = ( /obj/structure/closet/firecloset, /obj/effect/decal/cleanable/dirt, @@ -37957,8 +37948,16 @@ /turf/open/floor/iron, /area/station/maintenance/department/medical/central) "nFA" = ( -/obj/structure/disposalpipe/segment, -/obj/effect/landmark/start/janitor, +/obj/structure/window/reinforced/spawner/directional/north, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/conveyor_switch/oneway{ + dir = 4; + id = "garbage"; + name = "trash chute" + }, /turf/open/floor/iron/white/small, /area/station/service/janitor) "nFD" = ( @@ -38221,7 +38220,9 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/mapping_helpers/broken_floor, -/obj/machinery/light/small/directional/east, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /turf/open/floor/iron, /area/station/maintenance/hallway/abandoned_command) "nJU" = ( @@ -39660,14 +39661,19 @@ /turf/open/floor/iron/white/small, /area/station/medical/cryo) "onR" = ( -/obj/structure/disposalpipe/sorting/mail/flip{ +/obj/structure/disposalpipe/segment{ dir = 4 }, -/obj/effect/turf_decal/delivery/white{ - color = "#52B4E9" +/obj/structure/table, +/obj/item/clothing/gloves/color/orange{ + pixel_x = 4; + pixel_y = -2 }, -/obj/vehicle/ridden/janicart, -/obj/effect/mapping_helpers/mail_sorting/service/janitor_closet, +/obj/item/key/janitor{ + pixel_x = -3; + pixel_y = 6 + }, +/obj/structure/cable, /turf/open/floor/iron/white/small, /area/station/service/janitor) "onX" = ( @@ -41415,7 +41421,7 @@ /obj/machinery/door/airlock{ name = "Maintenance" }, -/obj/effect/mapping_helpers/airlock/access/any/service/maintenance, +/obj/effect/mapping_helpers/airlock/access/any/command/maintenance, /turf/open/floor/plating, /area/station/maintenance/hallway/abandoned_command) "oWr" = ( @@ -41924,6 +41930,8 @@ }, /obj/effect/mapping_helpers/airlock/abandoned, /obj/structure/barricade/wooden/crude, +/obj/effect/mapping_helpers/airlock/locked, +/obj/effect/mapping_helpers/airlock/welded, /turf/open/floor/iron/textured_half{ dir = 8 }, @@ -42046,6 +42054,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/start/janitor, +/obj/structure/cable, /turf/open/floor/iron, /area/station/service/janitor) "pil" = ( @@ -42167,6 +42176,13 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/recreation) +"pke" = ( +/obj/machinery/door/airlock/centcom{ + name = "Disposals Access:" + }, +/obj/effect/mapping_helpers/airlock/access/any/service/janitor, +/turf/open/floor/plating, +/area/station/maintenance/fore/greater) "pkh" = ( /obj/effect/spawner/random/decoration/showcase, /obj/structure/window/spawner/directional/south, @@ -42904,6 +42920,7 @@ /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/decal/cleanable/dirt, +/obj/structure/cable, /turf/open/floor/iron, /area/station/service/janitor) "pwA" = ( @@ -44327,7 +44344,7 @@ /area/station/maintenance/port/lesser) "pTr" = ( /obj/structure/table, -/obj/item/surgery_tray{ +/obj/item/surgery_tray/full{ pixel_y = -5 }, /obj/item/wirecutters{ @@ -44578,6 +44595,7 @@ /obj/machinery/door/airlock/centcom{ name = "Custodial Closet" }, +/obj/structure/cable, /turf/open/floor/iron/textured_half, /area/station/service/janitor) "pWZ" = ( @@ -48811,18 +48829,9 @@ /turf/open/floor/plating, /area/station/maintenance/department/science/xenobiology) "roB" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/machinery/conveyor{ - dir = 1; - id = "garbage"; - name = "trash belt" - }, -/turf/open/floor/plating, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/delivery, +/turf/open/floor/iron/white/small, /area/station/service/janitor) "roC" = ( /obj/structure/cable, @@ -51183,20 +51192,26 @@ /turf/open/floor/iron/white/small, /area/station/service/hydroponics) "saD" = ( -/obj/structure/disposalpipe/trunk{ - dir = 8 +/obj/machinery/camera/directional/south, +/obj/machinery/light/small/directional/south, +/obj/machinery/power/apc/auto_name/directional/south, +/obj/structure/disposalpipe/segment{ + dir = 4 }, -/obj/effect/turf_decal/stripes/end{ - dir = 8 +/obj/structure/table, +/obj/item/storage/box/mousetraps{ + pixel_x = -3; + pixel_y = 8 }, -/obj/structure/disposaloutlet{ - dir = 4 +/obj/item/restraints/legcuffs/beartrap{ + pixel_x = 8; + pixel_y = 13 }, -/obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/machinery/camera/directional/south, -/obj/machinery/light/small/directional/south, -/turf/open/floor/plating, +/obj/item/flashlight{ + pixel_y = 4 + }, +/obj/structure/cable, +/turf/open/floor/iron/white/small, /area/station/service/janitor) "saY" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -55532,10 +55547,6 @@ /obj/effect/mapping_helpers/airlock/access/all/command/captain, /turf/open/floor/plating, /area/station/maintenance/hallway/abandoned_command) -"tyv" = ( -/obj/machinery/lapvend, -/turf/open/floor/iron/white, -/area/station/hallway/primary/starboard) "tyx" = ( /obj/structure/disposalpipe/segment{ dir = 6 @@ -55605,21 +55616,11 @@ /turf/open/floor/plating, /area/station/science/lobby) "tzD" = ( -/obj/structure/cable, -/obj/effect/turf_decal/stripes/corner{ - dir = 4 - }, -/obj/structure/table, -/obj/item/restraints/legcuffs/beartrap{ - pixel_x = 8; - pixel_y = 13 - }, -/obj/item/flashlight{ - pixel_y = 4 +/obj/machinery/conveyor{ + dir = 8; + id = "garbage" }, -/obj/machinery/light/cold/directional/north, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/white/small, +/turf/open/floor/plating, /area/station/service/janitor) "tzF" = ( /obj/structure/cable, @@ -57793,13 +57794,6 @@ /obj/effect/turf_decal/trimline/neutral/line, /turf/open/floor/iron, /area/station/hallway/primary/starboard) -"ujl" = ( -/obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 8 - }, -/turf/open/floor/iron/white/small, -/area/station/service/janitor) "ujq" = ( /obj/structure/disposalpipe/segment, /obj/structure/closet/emcloset, @@ -57888,6 +57882,12 @@ /area/station/security/checkpoint/science) "ukW" = ( /obj/effect/decal/cleanable/dirt, +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, /turf/open/floor/iron/white/small, /area/station/service/janitor) "ulb" = ( @@ -57920,18 +57920,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/circuit, /area/station/tcommsat/server) -"ulM" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/machinery/mineral/stacking_machine{ - input_dir = 2 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/turf/open/floor/iron/white/small, -/area/station/service/janitor) "ulO" = ( /turf/open/floor/plating, /area/station/maintenance/department/medical/central) @@ -64051,8 +64039,14 @@ /turf/open/floor/grass, /area/station/service/hydroponics/garden/monastery) "wjM" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/decal/cleanable/dirt, +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white/small, /area/station/service/janitor) "wjY" = ( @@ -69214,16 +69208,6 @@ }, /turf/open/floor/iron/terracotta/small, /area/station/security/checkpoint/escape) -"xHm" = ( -/obj/structure/cable, -/obj/effect/spawner/structure/window/reinforced, -/obj/machinery/door/poddoor/shutters/preopen{ - dir = 8; - id = "com_guest"; - name = "Privacy Shutter" - }, -/turf/open/floor/plating, -/area/station/command/corporate_suite) "xHv" = ( /obj/structure/disposalpipe/trunk{ dir = 8 @@ -70730,7 +70714,7 @@ /obj/effect/turf_decal/siding/white, /obj/machinery/light/small/directional/south, /obj/structure/table/reinforced, -/obj/item/surgery_tray/morgue, +/obj/item/surgery_tray/full/morgue, /turf/open/floor/iron/small, /area/station/medical/morgue) "yaL" = ( @@ -98165,7 +98149,7 @@ qjy vPP otX hei -xHm +hei vPP hxJ jVe @@ -103830,9 +103814,9 @@ sOs xmO lKn nFW +dXO sRL sRL -nEJ nVX sRL sRL @@ -104089,10 +104073,10 @@ sHe nFW kam boX -kBH +asZ ukW cZL -xVV +sRL dCH ixP sRL @@ -104343,9 +104327,9 @@ kCW xID xmO sHs -nFW +pke tzD -ukW +cqS kCN wjM lcW @@ -104600,11 +104584,11 @@ rIJ rAG xmO sHe -mhW +nFW mEy ncf nFA -ujl +kBH onR xVV lOt @@ -104859,9 +104843,9 @@ xmO qzO nFW ghW -ulM +boX kCP -kbc +kBH saD sRL sRL @@ -105116,7 +105100,7 @@ sJR sIA jPq kaF -roB +ffD hTW roB lde @@ -105372,10 +105356,10 @@ xmO jsn sIS nFW +sRL +sRL xVV -xVV -xVV -xVV +sRL xVV sRL bFg @@ -111823,7 +111807,7 @@ rVX stP wbu tbD -tyv +ygu xdc ugC xSZ diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index b3ab8ca3b8e6cd..15c9aae2b719b6 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -2533,7 +2533,6 @@ /turf/open/space, /area/space/nearstation) "aFs" = ( -/obj/machinery/lapvend, /obj/effect/turf_decal/trimline/blue/filled/warning{ dir = 4 }, @@ -8180,14 +8179,14 @@ /turf/open/floor/iron, /area/station/commons/fitness/recreation) "bWw" = ( -/obj/machinery/button/flasher{ - id = "Cell 6"; - name = "Prisoner Flash"; - pixel_x = -25 - }, /obj/effect/turf_decal/tile/red{ dir = 4 }, +/obj/machinery/status_display/door_timer{ + id = "Isolation_Cell"; + name = "Isolation Cell"; + pixel_x = -32 + }, /turf/open/floor/iron, /area/station/security/execution/transfer) "bWD" = ( @@ -9197,6 +9196,12 @@ }, /turf/open/floor/wood, /area/station/medical/psychology) +"ckB" = ( +/obj/structure/closet/secure_closet/hop, +/obj/item/clothing/suit/costume/wellworn_shirt/graphic/ian, +/obj/item/bedsheet/ian, +/turf/open/floor/iron/grimy, +/area/station/command/heads_quarters/hop) "ckC" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -15840,7 +15845,7 @@ /area/station/cargo/lobby) "dRQ" = ( /obj/structure/table/glass, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/structure/window/reinforced/spawner/directional/west, /obj/item/clothing/gloves/latex, /obj/item/clothing/suit/apron/surgical, @@ -17313,7 +17318,9 @@ dir = 4; id = "garbage" }, -/obj/machinery/recycler, +/obj/machinery/recycler{ + dir = 8 + }, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line, /turf/open/floor/plating, @@ -23592,6 +23599,7 @@ dir = 5 }, /obj/item/radio/intercom/directional/south, +/obj/item/mod/module/signlang_radio, /turf/open/floor/iron/dark, /area/station/security/office) "fQF" = ( @@ -28117,7 +28125,7 @@ /area/station/medical/cryo) "gTH" = ( /obj/machinery/flasher/directional/south{ - id = "Cell 6" + id = "Isolation_Cell" }, /obj/machinery/light/small/broken/directional/south, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -52502,7 +52510,7 @@ dir = 4 }, /obj/structure/table/reinforced, -/obj/item/surgery_tray/morgue, +/obj/item/surgery_tray/full/morgue, /obj/effect/turf_decal/tile/dark_blue/half/contrasted{ dir = 4 }, @@ -61088,6 +61096,7 @@ /obj/machinery/power/apc/auto_name/directional/east, /obj/item/mod/module/tether, /obj/item/mod/module/tether, +/obj/item/stack/sheet/plasteel/fifty, /turf/open/floor/iron, /area/station/engineering/storage) "ptC" = ( @@ -77234,7 +77243,7 @@ /area/station/engineering/atmos) "tsx" = ( /obj/structure/table/glass, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/clothing/gloves/latex, /obj/item/clothing/suit/apron/surgical, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -78406,7 +78415,6 @@ /area/station/medical/morgue) "tGm" = ( /obj/structure/table/reinforced, -/obj/item/stack/sheet/plasteel/fifty, /obj/item/stack/sheet/rglass{ amount = 50; pixel_x = 2; @@ -78421,6 +78429,7 @@ /obj/item/mod/module/plasma_stabilizer, /obj/item/mod/module/thermal_regulator, /obj/item/mod/module/magboot, +/obj/item/mod/module/signlang_radio, /turf/open/floor/iron, /area/station/engineering/storage) "tGq" = ( @@ -93500,6 +93509,7 @@ dir = 1 }, /obj/machinery/digital_clock/directional/south, +/obj/item/mod/module/signlang_radio, /turf/open/floor/iron, /area/station/medical/storage) "xtZ" = ( @@ -95224,12 +95234,6 @@ "xPc" = ( /turf/closed/wall, /area/station/medical/virology) -"xPe" = ( -/obj/structure/closet/secure_closet/hop, -/obj/item/clothing/suit/costume/wellworn_shirt/graphic/ian, -/obj/item/bedsheet/ian, -/turf/open/floor/iron/grimy, -/area/station/command/heads_quarters/hop) "xPf" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -132136,7 +132140,7 @@ pRS pRS bLl kXb -xPe +ckB pRS oHJ qdA diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 5e1a887d1676c8..f3ff89fcc80d8d 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -789,6 +789,14 @@ /obj/machinery/light/floor, /turf/open/floor/iron, /area/station/command/bridge) +"aol" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/disposalpipe/segment, +/obj/machinery/firealarm/directional/east, +/turf/open/floor/iron, +/area/station/command/heads_quarters/hop) "aoo" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -5050,12 +5058,13 @@ /obj/item/clothing/gloves/color/yellow, /obj/structure/cable, /obj/item/mod/module/plasma_stabilizer, -/obj/item/mod/module/thermal_regulator, /obj/item/stock_parts/cell/emproof{ pixel_x = -4; pixel_y = -1 }, /obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/item/mod/module/signlang_radio, +/obj/item/mod/module/thermal_regulator, /turf/open/floor/iron/dark, /area/station/engineering/engine_smes) "bAR" = ( @@ -10855,7 +10864,7 @@ pixel_x = -4; pixel_y = 3 }, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/effect/turf_decal/tile/blue/half/contrasted{ dir = 1 }, @@ -13337,7 +13346,7 @@ network = list("ss13","medbay"); pixel_x = 22 }, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/effect/turf_decal/tile/blue/half/contrasted{ dir = 1 }, @@ -13613,7 +13622,9 @@ }, /area/icemoon/underground/explored) "ebC" = ( -/obj/machinery/recycler, +/obj/machinery/recycler{ + dir = 8 + }, /obj/machinery/conveyor{ dir = 4; id = "garbage" @@ -15534,13 +15545,6 @@ /obj/item/clothing/under/costume/jabroni, /turf/open/floor/iron, /area/station/maintenance/starboard/fore) -"eHK" = ( -/obj/item/radio/intercom/directional/south, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/iron/smooth, -/area/station/security/execution/transfer) "eHT" = ( /obj/structure/cable, /obj/effect/spawner/random/structure/steam_vent, @@ -18655,7 +18659,6 @@ "fJG" = ( /obj/structure/rack, /obj/item/hand_labeler, -/obj/item/hand_labeler, /obj/structure/cable, /obj/effect/turf_decal/tile/red, /turf/open/floor/iron/textured, @@ -18709,6 +18712,7 @@ /obj/effect/turf_decal/tile/neutral/half/contrasted{ dir = 4 }, +/obj/machinery/firealarm/directional/north, /turf/open/floor/iron/dark/side{ dir = 4 }, @@ -19200,6 +19204,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/disposalpipe/segment, /obj/effect/mapping_helpers/airlock/access/all/command/general, +/obj/machinery/door/firedoor, /turf/open/floor/wood, /area/station/command/meeting_room) "fTo" = ( @@ -25451,6 +25456,7 @@ id = "medsecprivacy"; name = "Privacy Shutters" }, +/obj/machinery/door/firedoor, /turf/open/floor/plating, /area/station/security/checkpoint/medical) "hSF" = ( @@ -26315,6 +26321,11 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 }, +/obj/machinery/status_display/door_timer{ + id = "Isolation_Cell"; + name = "Isolation Cell"; + pixel_x = -32 + }, /turf/open/floor/iron/smooth, /area/station/security/execution/transfer) "ihG" = ( @@ -26537,6 +26548,7 @@ }, /obj/effect/mapping_helpers/airlock/access/all/medical/general, /obj/effect/turf_decal/tile/blue/full, +/obj/machinery/door/firedoor, /turf/open/floor/iron/large, /area/station/maintenance/aft/greater) "ikz" = ( @@ -28028,6 +28040,7 @@ /obj/effect/mapping_helpers/airlock/unres, /obj/effect/mapping_helpers/airlock/access/all/medical/general, /obj/effect/turf_decal/tile/blue/full, +/obj/machinery/door/firedoor, /turf/open/floor/iron/large, /area/station/medical/medbay/lobby) "iIF" = ( @@ -30465,6 +30478,10 @@ /obj/structure/cable, /turf/open/floor/iron/white, /area/station/medical/storage) +"jyg" = ( +/obj/machinery/firealarm/directional/north, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "jyh" = ( /obj/structure/table/wood, /obj/effect/turf_decal/siding/wood{ @@ -34808,6 +34825,7 @@ /obj/item/mod/module/plasma_stabilizer, /obj/item/mod/module/thermal_regulator, /obj/effect/turf_decal/tile/blue/full, +/obj/item/mod/module/signlang_radio, /turf/open/floor/iron/dark/smooth_large, /area/station/medical/storage) "kKa" = ( @@ -40386,7 +40404,6 @@ }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/door/firedoor, /obj/structure/cable, /obj/effect/mapping_helpers/airlock/access/all/security/general, /turf/open/floor/iron/dark, @@ -45964,7 +45981,7 @@ "oiv" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/structure/table/reinforced, -/obj/item/surgery_tray/morgue, +/obj/item/surgery_tray/full/morgue, /turf/open/floor/iron/dark, /area/station/medical/morgue) "oiy" = ( @@ -47315,6 +47332,9 @@ pixel_y = 9 }, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/obj/item/radio/intercom/directional/east{ + pixel_y = -6 + }, /turf/open/floor/iron/smooth, /area/station/security/execution/transfer) "oBp" = ( @@ -51215,6 +51235,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/disposalpipe/segment, /obj/effect/mapping_helpers/airlock/access/all/command/hop, +/obj/machinery/door/firedoor, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) "pJQ" = ( @@ -53423,6 +53444,7 @@ /obj/machinery/door/window/left/directional/north{ name = "Armory Desk" }, +/obj/item/hand_labeler, /turf/open/floor/iron, /area/station/ai_monitored/security/armory/upper) "quB" = ( @@ -57026,8 +57048,9 @@ "rzr" = ( /obj/structure/table, /obj/item/mod/module/plasma_stabilizer, -/obj/item/mod/module/thermal_regulator, /obj/item/assembly/flash/handheld, +/obj/item/mod/module/signlang_radio, +/obj/item/mod/module/thermal_regulator, /turf/open/floor/iron/dark/textured_half{ dir = 1 }, @@ -57801,9 +57824,7 @@ dir = 1 }, /obj/structure/sign/warning/cold_temp/directional/east, -/obj/effect/turf_decal/stripes/line{ - dir = 2 - }, +/obj/effect/turf_decal/stripes/line, /turf/open/floor/plating, /area/station/maintenance/disposal) "rLV" = ( @@ -59103,6 +59124,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/mapping_helpers/airlock/access/all/command/hop, +/obj/machinery/door/firedoor, /turf/open/floor/wood, /area/station/command/heads_quarters/hop) "shT" = ( @@ -61239,6 +61261,7 @@ id = "hopflash"; pixel_y = -23 }, +/obj/machinery/door/firedoor, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) "sMY" = ( @@ -65071,7 +65094,6 @@ /area/station/engineering/storage) "uaI" = ( /obj/structure/closet/secure_closet/brig, -/obj/machinery/airalarm/directional/north, /turf/open/floor/iron/smooth, /area/station/security/execution/transfer) "uaT" = ( @@ -66174,6 +66196,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/visible, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"utN" = ( +/obj/machinery/firealarm/directional/east, +/turf/open/floor/wood, +/area/station/command/meeting_room) "utR" = ( /obj/effect/turf_decal/tile/blue{ dir = 8 @@ -73921,6 +73947,7 @@ /obj/effect/turf_decal/tile/neutral/half/contrasted{ dir = 8 }, +/obj/machinery/firealarm/directional/north, /turf/open/floor/iron/dark/side{ dir = 8 }, @@ -74795,6 +74822,13 @@ }, /turf/open/lava/plasma/ice_moon, /area/icemoon/underground/explored) +"xcJ" = ( +/obj/effect/turf_decal/tile/blue{ + dir = 8 + }, +/obj/machinery/firealarm/directional/south, +/turf/open/floor/iron, +/area/station/hallway/primary/starboard) "xcW" = ( /obj/machinery/atmospherics/pipe/multiz/scrubbers/visible/layer2{ dir = 1 @@ -75387,7 +75421,6 @@ /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat_interior) "xlf" = ( -/obj/machinery/lapvend, /obj/effect/turf_decal/tile/purple/half/contrasted{ dir = 8 }, @@ -76807,6 +76840,7 @@ id = "medsecprivacy"; name = "Privacy Shutters" }, +/obj/machinery/door/firedoor, /turf/open/floor/plating, /area/station/security/checkpoint/medical) "xGI" = ( @@ -77444,6 +77478,7 @@ c_tag = "Atmospherics Incinerator" }, /obj/machinery/atmospherics/components/tank/plasma, +/obj/machinery/firealarm/directional/west, /turf/open/floor/iron, /area/station/maintenance/disposal/incinerator) "xTw" = ( @@ -171409,7 +171444,7 @@ xHE xHE hgM fvO -eHK +mBa hgM mKq xEd @@ -171666,7 +171701,7 @@ uME uME uME bYB -mBa +hBg hgM xhK xhK @@ -236744,7 +236779,7 @@ nDA vvi xpJ vYs -nDA +aol gCn pJN dZQ @@ -236989,7 +237024,7 @@ xKJ rmM pZh oYI -wzk +utN uPY knU kPv @@ -250096,7 +250131,7 @@ xbf kKL rjP qEM -pxn +xcJ vBG vBG vBG @@ -253692,7 +253727,7 @@ pDS sEi bwl hUD -lso +jyg cYE acw ult diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index f112651342bb6d..cfa13aef72e1a4 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -2419,7 +2419,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, -/obj/machinery/destructive_scanner, /obj/effect/turf_decal/tile/purple/half/contrasted{ dir = 1 }, @@ -6973,10 +6972,10 @@ c_tag = "Science Lobby"; network = list("ss13","rd") }, -/obj/machinery/vending/modularpc, /obj/effect/turf_decal/tile/purple/half/contrasted{ dir = 1 }, +/obj/machinery/destructive_scanner, /turf/open/floor/iron/white, /area/station/science/lobby) "cAG" = ( @@ -8267,7 +8266,7 @@ /obj/item/bedsheet/red, /obj/machinery/airalarm/directional/east, /obj/machinery/flasher/directional/north{ - id = "IsolationFlash" + id = "IsolationCell" }, /obj/effect/turf_decal/tile/red/fourcorners, /turf/open/floor/iron/white, @@ -11944,7 +11943,6 @@ /turf/open/floor/iron, /area/station/maintenance/starboard/greater) "esK" = ( -/obj/machinery/firealarm/directional/east, /obj/structure/cable, /obj/machinery/light/small/directional/east, /turf/open/floor/iron/dark, @@ -12997,19 +12995,11 @@ dir = 8 }, /obj/machinery/light/small/directional/north, -/obj/item/surgery_tray/morgue, +/obj/item/surgery_tray/full/morgue, /turf/open/floor/iron/dark/smooth_edge{ dir = 8 }, /area/station/medical/morgue) -"eOD" = ( -/obj/structure/chair/comfy{ - dir = 1 - }, -/obj/item/clothing/suit/costume/wellworn_shirt/messy/graphic/gamer, -/obj/item/clothing/head/fedora, -/turf/open/floor/plating, -/area/station/maintenance/port/aft) "eOJ" = ( /obj/effect/turf_decal/stripes/line, /obj/structure/cable, @@ -16151,6 +16141,9 @@ /obj/structure/cable, /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /turf/open/floor/iron/white, /area/station/medical/medbay/central) "fYC" = ( @@ -20019,6 +20012,7 @@ }, /obj/item/mod/module/plasma_stabilizer, /obj/item/mod/module/thermal_regulator, +/obj/item/mod/module/signlang_radio, /turf/open/floor/iron/dark, /area/station/medical/storage) "hwg" = ( @@ -26886,14 +26880,14 @@ /turf/open/floor/plating, /area/station/maintenance/starboard/aft) "jJp" = ( -/obj/machinery/button/flasher{ - id = "IsolationFlash"; - pixel_x = -23; - pixel_y = 8 - }, /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/status_display/door_timer{ + id = "IsolationCell"; + name = "Isolation Cell"; + pixel_x = -32 + }, /turf/open/floor/iron, /area/station/security/execution/transfer) "jJC" = ( @@ -37007,7 +37001,7 @@ /obj/effect/turf_decal/tile/blue/half/contrasted{ dir = 1 }, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/clothing/gloves/latex, /obj/item/clothing/suit/apron/surgical, /turf/open/floor/iron/white, @@ -38214,6 +38208,7 @@ dir = 4 }, /obj/structure/sign/poster/official/random/directional/north, +/obj/item/mod/module/signlang_radio, /turf/open/floor/iron/dark/corner{ dir = 1 }, @@ -41917,6 +41912,7 @@ /obj/effect/mapping_helpers/airlock/access/all/medical/coroner, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/disposalpipe/segment, /turf/open/floor/iron/dark, /area/station/medical/morgue) "pdX" = ( @@ -45297,7 +45293,6 @@ }, /obj/item/defibrillator/loaded, /obj/structure/window/spawner/directional/west, -/obj/machinery/status_display/evac/directional/east, /turf/open/floor/iron/dark, /area/station/medical/storage) "qph" = ( @@ -54907,6 +54902,9 @@ /obj/item/mod/module/plasma_stabilizer{ pixel_x = 16 }, +/obj/item/mod/module/signlang_radio{ + pixel_x = 16 + }, /obj/item/mod/module/thermal_regulator{ pixel_x = 16 }, @@ -56554,11 +56552,11 @@ /turf/open/floor/iron/white, /area/station/medical/chemistry) "ulX" = ( -/obj/machinery/lapvend, /obj/structure/cable, /obj/effect/turf_decal/tile/purple/half/contrasted{ dir = 1 }, +/obj/machinery/vending/modularpc, /turf/open/floor/iron/white, /area/station/science/lobby) "umS" = ( @@ -56810,6 +56808,7 @@ /obj/effect/turf_decal/tile/red/half/contrasted{ dir = 1 }, +/obj/machinery/firealarm/directional/east, /turf/open/floor/iron/dark, /area/station/security/execution/education) "urs" = ( @@ -57132,6 +57131,14 @@ /obj/machinery/duct, /turf/open/floor/iron, /area/station/engineering/main) +"uwh" = ( +/obj/structure/chair/comfy{ + dir = 1 + }, +/obj/item/clothing/suit/costume/wellworn_shirt/messy/graphic/gamer, +/obj/item/clothing/head/fedora, +/turf/open/floor/plating, +/area/station/maintenance/port/aft) "uwx" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -57559,7 +57566,9 @@ dir = 4; id = "garbage" }, -/obj/machinery/recycler, +/obj/machinery/recycler{ + dir = 8 + }, /turf/open/floor/plating, /area/station/maintenance/disposal) "uEO" = ( @@ -83216,7 +83225,7 @@ jUb jUb jUb eCK -eOD +uwh jUb nCw jUb diff --git a/_maps/map_files/Mining/Lavaland.dmm b/_maps/map_files/Mining/Lavaland.dmm index e96bc43b16ba7f..5f7a19198bbe91 100644 --- a/_maps/map_files/Mining/Lavaland.dmm +++ b/_maps/map_files/Mining/Lavaland.dmm @@ -6773,7 +6773,9 @@ /turf/open/floor/plating, /area/mine/production) "PL" = ( -/obj/machinery/recycler, +/obj/machinery/recycler{ + dir = 8 + }, /obj/machinery/conveyor{ dir = 4; id = "mining_disposals" diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index f701e36239c74a..d9fff1d8af0ac2 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -937,12 +937,6 @@ }, /turf/open/floor/plating, /area/station/science/xenobiology) -"alE" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/brown/visible, -/obj/effect/turf_decal/stripes/line, -/obj/structure/cable, -/turf/open/floor/engine, -/area/station/engineering/supermatter/room) "alK" = ( /obj/machinery/modular_computer/preset/id{ dir = 4 @@ -4166,7 +4160,6 @@ /turf/open/floor/catwalk_floor, /area/station/maintenance/floor3/port/aft) "bcm" = ( -/obj/machinery/lapvend, /obj/machinery/camera/autoname/directional/west, /turf/open/floor/iron/dark/side{ dir = 8 @@ -4704,7 +4697,9 @@ /turf/open/floor/iron, /area/station/science/robotics/lab) "biF" = ( -/obj/machinery/recycler, +/obj/machinery/recycler{ + dir = 8 + }, /obj/machinery/conveyor{ dir = 4; id = "disposals" @@ -6595,7 +6590,6 @@ dir = 4 }, /obj/machinery/status_display/evac/directional/north, -/obj/structure/cable, /turf/open/floor/engine, /area/station/engineering/supermatter/room) "bDU" = ( @@ -7219,6 +7213,7 @@ /obj/machinery/atmospherics/components/binary/pump{ name = "Atmospherics-Supermatter Connection" }, +/obj/structure/cable, /turf/open/floor/engine, /area/station/engineering/supermatter/room) "bNU" = ( @@ -20832,14 +20827,9 @@ /obj/effect/turf_decal/trimline/yellow/corner{ dir = 1 }, -/obj/item/stock_parts/matter_bin{ - pixel_x = 2; - pixel_y = -5 - }, -/obj/item/stock_parts/micro_laser{ - pixel_y = 7 - }, -/obj/item/trash/boritos/green, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/signlang_radio, +/obj/item/mod/module/thermal_regulator, /turf/open/floor/iron/corner{ dir = 1 }, @@ -26003,7 +25993,6 @@ /area/station/engineering/supermatter) "gSf" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/brown/visible, -/obj/structure/cable, /obj/machinery/light/floor, /turf/open/floor/iron/dark/textured_large, /area/station/engineering/supermatter/room) @@ -26334,7 +26323,7 @@ dir = 1 }, /obj/structure/table/reinforced/rglass, -/obj/item/surgery_tray/morgue, +/obj/item/surgery_tray/full/morgue, /obj/machinery/digital_clock/directional/north, /turf/open/floor/iron/dark, /area/station/medical/morgue) @@ -31982,6 +31971,9 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/signlang_radio, +/obj/item/mod/module/thermal_regulator, /turf/open/floor/iron/dark, /area/station/security/eva) "iuE" = ( @@ -33242,7 +33234,6 @@ "iMV" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/visible, /obj/machinery/status_display/evac/directional/south, -/obj/structure/cable, /turf/open/floor/engine, /area/station/engineering/supermatter/room) "iMX" = ( @@ -45900,6 +45891,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/dark, /area/station/maintenance/floor2/starboard/aft) +"lZi" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/visible, +/turf/open/floor/engine, +/area/station/engineering/supermatter/room) "lZl" = ( /obj/structure/reagent_dispensers/plumbed, /obj/effect/decal/cleanable/dirt, @@ -46117,7 +46112,6 @@ }, /obj/structure/table/reinforced, /obj/item/storage/medkit/regular, -/obj/structure/window/reinforced/spawner/directional/east, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/door/window/right/directional/south{ name = "First Aid Supplies"; @@ -47399,7 +47393,6 @@ /turf/open/floor/iron/dark, /area/station/command/heads_quarters/hop) "msf" = ( -/obj/machinery/lapvend, /obj/machinery/light/directional/north, /obj/effect/turf_decal/trimline/purple/filled/corner{ dir = 1 @@ -48444,7 +48437,10 @@ }, /obj/machinery/computer/pod/old/mass_driver_controller/ordnancedriver, /obj/structure/table, -/obj/item/binoculars, +/obj/item/binoculars{ + pixel_x = 6; + pixel_y = 6 + }, /obj/effect/turf_decal/siding/thinplating/dark{ dir = 5 }, @@ -49119,6 +49115,7 @@ "mOT" = ( /obj/machinery/light/directional/north, /obj/machinery/airalarm/directional/north, +/obj/structure/cable, /turf/open/floor/engine, /area/station/engineering/supermatter/room) "mPs" = ( @@ -54238,11 +54235,8 @@ /obj/structure/window/reinforced/spawner/directional/west, /obj/item/storage/medkit/regular, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/door/window/left/directional/south{ - name = "First Aid Supplies"; - req_access = list("medical") - }, /obj/effect/turf_decal/tile/blue/fourcorners, +/obj/structure/window/reinforced/spawner/directional/south, /turf/open/floor/iron/white/textured, /area/station/medical/storage) "odz" = ( @@ -54965,7 +54959,7 @@ /turf/open/floor/iron, /area/station/hallway/secondary/exit) "onz" = ( -/obj/item/surgery_tray{ +/obj/item/surgery_tray/full{ pixel_y = 13 }, /obj/item/reagent_containers/medigel/sterilizine{ @@ -58301,7 +58295,7 @@ /turf/open/floor/plating, /area/station/security/execution/transfer) "pjR" = ( -/obj/item/surgery_tray{ +/obj/item/surgery_tray/full{ pixel_y = 13 }, /obj/item/reagent_containers/medigel/sterilizine{ @@ -59292,7 +59286,6 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, -/obj/structure/cable, /turf/open/floor/engine, /area/station/engineering/supermatter/room) "pxw" = ( @@ -59492,8 +59485,8 @@ /area/station/service/hydroponics) "pzm" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/orange/visible, -/obj/structure/cable, /obj/machinery/light/small/directional/north, +/obj/structure/cable, /turf/open/floor/plating, /area/station/engineering/supermatter/room) "pzu" = ( @@ -60343,7 +60336,6 @@ }, /obj/machinery/atmospherics/pipe/smart/manifold4w/brown/visible, /obj/machinery/camera/autoname/directional/west, -/obj/structure/cable, /turf/open/floor/iron/dark/textured_large, /area/station/engineering/supermatter/room) "pMe" = ( @@ -60906,6 +60898,7 @@ /obj/effect/turf_decal/siding/thinplating_new/dark{ dir = 9 }, +/obj/structure/cable, /turf/open/floor/iron/dark/textured_corner, /area/station/engineering/supermatter/room) "pUl" = ( @@ -66367,8 +66360,8 @@ dir = 1 }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, /obj/effect/mapping_helpers/airlock/access/any/engineering/general, +/obj/structure/cable, /turf/open/floor/plating, /area/station/engineering/supermatter/room) "rpA" = ( @@ -67124,11 +67117,6 @@ "rAy" = ( /turf/open/floor/pod/light, /area/station/maintenance/floor4/starboard) -"rAD" = ( -/obj/machinery/atmospherics/components/binary/valve, -/obj/structure/cable, -/turf/open/floor/engine, -/area/station/engineering/supermatter/room) "rAE" = ( /obj/machinery/computer/records/security{ dir = 4 @@ -68090,6 +68078,12 @@ "rOY" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/tile/blue/fourcorners, +/obj/structure/window/reinforced/spawner/directional/east, +/obj/structure/table/reinforced, +/obj/structure/window/reinforced/spawner/directional/south, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/signlang_radio, +/obj/item/mod/module/thermal_regulator, /turf/open/floor/iron/white/textured, /area/station/medical/storage) "rPi" = ( @@ -69099,7 +69093,6 @@ "sdt" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/brown/visible, /obj/machinery/meter, -/obj/structure/cable, /turf/open/floor/iron/dark/textured_half, /area/station/engineering/supermatter/room) "sdA" = ( @@ -72241,7 +72234,6 @@ /obj/effect/turf_decal/stripes/line, /obj/effect/turf_decal/stripes/red/line, /obj/machinery/atmospherics/pipe/smart/manifold4w/brown/visible, -/obj/structure/cable, /turf/open/floor/iron/dark/textured_large, /area/station/engineering/supermatter/room) "sWC" = ( @@ -72650,6 +72642,7 @@ /obj/machinery/button/door/directional/south{ id = "radshutnorth" }, +/obj/structure/cable, /turf/open/floor/engine, /area/station/engineering/supermatter/room) "tat" = ( @@ -74601,6 +74594,12 @@ dir = 8 }, /area/station/hallway/secondary/exit/departure_lounge) +"tAC" = ( +/obj/machinery/power/apc/auto_name/directional/north, +/obj/effect/turf_decal/stripes/end, +/obj/structure/cable, +/turf/open/floor/plating, +/area/station/engineering/supermatter/room) "tAE" = ( /obj/machinery/vending/cola/starkist, /turf/open/floor/wood, @@ -78306,8 +78305,8 @@ dir = 1 }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, /obj/effect/mapping_helpers/airlock/access/any/engineering/general, +/obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/floor1/port/aft) "uCv" = ( @@ -87392,14 +87391,6 @@ /obj/structure/grille, /turf/open/floor/plating/airless, /area/station/service/chapel/funeral) -"wOP" = ( -/obj/structure/cable, -/obj/machinery/power/apc/auto_name/directional/north, -/obj/effect/turf_decal/stripes/line{ - dir = 6 - }, -/turf/open/floor/plating, -/area/station/engineering/supermatter/room) "wPn" = ( /obj/effect/turf_decal/trimline/green/filled/line{ dir = 4 @@ -137905,7 +137896,7 @@ rBP jcr rBP rBP -wOP +xgW xgW xgW xgW @@ -138418,7 +138409,7 @@ oIy oIy tjV xgW -xgW +mVF pUf eCQ uyD @@ -138675,7 +138666,7 @@ whF oIy aDf xgW -xgW +mVF wmC sly uyD @@ -139444,7 +139435,7 @@ nIJ uLB rAm sAH -xgW +tAC jSD fcp iCk @@ -139703,7 +139694,7 @@ qEw sAH xgW kfo -iyT +lZi kcB ppO fJE @@ -139713,7 +139704,7 @@ wCu vap kBK juf -klY +wOm kfo wfl dEc @@ -140217,17 +140208,17 @@ uEu sAH bQz uCe -iyT -mVF -alE +lZi +xgW +pIZ gSf sWB sdt pMa gSf pxv -rAD -klY +jER +wOm rpD tyQ dEc diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm index 13519c78053e38..20fd4a5e14111f 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -5373,7 +5373,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/closed/wall/r_wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "atA" = ( /obj/machinery/door/window/brigdoor/security/cell{ id = "Cell 2"; @@ -16469,7 +16469,7 @@ /obj/machinery/door/airlock/corporate, /obj/effect/mapping_helpers/airlock/access/all/cent_com/rep_door, /turf/open/floor/iron, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "bgc" = ( /obj/machinery/atmospherics/components/binary/pump/on{ dir = 4; @@ -16757,11 +16757,11 @@ /obj/machinery/holopad, /obj/effect/turf_decal/bot, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "bgV" = ( /obj/structure/cable, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "bgW" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/hidden/layer4, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -16778,20 +16778,20 @@ }, /obj/item/taperecorder, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "bgX" = ( /obj/machinery/light_switch{ pixel_x = 25 }, /obj/machinery/modular_computer/preset/command, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "bgY" = ( /obj/item/radio/intercom{ pixel_y = 26 }, /turf/closed/wall/r_wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "bgZ" = ( /obj/structure/disposalpipe/sorting/mail{ dir = 1; @@ -16967,12 +16967,11 @@ /area/station/maintenance/department/cargo) "bhE" = ( /turf/closed/wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "bhJ" = ( /obj/effect/turf_decal/bot, -/obj/machinery/lapvend, /turf/open/floor/iron, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "bhL" = ( /obj/machinery/navbeacon{ codes_txt = "patrol;next_patrol=BrigS1"; @@ -17167,7 +17166,7 @@ /obj/structure/closet/secure_closet/nanotrasen_consultant/station, /obj/item/clothing/under/rank/centcom/intern, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "biM" = ( /obj/structure/cable, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -17175,7 +17174,7 @@ }, /obj/machinery/power/apc/auto_name/directional/south, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "biO" = ( /obj/structure/sign/poster/official/random/directional/south, /obj/structure/disposalpipe/segment{ @@ -18979,7 +18978,7 @@ "bpV" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/table, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /turf/open/floor/iron/dark, /area/station/medical/morgue) "bpW" = ( @@ -22239,8 +22238,8 @@ /obj/structure/table/glass, /obj/item/tank/internals/anesthetic, /obj/item/clothing/mask/breath/medical, -/obj/item/surgery_tray, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, +/obj/item/surgery_tray/full, /obj/item/reagent_containers/cup/bottle/ethanol, /obj/item/reagent_containers/cup/bottle/ethanol, /obj/item/blood_filter, @@ -22726,7 +22725,7 @@ /area/station/medical/surgery) "bEv" = ( /obj/structure/table/glass, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/machinery/airalarm/directional/north, /turf/open/floor/iron/white, /area/station/medical/surgery) @@ -23153,9 +23152,7 @@ /turf/open/floor/iron/white, /area/station/medical/medbay/central) "bGT" = ( -/obj/machinery/dish_drive/bullet{ - succrange = 2 - }, +/obj/machinery/dish_drive/bullet, /turf/open/floor/iron/dark, /area/station/ai_monitored/security/armory) "bGU" = ( @@ -24037,7 +24034,7 @@ "bLE" = ( /obj/machinery/light/directional/south, /obj/structure/table/glass, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/machinery/airalarm/directional/south, /turf/open/floor/iron/white, /area/station/medical/surgery) @@ -34678,7 +34675,7 @@ dir = 8 }, /turf/open/floor/carpet, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "dHU" = ( /obj/machinery/atmospherics/pipe/smart/simple/purple/visible{ dir = 4 @@ -35937,7 +35934,7 @@ /obj/structure/cable, /obj/structure/table/wood, /turf/open/floor/carpet, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "eRm" = ( /obj/effect/turf_decal/tile/neutral{ dir = 4 @@ -36196,7 +36193,7 @@ dir = 4 }, /turf/open/floor/carpet, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "fce" = ( /turf/open/floor/plating, /area/station/maintenance/department/engine/atmos) @@ -37012,7 +37009,7 @@ "fEY" = ( /obj/structure/sign/poster/official/random/directional/west, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "fEZ" = ( /obj/effect/turf_decal/stripes/corner{ dir = 8 @@ -37610,7 +37607,7 @@ /obj/structure/flora/grass/jungle, /obj/structure/flora/bush/flowers_pp/style_random, /turf/open/floor/grass, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "gbu" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating/airless, @@ -38993,7 +38990,7 @@ pixel_x = -10 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "haG" = ( /obj/effect/turf_decal/stripes/line, /obj/effect/turf_decal/trimline/yellow/filled/line, @@ -41772,7 +41769,7 @@ pixel_y = 14 }, /turf/open/floor/iron/dark, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "jjC" = ( /obj/structure/rack, /obj/item/storage/briefcase{ @@ -42130,7 +42127,7 @@ }, /obj/structure/cable, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "jyg" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -42190,7 +42187,7 @@ }, /obj/structure/cable, /turf/open/floor/iron, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "jzL" = ( /obj/machinery/requests_console{ department = "Cargo Bay"; @@ -42987,7 +42984,7 @@ /obj/machinery/power/apc/auto_name/directional/east, /obj/structure/cable, /turf/open/floor/carpet, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "kif" = ( /obj/machinery/holopad, /turf/open/floor/iron, @@ -43260,7 +43257,7 @@ /area/station/medical/storage) "kvK" = ( /turf/closed/wall/r_wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "kvR" = ( /obj/machinery/power/emitter, /turf/open/floor/plating, @@ -43646,7 +43643,7 @@ /area/station/maintenance/department/cargo) "kIS" = ( /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "kJw" = ( /obj/machinery/door/airlock/maintenance{ name = "Firing Range Target" @@ -44917,7 +44914,7 @@ pixel_y = 4 }, /turf/open/floor/carpet, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "lHU" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -45586,7 +45583,7 @@ pixel_y = 8 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "mja" = ( /obj/machinery/door/firedoor/heavy, /obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ @@ -45750,7 +45747,7 @@ }, /obj/effect/landmark/start/nanotrasen_consultant, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "mrM" = ( /obj/effect/turf_decal/trimline/dark_blue/filled/line{ dir = 8 @@ -47451,7 +47448,7 @@ "nGZ" = ( /obj/structure/closet/secure_closet/blueshield, /turf/open/floor/iron/dark, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "nHh" = ( /obj/effect/turf_decal/tile/blue{ dir = 1 @@ -48634,7 +48631,7 @@ /obj/effect/mapping_helpers/airlock/access/all/command/captain, /obj/structure/cable, /turf/open/floor/iron/dark, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "oAd" = ( /obj/structure/cable, /obj/effect/turf_decal/trimline/yellow/filled/line{ @@ -49620,7 +49617,7 @@ /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, /turf/open/floor/plating, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "pkn" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/hidden/layer4, @@ -51044,7 +51041,7 @@ /area/station/security/office) "qml" = ( /turf/open/floor/carpet, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "qnJ" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -51073,7 +51070,7 @@ "qoh" = ( /obj/effect/turf_decal/delivery, /turf/open/floor/iron, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "qoi" = ( /obj/machinery/vending/medical, /obj/effect/turf_decal/trimline/blue/filled/line{ @@ -51508,7 +51505,7 @@ dir = 4 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "qAj" = ( /obj/effect/turf_decal/tile/blue{ dir = 1 @@ -51924,7 +51921,7 @@ /obj/machinery/newscaster/directional/south, /obj/machinery/light/directional/east, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "qUw" = ( /obj/item/kirbyplants/organic/plant20, /obj/effect/turf_decal/tile/neutral{ @@ -51948,7 +51945,7 @@ /area/station/medical/storage) "qVb" = ( /turf/closed/wall/r_wall, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "qVi" = ( /obj/structure/sign/warning/vacuum/external/directional/east, /turf/open/floor/plating, @@ -53692,7 +53689,7 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /obj/structure/cable, /turf/open/floor/carpet, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "skj" = ( /obj/machinery/dna_scannernew, /obj/effect/turf_decal/tile/neutral, @@ -54102,7 +54099,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, /turf/open/floor/iron/dark, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "sDw" = ( /obj/effect/landmark/start/bouncer, /turf/open/floor/iron/dark, @@ -55465,7 +55462,7 @@ pixel_y = 2 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "tGm" = ( /obj/machinery/atmospherics/pipe/smart/simple/dark/visible, /turf/open/floor/iron, @@ -58377,7 +58374,7 @@ /obj/structure/flora/grass/jungle, /obj/structure/flora/bush/flowers_pp/style_random, /turf/open/floor/grass, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "vOw" = ( /obj/machinery/door/airlock/grunge{ name = "Library" @@ -59480,7 +59477,7 @@ dir = 1 }, /turf/open/floor/carpet, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "wFI" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -59580,7 +59577,7 @@ /obj/structure/flora/bush/flowers_pp/style_random, /obj/structure/curtain/cloth/fancy, /turf/open/floor/grass, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "wIX" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, diff --git a/_maps/map_files/VoidRaptor/VoidRaptor.dmm b/_maps/map_files/VoidRaptor/VoidRaptor.dmm index 73ae6804c84719..c3918c21108096 100644 --- a/_maps/map_files/VoidRaptor/VoidRaptor.dmm +++ b/_maps/map_files/VoidRaptor/VoidRaptor.dmm @@ -13,7 +13,7 @@ "aal" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/maintenance/two, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/starboard/aft) "aau" = ( /obj/item/kirbyplants/random, @@ -581,6 +581,11 @@ }, /turf/open/floor/iron/white, /area/station/medical/storage) +"aiq" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/spawner/random/trash/garbage, +/turf/open/floor/plating, +/area/station/maintenance/department/crew_quarters/bar) "air" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating/airless, @@ -1278,6 +1283,9 @@ /obj/effect/turf_decal/bot_white, /turf/open/floor/iron/grimy, /area/station/service/library) +"asX" = ( +/turf/closed/wall, +/area/station/medical/office) "atb" = ( /obj/effect/turf_decal/siding/wood{ dir = 8 @@ -2619,7 +2627,7 @@ "aNf" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/light/small/directional/west, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/starboard/aft) "aNg" = ( /obj/machinery/computer/upload/ai{ @@ -2887,7 +2895,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "aRc" = ( /obj/machinery/atmospherics/pipe/smart/simple/dark/hidden, /turf/open/floor/iron/white/smooth_large, @@ -3232,7 +3240,7 @@ /area/station/medical/chemistry) "aWh" = ( /obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/engine/atmos) "aWs" = ( /obj/structure/rack, @@ -3400,6 +3408,13 @@ /obj/structure/tank_holder/oxygen, /turf/open/floor/iron/edge, /area/station/commons/fitness/recreation) +"aXl" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment, +/turf/open/floor/plating, +/area/station/maintenance/starboard/greater) "aXm" = ( /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/access/all/service/general, @@ -3440,6 +3455,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/catwalk_floor, /area/station/hallway/secondary/construction) +"aXG" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/aft) "aXM" = ( /turf/closed/wall/mineral/plastitanium, /area/station/science/research) @@ -3622,7 +3641,7 @@ "bao" = ( /obj/structure/trash_pile, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/science/ordnance_maint) "baw" = ( /obj/effect/turf_decal/trimline/brown/filled/line{ @@ -3660,7 +3679,7 @@ }, /obj/structure/sign/calendar/directional/north, /turf/open/floor/wood/large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "baU" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 @@ -3716,7 +3735,7 @@ /area/station/maintenance/solars/port/fore) "bbN" = ( /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/engine/atmos/lesser) "bbU" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ @@ -3953,6 +3972,10 @@ dir = 8 }, /area/station/science/ordnance) +"beq" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/starboard/greater) "bes" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -4017,16 +4040,25 @@ /turf/open/space, /area/space/nearstation) "bgo" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/spawner/random/structure/crate_empty, -/obj/effect/spawner/random/maintenance/three, -/turf/open/floor/iron/smooth, +/obj/machinery/door/airlock/maintenance{ + name = "Exam Room Maintenance" + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/effect/mapping_helpers/airlock/access/any/medical/general, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/department/medical/central) "bgy" = ( /obj/structure/chair/wood, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/carpet/stellar, /area/station/service/chapel/funeral) +"bgz" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/aft) "bgF" = ( /obj/effect/turf_decal/trimline/yellow/filled/corner{ dir = 8 @@ -4044,7 +4076,7 @@ pixel_y = 10 }, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "bhv" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /obj/machinery/airalarm/directional/west, @@ -4898,6 +4930,13 @@ }, /turf/open/floor/wood, /area/station/service/bar) +"bvt" = ( +/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/port) "bvv" = ( /obj/machinery/door/airlock/public/glass{ name = "Janitorial" @@ -4943,10 +4982,6 @@ /obj/item/flashlight/lamp, /turf/open/floor/iron/white, /area/station/medical/virology) -"bwm" = ( -/obj/structure/disposalpipe/segment, -/turf/closed/wall/r_wall, -/area/station/maintenance/department/medical/central) "bwv" = ( /obj/effect/spawner/random/structure/crate, /obj/effect/decal/cleanable/dirt, @@ -5514,7 +5549,6 @@ }, /area/station/medical/medbay/lobby) "bGd" = ( -/obj/machinery/iv_drip, /obj/effect/turf_decal/tile/blue/fourcorners, /obj/structure/cable, /turf/open/floor/iron/freezer, @@ -5799,7 +5833,7 @@ "bLv" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/sign/poster/random/directional/south, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/aft) "bLx" = ( /obj/structure/cable, @@ -5890,7 +5924,9 @@ name = "medbay camera"; network = list("ss13","medbay") }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 1 + }, /turf/open/floor/iron/showroomfloor, /area/station/medical/coldroom) "bMR" = ( @@ -6201,7 +6237,7 @@ dir = 8 }, /turf/open/floor/wood/large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "bRM" = ( /obj/effect/turf_decal/trimline/green/filled/line{ dir = 1 @@ -6376,7 +6412,7 @@ "bUl" = ( /obj/structure/sign/departments/custodian/directional/west, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/starboard/greater) "bUt" = ( /obj/effect/turf_decal/siding/wood{ @@ -7114,6 +7150,13 @@ /obj/machinery/status_display/ai, /turf/closed/wall, /area/station/engineering/atmos) +"cgH" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/port/greater) "cgT" = ( /obj/effect/turf_decal/trimline/blue/line, /obj/effect/landmark/start/medical_doctor, @@ -7427,7 +7470,7 @@ /area/station/engineering/supermatter/room) "cmH" = ( /turf/closed/wall/r_wall, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "cmM" = ( /obj/structure/chair/office/light{ dir = 4 @@ -7664,7 +7707,7 @@ }, /obj/effect/turf_decal/box, /turf/open/floor/wood/large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "cpP" = ( /obj/structure/lattice/catwalk, /obj/machinery/camera/directional/west{ @@ -8273,7 +8316,7 @@ /turf/open/floor/catwalk_floor, /area/station/security/execution/transfer) "czs" = ( -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/engine) "czC" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -8325,7 +8368,7 @@ /obj/item/storage/secure/safe/directional/east, /obj/machinery/newscaster/directional/south, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "cAQ" = ( /obj/machinery/computer/operating, /obj/effect/turf_decal/trimline/blue/filled/warning{ @@ -8557,6 +8600,22 @@ /obj/structure/cable, /turf/open/floor/iron/solarpanel/airless, /area/station/solars/port/aft) +"cEB" = ( +/obj/machinery/digital_clock/directional/north, +/obj/structure/table/glass, +/obj/item/paper_bin{ + pixel_x = -3; + pixel_y = 4 + }, +/obj/item/pen{ + pixel_x = -3; + pixel_y = 4 + }, +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 1 + }, +/turf/open/floor/iron/white/smooth_edge, +/area/station/medical/office) "cEE" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ dir = 4 @@ -8570,6 +8629,16 @@ dir = 8 }, /area/station/engineering/lobby) +"cEL" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/port) "cEP" = ( /obj/effect/spawner/random/structure/girder, /turf/open/floor/iron/smooth, @@ -8657,6 +8726,19 @@ }, /turf/open/floor/iron/dark/smooth_large, /area/station/command/bridge) +"cGu" = ( +/obj/machinery/firealarm/directional/east{ + pixel_y = 5 + }, +/obj/machinery/light_switch/directional/east{ + pixel_y = 6; + pixel_x = 23 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 5 + }, +/turf/open/floor/iron/white, +/area/station/medical/office) "cGw" = ( /obj/machinery/atmospherics/components/unary/outlet_injector/monitored/air_input{ dir = 4 @@ -8816,7 +8898,7 @@ "cIc" = ( /obj/machinery/light/small/directional/north, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/science/ordnance_maint) "cIr" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -8938,7 +9020,7 @@ "cJm" = ( /obj/effect/decal/cleanable/dirt, /obj/item/stack/sheet/cardboard, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/greater) "cJo" = ( /obj/structure/chair/office{ @@ -9580,7 +9662,7 @@ pixel_x = -32 }, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "cTO" = ( /obj/structure/trash_pile, /turf/open/floor/iron/smooth, @@ -9606,7 +9688,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/trash/garbage, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/aft) "cUH" = ( /obj/effect/turf_decal/trimline/blue/filled/warning{ @@ -9672,7 +9754,7 @@ /obj/item/stack/sheet/glass{ amount = 4 }, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/fore) "cVI" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -9727,7 +9809,7 @@ /obj/machinery/power/apc/auto_name/directional/east, /obj/structure/chair/comfy, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "cXd" = ( /obj/effect/turf_decal/stripes/line{ dir = 9 @@ -10060,7 +10142,7 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/spawner/random/trash/garbage, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "dbQ" = ( /obj/effect/turf_decal/trimline/purple/filled/line{ @@ -10149,6 +10231,12 @@ dir = 8 }, /area/station/commons/fitness/recreation) +"dcL" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/aft/greater) "dcR" = ( /obj/machinery/door/airlock/external{ name = "External Solar Access" @@ -10198,15 +10286,12 @@ /turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/aft/greater) "ddB" = ( -/obj/structure/table, -/obj/machinery/computer/records/security/laptop{ - dir = 4 - }, /obj/structure/cable, -/obj/item/storage/fancy/donut_box{ - pixel_y = 17 - }, /obj/effect/turf_decal/tile/purple/fourcorners, +/obj/machinery/computer/records/security{ + dir = 4 + }, +/obj/effect/turf_decal/bot, /turf/open/floor/iron/dark, /area/station/security/corrections_officer) "ddH" = ( @@ -11049,6 +11134,13 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/fore) +"dqM" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment, +/turf/open/floor/plating, +/area/station/maintenance/department/crew_quarters/bar) "dqT" = ( /obj/structure/railing/corner, /obj/structure/cable/layer3, @@ -11315,7 +11407,7 @@ "dul" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/trash_pile, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "duq" = ( /obj/structure/window/reinforced/spawner/directional/north, @@ -11351,6 +11443,10 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron/smooth_large, /area/station/hallway/secondary/entry) +"duy" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/starboard/aft) "duG" = ( /obj/structure/cable/multilayer/connected, /turf/open/floor/circuit, @@ -11670,7 +11766,7 @@ /obj/machinery/photocopier, /obj/effect/turf_decal/bot, /turf/open/floor/wood/large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "dzy" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ dir = 9 @@ -11682,7 +11778,7 @@ /area/station/hallway/primary/aft) "dzC" = ( /obj/effect/decal/cleanable/glass, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/aft/lesser) "dzE" = ( /obj/structure/chair/comfy/beige{ @@ -12032,6 +12128,7 @@ /obj/machinery/newscaster/directional/east, /obj/machinery/duct, /obj/effect/turf_decal/box/blue, +/obj/item/bedsheet/medical, /turf/open/floor/iron/freezer, /area/station/medical/treatment_center) "dEb" = ( @@ -12157,6 +12254,15 @@ }, /obj/structure/closet/crate/internals, /obj/effect/turf_decal/bot, +/obj/item/tank/internals/emergency_oxygen, +/obj/item/tank/internals/emergency_oxygen, +/obj/item/tank/internals/nitrogen/belt, +/obj/item/tank/internals/nitrogen/belt, +/obj/item/clothing/mask/breath/vox, +/obj/item/clothing/mask/breath/vox, +/obj/item/clothing/mask/breath/vox, +/obj/item/clothing/mask/breath/vox, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/hidden, /turf/open/floor/iron/showroomfloor, /area/station/medical/coldroom) "dGw" = ( @@ -12257,7 +12363,7 @@ dir = 8 }, /turf/open/floor/wood/large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "dHa" = ( /obj/structure/bookcase/random/religion, /obj/effect/turf_decal/siding/wood{ @@ -12971,7 +13077,7 @@ /area/station/service/chapel/office) "dQq" = ( /obj/effect/decal/cleanable/glass, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/fore) "dQr" = ( /obj/structure/bed/medical{ @@ -13106,7 +13212,7 @@ /obj/effect/spawner/random/structure/steam_vent, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/department/engine/atmos/lesser) "dSI" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ @@ -13469,7 +13575,7 @@ /area/station/engineering/supermatter/room) "dXM" = ( /obj/effect/spawner/random/trash/grime, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "dXU" = ( /obj/effect/spawner/structure/window/reinforced/plasma, @@ -13712,7 +13818,7 @@ /area/station/ai_monitored/turret_protected/ai) "eak" = ( /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/medical/central) "eam" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -13833,6 +13939,11 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/kitchen, /area/station/service/kitchen/abandoned) +"ebS" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/spawner/random/trash/mess, +/turf/open/floor/plating, +/area/station/maintenance/department/engine/atmos) "eci" = ( /obj/effect/landmark/event_spawn, /turf/open/floor/iron/smooth_large, @@ -14119,6 +14230,12 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron/dark/smooth_edge, /area/station/hallway/secondary/command) +"efn" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/holopad, +/obj/effect/turf_decal/bot, +/turf/open/floor/iron/white/smooth_large, +/area/station/medical/exam_room) "efo" = ( /obj/structure/chair/sofa/bench/left{ dir = 1 @@ -14599,7 +14716,7 @@ pixel_y = 3 }, /turf/open/floor/wood/large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "elo" = ( /obj/effect/decal/cleanable/dirt, /obj/item/chair/stool, @@ -14646,7 +14763,7 @@ /area/station/maintenance/aft/greater) "emd" = ( /obj/effect/spawner/random/structure/crate_abandoned, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/aft/greater) "eme" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -15642,6 +15759,13 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron/smooth_large, /area/station/cargo/sorting) +"eBy" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/aft/greater) "eBD" = ( /obj/effect/turf_decal/trimline/green/filled/line{ dir = 8 @@ -15969,7 +16093,7 @@ dir = 8 }, /turf/open/floor/iron/dark/smooth_large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "eFg" = ( /obj/structure/chair/comfy/beige{ dir = 1 @@ -16096,7 +16220,7 @@ /area/station/maintenance/department/science/ordnance_maint) "eGo" = ( /obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "eGs" = ( /obj/effect/turf_decal/siding/thinplating/corner{ @@ -16365,6 +16489,13 @@ dir = 1 }, /area/station/maintenance/disposal/incinerator) +"eKs" = ( +/obj/structure/filingcabinet/medical, +/obj/effect/turf_decal/trimline/blue/filled/line, +/turf/open/floor/iron/white/smooth_edge{ + dir = 1 + }, +/area/station/medical/office) "eKx" = ( /obj/effect/landmark/blobstart, /obj/effect/landmark/event_spawn, @@ -16487,7 +16618,7 @@ /turf/open/floor/iron/smooth, /area/station/maintenance/department/science/ordnance_maint) "eMd" = ( -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "eMe" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -16627,7 +16758,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/landmark/start/blueshield, /turf/open/floor/carpet/cyan, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "ePm" = ( /obj/machinery/holopad, /obj/effect/turf_decal/box, @@ -16764,7 +16895,7 @@ }, /obj/machinery/digital_clock/directional/west, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "eRt" = ( /obj/machinery/airalarm/directional/north, /obj/effect/turf_decal/trimline/yellow/filled/warning{ @@ -16799,7 +16930,7 @@ dir = 4 }, /turf/open/floor/wood/large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "eSb" = ( /obj/machinery/conveyor/inverted{ dir = 10; @@ -16865,7 +16996,7 @@ /area/station/security/prison/garden) "eTo" = ( /obj/effect/spawner/random/structure/closet_maintenance, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/starboard/greater) "eTD" = ( /obj/effect/turf_decal/weather/sand{ @@ -16913,7 +17044,7 @@ dir = 8 }, /turf/open/floor/iron/dark/smooth_large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "eUm" = ( /obj/structure/bed, /obj/item/bedsheet/yellow, @@ -17682,7 +17813,7 @@ "fgd" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/wood/large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "fgh" = ( /obj/effect/turf_decal/tile/blue{ dir = 8 @@ -17909,7 +18040,7 @@ "fkI" = ( /obj/structure/railing, /obj/structure/table/glass, -/obj/structure/bedsheetbin, +/obj/structure/towel_bin, /turf/open/floor/iron/white/small, /area/station/common/pool) "fkM" = ( @@ -18353,6 +18484,11 @@ dir = 4 }, /area/station/engineering/atmos/storage/gas) +"fpE" = ( +/obj/structure/cable, +/obj/effect/spawner/random/trash/garbage, +/turf/open/floor/plating, +/area/station/maintenance/department/security/brig) "fpH" = ( /turf/closed/wall/r_wall, /area/station/engineering/atmos/storage) @@ -18662,6 +18798,7 @@ dir = 9 }, /obj/effect/turf_decal/stripes/red/box, +/obj/structure/sign/delam_procedure/directional/east, /turf/open/floor/engine, /area/station/engineering/supermatter/room) "fvr" = ( @@ -18727,7 +18864,7 @@ }, /obj/effect/turf_decal/tile/dark_blue/full, /turf/open/floor/iron/dark/smooth_large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "fwW" = ( /obj/effect/turf_decal/trimline/brown/filled/warning{ dir = 1 @@ -19517,7 +19654,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/starboard/aft) "fKt" = ( /obj/machinery/atmospherics/pipe/smart/simple/purple/visible{ @@ -19676,7 +19813,7 @@ "fMW" = ( /obj/effect/landmark/start/janitor, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/starboard/greater) "fNt" = ( /obj/effect/decal/cleanable/dirt, @@ -20004,7 +20141,6 @@ /area/station/commons/dorms) "fTs" = ( /obj/effect/turf_decal/box, -/obj/machinery/light/small/directional/west, /turf/open/floor/iron/smooth, /area/station/science/research/abandoned) "fTA" = ( @@ -20108,10 +20244,10 @@ /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 5 }, -/obj/structure/closet/crate/medical, /obj/machinery/light_switch/directional/east, /obj/effect/turf_decal/bot, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/closet/crate/freezer/surplus_limbs, /turf/open/floor/iron/showroomfloor, /area/station/medical/coldroom) "fUB" = ( @@ -20648,7 +20784,7 @@ /obj/structure/cable, /obj/effect/decal/cleanable/dirt, /obj/structure/sign/poster/random/directional/east, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/starboard/aft) "gcg" = ( /obj/structure/closet/crate/goldcrate, @@ -20856,6 +20992,9 @@ /obj/machinery/telecomms/bus/preset_one, /turf/open/floor/circuit/telecomms/server, /area/station/tcommsat/server) +"gfv" = ( +/turf/open/floor/plating, +/area/station/maintenance/aft/greater) "gfw" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 8 @@ -21048,6 +21187,9 @@ /obj/machinery/newscaster/directional/west, /obj/machinery/duct, /obj/effect/turf_decal/box/blue, +/obj/item/bedsheet/medical{ + dir = 4 + }, /turf/open/floor/iron/freezer, /area/station/medical/treatment_center) "giC" = ( @@ -21261,8 +21403,8 @@ /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 1 }, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 4 +/obj/machinery/atmospherics/pipe/layer_manifold/supply/hidden{ + dir = 8 }, /turf/open/floor/iron/showroomfloor, /area/station/medical/coldroom) @@ -21469,7 +21611,7 @@ /area/station/science/ordnance) "gmJ" = ( /obj/effect/spawner/random/structure/crate, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/greater) "gmL" = ( /obj/machinery/door/firedoor, @@ -22052,7 +22194,6 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/duct, -/obj/item/kirbyplants/random, /turf/open/floor/iron/white/smooth_large, /area/station/medical/storage) "gwc" = ( @@ -22826,7 +22967,7 @@ /obj/structure/cable, /obj/structure/sign/calendar/directional/south, /turf/open/floor/wood/large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "gHG" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -22848,6 +22989,10 @@ /obj/effect/landmark/start/roboticist, /turf/open/floor/wood/large, /area/station/science/research) +"gHM" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/hidden, +/turf/open/floor/catwalk_floor/iron_smooth, +/area/station/maintenance/department/medical/central) "gHW" = ( /obj/structure/table/optable{ desc = "A cold, hard place for your final rest."; @@ -23719,7 +23864,15 @@ pixel_y = 5 }, /turf/closed/wall/r_wall, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) +"gTk" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/department/crew_quarters/bar) "gTJ" = ( /obj/effect/mapping_helpers/airlock/unres{ dir = 1 @@ -23770,7 +23923,7 @@ dir = 1 }, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "gUC" = ( /obj/machinery/power/shuttle_engine/heater, /obj/effect/turf_decal/stripes/line{ @@ -24224,10 +24377,6 @@ }, /turf/open/floor/wood, /area/station/maintenance/department/engine/atmos) -"hbc" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/catwalk_floor/iron_smooth, -/area/station/maintenance/department/security/brig) "hbf" = ( /obj/effect/turf_decal/tile/yellow/opposingcorners, /obj/effect/turf_decal/tile/red/opposingcorners{ @@ -24253,8 +24402,11 @@ /obj/effect/turf_decal/box/white{ color = "#52B4E9" }, -/obj/machinery/portable_atmospherics/canister/oxygen, /obj/machinery/light/cold/directional/south, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/anesthetic_mix, /turf/open/floor/iron/showroomfloor, /area/station/medical/coldroom) "hbG" = ( @@ -24586,7 +24738,7 @@ "hfT" = ( /obj/structure/trash_pile, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/crew_quarters/bar) "hfU" = ( /turf/closed/wall, @@ -24726,7 +24878,7 @@ "hhQ" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/light/small/directional/north, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/aft) "hhT" = ( /obj/structure/cable, @@ -25080,7 +25232,7 @@ "hnn" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/trash_pile, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/aft/greater) "hns" = ( /obj/machinery/door/firedoor, @@ -25183,7 +25335,7 @@ "hpq" = ( /obj/effect/spawner/random/maintenance/two, /obj/item/stack/sheet/iron/five, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/fore) "hpE" = ( /obj/structure/disposalpipe/segment{ @@ -25201,7 +25353,7 @@ /area/station/maintenance/starboard/aft) "hqd" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/starboard/greater) "hqe" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -25457,7 +25609,7 @@ "hut" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/trash/garbage, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/starboard/aft) "huv" = ( /obj/machinery/airalarm/directional/west, @@ -25929,7 +26081,7 @@ /area/station/engineering/supermatter/room) "hAp" = ( /obj/structure/trash_pile, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/medical/central) "hAu" = ( /obj/structure/table/glass, @@ -26219,7 +26371,7 @@ "hDI" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/medical/minor_healing, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "hDY" = ( /obj/machinery/computer/atmos_control/mix_tank{ @@ -26346,7 +26498,7 @@ "hEZ" = ( /obj/effect/spawner/random/trash/mess, /obj/structure/sign/poster/random/directional/west, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/fore) "hFa" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ @@ -26965,7 +27117,7 @@ pixel_y = 7 }, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "hQW" = ( /obj/effect/turf_decal/trimline/red/filled/line, /obj/structure/disposalpipe/segment{ @@ -27176,11 +27328,6 @@ }, /turf/open/floor/pod/dark, /area/station/service/chapel/office) -"hTn" = ( -/obj/effect/spawner/structure/window/reinforced/plasma, -/obj/item/folder/biscuit/confidential/delam, -/turf/open/floor/plating/airless, -/area/station/engineering/supermatter/room) "hTr" = ( /obj/effect/turf_decal/trimline/yellow/filled/warning{ dir = 10 @@ -27581,6 +27728,13 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/kitchen, /area/station/service/kitchen/abandoned) +"hYA" = ( +/obj/structure/cable, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/department/engine/atmos/lesser) "hYJ" = ( /obj/structure/bed, /obj/structure/railing, @@ -27691,9 +27845,8 @@ /turf/open/floor/wood/large, /area/station/science/research) "iaq" = ( -/obj/machinery/light/small/directional/south, /obj/structure/extinguisher_cabinet/directional/south, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "iay" = ( /turf/closed/wall, @@ -27731,13 +27884,13 @@ }, /obj/effect/turf_decal/bot, /obj/machinery/button/door/directional/east{ - id = "cargounload"; + id = 68; layer = 4; - name = "Loading Doors"; + name = "Unloading Doors"; pixel_y = 6 }, /obj/machinery/button/door/directional/east{ - id = "cargoload"; + id = 69; layer = 4; name = "Loading Doors"; pixel_y = -6 @@ -27823,6 +27976,20 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/department/engine) +"icH" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/effect/turf_decal/trimline/blue/filled/line, +/obj/machinery/light/cold/directional/south, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, +/turf/open/floor/iron/white/smooth_edge{ + dir = 1 + }, +/area/station/medical/exam_room) "icI" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -27832,6 +27999,16 @@ "icP" = ( /turf/open/floor/glass/reinforced, /area/station/medical/medbay/central) +"idg" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/power/apc/auto_name/directional/north, +/turf/open/floor/plating, +/area/station/maintenance/department/medical/central) "idl" = ( /obj/structure/chair/sofa/right/maroon{ dir = 1 @@ -28122,6 +28299,13 @@ /obj/item/radio, /turf/open/floor/iron/smooth, /area/station/security/checkpoint/supply) +"ijj" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/port) "ijw" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -28162,11 +28346,13 @@ /turf/open/floor/pod/dark, /area/station/service/chapel) "ikc" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/disposalpipe/segment{ +/obj/structure/disposalpipe/junction/flip{ dir = 4 }, -/turf/open/floor/iron/smooth, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/department/medical/central) "ike" = ( /obj/effect/turf_decal/box/corners{ @@ -28293,7 +28479,7 @@ dir = 4 }, /turf/open/floor/carpet/cyan, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "ilY" = ( /obj/effect/turf_decal/trimline/yellow/filled/line, /obj/effect/turf_decal/trimline/blue/filled/line, @@ -28309,6 +28495,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold/dark/hidden, /turf/open/floor/iron/white/smooth_large, /area/station/science/xenobiology) +"imc" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/port) "imd" = ( /obj/effect/turf_decal/siding/wood{ dir = 10 @@ -28377,7 +28569,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/carpet/cyan, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "inc" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/door/window/left/directional/west{ @@ -28771,10 +28963,10 @@ /area/station/maintenance/port/central) "irm" = ( /obj/structure/cable, -/obj/structure/closet/secure_closet/medical2, /obj/machinery/power/apc/auto_name/directional/west, /obj/effect/turf_decal/tile/blue/fourcorners, /obj/effect/turf_decal/bot, +/obj/machinery/iv_drip, /turf/open/floor/iron/freezer, /area/station/medical/treatment_center) "iru" = ( @@ -28823,6 +29015,18 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron/smooth_edge, /area/station/engineering/atmos) +"irU" = ( +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/obj/structure/cable, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/white, +/area/station/medical/exam_room) "irZ" = ( /obj/effect/turf_decal/trimline/neutral/filled/warning{ dir = 4 @@ -28849,6 +29053,10 @@ }, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"ish" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/aft/greater) "isk" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/table/wood, @@ -28863,6 +29071,11 @@ }, /turf/open/floor/iron/dark/smooth_large, /area/station/security/prison) +"isr" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/trash_pile, +/turf/open/floor/plating, +/area/station/maintenance/department/engine) "iss" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -29089,7 +29302,7 @@ }, /obj/structure/cable, /turf/open/floor/plating, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "iuX" = ( /obj/structure/sign/nanotrasen{ pixel_x = 32 @@ -29651,7 +29864,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "iCx" = ( /obj/structure/chair/plastic{ dir = 4 @@ -29715,7 +29928,7 @@ "iDu" = ( /obj/effect/spawner/random/trash/garbage, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/engine/atmos) "iDC" = ( /obj/effect/turf_decal/stripes/line{ @@ -29884,7 +30097,7 @@ dir = 4 }, /turf/open/floor/iron/dark/smooth_large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "iGy" = ( /obj/structure/sign/logo{ icon_state = "nanotrasen_sign3"; @@ -30063,7 +30276,7 @@ "iJi" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/trash_pile, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/engine/atmos) "iJn" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ @@ -30115,13 +30328,6 @@ /obj/effect/spawner/random/structure/grille, /turf/open/floor/iron/smooth, /area/station/maintenance/port/fore) -"iJJ" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/closet/emcloset, -/obj/effect/turf_decal/bot, -/obj/machinery/light/small/directional/south, -/turf/open/floor/iron/smooth, -/area/station/maintenance/department/science/ordnance_maint) "iJR" = ( /obj/effect/turf_decal/stripes/red/full, /obj/effect/turf_decal/stripes/line{ @@ -30880,7 +31086,7 @@ /obj/structure/filingcabinet/employment, /obj/effect/turf_decal/bot, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "iVS" = ( /obj/structure/disposaloutlet{ dir = 8 @@ -31064,7 +31270,7 @@ dir = 6 }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/port) "iXB" = ( /obj/structure/chair/stool/bar, @@ -31141,7 +31347,7 @@ dir = 10 }, /turf/open/floor/iron/dark/smooth_large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "iYz" = ( /obj/machinery/holopad, /obj/effect/turf_decal/bot, @@ -31206,7 +31412,7 @@ /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, /turf/open/floor/plating, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "iZs" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -32026,7 +32232,7 @@ /area/station/command/gateway) "jlB" = ( /turf/closed/wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "jlD" = ( /obj/machinery/ore_silo, /obj/effect/turf_decal/bot, @@ -32330,6 +32536,18 @@ "jqn" = ( /turf/closed/wall, /area/station/maintenance/port/upper) +"jqH" = ( +/obj/machinery/power/apc/auto_name/directional/east, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 4 + }, +/obj/structure/cable, +/turf/open/floor/iron/white/smooth_edge{ + dir = 8 + }, +/area/station/medical/office) "jqL" = ( /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/skyrat_decals/enclave/middle/right{ @@ -32527,10 +32745,19 @@ "jtc" = ( /turf/open/floor/carpet, /area/station/commons/dorms) +"jte" = ( +/turf/open/floor/plating, +/area/station/maintenance/department/engine/atmos) "jtf" = ( /obj/structure/disposalpipe/segment, /turf/open/floor/iron/large, /area/station/hallway/primary/central/aft) +"jtq" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/port/greater) "jty" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -33210,6 +33437,13 @@ /obj/structure/cable, /turf/open/floor/iron/smooth, /area/station/engineering/atmos/hfr_room) +"jCq" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/aft/lesser) "jCv" = ( /obj/machinery/atmospherics/components/binary/pump/on{ dir = 8 @@ -33868,7 +34102,7 @@ /area/station/service/theater) "jKu" = ( /obj/structure/trash_pile, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/engine/atmos/lesser) "jKx" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ @@ -33956,7 +34190,7 @@ /area/station/cargo/office) "jLS" = ( /obj/structure/trash_pile, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/greater) "jMc" = ( /obj/effect/turf_decal/trimline/brown/filled/line{ @@ -34556,7 +34790,7 @@ /obj/machinery/status_display/ai/directional/north, /obj/effect/turf_decal/bot, /turf/open/floor/carpet/cyan, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "jVx" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -34570,6 +34804,16 @@ /obj/effect/spawner/random/trash/garbage, /turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/port/central) +"jVE" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/department/medical) "jVG" = ( /obj/machinery/computer/security/qm{ dir = 1 @@ -34644,7 +34888,7 @@ }, /mob/living/basic/pet/dog/dobermann/walter, /turf/open/floor/wood/large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "jXc" = ( /obj/effect/turf_decal/siding/wood{ dir = 6 @@ -35478,7 +35722,7 @@ /obj/effect/turf_decal/siding/wood, /obj/structure/cable, /turf/open/floor/wood/large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "kjl" = ( /obj/effect/landmark/start/hangover, /obj/effect/spawner/random/engineering/tracking_beacon, @@ -35726,6 +35970,9 @@ }, /turf/open/floor/iron/large, /area/station/commons/vacant_room/commissary) +"knn" = ( +/turf/open/floor/plating, +/area/station/maintenance/port/fore) "knu" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 4 @@ -35931,6 +36178,13 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron/smooth_large, /area/station/cargo/sorting) +"kpB" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/starboard/aft) "kpG" = ( /obj/machinery/airalarm/directional/north, /obj/effect/turf_decal/siding/wood{ @@ -36191,6 +36445,12 @@ dir = 4 }, /area/station/engineering/atmos) +"kux" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/department/engine) "kuF" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -36238,7 +36498,7 @@ /obj/item/stack/sheet/glass{ amount = 4 }, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/starboard/greater) "kvj" = ( /obj/machinery/light/floor, @@ -36640,7 +36900,7 @@ /obj/effect/turf_decal/siding/wood/end, /obj/effect/turf_decal/box, /turf/open/floor/wood/large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "kzM" = ( /obj/machinery/field/generator, /obj/effect/turf_decal/stripes/line, @@ -36659,6 +36919,20 @@ }, /turf/open/floor/iron/freezer, /area/station/medical/treatment_center) +"kzV" = ( +/obj/structure/chair/office{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/obj/machinery/airalarm/directional/south, +/obj/structure/cable, +/obj/effect/turf_decal/trimline/blue/filled/line, +/turf/open/floor/iron/white/smooth_edge{ + dir = 1 + }, +/area/station/medical/exam_room) "kAd" = ( /obj/effect/turf_decal/stripes/end, /obj/effect/turf_decal/siding/thinplating/dark/end, @@ -36694,7 +36968,7 @@ /area/station/ai_monitored/turret_protected/aisat/foyer) "kAm" = ( /turf/closed/wall, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "kAq" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -37089,7 +37363,7 @@ dir = 4 }, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "kFf" = ( /obj/machinery/holopad/secure, /obj/effect/turf_decal/siding/wood, @@ -37156,7 +37430,7 @@ "kFT" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/trash/garbage, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/aft/lesser) "kFW" = ( /obj/effect/turf_decal/trimline/purple/filled/warning{ @@ -37603,6 +37877,10 @@ /obj/effect/landmark/generic_maintenance_landmark, /turf/open/floor/iron/smooth, /area/station/maintenance/port/fore) +"kLl" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/science/research/abandoned) "kLz" = ( /turf/open/floor/iron/cafeteria, /area/station/service/cafeteria) @@ -37709,7 +37987,6 @@ /area/station/engineering/atmos/storage) "kMI" = ( /obj/structure/tank_holder/extinguisher, -/obj/machinery/light/small/directional/south, /turf/open/floor/iron/smooth, /area/station/maintenance/port) "kMM" = ( @@ -37970,7 +38247,7 @@ /area/station/command/heads_quarters/captain/private) "kRg" = ( /obj/structure/table/reinforced, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/machinery/status_display/evac/directional/south, /obj/item/reagent_containers/spray/cleaner, /turf/open/floor/iron/dark/smooth_large, @@ -38052,7 +38329,7 @@ specialfunctions = 4 }, /turf/open/floor/carpet/cyan, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "kSA" = ( /obj/effect/turf_decal/bot, /obj/effect/landmark/event_spawn, @@ -38751,6 +39028,7 @@ /area/station/hallway/secondary/entry) "lcd" = ( /obj/structure/table, +/obj/item/storage/fancy/donut_box, /turf/open/floor/glass/reinforced, /area/station/security/execution/transfer) "lcf" = ( @@ -38767,6 +39045,7 @@ /area/station/engineering/atmos/hfr_room) "lcn" = ( /obj/effect/turf_decal/stripes/red/box, +/obj/structure/sign/delam_procedure/directional/east, /turf/open/floor/iron/smooth, /area/station/engineering/main) "lcr" = ( @@ -39102,7 +39381,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/department/medical/central) "lgZ" = ( /obj/machinery/door/airlock/security{ @@ -39206,6 +39485,7 @@ }, /obj/structure/extinguisher_cabinet/directional/west, /obj/effect/turf_decal/bot, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, /obj/structure/rack, /turf/open/floor/iron/showroomfloor, /area/station/medical/coldroom) @@ -39213,7 +39493,6 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/item/kirbyplants/random, /obj/machinery/duct, /turf/open/floor/iron/white/smooth_large, /area/station/medical/storage) @@ -39272,7 +39551,7 @@ pixel_y = 5 }, /turf/open/floor/wood/large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "lji" = ( /obj/structure/window/reinforced/plasma/spawner/directional/west, /obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/visible, @@ -39287,14 +39566,6 @@ "ljI" = ( /turf/closed/wall, /area/station/medical/morgue) -"ljL" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/light/small/directional/east, -/turf/open/floor/catwalk_floor/iron_smooth, -/area/station/maintenance/department/science/ordnance_maint) "ljV" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -39620,6 +39891,12 @@ }, /turf/open/floor/iron/grimy, /area/station/commons/lounge) +"lnU" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/port/greater) "lnX" = ( /obj/effect/turf_decal/trimline/dark_red/warning{ dir = 1 @@ -39762,6 +40039,14 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/smooth_large, /area/station/engineering/lobby) +"lqL" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/starboard/greater) "lqR" = ( /obj/item/folder/red{ pixel_x = -3; @@ -39797,7 +40082,7 @@ /obj/item/bedsheet/nanotrasen/double, /obj/machinery/newscaster/directional/west, /turf/open/floor/carpet/cyan, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "lrh" = ( /obj/effect/turf_decal/trimline/blue/filled/warning{ dir = 10 @@ -40311,6 +40596,10 @@ dir = 1 }, /area/station/hallway/secondary/command) +"lyJ" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/department/science/ordnance_maint) "lyY" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/door/poddoor/preopen{ @@ -40774,7 +41063,7 @@ "lFl" = ( /obj/effect/spawner/random/trash/garbage, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/science/ordnance_maint) "lFE" = ( /obj/structure/lattice/catwalk, @@ -40876,6 +41165,15 @@ /obj/effect/mapping_helpers/airlock/access/any/science/xenobio, /turf/open/floor/iron/white/smooth_large, /area/station/science/xenobiology) +"lGy" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/department/crew_quarters/bar) "lGB" = ( /obj/structure/table/reinforced, /turf/open/floor/iron/dark/textured_large, @@ -40896,7 +41194,7 @@ dir = 6 }, /obj/effect/turf_decal/tile/blue/full, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/structure/sign/poster/official/random/directional/south, /obj/structure/sign/nanotrasen{ pixel_x = 32 @@ -41310,6 +41608,9 @@ name = "Cold Room Maintenance" }, /obj/effect/mapping_helpers/airlock/access/all/medical/surgery, +/obj/machinery/atmospherics/pipe/heat_exchanging/junction{ + dir = 1 + }, /turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/department/medical/central) "lMC" = ( @@ -41431,7 +41732,7 @@ "lOd" = ( /obj/effect/spawner/random/maintenance/four, /obj/effect/spawner/random/entertainment/money, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/medical) "lOi" = ( /obj/effect/turf_decal/tile/red/anticorner{ @@ -41539,6 +41840,10 @@ /obj/structure/window/reinforced/fulltile, /turf/open/misc/asteroid, /area/station/engineering/lobby) +"lQf" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/department/crew_quarters/bar) "lQh" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -43156,6 +43461,9 @@ /obj/effect/turf_decal/tile/dark_blue/fourcorners, /turf/open/floor/iron/dark, /area/station/medical/medbay/central) +"mlv" = ( +/turf/open/floor/plating, +/area/station/maintenance/department/crew_quarters/bar) "mlP" = ( /obj/structure/disposalpipe/segment{ dir = 9 @@ -44645,6 +44953,12 @@ }, /turf/open/floor/iron/white/smooth_large, /area/station/science/auxlab) +"mJA" = ( +/obj/machinery/atmospherics/components/unary/thermomachine/freezer/on/coldroom{ + dir = 4 + }, +/turf/open/floor/catwalk_floor/iron_smooth, +/area/station/maintenance/department/medical/central) "mJB" = ( /obj/structure/disposalpipe/segment, /turf/open/floor/iron/freezer, @@ -44767,7 +45081,7 @@ /turf/open/floor/wood/large, /area/station/service/library) "mLy" = ( -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/starboard/greater) "mLz" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -44986,7 +45300,7 @@ }, /obj/effect/turf_decal/tile/dark_blue/full, /turf/open/floor/iron/dark/smooth_large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "mOa" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 4 @@ -45343,6 +45657,10 @@ }, /turf/open/floor/engine, /area/station/ai_monitored/security/armory) +"mTl" = ( +/obj/effect/landmark/event_spawn, +/turf/open/floor/iron/white/smooth_large, +/area/station/medical/exam_room) "mTv" = ( /obj/effect/spawner/random/structure/girder, /turf/open/floor/iron/smooth, @@ -45398,7 +45716,7 @@ "mUE" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/cobweb, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "mUF" = ( /obj/structure/chair/stool/directional/west, @@ -45759,6 +46077,9 @@ }, /turf/open/floor/iron/smooth_large, /area/station/command/cc_dock) +"mYn" = ( +/turf/open/floor/plating, +/area/station/maintenance/department/science/ordnance_maint) "mYv" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, @@ -45790,7 +46111,7 @@ dir = 1 }, /turf/open/floor/iron/dark/smooth_large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "mYL" = ( /obj/effect/turf_decal/trimline/red/filled/warning{ dir = 1 @@ -45931,7 +46252,7 @@ /area/station/engineering/atmos) "naG" = ( /obj/structure/reagent_dispensers/fueltank, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/greater) "naI" = ( /obj/item/radio/intercom/directional/east, @@ -46180,7 +46501,7 @@ }, /obj/structure/table/wood, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "ngt" = ( /obj/machinery/power/shuttle_engine/heater, /obj/effect/turf_decal/stripes/line{ @@ -46208,6 +46529,15 @@ dir = 4 }, /area/station/hallway/secondary/command) +"ngZ" = ( +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 1 + }, +/turf/open/floor/iron/white/smooth_edge, +/area/station/medical/exam_room) "nhc" = ( /obj/structure/grille, /turf/closed/wall/r_wall/rust, @@ -46868,7 +47198,7 @@ pixel_y = 5 }, /turf/closed/wall/r_wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "npP" = ( /obj/effect/turf_decal/siding/wood{ dir = 6 @@ -47074,7 +47404,6 @@ "ntn" = ( /obj/structure/table, /obj/effect/spawner/random/maintenance, -/obj/machinery/light/small/directional/east, /obj/item/storage/box, /turf/open/floor/iron/smooth, /area/station/maintenance/aft/lesser) @@ -47190,7 +47519,6 @@ "nub" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/trash/mopbucket, -/obj/machinery/light/small/directional/east, /turf/open/floor/iron/smooth, /area/station/maintenance/aft/greater) "nuf" = ( @@ -47402,6 +47730,9 @@ }, /turf/open/floor/engine/vacuum, /area/station/science/ordnance/burnchamber) +"nwW" = ( +/turf/closed/wall, +/area/station/medical/exam_room) "nwY" = ( /obj/item/kirbyplants/random, /obj/structure/sign/poster/official/random/directional/west, @@ -47536,7 +47867,7 @@ "nzb" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/trash/caution_sign, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/engine) "nzh" = ( /obj/effect/turf_decal/siding/wood{ @@ -47579,7 +47910,7 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/department/medical/central) "nzD" = ( /obj/effect/turf_decal/trimline/red/filled/warning{ @@ -47656,7 +47987,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/spawner/random/trash/garbage, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/aft/lesser) "nAw" = ( /obj/effect/spawner/structure/window/reinforced, @@ -47829,6 +48160,11 @@ /obj/effect/turf_decal/bot, /turf/open/floor/glass/reinforced, /area/station/security/office) +"nES" = ( +/obj/structure/cable, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/department/engine/atmos/lesser) "nEW" = ( /obj/machinery/atmospherics/pipe/smart/simple/orange/visible{ dir = 4 @@ -47925,6 +48261,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold/cyan/visible/layer2, /turf/open/floor/iron/smooth, /area/station/hallway/primary/aft) +"nGb" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/aft) "nGg" = ( /obj/structure/closet/radiation, /obj/effect/turf_decal/box, @@ -47998,7 +48341,7 @@ /area/station/service/hydroponics) "nHD" = ( /obj/effect/spawner/random/structure/crate, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/security/brig) "nHY" = ( /obj/structure/fluff/arc, @@ -48715,7 +49058,7 @@ /area/station/commons/dorms) "nRd" = ( /obj/effect/spawner/random/structure/crate_abandoned, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/crew_quarters/bar) "nRo" = ( /obj/structure/cable, @@ -49481,7 +49824,7 @@ pixel_y = 32 }, /turf/open/floor/wood/large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "oaD" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -49500,7 +49843,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, -/obj/effect/mapping_helpers/airlock/access/all/security/general, +/obj/effect/mapping_helpers/airlock/access/all/security/entrance, /turf/open/floor/iron/dark/smooth_large, /area/station/security/brig) "oaL" = ( @@ -49783,7 +50126,7 @@ dir = 5 }, /obj/effect/turf_decal/tile/blue/full, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/structure/sign/nanotrasen{ pixel_x = 32 }, @@ -49798,6 +50141,19 @@ /obj/effect/decal/cleanable/cobweb, /turf/open/floor/iron/smooth, /area/station/maintenance/department/engine/atmos/lesser) +"ofF" = ( +/obj/structure/trash_pile, +/turf/open/floor/plating, +/area/station/maintenance/starboard/greater) +"ofG" = ( +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 1 + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 4 + }, +/turf/open/floor/iron/white/smooth_edge, +/area/station/medical/exam_room) "ofY" = ( /obj/structure/table/reinforced, /obj/effect/turf_decal/bot, @@ -49816,6 +50172,7 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, +/obj/machinery/light/cold/directional/south, /turf/open/floor/iron/white/smooth_edge{ dir = 1 }, @@ -49916,7 +50273,7 @@ }, /obj/structure/table/wood, /turf/open/floor/carpet/cyan, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "ohz" = ( /obj/machinery/light/cold/directional/north, /obj/effect/turf_decal/trimline/white/end, @@ -50405,6 +50762,18 @@ /obj/structure/window/spawner/directional/north, /turf/open/floor/grass, /area/station/hallway/secondary/exit/departure_lounge) +"ooU" = ( +/obj/machinery/door/airlock/medical{ + name = "Exam Room" + }, +/obj/effect/mapping_helpers/airlock/access/any/medical/general, +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/iron/white/smooth_large, +/area/station/medical/exam_room) "ooW" = ( /obj/effect/turf_decal/trimline/dark_red/arrow_cw{ dir = 1 @@ -50851,6 +51220,11 @@ dir = 4 }, /area/station/cargo/drone_bay) +"ouX" = ( +/obj/structure/cable, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/department/security/brig) "ovf" = ( /obj/effect/turf_decal/trimline/blue/filled/warning{ dir = 4 @@ -50880,7 +51254,7 @@ dir = 9 }, /turf/open/floor/iron/dark/smooth_large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "ovT" = ( /obj/effect/turf_decal/trimline/yellow/filled/line, /obj/effect/turf_decal/trimline/blue/filled/line, @@ -51012,6 +51386,10 @@ }, /turf/open/floor/plating, /area/station/science/research) +"oxA" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/port/aft) "oxE" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/mech_bay_recharge_port, @@ -51321,7 +51699,7 @@ /area/station/hallway/primary/central/fore) "oBW" = ( /obj/effect/spawner/random/trash/garbage, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) "oCl" = ( /turf/closed/wall/r_wall, @@ -51423,10 +51801,6 @@ }, /turf/open/floor/iron/dark, /area/station/science/robotics/lab) -"oEf" = ( -/obj/machinery/light/small/directional/west, -/turf/open/floor/iron/smooth, -/area/station/maintenance/port/aft) "oEk" = ( /obj/machinery/airalarm/directional/east, /obj/machinery/light/small/directional/east, @@ -51772,7 +52146,7 @@ }, /obj/machinery/light_switch/directional/north, /turf/open/floor/carpet/cyan, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "oIp" = ( /obj/machinery/camera/directional/north{ c_tag = "Prison - Pool"; @@ -51987,6 +52361,7 @@ /area/station/medical/virology) "oLS" = ( /obj/effect/landmark/event_spawn, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/showroomfloor, /area/station/medical/coldroom) "oLT" = ( @@ -52833,13 +53208,13 @@ name = "curtain" }, /turf/open/floor/grass, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "oXG" = ( /obj/effect/decal/cleanable/dirt, /obj/item/trash/popcorn, /obj/effect/landmark/generic_maintenance_landmark, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/aft/lesser) "oXI" = ( /turf/closed/wall, @@ -52871,7 +53246,7 @@ /turf/open/floor/circuit/telecomms/server, /area/station/tcommsat/server) "oXT" = ( -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/greater) "oXW" = ( /obj/structure/cable, @@ -52995,6 +53370,14 @@ "oZv" = ( /turf/open/floor/iron/smooth_large, /area/station/science/ordnance) +"oZB" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment, +/obj/effect/spawner/random/structure/steam_vent, +/turf/open/floor/plating, +/area/station/maintenance/department/crew_quarters/bar) "oZE" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -53245,6 +53628,25 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/eva_shed/port) +"pcS" = ( +/obj/structure/table/glass, +/obj/machinery/computer/records/medical/laptop{ + dir = 4; + pixel_x = 3; + pixel_y = 2 + }, +/obj/machinery/power/apc/auto_name/directional/south, +/obj/structure/cable, +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 10 + }, +/obj/machinery/camera/directional/west{ + c_tag = "Medbay - Exam Room"; + name = "medical camera"; + network = list("ss13","medical") + }, +/turf/open/floor/iron/white, +/area/station/medical/exam_room) "pdc" = ( /obj/structure/disposalpipe/segment, /obj/structure/extinguisher_cabinet/directional/east, @@ -53688,7 +54090,7 @@ "phK" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/sign/poster/random/directional/west, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/starboard/aft) "pic" = ( /obj/structure/flora/grass/jungle, @@ -53932,6 +54334,23 @@ dir = 8 }, /area/station/hallway/primary/fore) +"plo" = ( +/obj/structure/table/glass, +/obj/item/paper_bin/carbon{ + pixel_x = -3; + pixel_y = 5 + }, +/obj/item/pen{ + pixel_x = -3; + pixel_y = 7 + }, +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 8 + }, +/turf/open/floor/iron/white/smooth_edge{ + dir = 4 + }, +/area/station/medical/exam_room) "plF" = ( /obj/machinery/photocopier, /obj/machinery/power/apc/auto_name/directional/north, @@ -54141,6 +54560,10 @@ /obj/effect/landmark/event_spawn, /turf/open/floor/iron/smooth_large, /area/station/engineering/atmos/storage/gas) +"pnU" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/port/fore) "pnV" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/disposalpipe/segment{ @@ -54502,7 +54925,7 @@ id = "cargounload" }, /obj/machinery/door/poddoor{ - id = "cargounload"; + id = 68; name = "Supply Dock Unloading Door" }, /turf/open/floor/iron/smooth_large, @@ -54900,6 +55323,25 @@ }, /turf/open/floor/iron/dark/smooth_large, /area/station/service/hydroponics/garden) +"pAE" = ( +/obj/structure/table/glass, +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 5 + }, +/obj/item/folder/white{ + pixel_y = 4 + }, +/obj/item/flashlight/pen{ + pixel_y = 4 + }, +/obj/item/clothing/neck/stethoscope{ + pixel_y = 4 + }, +/obj/machinery/firealarm/directional/east, +/obj/machinery/light/cold/directional/east, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/white, +/area/station/medical/exam_room) "pAI" = ( /obj/effect/turf_decal/trimline/yellow/filled/warning, /obj/effect/turf_decal/trimline/blue/filled/warning, @@ -55009,7 +55451,7 @@ /area/station/engineering/lobby) "pBZ" = ( /obj/effect/spawner/random/maintenance/two, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/engine/atmos) "pCd" = ( /obj/machinery/duct, @@ -55052,7 +55494,7 @@ dir = 1 }, /turf/open/floor/iron/dark/smooth_large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "pCA" = ( /obj/structure/fans/tiny/forcefield{ dir = 4 @@ -55165,7 +55607,7 @@ /obj/structure/disposalpipe/segment{ dir = 5 }, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/department/crew_quarters/bar) "pDV" = ( /turf/open/floor/iron/white/smooth_large, @@ -55266,7 +55708,7 @@ }, /obj/machinery/firealarm/directional/south, /turf/open/floor/carpet/cyan, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "pGl" = ( /obj/effect/mapping_helpers/airlock/access/all/science/general, /obj/machinery/door/airlock/maintenance_hatch{ @@ -55443,7 +55885,7 @@ /obj/machinery/holopad, /obj/effect/turf_decal/bot, /turf/open/floor/wood/large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "pIm" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -55717,6 +56159,15 @@ }, /turf/open/floor/carpet, /area/station/commons/dorms) +"pMG" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/greater) "pMO" = ( /obj/machinery/newscaster/directional/north, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -56124,7 +56575,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/spawner/random/structure/steam_vent, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/aft/greater) "pSX" = ( /obj/machinery/door/firedoor, @@ -57349,14 +57800,15 @@ /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 8 }, -/obj/structure/closet/crate/freezer/blood, /obj/effect/turf_decal/bot, +/obj/machinery/atmospherics/components/binary/pump/on, +/obj/structure/closet/crate/freezer/blood, /turf/open/floor/iron/showroomfloor, /area/station/medical/coldroom) "qgK" = ( -/obj/structure/closet/secure_closet/medical2, /obj/effect/turf_decal/tile/blue/fourcorners, /obj/effect/turf_decal/bot, +/obj/machinery/iv_drip, /turf/open/floor/iron/freezer, /area/station/medical/treatment_center) "qgS" = ( @@ -57370,7 +57822,6 @@ }, /area/station/science/xenobiology) "qgT" = ( -/obj/machinery/lapvend, /turf/open/floor/iron/white, /area/station/hallway/primary/fore) "qha" = ( @@ -57466,7 +57917,7 @@ }, /obj/effect/turf_decal/bot, /turf/open/floor/wood/large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "qhT" = ( /obj/machinery/door/airlock/external{ name = "Departure Shuttle Airlock"; @@ -57588,6 +58039,20 @@ }, /turf/open/floor/plating, /area/space/nearstation) +"qkb" = ( +/obj/structure/bed/pod{ + desc = "An old medical bed, just waiting for replacement with something up to date."; + name = "medical bed" + }, +/obj/item/bedsheet/medical, +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/white/smooth_edge{ + dir = 8 + }, +/area/station/medical/exam_room) "qki" = ( /obj/structure/table/reinforced, /obj/item/assembly/voice{ @@ -57721,7 +58186,7 @@ "qmk" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/trash/moisture_trap, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/crew_quarters/bar) "qmn" = ( /obj/effect/decal/cleanable/dirt, @@ -57945,7 +58410,7 @@ pixel_x = 16 }, /turf/open/floor/wood/large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "qpe" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 1 @@ -58050,7 +58515,7 @@ "qqg" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/sign/poster/random/directional/west, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/aft/lesser) "qqs" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -58705,7 +59170,7 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "qAu" = ( /obj/machinery/conveyor{ @@ -58716,7 +59181,7 @@ /area/station/cargo/storage) "qAD" = ( /obj/effect/spawner/random/trash/mess, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/engine/atmos) "qAI" = ( /obj/structure/table/glass, @@ -58758,7 +59223,7 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/spawner/random/structure/steam_vent, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "qBp" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -59560,7 +60025,7 @@ /area/station/engineering/atmos/storage/gas) "qMB" = ( /obj/effect/spawner/random/trash/mess, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "qMC" = ( /obj/effect/turf_decal/trimline/green/filled/warning{ @@ -59744,7 +60209,7 @@ "qQC" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/plastic, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "qQJ" = ( /obj/machinery/status_display/ai/directional/north, @@ -60086,6 +60551,12 @@ dir = 4 }, /area/station/security/prison) +"qUt" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/department/crew_quarters/bar) "qUF" = ( /obj/effect/turf_decal/trimline/purple/filled/line{ dir = 8 @@ -60270,7 +60741,7 @@ dir = 4 }, /obj/effect/spawner/random/structure/steam_vent, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/starboard/greater) "qXm" = ( /obj/structure/trash_pile, @@ -60992,7 +61463,8 @@ /area/station/commons/fitness/recreation/entertainment) "riy" = ( /obj/structure/closet/secure_closet/evidence{ - name = "Brig Officer's Locker" + name = "Brig Officer's Locker"; + req_one_access = list("brig") }, /obj/machinery/requests_console/auto_name/directional/west, /obj/machinery/light_switch/directional/south, @@ -61382,7 +61854,7 @@ /area/station/security/detectives_office) "rnL" = ( /obj/effect/spawner/random/trash/garbage, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port) "rnR" = ( /obj/structure/rack, @@ -61395,7 +61867,7 @@ "rnV" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/trash/hobo_squat, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/aft/lesser) "rog" = ( /obj/effect/turf_decal/trimline/green/filled/line{ @@ -61409,7 +61881,7 @@ /area/station/hallway/primary/aft) "rol" = ( /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/greater) "ron" = ( /obj/machinery/atmospherics/components/binary/pump/off, @@ -61590,7 +62062,7 @@ /area/station/engineering/power_room) "rrb" = ( /obj/structure/trash_pile, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/medical) "rrg" = ( /obj/effect/turf_decal/trimline/blue/filled/warning{ @@ -62053,7 +62525,7 @@ dir = 4 }, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "rzh" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/siding/wood, @@ -62095,7 +62567,7 @@ /area/station/engineering/atmos) "rzT" = ( /obj/effect/mapping_helpers/burnt_floor, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/aft) "rAh" = ( /obj/effect/turf_decal/bot, @@ -62442,7 +62914,7 @@ dir = 8 }, /turf/open/floor/iron/dark/smooth_large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "rDP" = ( /obj/machinery/computer/shuttle/mining{ dir = 1; @@ -62457,7 +62929,7 @@ "rDU" = ( /obj/effect/decal/cleanable/dirt, /obj/item/storage/box/lights/mixed, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/greater) "rEe" = ( /obj/machinery/status_display/evac/directional/west, @@ -62759,6 +63231,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/checker, /area/station/science/lab) +"rJa" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/department/engine/atmos) "rJe" = ( /obj/effect/turf_decal/vg_decals/atmos/carbon_dioxide, /turf/open/floor/engine/co2, @@ -63343,6 +63819,10 @@ /obj/structure/lattice/catwalk, /turf/open/space, /area/station/solars/starboard/aft) +"rSG" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/port) "rSO" = ( /obj/structure/table, /obj/item/plate, @@ -63738,7 +64218,7 @@ "rXL" = ( /obj/effect/spawner/random/trash/garbage, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/crew_quarters/bar) "rXU" = ( /obj/effect/turf_decal/trimline/yellow/filled/line, @@ -63795,7 +64275,7 @@ /area/station/hallway/primary/aft) "rYT" = ( /obj/item/robot_suit, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/science/research/abandoned) "rYX" = ( /obj/structure/cable, @@ -64101,7 +64581,7 @@ name = "command camera" }, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "sfc" = ( /obj/effect/spawner/structure/window, /turf/open/floor/plating, @@ -64146,7 +64626,7 @@ pixel_y = 10 }, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "sfx" = ( /obj/effect/turf_decal/tile/neutral{ dir = 8 @@ -64218,7 +64698,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/structure/crate_empty, /obj/effect/spawner/random/maintenance/three, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/greater) "sgn" = ( /obj/effect/spawner/structure/window/reinforced, @@ -64342,7 +64822,7 @@ /area/station/medical/medbay/central) "shE" = ( /obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/aft/lesser) "shM" = ( /obj/structure/closet/crate/bin, @@ -64801,14 +65281,6 @@ /obj/effect/turf_decal/trimline/blue/mid_joiner, /turf/open/floor/iron/dark/smooth_large, /area/station/hallway/secondary/command) -"spf" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/light/small/directional/south, -/turf/open/floor/catwalk_floor/iron_smooth, -/area/station/maintenance/aft/greater) "spi" = ( /obj/structure/table, /obj/item/flashlight{ @@ -64904,7 +65376,7 @@ name = "curtain" }, /turf/open/floor/grass, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "spQ" = ( /obj/item/stack/sheet/iron/fifty{ pixel_y = 3 @@ -65067,6 +65539,12 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron/smooth_edge, /area/station/cargo/lobby) +"ssU" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/department/engine/atmos) "ssV" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -65629,7 +66107,7 @@ }, /obj/effect/turf_decal/tile/dark_blue/full, /turf/open/floor/iron/dark/smooth_large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "sCw" = ( /obj/machinery/door/airlock/maintenance_hatch, /obj/effect/mapping_helpers/airlock/abandoned, @@ -65652,7 +66130,7 @@ /area/station/medical/psychology) "sCN" = ( /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/security/brig) "sCO" = ( /obj/structure/table/reinforced, @@ -65800,7 +66278,7 @@ }, /obj/effect/decal/cleanable/dirt, /obj/machinery/door/poddoor{ - id = "cargoload"; + id = 69; name = "Supply Dock Loading Door" }, /turf/open/floor/iron/smooth_large, @@ -66461,7 +66939,7 @@ }, /obj/structure/cable, /turf/open/floor/plating, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "sLa" = ( /obj/machinery/nuclearbomb/selfdestruct, /obj/item/toy/figure/syndie{ @@ -66731,8 +67209,11 @@ /obj/effect/turf_decal/box/white{ color = "#52B4E9" }, -/obj/machinery/portable_atmospherics/canister/oxygen, /obj/structure/sign/poster/official/science/directional/south, +/obj/machinery/atmospherics/pipe/heat_exchanging/junction{ + dir = 4 + }, +/obj/machinery/portable_atmospherics/canister/anesthetic_mix, /turf/open/floor/iron/showroomfloor, /area/station/medical/coldroom) "sNz" = ( @@ -67706,6 +68187,13 @@ dir = 8 }, /area/station/hallway/secondary/command) +"taC" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/spawner/random/trash/garbage, +/turf/open/floor/plating, +/area/station/maintenance/department/engine) "taK" = ( /obj/effect/turf_decal/bot, /obj/structure/closet/secure_closet/engineering_personal, @@ -67915,7 +68403,7 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/spawner/random/trash/garbage, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/port) "tdO" = ( /obj/machinery/door/firedoor, @@ -68143,6 +68631,10 @@ /obj/effect/spawner/random/structure/table_or_rack, /turf/open/floor/iron/smooth, /area/station/maintenance/department/science/xenobiology) +"tgU" = ( +/obj/effect/spawner/random/trash/garbage, +/turf/open/floor/plating, +/area/station/maintenance/port/aft) "thd" = ( /obj/structure/cable, /obj/effect/turf_decal/trimline/yellow/filled/warning{ @@ -68542,6 +69034,15 @@ dir = 4 }, /area/station/engineering/atmos/pumproom) +"tme" = ( +/obj/structure/table/glass, +/obj/structure/sign/calendar/directional/north, +/obj/machinery/computer/records/medical/laptop, +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 9 + }, +/turf/open/floor/iron/white, +/area/station/medical/office) "tmu" = ( /obj/structure/window/reinforced/spawner/directional/west, /obj/effect/landmark/secequipment, @@ -69191,6 +69692,24 @@ }, /turf/open/floor/iron/dark/smooth_large, /area/station/command/bridge) +"tvc" = ( +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/obj/machinery/disposal/bin, +/obj/effect/turf_decal/box, +/obj/machinery/light_switch/directional/west{ + pixel_y = -15 + }, +/obj/machinery/button/door/directional/west{ + id = "medexamshutter"; + name = "Privacy Shutter Control" + }, +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 9 + }, +/turf/open/floor/iron/white, +/area/station/medical/exam_room) "tve" = ( /obj/machinery/portable_atmospherics/canister, /obj/effect/turf_decal/box, @@ -69619,6 +70138,11 @@ }, /turf/open/floor/iron/dark/smooth_large, /area/station/hallway/secondary/exit/departure_lounge) +"tzN" = ( +/obj/machinery/holopad, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/white/smooth_large, +/area/station/medical/office) "tzT" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -69820,11 +70344,6 @@ /obj/structure/sign/warning/vacuum, /turf/closed/wall/r_wall, /area/station/science/ordnance/testlab) -"tCp" = ( -/obj/machinery/light/small/directional/east, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, -/area/station/maintenance/aft/lesser) "tCx" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -71192,6 +71711,10 @@ }, /turf/open/floor/carpet/orange, /area/station/command/heads_quarters/ce) +"tYr" = ( +/obj/structure/cable, +/turf/open/floor/plating, +/area/station/maintenance/department/security/brig) "tYS" = ( /obj/structure/railing{ dir = 5 @@ -71336,7 +71859,7 @@ pixel_y = 4 }, /turf/open/floor/carpet/cyan, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "uaE" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ dir = 4 @@ -71555,6 +72078,12 @@ /obj/effect/turf_decal/loading_area, /turf/open/floor/iron/smooth_large, /area/station/cargo/storage) +"udp" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plating, +/area/station/maintenance/aft) "uds" = ( /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/trimline/red/filled/warning{ @@ -71953,7 +72482,7 @@ }, /obj/effect/turf_decal/bot, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "ujK" = ( /obj/structure/window/reinforced/spawner/directional/north{ pixel_y = 1 @@ -71974,6 +72503,9 @@ }, /turf/open/floor/iron/dark, /area/station/security/brig) +"ukh" = ( +/turf/open/floor/plating, +/area/station/maintenance/port) "ukB" = ( /obj/structure/table/reinforced, /obj/item/pipe_dispenser, @@ -72297,7 +72829,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/decal/cleanable/dirt, /obj/structure/sign/poster/random/directional/south, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/aft/greater) "uon" = ( /obj/structure/cable, @@ -72715,6 +73247,12 @@ dir = 4 }, /area/station/commons/fitness/recreation/entertainment) +"utq" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/spawner/random/structure/crate_empty, +/obj/effect/spawner/random/maintenance/three, +/turf/open/floor/plating, +/area/station/maintenance/department/medical/central) "utx" = ( /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible{ dir = 9 @@ -72905,6 +73443,13 @@ dir = 1 }, /area/station/engineering/atmos) +"uvB" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/department/engine/atmos) "uvC" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 @@ -72932,7 +73477,7 @@ dir = 4 }, /turf/open/floor/carpet/cyan, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "uvX" = ( /obj/item/radio/intercom/directional/east, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, @@ -74182,7 +74727,7 @@ }, /obj/effect/turf_decal/stripes/line, /turf/open/floor/wood/large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "uNs" = ( /obj/structure/table, /obj/item/kitchen/rollingpin{ @@ -74657,7 +75202,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "uTD" = ( /obj/machinery/holopad, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -74817,6 +75362,10 @@ }, /turf/open/floor/iron/smooth, /area/station/command/cc_dock) +"uVV" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/aft/lesser) "uVW" = ( /obj/structure/table/wood, /obj/machinery/power/apc/auto_name/directional/east, @@ -75185,7 +75734,9 @@ /turf/open/floor/iron/grimy, /area/station/commons/lounge) "vck" = ( -/obj/machinery/recycler, +/obj/machinery/recycler{ + dir = 8 + }, /obj/machinery/conveyor{ dir = 4; id = "garbage" @@ -75384,6 +75935,13 @@ /obj/structure/reagent_dispensers/fueltank, /turf/open/floor/iron/smooth, /area/station/maintenance/department/science/xenobiology) +"vfE" = ( +/obj/structure/table, +/obj/structure/towel_bin, +/turf/open/floor/iron/dark/smooth_edge{ + dir = 4 + }, +/area/station/security/prison) "vfJ" = ( /obj/structure/sign/departments/security/directional/east, /obj/effect/turf_decal/trimline/red/filled/line{ @@ -75502,6 +76060,22 @@ /obj/structure/cable, /turf/open/space/basic, /area/station/solars/aisat) +"vij" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/port/greater) +"vik" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/department/medical) "vio" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -76621,7 +77195,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/aft/greater) "vxv" = ( /mob/living/basic/butterfly, @@ -76732,6 +77306,11 @@ dir = 8 }, /area/station/medical/virology) +"vzg" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/spawner/random/trash/garbage, +/turf/open/floor/plating, +/area/station/maintenance/department/science/ordnance_maint) "vzj" = ( /obj/structure/closet/firecloset/wall{ pixel_x = -32 @@ -76813,10 +77392,24 @@ /obj/machinery/power/shuttle_engine/heater, /turf/open/floor/plating, /area/space/nearstation) +"vAC" = ( +/obj/structure/chair/office{ + dir = 1 + }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 8 + }, +/turf/open/floor/iron/white/smooth_edge{ + dir = 4 + }, +/area/station/medical/office) "vAT" = ( /obj/effect/spawner/random/structure/crate, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/aft/lesser) "vAX" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -77009,7 +77602,7 @@ pixel_y = 32 }, /turf/open/floor/carpet/cyan, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "vEx" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -77171,7 +77764,7 @@ /obj/effect/landmark/start/nanotrasen_consultant, /obj/structure/cable, /turf/open/floor/wood/large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "vGs" = ( /obj/effect/turf_decal/arrows/white, /turf/open/floor/iron/dark/smooth_large, @@ -77343,6 +77936,21 @@ }, /turf/open/floor/iron/small, /area/station/hallway/primary/central) +"vIY" = ( +/obj/machinery/camera/directional/east{ + c_tag = "Medbay - Charting Office"; + name = "medbay camera"; + network = list("ss13","medbay") + }, +/obj/machinery/airalarm/directional/east, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 6 + }, +/turf/open/floor/iron/white, +/area/station/medical/office) "vJm" = ( /obj/effect/turf_decal/siding/wood{ dir = 10 @@ -77377,7 +77985,7 @@ name = "curtain" }, /turf/open/floor/grass, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "vJI" = ( /obj/structure/chair/office, /obj/machinery/newscaster/directional/east, @@ -77779,6 +78387,9 @@ dir = 8 }, /area/station/science/robotics/lab) +"vOX" = ( +/turf/closed/wall/r_wall, +/area/station/medical/exam_room) "vOZ" = ( /obj/effect/turf_decal/tile/green/diagonal_centre, /turf/open/floor/iron/diagonal, @@ -78502,7 +79113,7 @@ "vYT" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/trash/moisture_trap, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/starboard/greater) "vZa" = ( /obj/effect/turf_decal/stripes/corner{ @@ -78897,11 +79508,6 @@ /obj/effect/turf_decal/trimline/blue/mid_joiner, /turf/open/space/basic, /area/space) -"wen" = ( -/obj/machinery/iv_drip, -/obj/effect/turf_decal/tile/blue/fourcorners, -/turf/open/floor/iron/freezer, -/area/station/medical/treatment_center) "wev" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -78959,6 +79565,18 @@ /obj/machinery/light/cold/directional/south, /turf/open/floor/iron/white, /area/station/medical/storage) +"wfk" = ( +/obj/machinery/door/airlock/medical{ + name = "Medbay Office" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/line, +/obj/machinery/door/firedoor, +/obj/effect/mapping_helpers/airlock/access/any/medical/general, +/turf/open/floor/iron/white/smooth_large, +/area/station/medical/office) "wfp" = ( /obj/structure/closet, /obj/structure/window/spawner/directional/south, @@ -79277,7 +79895,6 @@ "wkc" = ( /obj/machinery/portable_atmospherics/scrubber, /obj/effect/turf_decal/delivery, -/obj/machinery/light/small/directional/east, /turf/open/floor/iron/smooth, /area/station/maintenance/aft/lesser) "wkj" = ( @@ -79376,7 +79993,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, -/obj/effect/mapping_helpers/airlock/access/all/security/general, +/obj/effect/mapping_helpers/airlock/access/all/security/entrance, /turf/open/floor/iron/dark/smooth_large, /area/station/security/brig) "wlV" = ( @@ -79418,7 +80035,7 @@ /obj/machinery/light/warm/directional/north, /obj/effect/landmark/start/nanotrasen_consultant, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "wmv" = ( /obj/structure/flora/grass/jungle, /obj/structure/window/fulltile, @@ -79655,6 +80272,12 @@ }, /turf/open/floor/circuit/green, /area/station/ai_monitored/turret_protected/ai) +"wpK" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/port/aft) "wpL" = ( /obj/effect/turf_decal/trimline/yellow/filled/corner, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -79667,13 +80290,6 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron/smooth_large, /area/station/hallway/primary/aft) -"wpU" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/power/apc/auto_name/directional/north, -/turf/open/floor/catwalk_floor/iron_smooth, -/area/station/maintenance/department/medical/central) "wqd" = ( /turf/closed/wall, /area/station/service/kitchen/abandoned) @@ -79947,6 +80563,9 @@ /turf/open/floor/glass/reinforced, /area/station/medical/medbay/central) "wtc" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, /turf/open/floor/iron/showroomfloor, /area/station/medical/coldroom) "wtg" = ( @@ -80250,6 +80869,15 @@ }, /turf/open/floor/engine, /area/station/science/xenobiology) +"wxG" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/machinery/door/poddoor/shutters/preopen{ + dir = 1; + name = "Exam Room Shutters"; + id = "medexamshutter" + }, +/turf/open/floor/plating, +/area/station/medical/exam_room) "wxO" = ( /obj/structure/chair, /obj/effect/turf_decal/stripes/line{ @@ -80629,7 +81257,7 @@ /area/station/common/pool) "wCb" = ( /obj/effect/spawner/random/trash/mopbucket, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/medical/central) "wCh" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, @@ -80803,7 +81431,7 @@ /obj/structure/extinguisher_cabinet/directional/south, /obj/effect/landmark/event_spawn, /turf/open/floor/carpet/cyan, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "wEC" = ( /obj/structure/table, /obj/item/stock_parts/subspace/analyzer, @@ -80857,6 +81485,15 @@ /obj/machinery/door/firedoor, /turf/open/floor/iron/smooth_large, /area/station/hallway/primary/aft) +"wFc" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/department/medical/central) "wFd" = ( /obj/structure/railing, /obj/structure/disposalpipe/segment{ @@ -80935,6 +81572,16 @@ dir = 1 }, /area/station/engineering/atmos/storage) +"wGg" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/hidden, +/turf/open/floor/plating, +/area/station/maintenance/department/medical/central) "wGw" = ( /obj/machinery/holopad, /obj/effect/turf_decal/bot, @@ -81401,7 +82048,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "wMI" = ( /obj/structure/fluff/paper/stack, /obj/item/paper/crumpled{ @@ -81527,8 +82174,8 @@ }, /obj/machinery/airalarm/directional/east, /obj/effect/mapping_helpers/airalarm/tlv_cold_room, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 1 +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 10 }, /turf/open/floor/iron/showroomfloor, /area/station/medical/coldroom) @@ -81740,7 +82387,7 @@ dir = 9 }, /turf/open/floor/iron/dark/smooth_large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "wSg" = ( /obj/machinery/computer/communications, /obj/structure/cable, @@ -82352,7 +82999,7 @@ /obj/item/radio/intercom/directional/south, /obj/machinery/airalarm/directional/west, /turf/open/floor/carpet/cyan, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "xfx" = ( /obj/structure/railing{ dir = 6 @@ -82462,6 +83109,10 @@ }, /turf/open/floor/iron/dark/smooth_large, /area/station/medical/chemistry) +"xgK" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/department/engine) "xgQ" = ( /obj/structure/table/reinforced/plastitaniumglass, /obj/item/toy/captainsaid/collector, @@ -82480,7 +83131,7 @@ /obj/structure/grandfatherclock, /obj/structure/cable, /turf/open/floor/wood/large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "xhb" = ( /obj/structure/window/reinforced/spawner/directional/south, /obj/structure/table, @@ -82513,7 +83164,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/department/engine) "xhS" = ( /obj/structure/reagent_dispensers/fueltank, @@ -82543,6 +83194,17 @@ }, /turf/open/floor/iron/dark/smooth_large, /area/station/security/execution/education) +"xim" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/hidden, +/turf/open/floor/plating, +/area/station/maintenance/department/medical/central) "xir" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/carpet/black, @@ -82762,7 +83424,7 @@ /area/station/commons/dorms) "xlE" = ( /turf/closed/wall/r_wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "xlM" = ( /obj/structure/table/reinforced, /obj/machinery/door/firedoor, @@ -82822,6 +83484,16 @@ dir = 1 }, /area/station/commons/dorms/laundry) +"xmF" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/department/medical/central) "xmH" = ( /obj/effect/spawner/random/engineering/atmospherics_portable, /obj/effect/turf_decal/delivery, @@ -82923,7 +83595,7 @@ "xnR" = ( /obj/structure/cable, /obj/item/stack/sheet/cardboard, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/department/security/brig) "xnU" = ( /obj/machinery/door/airlock/public/glass{ @@ -82947,6 +83619,14 @@ }, /turf/open/floor/iron/smooth, /area/station/maintenance/port/central) +"xof" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/aft/lesser) "xoG" = ( /obj/machinery/biogenerator, /obj/item/reagent_containers/cup/beaker{ @@ -83259,6 +83939,16 @@ dir = 8 }, /area/station/medical/medbay/central) +"xrG" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Medical Office Maintenance" + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/obj/effect/mapping_helpers/airlock/access/any/medical/general, +/turf/open/floor/catwalk_floor/iron_smooth, +/area/station/maintenance/department/medical/central) "xrH" = ( /obj/effect/spawner/random/engineering/tracking_beacon, /obj/machinery/holopad, @@ -83491,7 +84181,7 @@ amount = 4 }, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port) "xvt" = ( /obj/effect/turf_decal/weather/sand, @@ -83561,6 +84251,10 @@ }, /turf/open/floor/iron/dark/smooth_edge, /area/station/hallway/secondary/command) +"xwf" = ( +/obj/structure/trash_pile, +/turf/open/floor/plating, +/area/station/maintenance/port/aft) "xwm" = ( /obj/structure/cable, /obj/structure/disposalpipe/junction/flip{ @@ -83571,6 +84265,15 @@ /obj/machinery/duct, /turf/open/floor/iron/smooth_large, /area/station/engineering/power_room) +"xwC" = ( +/obj/machinery/photocopier, +/obj/effect/turf_decal/bot, +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 10 + }, +/obj/machinery/light/cold/directional/south, +/turf/open/floor/iron/white, +/area/station/medical/office) "xwO" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -83739,7 +84442,7 @@ dir = 8 }, /turf/open/floor/carpet/cyan, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "xyX" = ( /obj/effect/mapping_helpers/airlock/locked, /obj/effect/turf_decal/stripes/line{ @@ -83784,8 +84487,8 @@ id_tag = "MedbayFoyer"; name = "Emergency Medical Entrance" }, -/obj/effect/mapping_helpers/airlock/access/any/medical/morgue, /obj/effect/mapping_helpers/airlock/unres, +/obj/effect/mapping_helpers/airlock/access/any/medical/general, /turf/open/floor/iron/white/smooth_large, /area/station/medical/treatment_center) "xzN" = ( @@ -83818,7 +84521,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/decal/cleanable/dirt, /obj/machinery/power/apc/auto_name/directional/north, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/aft/lesser) "xAo" = ( /obj/structure/cable, @@ -84070,7 +84773,7 @@ /turf/open/floor/iron/small, /area/station/hallway/primary/central) "xFo" = ( -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) "xFt" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -84217,7 +84920,7 @@ "xGr" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/trash/garbage, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "xGv" = ( /obj/effect/turf_decal/trimline/purple/filled/corner{ @@ -84504,7 +85207,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/disposalpipe/segment, /obj/structure/sign/poster/contraband/random/directional/east, -/turf/open/floor/catwalk_floor/iron_smooth, +/turf/open/floor/plating, /area/station/maintenance/starboard/greater) "xLX" = ( /obj/effect/decal/cleanable/dirt, @@ -85090,7 +85793,7 @@ /obj/effect/turf_decal/bot, /obj/machinery/holopad, /turf/open/floor/wood/large, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "xTN" = ( /obj/effect/turf_decal/trimline/brown/filled/corner{ dir = 8 @@ -85718,7 +86421,7 @@ "ydA" = ( /obj/effect/mapping_helpers/broken_floor, /obj/effect/spawner/random/trash/grime, -/turf/open/floor/iron/smooth, +/turf/open/floor/plating, /area/station/maintenance/port/aft) "ydE" = ( /obj/structure/cable, @@ -105652,7 +106355,7 @@ ttw ttw ttw sAM -fDA +jVE cvH knY xhU @@ -105665,10 +106368,10 @@ cvH grR mUM rcl -rcl -rcl -rcl -rcl +pxe +pxe +pxe +pxe oQo pxe ttw @@ -105909,7 +106612,7 @@ ttw ttw ttw sAM -fDA +jVE cvH cvH cvH @@ -105925,10 +106628,10 @@ rcl liB qgv dGj -rcl -oQo pxe -ttw +wFc +pxe +pxe ttw ttw ttw @@ -106166,7 +106869,7 @@ ttw ttw sAM sAM -nvM +vik qFH sAM oXc @@ -106182,10 +106885,10 @@ pcx gjT wtc sNq -rcl -oQo pxe -ttw +wFc +mJA +pxe ttw ttw ttw @@ -106235,7 +106938,7 @@ ydA sWI ron lQt -pZH +oxA ipJ dwi vPk @@ -106439,10 +107142,10 @@ flH mdK oLS hbE -rcl -oQo pxe -ttw +wGg +gHM +pxe ttw ttw ttw @@ -106490,9 +107193,9 @@ xtV dUO lQt eMd -pZH -pZH -pZH +oxA +oxA +oxA uUU ptY voU @@ -106697,9 +107400,9 @@ fUy bMN wNJ lMx -xNL +xim +pxe pxe -ttw ttw ttw ttw @@ -106747,7 +107450,7 @@ xtV aDC qQC qMB -spp +xwf yaE oNW uUU @@ -106953,8 +107656,8 @@ rcl rcl rcl rcl -rcl -xNL +pxe +xmF pxe ttw ttw @@ -106976,7 +107679,7 @@ nhU vAk qbS xiD -vAk +rSG vAk ryX kMf @@ -106988,16 +107691,16 @@ uUU uUU uUU uUU -spp +xwf eWw uUU oNW lUi pZH -tqv -pZH -pZH -pZH +tgU +oxA +oxA +oxA nSF bcq uUU @@ -107206,12 +107909,12 @@ hIh abQ aCm xZk -abQ -ttw -ttw -ttw -hxT -xNL +asX +tme +vAC +xwC +pxe +xmF hxT ttw ttw @@ -107230,44 +107933,44 @@ sEq sEq pkR nhU -qbS +ukh +rSG +bvt +ukh +ukh vAk -xiD qbS -qbS -vAk -qbS -vAk -vAk +rSG +rSG qbS uUU qmn dul xGr pZH -pZH +oxA +eMd eMd -oEf tqv -pZH -pZH -pZH -pZH +oxA +oxA +oxA +oxA pZH eMd nSF pZH uUU mUE -pZH +oxA hDI dul ptX sSH qIS -pZH +oxA dXM -pZH +oxA iaq uUU jwC @@ -107412,7 +108115,7 @@ paS eyy rcr nFs -bQF +mYn oKR oBd uvj @@ -107463,10 +108166,10 @@ bxX rFD jzo xry -rFD -ttw -ttw -ttw +asX +cEB +tzN +eKs pxe xNL pxe @@ -107486,9 +108189,9 @@ kZJ kZJ kRE pkR -nhU -nhU -nhU +imc +imc +imc nMv nhU nhU @@ -107501,14 +108204,14 @@ pGY kUr tjw dbP +wpK eLz -eLz -eLz -eLz -eLz -eLz -eLz -eLz +wpK +wpK +wpK +wpK +wpK +wpK eLz eLz eLz @@ -107518,8 +108221,8 @@ gEq eLz eLz qAt -eLz -eLz +wpK +wpK qBl eLz eLz @@ -107669,8 +108372,8 @@ xyX eyy kJq nFs -oKR -hAA +lyJ +vzg rcf mbJ odJ @@ -107720,11 +108423,11 @@ abQ rFD icP icP -rFD -ttw -ttw -ttw -hxT +wfk +cGu +jqH +vIY +xrG oQo fUk ttw @@ -107735,7 +108438,7 @@ lvJ cJm xWK hbp -vGO +cgH cgZ wxn qlA @@ -107743,7 +108446,7 @@ qFA qFA rDm pkR -nhU +imc vAk lMS alm @@ -107926,7 +108629,7 @@ wlV eyy qtl nFs -oKR +lyJ oKR ixT uvj @@ -107977,10 +108680,10 @@ abQ ybI icP icP -rFD -ttw -ttw -ttw +asX +asX +asX +asX pxe oQo pxe @@ -107992,7 +108695,7 @@ rol rol sgk kIm -vGO +cgH cgZ wNh qlA @@ -108000,7 +108703,7 @@ qFA krh fZT pkR -nhU +imc eVW lMS ipg @@ -108234,11 +108937,11 @@ dMY icP rBo icP -rFD -ttw -ttw -ttw -hxT +wxG +tvc +plo +pcS +pxe oQo hxT ttw @@ -108257,8 +108960,8 @@ qFA krh oJG pkR -pXE -vAk +ijj +rSG lMS ipg fSa @@ -108491,10 +109194,10 @@ abQ wsZ icP icP -rFD -ttw -ttw -pxe +ooU +ngZ +efn +kzV pxe wSR pxe @@ -108506,7 +109209,7 @@ cgZ qHg xMk cgZ -sYt +lnU cgZ wNh oMd @@ -108515,7 +109218,7 @@ krh xOz pkR nhU -vAk +rSG lMS ipg fSa @@ -108748,12 +109451,12 @@ abQ rFD icP icP -rFD -ttw -ttw +wxG +ofG +mTl +icH pxe -wpU -oQo +idg lgX lgX lgX @@ -108763,7 +109466,7 @@ sud iii jom wKf -sYt +lnU cgZ wNh oMd @@ -108952,7 +109655,7 @@ aFO mSI enW dUw -oKR +lyJ uss wqg wqg @@ -109005,14 +109708,14 @@ xMq rFD pyQ pyQ -rFD -ttw -ttw -hxT +wxG +pAE +qkb +irU bgo ikc jwV -eak +utq lgX gMx wKf @@ -109020,7 +109723,7 @@ ryt olf rLZ wKf -sYt +lnU cgZ wxn oMd @@ -109262,10 +109965,10 @@ sAM sAM rNH hEf -abQ -lAB -lAB -lAB +nwW +vOX +vOX +vOX lAB mDL lAB @@ -109277,7 +109980,7 @@ gQi qaN kEw wKf -vGO +cgH cgZ wNh qFA @@ -109467,7 +110170,7 @@ btZ enW lpz qwH -oKR +lyJ bao uvj uvj @@ -109526,7 +110229,7 @@ erF gzy xWN lpZ -bwm +lAB duU eak ukV @@ -109534,7 +110237,7 @@ iSK bDF coR cgZ -vGO +cgH cgZ wNh qFA @@ -109799,7 +110502,7 @@ oON krh xZo pkR -nhU +imc nQG lMS deE @@ -110056,8 +110759,8 @@ qFA hzD kXW pkR -nhU -vAk +imc +rSG lMS wMb jmT @@ -110750,7 +111453,7 @@ eFQ fLX eFQ qwH -ljL +eFQ uRe ekX uvj @@ -111083,7 +111786,7 @@ fia jNA tAw pkR -vAk +rSG nhU hCL twe @@ -111259,7 +111962,7 @@ xsF xMq uvj lKX -iJJ +oBd uvj uvj iIq @@ -111520,8 +112223,8 @@ rcf uvj ioI nGH -nGH -eWu +lQf +mlv kIf wjI ffz @@ -111597,7 +112300,7 @@ kbV vco wLc pkR -lGH +cEL xvp lMS nXs @@ -111776,9 +112479,9 @@ rWs uvj uvj xmH -nGH +lQf rXL -nGH +lQf nRd wjI nSU @@ -112030,12 +112733,12 @@ ttw ttw rpk aUu -gGT +aiq wjI gwZ nGH ayc -eWu +mlv lsn wjI vSj @@ -112150,7 +112853,7 @@ tBC luV toq jKu -fpk +nES xVm iHL eJf @@ -112287,7 +112990,7 @@ wjI wjI wjI dTz -nGH +lQf wjI wjI wjI @@ -112407,7 +113110,7 @@ rOM vIt toq jKu -fpk +nES xVm eRt izg @@ -112551,9 +113254,9 @@ pKM oqF pKM pKM -pKM +dqM pDx -see +qUt see wjI mhe @@ -112765,10 +113468,10 @@ oQh veh veh hpq -gQh +knn eSD gQh -aXD +pnU xsZ gQh lrY @@ -112781,11 +113484,11 @@ lrY hml vHV dQq -gQh +knn gbM jYe mPw -aXD +pnU bcf vtD wPO @@ -112807,8 +113510,8 @@ vew clk gAG bnJ -nGH -nGH +lQf +lQf vWf nGH lbi @@ -112850,7 +113553,7 @@ etW rMu ups ufc -wen +ufc jRj rnF kUZ @@ -112878,7 +113581,7 @@ aFU sHv wiz rol -bXt +jtq sHv mjM biU @@ -112921,7 +113624,7 @@ dYh xtF toq nFg -wme +hYA xVm tXe kth @@ -113020,8 +113723,8 @@ veh vlt tTQ aXD -gQh -gQh +knn +knn tTQ pCm pCm @@ -113135,7 +113838,7 @@ sea sHv naG rol -bXt +jtq sHv dWt eUH @@ -113323,7 +114026,7 @@ lov jFt ydK wjI -vWf +lGy eWu nPV wjI @@ -113391,7 +114094,7 @@ jpF uUS sHv pRv -pIN +vij bXt sHv thY @@ -113580,8 +114283,8 @@ gNh rUo wQg wjI -vWf -nGH +lGy +lQf omw wjI mhe @@ -113648,7 +114351,7 @@ ads vxT sHv jLS -bXt +jtq sHv sHv fXP @@ -113837,8 +114540,8 @@ iVy jQM moF wjI -vWf -eWu +lGy +mlv jFH wjI nqC @@ -114195,16 +114898,16 @@ tFt qAN xJH svC -svC -svC -svC -svC +rJa +rJa +rJa +rJa juO -svC +rJa qqa -svC +rJa aWh -svC +rJa oza cwa brI @@ -114453,9 +115156,9 @@ pLI fwB fwB fwB -fwB -fwB -fwB +ssU +ssU +ssU fwB fwB brI @@ -114609,7 +115312,7 @@ cgx rIQ wjI vWf -eWu +mlv xOR wjI wjI @@ -114707,18 +115410,18 @@ qUI kbv tFt dHe -fbY +ebS pBZ hQp btf lDP iDu -rOQ +jte wrg brI brI mrV -cwa +uvB fbY wRj brI @@ -114867,10 +115570,10 @@ xWf wjI uZo oqF -pKM -ucl -pKM -pKM +dqM +oZB +dqM +dqM pVu vmf dPm @@ -114964,7 +115667,7 @@ crK ubZ tFt pLI -svC +rJa gjs brI brI @@ -114975,8 +115678,8 @@ fwB iUL brI dVe -cwa -rOQ +uvB +jte hUR brI xMq @@ -115233,7 +115936,7 @@ rOQ svC frl cwa -rOQ +jte brI brI brI @@ -115485,10 +116188,10 @@ eYM brI iJi svC -cwa -cwa -cwa -cwa +uvB +uvB +uvB +uvB cwa xRu gls @@ -115643,7 +116346,7 @@ rWc poX leB uZo -oqF +gTk kZX pKM nvZ @@ -117027,7 +117730,7 @@ rin lFE pEt rgE -eUp +kux owF puj kCR @@ -117284,7 +117987,7 @@ rin lFE pEt veD -eUp +kux cGZ kzc vQS @@ -117541,7 +118244,7 @@ kmZ lFE pEt evE -eUp +kux qbp qbp gmz @@ -117797,7 +118500,7 @@ tZZ xMq lFE pEt -awv +isr xhr lhE qbp @@ -118055,7 +118758,7 @@ xMq lFE pEt awv -eUp +kux jfq qbp nIl @@ -118827,7 +119530,7 @@ vVU egH hAk ulH -gXR +xgK qbp nIl pkp @@ -120112,7 +120815,7 @@ hUc aEC pEt eUp -gXR +xgK vau qbp rTG @@ -121120,7 +121823,7 @@ xMx iPJ mTO hYs -hTn +hLh cju tUK orq @@ -121139,7 +121842,7 @@ oCl oCl pEt pEt -eUp +kux koQ qbp nIl @@ -121396,7 +122099,7 @@ xMq xMq pEt eRP -ycu +taC rfk qbp nIl @@ -121633,7 +122336,7 @@ jEj hxy uxG trA -uxG +sRR oCl oCl hLh @@ -121653,8 +122356,8 @@ svT xMq dXU awv -ycu -gXR +taC +xgK qbp nIl pkp @@ -121910,8 +122613,8 @@ xMq xMq pEt qXm -eUp -gXR +kux +xgK qbp rTG pkp @@ -122139,11 +122842,11 @@ tpL dAD kGP phK -cCJ +duy tTt agW mto -cCJ +duy vlh dZH kbf @@ -122167,7 +122870,7 @@ oCl oCl pEt gug -eUp +kux wHN qbp qbp @@ -122424,7 +123127,7 @@ fzm nUU pEt nMu -eUp +kux eUp eUp dyl @@ -122654,9 +123357,9 @@ fAJ fAJ hgW hOj -cCJ -cCJ -cCJ +duy +duy +duy jnT vlh bSV @@ -122681,8 +123384,8 @@ ldR bru sAx xck -gXR -gXR +xgK +xgK eUp evE qbp @@ -122913,7 +123616,7 @@ fAJ fAJ aGq iyw -cCJ +duy jnT vlh mWF @@ -123455,7 +124158,7 @@ iBF iBF fer fqz -jnZ +aXG xGA gdu pkp @@ -123712,7 +124415,7 @@ avf iBF clM sLc -jnZ +aXG xGA myC pkp @@ -124227,7 +124930,7 @@ iBF bxt sLc kVU -tER +bgz tER iPh vPx @@ -124482,9 +125185,9 @@ jDY vWd iBF ygc -jnZ -sLc -jnZ +aXG +udp +aXG sJd sJd sJd @@ -124650,10 +125353,10 @@ vLO dUD ecR ecR -ssV -ssV -ecR -ecR +aXl +aXl +lqL +lqL nRG ssV ecR @@ -125150,8 +125853,8 @@ kit xQj iNV iNV -rIe -qGT +ofF +pMG vLe rne egh @@ -125407,8 +126110,8 @@ pAD cuF iNV dzp -gYP -qGT +beq +pMG vLe hlD dnq @@ -125511,7 +126214,7 @@ hNu uAD iPZ obh -nnm +nGb fPm sJd jOm @@ -125768,7 +126471,7 @@ jwq pRr iPZ hhQ -nnm +nGb mUp sJd xmL @@ -125922,7 +126625,7 @@ hRp iFc qXe iNV -qGT +pMG bSp aoD gYP @@ -126026,7 +126729,7 @@ weW iPZ rzT cUA -nnm +nGb ptO jKW sPT @@ -126183,10 +126886,10 @@ sJy ssV ssV xLQ -ssV -ssV -ssV -ssV +aXl +aXl +aXl +aXl nRG uEF ykh @@ -126520,7 +127223,7 @@ qeS fKq fKq gcc -kAL +kpB sID kAL uXM @@ -126933,9 +127636,9 @@ afj ndR fTi fTi -hmN -fTi -oUo +ouX +tYr +fpE hmN hmN pWC @@ -127296,7 +127999,7 @@ pEn scP mpm fuK -jya +ish ktu pEn sDL @@ -127472,7 +128175,7 @@ pzh pzh vRf pzh -pzh +mLy ykh irO bcY @@ -127551,9 +128254,9 @@ tKV tKV pEn oec -hyV -tJj -jya +gfv +dcL +ish aVb yiU dJY @@ -127567,7 +128270,7 @@ sak sak sak sak -aEH +uVV qaO kLc unI @@ -127729,7 +128432,7 @@ wqd ePH ePH wqd -pzh +mLy ykh ykh ykh @@ -127809,7 +128512,7 @@ tKV pEn pEn jya -tJj +dcL aPu yiU yiU @@ -127817,7 +128520,7 @@ pEn xlM oIw pEn -jya +ish noI sak hCA @@ -127826,7 +128529,7 @@ kcW sak kFT eWs -aEH +uVV djs hMy olE @@ -127986,7 +128689,7 @@ wcb sEc jhT gap -pzh +mLy eTo iNV tzI @@ -128066,15 +128769,15 @@ tKV pEn ipp jya -tJj -jya +dcL +ish hnn pEn fXG lUm pit jya -jya +ish noI vmX wLt @@ -128243,7 +128946,7 @@ qRv hrZ idl ePH -pzh +mLy pzh wgI hyf @@ -128340,7 +129043,7 @@ bWt sak kFh eWs -aEH +uVV djs ltn olE @@ -128580,7 +129283,7 @@ tKV pEn xOh jya -spf +nrb iay iay iay @@ -128596,8 +129299,8 @@ aLU oVX sak tuk -qaO -aEH +jCq +uVV unI uXf xnu @@ -129093,14 +129796,14 @@ tKV tKV pEn frV -jya -tJj +ish +dcL vBb bjg kAN -vty -vty -vty +kLl +kLl +kLl pSJ vty rgH @@ -129110,7 +129813,7 @@ ufe ntn gLb lAi -eWs +xof aEH unI dNL @@ -129350,21 +130053,21 @@ kEm kEm pEn pEn -jya +ish pSK iay dBC -vty -vty +kLl +kLl rYT mPs dNh -vty +kLl cQb iay dzC oXG -aEH +uVV xRx wIM eWs @@ -129616,12 +130319,12 @@ oSa dDq dsL pSJ -vty +kLl eQi iay tnp -aEH -aEH +uVV +uVV shE lAi dsg @@ -130275,10 +130978,10 @@ mrZ fTi oUo fTi -hbc -fTi +sCN +tYr xnR -fTi +tYr fTi iwq rCm @@ -130393,8 +131096,8 @@ aBh mqd iiO qqg -aEH -aEH +uVV +uVV qaO hmY unI @@ -130636,21 +131339,21 @@ fyy kEm pEn hyV -nrb -nrb +eBy +eBy xJr nrb -nrb +eBy nrb vHa qaO qaO qaO qaO -qaO -qaO +jCq +jCq nAp -qaO +jCq qaO qaO wsc @@ -130894,10 +131597,10 @@ gNu pEn bKE jya -jya -jya -jya -jya +ish +ish +ish +ish rtr pEn dFG @@ -130909,7 +131612,7 @@ lAi lAi kLc tyt -aEH +uVV ajL lAi uLA @@ -131153,8 +131856,8 @@ bKE wrR emd nub -jya -hyV +ish +gfv pEn pEn pIm @@ -131418,7 +132121,7 @@ cDs lOz lAi sdb -tCp +uVV jDi lAi lAi @@ -134386,7 +135089,7 @@ iID kFZ kFZ tyY -kFZ +vfE mxe pEu pEu diff --git a/_maps/map_files/debug/runtimestation.dmm b/_maps/map_files/debug/runtimestation.dmm index 4072ee21a70f50..a475bd6401385c 100644 --- a/_maps/map_files/debug/runtimestation.dmm +++ b/_maps/map_files/debug/runtimestation.dmm @@ -662,6 +662,7 @@ "cK" = ( /obj/machinery/light/directional/south, /obj/structure/table/glass, +/obj/item/disk/surgery/debug, /obj/item/storage/box/monkeycubes{ pixel_x = 6; pixel_y = 1 @@ -676,8 +677,7 @@ /turf/open/floor/iron/white/corner, /area/station/medical/medbay) "cL" = ( -/obj/item/storage/backpack/duffelbag/syndie/surgery, -/obj/item/disk/surgery/debug, +/obj/item/surgery_tray/full/advanced, /obj/structure/table/glass, /obj/effect/turf_decal/tile/blue{ dir = 8 diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index 704c4629463092..9b6c1b6d5d5187 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -6193,6 +6193,19 @@ }, /turf/open/floor/iron/dark, /area/centcom/central_command_areas/evacuation) +"Ci" = ( +/obj/structure/table/reinforced, +/obj/item/surgery_tray/full{ + pixel_y = 10; + pixel_x = 2 + }, +/obj/item/storage/box/masks{ + pixel_x = -6; + pixel_y = 4 + }, +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/iron/white, +/area/centcom/central_command_areas/evacuation/ship) "Co" = ( /obj/effect/turf_decal/tile/brown/half/contrasted{ dir = 4 @@ -7002,18 +7015,6 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/iron/smooth_edge, /area/centcom/central_command_areas/evacuation/ship) -"Hh" = ( -/obj/structure/table/wood, -/obj/item/flashlight/lamp, -/obj/machinery/requests_console/directional/north{ - department = "Captain's Desk"; - name = "CentCom Requests Console" - }, -/obj/effect/mapping_helpers/requests_console/announcement, -/obj/effect/mapping_helpers/requests_console/information, -/obj/effect/mapping_helpers/requests_console/assistance, -/turf/open/floor/iron/grimy, -/area/centcom/central_command_areas/admin) "Hi" = ( /obj/effect/turf_decal/tile/green, /obj/machinery/light/directional/south, @@ -9678,19 +9679,6 @@ }, /turf/open/floor/iron, /area/centcom/central_command_areas/armory) -"Vh" = ( -/obj/structure/table/reinforced, -/obj/item/surgery_tray{ - pixel_y = 10; - pixel_x = 2 - }, -/obj/item/storage/box/masks{ - pixel_x = -6; - pixel_y = 4 - }, -/obj/effect/turf_decal/stripes/line, -/turf/open/floor/iron/white, -/area/centcom/central_command_areas/evacuation/ship) "Vi" = ( /obj/item/book/manual/wiki/security_space_law, /obj/structure/table/wood, @@ -10547,6 +10535,18 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/centcom/central_command_areas/armory) +"Zw" = ( +/obj/structure/table/wood, +/obj/item/flashlight/lamp, +/obj/machinery/requests_console/directional/north{ + department = "Captain's Desk"; + name = "CentCom Requests Console" + }, +/obj/effect/mapping_helpers/requests_console/announcement, +/obj/effect/mapping_helpers/requests_console/information, +/obj/effect/mapping_helpers/requests_console/assistance, +/turf/open/floor/iron/grimy, +/area/centcom/central_command_areas/admin) "Zx" = ( /obj/machinery/computer/records/security{ dir = 8 @@ -37631,7 +37631,7 @@ Lt aa aa Lt -Vh +Ci LI CH CH @@ -48880,7 +48880,7 @@ On vo fP On -Hh +Zw XV hd To diff --git a/_maps/map_files/generic/CentCom_skyrat_z2.dmm b/_maps/map_files/generic/CentCom_skyrat_z2.dmm index a16d9be1ce7795..d187e5f5dac48f 100644 --- a/_maps/map_files/generic/CentCom_skyrat_z2.dmm +++ b/_maps/map_files/generic/CentCom_skyrat_z2.dmm @@ -6398,7 +6398,7 @@ /turf/open/floor/iron, /area/centcom/holding/cafe) "goK" = ( -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/effect/turf_decal/tile/blue{ dir = 8 }, @@ -9493,7 +9493,7 @@ /turf/open/floor/iron/dark, /area/centcom/interlink) "ovH" = ( -/obj/machinery/vending/wardrobe/syndie_wardrobe{ +/obj/machinery/vending/wardrobe/syndie_wardrobe/ghost_cafe{ default_price = 0; extra_price = 0; fair_market_price = 0 @@ -13429,7 +13429,7 @@ /area/centcom/holding/cafe) "ycL" = ( /obj/structure/table/optable, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/effect/turf_decal/bot_blue, /turf/open/floor/iron/white, /area/centcom/interlink) diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index aea13abc6e3eee..4ef52187a09333 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -3806,6 +3806,23 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/hallway/secondary/service) +"axh" = ( +/obj/structure/rack, +/obj/item/clothing/glasses/meson{ + pixel_y = 4 + }, +/obj/item/lighter, +/obj/item/reagent_containers/pill/patch/aiuri, +/obj/item/stock_parts/cell/high, +/obj/effect/turf_decal/trimline/yellow/filled/line{ + dir = 1 + }, +/obj/structure/window/reinforced/spawner/directional/west, +/obj/item/computer_disk/engineering, +/obj/item/computer_disk/engineering, +/obj/item/computer_disk/engineering, +/turf/open/floor/iron, +/area/station/command/heads_quarters/ce) "axp" = ( /obj/effect/turf_decal/trimline/red/filled/line{ dir = 8 @@ -13432,7 +13449,7 @@ dir = 1 }, /obj/item/radio/intercom/directional/north, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /turf/open/floor/iron/white, /area/station/medical/surgery/aft) "dCG" = ( @@ -18115,6 +18132,17 @@ /obj/machinery/light/warm/directional/east, /turf/open/floor/iron/dark, /area/station/service/chapel) +"frL" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 9 + }, +/obj/machinery/status_display/door_timer{ + id = "Isolation_C"; + name = "Isolation Cell C"; + pixel_y = 32 + }, +/turf/open/floor/iron, +/area/station/security/execution/transfer) "frN" = ( /obj/effect/spawner/structure/window/reinforced/plasma, /turf/open/floor/plating, @@ -20724,7 +20752,9 @@ dir = 4; id = "cargolower" }, -/obj/machinery/recycler, +/obj/machinery/recycler{ + dir = 8 + }, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/disposal) @@ -32041,6 +32071,7 @@ /area/station/hallway/primary/tram/center) "kwG" = ( /obj/effect/turf_decal/trimline/red/filled/line, +/obj/machinery/airalarm/directional/south, /turf/open/floor/iron, /area/station/security/execution/transfer) "kwN" = ( @@ -32474,8 +32505,6 @@ }, /obj/item/storage/box/syringes, /obj/item/mod/module/plasma_stabilizer, -/obj/item/mod/module/thermal_regulator, -/obj/item/gun/syringe, /obj/machinery/door/window/left/directional/west{ name = "Secure Medical Storage"; req_access = list("medical") @@ -32483,6 +32512,9 @@ /obj/effect/turf_decal/siding/white{ dir = 8 }, +/obj/item/mod/module/signlang_radio, +/obj/item/mod/module/thermal_regulator, +/obj/item/gun/syringe, /turf/open/floor/iron/dark, /area/station/medical/storage) "kGo" = ( @@ -37261,23 +37293,6 @@ "mjM" = ( /turf/closed/wall, /area/station/security/medical) -"mjX" = ( -/obj/structure/rack, -/obj/item/clothing/glasses/meson{ - pixel_y = 4 - }, -/obj/item/lighter, -/obj/item/reagent_containers/pill/patch/aiuri, -/obj/item/stock_parts/cell/high, -/obj/effect/turf_decal/trimline/yellow/filled/line{ - dir = 1 - }, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/item/computer_disk/engineering, -/obj/item/computer_disk/engineering, -/obj/item/computer_disk/engineering, -/turf/open/floor/iron, -/area/station/command/heads_quarters/ce) "mki" = ( /obj/machinery/door/airlock/command{ name = "Head of Personnel" @@ -40600,6 +40615,7 @@ }, /obj/structure/rack, /obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/signlang_radio, /obj/item/mod/module/thermal_regulator, /turf/open/floor/iron, /area/station/engineering/engine_smes) @@ -41672,17 +41688,6 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/exit) -"nQv" = ( -/obj/effect/turf_decal/trimline/neutral/warning, -/obj/structure/table/reinforced, -/obj/item/table_clock{ - pixel_y = 8 - }, -/obj/structure/window/reinforced/spawner/directional/north, -/obj/item/surgery_tray/morgue, -/obj/structure/window/reinforced/spawner/directional/west, -/turf/open/floor/iron/dark, -/area/station/medical/morgue) "nQB" = ( /obj/effect/turf_decal/sand, /obj/effect/turf_decal/trimline/red/filled/line{ @@ -42947,6 +42952,11 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 1 }, +/obj/machinery/status_display/door_timer{ + id = "Isolation_D"; + name = "Isolation Cell D"; + pixel_y = -32 + }, /turf/open/floor/iron, /area/station/security/execution/transfer) "onc" = ( @@ -48618,6 +48628,17 @@ /obj/item/soap/syndie, /turf/open/floor/iron/showroomfloor, /area/station/commons/vacant_room) +"qtQ" = ( +/obj/effect/turf_decal/trimline/neutral/warning, +/obj/structure/table/reinforced, +/obj/item/table_clock{ + pixel_y = 8 + }, +/obj/structure/window/reinforced/spawner/directional/north, +/obj/item/surgery_tray/full/morgue, +/obj/structure/window/reinforced/spawner/directional/west, +/turf/open/floor/iron/dark, +/area/station/medical/morgue) "qtS" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/disposalpipe/segment{ @@ -48737,6 +48758,15 @@ /obj/item/storage/bag/money, /turf/open/floor/iron/dark, /area/station/cargo/miningdock/oresilo) +"qwV" = ( +/obj/effect/turf_decal/trimline/red/filled/line, +/obj/machinery/status_display/door_timer{ + id = "Isolation_B"; + name = "Isolation Cell B"; + pixel_y = -32 + }, +/turf/open/floor/iron, +/area/station/security/execution/transfer) "qwX" = ( /obj/structure/flora/bush/grassy/style_random, /turf/open/floor/grass, @@ -49871,6 +49901,17 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, /area/station/commons/dorms) +"qTt" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 1 + }, +/obj/machinery/status_display/door_timer{ + id = "Isolation_A"; + name = "Isolation Cell A"; + pixel_y = 32 + }, +/turf/open/floor/iron, +/area/station/security/execution/transfer) "qTv" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 4 @@ -55467,7 +55508,7 @@ /obj/effect/turf_decal/trimline/purple/filled/line{ dir = 1 }, -/obj/machinery/lapvend, +/obj/machinery/vending/robotics, /turf/open/floor/iron/white, /area/station/science/lobby) "sSH" = ( @@ -61818,7 +61859,7 @@ /obj/structure/table/glass, /obj/effect/turf_decal/trimline/blue/filled/line, /obj/item/radio/intercom/directional/south, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /turf/open/floor/iron/white, /area/station/medical/surgery/fore) "uWn" = ( @@ -67666,6 +67707,7 @@ "xfW" = ( /obj/structure/table, /obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/signlang_radio, /obj/item/mod/module/thermal_regulator, /turf/open/floor/iron, /area/station/security/office) @@ -83566,7 +83608,7 @@ jWs cuM uUD cWF -rnm +frL ajM ona cWF @@ -84337,9 +84379,9 @@ jWs cuM uUD cWF -fIH +qTt eTl -kwG +qwV cWF udO lrq @@ -102908,7 +102950,7 @@ dor fSp vKv roB -mjX +axh iHK bAK jsW @@ -172543,7 +172585,7 @@ hiZ wTP sFA uKP -nQv +qtQ qfS gNN whz diff --git a/_maps/shuttles/emergency_birdshot.dmm b/_maps/shuttles/emergency_birdshot.dmm index d861d6af348070..20ffeb679d7d83 100644 --- a/_maps/shuttles/emergency_birdshot.dmm +++ b/_maps/shuttles/emergency_birdshot.dmm @@ -751,7 +751,7 @@ /area/shuttle/escape) "Ko" = ( /obj/structure/table/optable, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/clothing/mask/surgical, /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/mineral/titanium/white, diff --git a/_maps/shuttles/emergency_donut.dmm b/_maps/shuttles/emergency_donut.dmm index be456bdb4f4b77..67dc9f62da7ae4 100644 --- a/_maps/shuttles/emergency_donut.dmm +++ b/_maps/shuttles/emergency_donut.dmm @@ -317,7 +317,7 @@ /turf/open/floor/plating/airless, /area/shuttle/escape) "ed" = ( -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/clothing/suit/apron/surgical, /obj/item/clothing/mask/surgical, /obj/structure/table/optable, diff --git a/_maps/shuttles/emergency_fish.dmm b/_maps/shuttles/emergency_fish.dmm index 69bf06c0fa3e9a..99e9848a0b0487 100644 --- a/_maps/shuttles/emergency_fish.dmm +++ b/_maps/shuttles/emergency_fish.dmm @@ -849,7 +849,7 @@ /area/shuttle/escape) "VD" = ( /obj/structure/table/glass, -/obj/item/surgery_tray{ +/obj/item/surgery_tray/full{ pixel_y = 6 }, /obj/effect/turf_decal/tile/blue/anticorner/contrasted{ diff --git a/_maps/shuttles/emergency_humpback.dmm b/_maps/shuttles/emergency_humpback.dmm new file mode 100644 index 00000000000000..f4c50bf6b84ec3 --- /dev/null +++ b/_maps/shuttles/emergency_humpback.dmm @@ -0,0 +1,1308 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"ao" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/visible, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape/brig) +"at" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 1 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"bL" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape/brig) +"bS" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/structure/chair/comfy/shuttle, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"bT" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"cK" = ( +/turf/open/floor/iron/smooth_half/airless, +/area/shuttle/escape) +"df" = ( +/obj/machinery/door/airlock/external, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/effect/turf_decal/siding/blue, +/obj/effect/mapping_helpers/airlock/access/all/command/general, +/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ + cycle_id = "evac3" + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"dl" = ( +/obj/structure/chair/sofa/right{ + dir = 4 + }, +/turf/open/floor/iron/smooth, +/area/shuttle/escape) +"dF" = ( +/obj/machinery/power/shuttle_engine/propulsion{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/plating/airless, +/area/shuttle/escape/brig) +"dP" = ( +/obj/structure/table/reinforced/plastitaniumglass, +/obj/effect/spawner/random/food_or_drink/booze, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"ed" = ( +/obj/structure/table, +/obj/item/storage/medkit/regular, +/obj/item/storage/medkit/toxin{ + pixel_x = 4; + pixel_y = 4 + }, +/turf/open/floor/wood/large, +/area/shuttle/escape) +"ez" = ( +/obj/machinery/door/airlock/public/glass{ + name = "Cyborg Bay" + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"eK" = ( +/obj/structure/window/reinforced/spawner/directional/south, +/obj/machinery/power/shuttle_engine/heater{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/plating/airless, +/area/shuttle/escape) +"eU" = ( +/obj/machinery/door/airlock/external/glass, +/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ + cycle_id = "evac3" + }, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"eW" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/machinery/status_display/evac/directional/east, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"fu" = ( +/obj/machinery/computer/emergency_shuttle{ + dir = 1 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"gL" = ( +/obj/machinery/door/airlock/security/glass{ + name = "Escape Shuttle Brig" + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/effect/mapping_helpers/airlock/access/all/security/general, +/obj/effect/mapping_helpers/airlock/cyclelink_helper, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape/brig) +"gW" = ( +/obj/structure/window/reinforced/plasma/spawner/directional/east, +/obj/machinery/vending/boozeomat/all_access, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"hd" = ( +/obj/machinery/atmospherics/components/binary/pump/on/supply{ + dir = 4 + }, +/obj/structure/extinguisher_cabinet/directional/south, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape/brig) +"he" = ( +/obj/machinery/vending/wallmed/directional/east, +/turf/open/floor/wood/large, +/area/shuttle/escape) +"hk" = ( +/obj/machinery/light/directional/north, +/obj/structure/table, +/obj/machinery/recharger, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape/brig) +"hp" = ( +/obj/structure/lattice/catwalk, +/turf/template_noop, +/area/shuttle/escape) +"hs" = ( +/obj/effect/turf_decal/siding/wood, +/turf/open/floor/iron/showroomfloor, +/area/shuttle/escape) +"hA" = ( +/turf/open/floor/iron/smooth_half/airless{ + dir = 1 + }, +/area/shuttle/escape) +"ig" = ( +/obj/structure/chair/comfy/shuttle{ + dir = 8 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"iW" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/structure/chair/comfy/shuttle, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"ji" = ( +/obj/machinery/door/airlock/external, +/obj/effect/turf_decal/siding/blue, +/obj/effect/mapping_helpers/airlock/access/all/command/general, +/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ + cycle_id = "evac3" + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"jJ" = ( +/obj/machinery/computer/arcade/orion_trail{ + dir = 1 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"kB" = ( +/obj/machinery/door/airlock/external, +/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ + cycle_id = "evac3" + }, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"kZ" = ( +/obj/structure/table, +/obj/item/storage/medkit/fire, +/obj/item/storage/medkit/brute{ + pixel_x = 4; + pixel_y = 4 + }, +/turf/open/floor/wood/large, +/area/shuttle/escape) +"my" = ( +/obj/machinery/computer/security{ + dir = 4 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"mF" = ( +/obj/effect/spawner/structure/window/reinforced/plasma/plastitanium, +/turf/open/floor/plating, +/area/shuttle/escape) +"mI" = ( +/obj/structure/lattice/catwalk, +/obj/structure/railing{ + dir = 8 + }, +/obj/structure/chair/plastic{ + dir = 8 + }, +/turf/template_noop, +/area/shuttle/escape) +"mO" = ( +/obj/structure/lattice/catwalk, +/obj/machinery/light/small/dim/directional/east, +/turf/template_noop, +/area/shuttle/escape) +"nm" = ( +/obj/structure/chair/stool/directional/south, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"ns" = ( +/obj/structure/table/reinforced/plastitaniumglass, +/obj/machinery/cell_charger, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"nG" = ( +/turf/open/floor/wood/large, +/area/shuttle/escape) +"nQ" = ( +/turf/closed/wall/mineral/plastitanium/nodiagonal, +/area/shuttle/escape/brig) +"oj" = ( +/obj/structure/table/reinforced/plastitaniumglass, +/obj/item/storage/fancy/donut_box, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"oO" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/turf/open/floor/iron/smooth, +/area/shuttle/escape) +"oP" = ( +/obj/structure/window/reinforced/plasma/spawner/directional/west, +/obj/structure/table/reinforced/plastitaniumglass, +/obj/machinery/chem_dispenser/drinks{ + dir = 4 + }, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"po" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/turf/open/floor/iron/smooth_corner/airless, +/area/shuttle/escape) +"pE" = ( +/obj/machinery/door/window/brigdoor/left/directional/east, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"qp" = ( +/obj/machinery/recharge_station, +/obj/machinery/light/small/directional/south, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"qP" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/machinery/light/small/dim/directional/west, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"rr" = ( +/obj/structure/chair/comfy/shuttle{ + dir = 4 + }, +/obj/machinery/status_display/evac/directional/west, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"rt" = ( +/obj/machinery/power/shuttle_engine/propulsion{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/plating/airless, +/area/shuttle/escape) +"rw" = ( +/obj/machinery/computer/crew{ + dir = 1 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"ry" = ( +/obj/structure/table, +/obj/item/trash/chips, +/turf/open/floor/iron/smooth, +/area/shuttle/escape) +"rA" = ( +/obj/structure/chair/comfy/shuttle{ + dir = 4 + }, +/obj/machinery/vending/wallmed/directional/west, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"rL" = ( +/obj/structure/lattice/catwalk, +/obj/structure/marker_beacon/jade, +/turf/template_noop, +/area/shuttle/escape) +"sQ" = ( +/obj/structure/window/reinforced/plasma/spawner/directional/south, +/obj/structure/window/reinforced/plasma/spawner/directional/east, +/obj/structure/window/reinforced/plasma/spawner/directional/west, +/obj/structure/window/reinforced/plasma/spawner/directional/north, +/obj/structure/bonfire/prelit, +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 8 + }, +/turf/open/floor/iron/smooth_corner/airless{ + dir = 1 + }, +/area/shuttle/escape) +"tY" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/machinery/button/flasher{ + pixel_y = 26; + pixel_x = 26; + id = "evacflash" + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"uw" = ( +/obj/machinery/computer/atmos_control/air_tank{ + atmos_chambers = list("evacair" = "Mixed Air Supply") + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape/brig) +"uW" = ( +/obj/machinery/recharge_station, +/obj/structure/extinguisher_cabinet/directional/south, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"vk" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/turf/open/floor/iron/smooth_half/airless, +/area/shuttle/escape) +"vn" = ( +/obj/structure/window/reinforced/spawner/directional/south, +/obj/machinery/power/shuttle_engine/heater{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/plating/airless, +/area/shuttle/escape/brig) +"vw" = ( +/turf/template_noop, +/area/template_noop) +"vF" = ( +/obj/structure/chair/stool/bar/directional/south{ + can_buckle = 1 + }, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"vO" = ( +/obj/structure/closet, +/obj/item/multitool, +/obj/effect/spawner/random/engineering/toolbox, +/obj/machinery/light/small/directional/north, +/obj/effect/spawner/random/contraband/narcotics, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"vR" = ( +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"wf" = ( +/obj/machinery/door/airlock/mining/glass{ + name = "Emergency Shuttle Cargo Hold" + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"xb" = ( +/obj/structure/sign/departments/medbay/alt, +/turf/closed/wall/mineral/plastitanium/nodiagonal, +/area/shuttle/escape/brig) +"xy" = ( +/obj/machinery/suit_storage_unit/standard_unit, +/obj/machinery/light/small/dim/directional/east, +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"yc" = ( +/obj/structure/statue/gold/hos, +/obj/machinery/light/floor, +/turf/open/floor/mineral/diamond, +/area/shuttle/escape) +"yh" = ( +/obj/structure/lattice/catwalk, +/obj/structure/railing{ + dir = 8 + }, +/obj/structure/table, +/obj/item/binoculars, +/turf/template_noop, +/area/shuttle/escape) +"yH" = ( +/obj/structure/chair/sofa/middle{ + dir = 4 + }, +/obj/machinery/light/directional/west, +/turf/open/floor/iron/smooth, +/area/shuttle/escape) +"yN" = ( +/obj/machinery/door/airlock/grunge{ + name = "Emergency Shuttle Airlock" + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"zn" = ( +/obj/structure/table, +/obj/item/surgery_tray/full, +/turf/open/floor/iron/showroomfloor, +/area/shuttle/escape) +"zr" = ( +/obj/structure/railing{ + dir = 4 + }, +/turf/open/floor/iron/smooth_half/airless{ + dir = 1 + }, +/area/shuttle/escape) +"zG" = ( +/obj/machinery/chem_master, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"zH" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"zZ" = ( +/obj/structure/table/reinforced/plastitaniumglass, +/obj/machinery/recharger, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"Af" = ( +/obj/structure/chair/comfy/shuttle{ + dir = 4 + }, +/obj/machinery/light/dim/directional/west, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"Ax" = ( +/obj/structure/railing/corner, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/turf/open/floor/iron/smooth_half/airless{ + dir = 4 + }, +/area/shuttle/escape) +"AA" = ( +/obj/machinery/suit_storage_unit/standard_unit, +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"Bu" = ( +/obj/structure/chair/comfy/shuttle{ + dir = 8 + }, +/obj/structure/extinguisher_cabinet/directional/east, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"Ch" = ( +/obj/structure/chair/sofa/left{ + dir = 4 + }, +/turf/open/floor/iron/smooth, +/area/shuttle/escape) +"Cl" = ( +/obj/machinery/door/airlock/medical/glass{ + name = "Medbay" + }, +/obj/effect/turf_decal/siding/wood, +/turf/open/floor/wood/large, +/area/shuttle/escape) +"CA" = ( +/obj/effect/spawner/random/structure/crate_loot, +/obj/effect/spawner/random/maintenance/seven, +/obj/item/reagent_containers/pill/maintenance, +/obj/item/reagent_containers/pill/maintenance, +/obj/item/reagent_containers/pill/maintenance, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"CH" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 8 + }, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"CW" = ( +/obj/structure/railing{ + dir = 4 + }, +/obj/structure/table, +/obj/item/binoculars, +/turf/open/floor/iron/smooth_corner/airless{ + dir = 1 + }, +/area/shuttle/escape) +"Df" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 1 + }, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"Dj" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/high_volume/siphon/monitored/air_output{ + dir = 1; + chamber_id = "evacair" + }, +/obj/machinery/light/small/directional/east, +/turf/open/floor/engine/air, +/area/shuttle/escape/brig) +"Ef" = ( +/obj/machinery/smartfridge/chemistry/preloaded, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"EJ" = ( +/obj/effect/turf_decal/siding/wood, +/obj/structure/extinguisher_cabinet/directional/west, +/turf/open/floor/iron/showroomfloor, +/area/shuttle/escape) +"EO" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"Fw" = ( +/obj/machinery/door/airlock/external/glass, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ + cycle_id = "evac3" + }, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"FG" = ( +/obj/machinery/door/airlock/security/glass{ + name = "Escape Shuttle Brig" + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/effect/mapping_helpers/airlock/access/all/security/general, +/obj/effect/turf_decal/stripes/line, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 1 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape/brig) +"FZ" = ( +/obj/structure/railing/corner, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/turf/open/floor/iron/smooth_half/airless{ + dir = 1 + }, +/area/shuttle/escape) +"GR" = ( +/turf/open/floor/iron/smooth, +/area/shuttle/escape) +"IB" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/turf/open/floor/mineral/diamond, +/area/shuttle/escape) +"JB" = ( +/obj/machinery/suit_storage_unit/standard_unit, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"JW" = ( +/obj/machinery/light/directional/north, +/obj/machinery/computer/operating, +/turf/open/floor/iron/showroomfloor, +/area/shuttle/escape) +"Kf" = ( +/obj/structure/table/reinforced/plastitaniumglass, +/obj/item/storage/box/drinkingglasses, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"Ko" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/machinery/airalarm/directional/east, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"Kv" = ( +/obj/structure/tank_dispenser/oxygen, +/obj/machinery/light/small/directional/west, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"KP" = ( +/obj/structure/window/reinforced/plasma/spawner/directional/west, +/obj/structure/table/reinforced/plastitaniumglass, +/obj/machinery/reagentgrinder, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"KX" = ( +/obj/effect/spawner/structure/window/reinforced/plasma/plastitanium, +/turf/open/floor/plating, +/area/shuttle/escape/brig) +"Lk" = ( +/obj/structure/statue/diamond/ai2, +/obj/machinery/light/floor, +/turf/open/floor/mineral/diamond, +/area/shuttle/escape) +"Lp" = ( +/obj/structure/closet/crate/secure/loot, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"LB" = ( +/obj/machinery/door/airlock/command{ + name = "Cockpit" + }, +/obj/effect/mapping_helpers/airlock/access/all/command/general, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/effect/turf_decal/siding/dark{ + dir = 1 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"LC" = ( +/obj/structure/chair/comfy/shuttle{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"LN" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"LY" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/machinery/flasher/directional/east{ + id = "evacflash" + }, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"MP" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/machinery/status_display/evac/directional/west, +/turf/open/floor/wood/large, +/area/shuttle/escape) +"MU" = ( +/obj/machinery/door/airlock/external, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ + cycle_id = "evac3" + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"MY" = ( +/obj/structure/railing/corner/end/flip, +/obj/structure/railing/corner/end{ + dir = 1 + }, +/turf/open/floor/iron/smooth_half/airless{ + dir = 1 + }, +/area/shuttle/escape) +"NR" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 4 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape/brig) +"Oj" = ( +/turf/closed/wall/mineral/plastitanium, +/area/shuttle/escape) +"Oo" = ( +/obj/structure/chair/comfy/shuttle{ + dir = 8 + }, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"Oq" = ( +/obj/effect/spawner/structure/window/reinforced/plasma/plastitanium, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/visible, +/turf/open/floor/plating, +/area/shuttle/escape/brig) +"Ot" = ( +/obj/machinery/door/airlock/external, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ + cycle_id = "evac3" + }, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"OO" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/turf/open/floor/wood/large, +/area/shuttle/escape) +"Pt" = ( +/obj/machinery/stasis, +/turf/open/floor/iron/showroomfloor, +/area/shuttle/escape) +"PS" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 8 + }, +/turf/open/floor/wood/large, +/area/shuttle/escape) +"PX" = ( +/obj/structure/chair/comfy/shuttle, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"Qe" = ( +/obj/machinery/light/directional/north, +/obj/machinery/atmospherics/components/unary/vent_pump/on, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"Sl" = ( +/turf/closed/wall/mineral/plastitanium/nodiagonal, +/area/shuttle/escape) +"Sx" = ( +/obj/structure/table/optable, +/turf/open/floor/iron/showroomfloor, +/area/shuttle/escape) +"SC" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/structure/extinguisher_cabinet/directional/west, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"SJ" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/machinery/light/directional/west, +/obj/machinery/vending/cigarette, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"Ta" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 4 + }, +/turf/open/floor/mineral/diamond, +/area/shuttle/escape) +"Te" = ( +/turf/closed/wall/mineral/plastitanium, +/area/shuttle/escape/brig) +"Ty" = ( +/obj/machinery/door/airlock/grunge{ + name = "Emergency Shuttle Airlock" + }, +/obj/docking_port/mobile/emergency, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"UR" = ( +/obj/machinery/status_display/evac/directional/north, +/turf/open/floor/iron/smooth, +/area/shuttle/escape) +"VH" = ( +/obj/structure/railing, +/turf/open/floor/iron/smooth_corner/airless{ + dir = 1 + }, +/area/shuttle/escape) +"VL" = ( +/obj/machinery/door/airlock/external, +/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ + cycle_id = "evac3" + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"WG" = ( +/obj/structure/chair/comfy/shuttle, +/obj/item/restraints/handcuffs, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape/brig) +"Xh" = ( +/obj/structure/window/reinforced/plasma/spawner/directional/west, +/obj/structure/table/reinforced/plastitaniumglass, +/obj/machinery/chem_dispenser/drinks/beer{ + dir = 4 + }, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"Xi" = ( +/obj/structure/window/reinforced/plasma/spawner/directional/east, +/obj/machinery/light/directional/south, +/obj/structure/closet/cabinet, +/obj/item/reagent_containers/cup/glass/shaker, +/obj/item/storage/fancy/cigarettes/cigars/havana, +/obj/item/instrument/guitar, +/turf/open/floor/mineral/plastitanium, +/area/shuttle/escape) +"Xv" = ( +/obj/machinery/door/airlock/external/glass, +/turf/open/floor/plating, +/area/shuttle/escape) +"XQ" = ( +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"Ys" = ( +/obj/machinery/computer/communications{ + dir = 1 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"YF" = ( +/obj/machinery/air_sensor/air_tank{ + chamber_id = "evacair" + }, +/turf/open/floor/engine/air, +/area/shuttle/escape/brig) +"Zs" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, +/obj/structure/extinguisher_cabinet/directional/east, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"ZG" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) +"ZR" = ( +/obj/machinery/light/directional/west, +/obj/structure/chair/comfy/shuttle{ + dir = 4 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/shuttle/escape) + +(1,1,1) = {" +vw +Te +Te +Te +Te +KX +nQ +yN +Sl +Ty +Sl +mI +yh +Sl +Oj +yN +Sl +yN +Sl +Sl +Oj +vw +vw +vw +vw +vw +"} +(2,1,1) = {" +dF +vn +WG +NR +KX +YF +KX +XQ +Oj +XQ +mF +hp +hp +mF +SJ +LN +ez +LN +at +qp +Sl +vw +vw +vw +vw +vw +"} +(3,1,1) = {" +dF +vn +WG +ao +Oq +Dj +KX +XQ +ZR +XQ +mF +hp +mO +mF +iW +XQ +Sl +ns +XQ +uW +Sl +vw +vw +vw +vw +vw +"} +(4,1,1) = {" +Te +nQ +hk +hd +Te +Te +nQ +ZG +ZG +ZG +Sl +Xv +Oj +Sl +bS +ZG +Sl +Xh +oP +KP +Sl +Sl +mF +mF +mF +vw +"} +(5,1,1) = {" +dF +vn +uw +ao +gL +bL +FG +EO +vR +vR +rr +vR +Af +rA +EO +vF +dP +vR +vR +Kf +mF +oj +my +zZ +mF +mF +"} +(6,1,1) = {" +dF +vn +nQ +Te +Te +Te +xb +EO +EO +EO +EO +EO +EO +vR +EO +vF +dP +zH +EO +zG +mF +XQ +ig +XQ +rw +mF +"} +(7,1,1) = {" +rt +eK +Pt +EJ +MP +OO +Cl +EO +CH +vR +vR +vR +EO +EO +EO +Df +Sl +gW +pE +Xi +Sl +Qe +LN +PX +fu +mF +"} +(8,1,1) = {" +rt +eK +Pt +hs +OO +nG +mF +vR +vR +Oo +Bu +Oo +EO +Oo +Ko +EO +EO +eW +EO +LY +LB +tY +Zs +XQ +Ys +mF +"} +(9,1,1) = {" +Oj +Sl +JW +hs +PS +nG +Ef +bT +LC +Sl +Sl +Sl +wf +Sl +Sl +Oj +Oj +Oj +Oj +Oj +Sl +mF +Sl +mF +mF +mF +"} +(10,1,1) = {" +rt +eK +Sx +hs +nG +ed +Sl +nm +jJ +Sl +CA +SC +EO +Sl +ry +Ch +yH +dl +GR +cK +VL +XQ +ji +Ta +Lk +mF +"} +(11,1,1) = {" +rt +eK +zn +hs +he +kZ +Oj +Sl +Sl +Oj +vO +EO +Lp +Oj +UR +GR +oO +oO +oO +vk +MU +LN +df +IB +yc +mF +"} +(12,1,1) = {" +vw +Oj +Oj +Oj +Oj +Oj +Oj +JB +Kv +Oj +Oj +wf +Oj +Sl +GR +po +FZ +zr +MY +CW +Sl +mF +Sl +mF +mF +mF +"} +(13,1,1) = {" +vw +vw +vw +vw +rt +eK +AA +zH +EO +Fw +qP +EO +qP +Ot +oO +Ax +sQ +vw +rL +vw +vw +vw +vw +vw +vw +vw +"} +(14,1,1) = {" +vw +vw +vw +vw +rt +eK +xy +vR +vR +eU +vR +CH +vR +kB +hA +VH +vw +vw +hp +vw +vw +vw +vw +vw +vw +vw +"} +(15,1,1) = {" +vw +vw +vw +vw +vw +Oj +Sl +kB +kB +Sl +mF +mF +mF +Sl +Oj +mF +vw +vw +rL +vw +vw +vw +vw +vw +vw +vw +"} +(16,1,1) = {" +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +hp +vw +vw +vw +vw +vw +vw +vw +"} +(17,1,1) = {" +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +vw +rL +vw +vw +vw +vw +vw +vw +vw +"} diff --git a/_maps/shuttles/emergency_lance.dmm b/_maps/shuttles/emergency_lance.dmm index 81eaec94c61194..c6c0d9d9c18db6 100644 --- a/_maps/shuttles/emergency_lance.dmm +++ b/_maps/shuttles/emergency_lance.dmm @@ -967,8 +967,8 @@ /obj/item/book/manual/wiki/surgery{ pixel_x = -15 }, -/obj/item/surgery_tray, -/obj/item/surgery_tray{ +/obj/item/surgery_tray/full, +/obj/item/surgery_tray/full{ pixel_x = 5 }, /obj/effect/turf_decal/tile/dark_blue/half/contrasted{ diff --git a/_maps/shuttles/emergency_mini.dmm b/_maps/shuttles/emergency_mini.dmm index 29f973398d36bd..73c5f42b38f065 100644 --- a/_maps/shuttles/emergency_mini.dmm +++ b/_maps/shuttles/emergency_mini.dmm @@ -227,7 +227,7 @@ "W" = ( /obj/structure/table, /obj/item/clothing/suit/apron/surgical, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /turf/open/floor/mineral/titanium/white, /area/shuttle/escape) "X" = ( diff --git a/_maps/shuttles/emergency_nature.dmm b/_maps/shuttles/emergency_nature.dmm index 4570d643bee822..95eada06cfb40a 100644 --- a/_maps/shuttles/emergency_nature.dmm +++ b/_maps/shuttles/emergency_nature.dmm @@ -498,7 +498,7 @@ /area/shuttle/escape) "sF" = ( /obj/effect/turf_decal/trimline/blue/filled/line, -/obj/item/surgery_tray{ +/obj/item/surgery_tray/full{ pixel_y = 5 }, /obj/structure/rack, diff --git a/_maps/shuttles/emergency_northstar.dmm b/_maps/shuttles/emergency_northstar.dmm index d51346fb179d71..20795c72317b92 100644 --- a/_maps/shuttles/emergency_northstar.dmm +++ b/_maps/shuttles/emergency_northstar.dmm @@ -127,7 +127,7 @@ "nC" = ( /obj/structure/table/reinforced/rglass, /obj/item/defibrillator/loaded, -/obj/item/surgery_tray{ +/obj/item/surgery_tray/full{ pixel_y = 13 }, /obj/effect/turf_decal/tile/blue/anticorner{ diff --git a/_maps/shuttles/emergency_russiafightpit.dmm b/_maps/shuttles/emergency_russiafightpit.dmm index a62e21c6ddbaa8..6d8a0e5e8fbcc8 100644 --- a/_maps/shuttles/emergency_russiafightpit.dmm +++ b/_maps/shuttles/emergency_russiafightpit.dmm @@ -438,7 +438,7 @@ "iJ" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/table, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/clothing/gloves/fingerless, /turf/open/floor/iron, /area/shuttle/escape) diff --git a/_maps/shuttles/emergency_shadow.dmm b/_maps/shuttles/emergency_shadow.dmm index a1c4cd7acc7429..15593e7e95661c 100644 --- a/_maps/shuttles/emergency_shadow.dmm +++ b/_maps/shuttles/emergency_shadow.dmm @@ -1000,7 +1000,7 @@ "Sb" = ( /obj/structure/table, /obj/structure/window/reinforced/spawner/directional/west, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/clothing/suit/apron/surgical, /obj/item/clothing/mask/surgical, /obj/item/clothing/gloves/latex/nitrile{ diff --git a/_maps/shuttles/emergency_tram.dmm b/_maps/shuttles/emergency_tram.dmm index f76c9aa787e345..5ec40d242d670e 100644 --- a/_maps/shuttles/emergency_tram.dmm +++ b/_maps/shuttles/emergency_tram.dmm @@ -203,7 +203,7 @@ /area/shuttle/escape) "aX" = ( /obj/structure/table/optable, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/clothing/mask/surgical, /turf/open/floor/mineral/titanium/blue, /area/shuttle/escape) diff --git a/_maps/shuttles/emergency_tranquility.dmm b/_maps/shuttles/emergency_tranquility.dmm index 5b66424a623bfb..a8a933b5b702bf 100644 --- a/_maps/shuttles/emergency_tranquility.dmm +++ b/_maps/shuttles/emergency_tranquility.dmm @@ -2562,7 +2562,7 @@ /obj/effect/turf_decal/tile/blue/opposingcorners, /obj/structure/table, /obj/item/lazarus_injector, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/item/clothing/gloves/latex/nitrile{ pixel_y = 4 }, diff --git a/_maps/shuttles/ruin_cyborg_mothership.dmm b/_maps/shuttles/ruin_cyborg_mothership.dmm index 15f1a5f0806d97..ac61c9b98df11f 100644 --- a/_maps/shuttles/ruin_cyborg_mothership.dmm +++ b/_maps/shuttles/ruin_cyborg_mothership.dmm @@ -1,13 +1,4 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"am" = ( -/obj/structure/lattice/catwalk, -/obj/structure/spacevine, -/obj/machinery/shieldgen{ - anchored = 1; - req_access = null - }, -/turf/template_noop, -/area/shuttle/ruin/cyborg_mothership) "aB" = ( /obj/machinery/conveyor{ dir = 8; @@ -21,8 +12,7 @@ id = "mothership_main" }, /obj/machinery/recycler{ - dir = 1; - eat_dir = 4 + dir = 8 }, /turf/open/floor/plating/airless, /area/shuttle/ruin/cyborg_mothership) @@ -58,6 +48,10 @@ }, /turf/template_noop, /area/shuttle/ruin/cyborg_mothership) +"dO" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/circuit/airless, +/area/shuttle/ruin/cyborg_mothership) "ey" = ( /obj/structure/table, /obj/item/toy/talking/ai{ @@ -77,13 +71,6 @@ }, /turf/open/floor/plating/airless, /area/shuttle/ruin/cyborg_mothership) -"eQ" = ( -/obj/effect/turf_decal/stripes/asteroid/line{ - dir = 1 - }, -/obj/machinery/light/floor, -/turf/open/floor/iron/showroomfloor, -/area/shuttle/ruin/cyborg_mothership) "fB" = ( /obj/structure/sign/warning/vacuum/external/directional/west, /obj/structure/closet/emcloset/anchored, @@ -130,17 +117,24 @@ }, /turf/open/floor/plating/airless, /area/shuttle/ruin/cyborg_mothership) +"ir" = ( +/obj/structure/table/optable, +/obj/effect/turf_decal/bot, +/turf/open/floor/iron/dark, +/area/shuttle/ruin/cyborg_mothership) "iv" = ( /obj/structure/lattice, /obj/structure/spacevine, /turf/template_noop, /area/shuttle/ruin/cyborg_mothership) -"iD" = ( -/obj/effect/turf_decal/stripes/asteroid/line{ - dir = 1 - }, -/obj/machinery/light/floor/broken, -/turf/open/floor/iron/showroomfloor, +"iN" = ( +/obj/structure/table, +/obj/effect/turf_decal/bot, +/obj/item/clothing/gloves/latex, +/obj/item/clothing/mask/surgical, +/obj/item/razor, +/obj/structure/mirror/directional/west, +/turf/open/floor/iron/dark, /area/shuttle/ruin/cyborg_mothership) "iO" = ( /obj/machinery/rnd/production/protolathe/offstation, @@ -150,13 +144,6 @@ }, /turf/open/floor/circuit/airless, /area/shuttle/ruin/cyborg_mothership) -"jl" = ( -/obj/item/stack/rods, -/obj/machinery/button/door/directional/east{ - id = "mothership_right" - }, -/turf/open/floor/circuit/airless, -/area/shuttle/ruin/cyborg_mothership) "jx" = ( /obj/effect/mapping_helpers/burnt_floor, /obj/effect/turf_decal/stripes/asteroid/line{ @@ -214,6 +201,13 @@ /obj/structure/plasticflaps, /turf/open/floor/plating/airless, /area/shuttle/ruin/cyborg_mothership) +"ms" = ( +/obj/item/stack/rods, +/obj/machinery/button/door/directional/east{ + id = "mothership_right" + }, +/turf/open/floor/circuit/airless, +/area/shuttle/ruin/cyborg_mothership) "mC" = ( /obj/machinery/mineral/ore_redemption/offstation{ input_dir = 4 @@ -221,6 +215,17 @@ /obj/structure/lattice/catwalk, /turf/open/space/basic, /area/shuttle/ruin/cyborg_mothership) +"mG" = ( +/obj/structure/table, +/obj/item/surgery_tray/full, +/obj/effect/turf_decal/bot, +/obj/structure/sink/directional/east, +/obj/item/toy/figure/borg{ + pixel_x = 7; + pixel_y = 12 + }, +/turf/open/floor/iron/dark, +/area/shuttle/ruin/cyborg_mothership) "mN" = ( /obj/machinery/conveyor{ dir = 4; @@ -286,17 +291,6 @@ /obj/structure/cable, /turf/open/floor/plating/airless, /area/shuttle/ruin/cyborg_mothership) -"oU" = ( -/mob/living/basic/hivebot/range, -/turf/open/floor/circuit/airless, -/area/shuttle/ruin/cyborg_mothership) -"pe" = ( -/obj/machinery/button/door/directional/west{ - id = "mothership_left" - }, -/obj/structure/cable, -/turf/open/floor/circuit/airless, -/area/shuttle/ruin/cyborg_mothership) "po" = ( /obj/machinery/door/airlock/hatch, /obj/structure/cable, @@ -322,18 +316,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/shuttle/ruin/cyborg_mothership) -"pR" = ( -/obj/machinery/camera/directional/south, -/obj/structure/cable, -/obj/machinery/power/apc/auto_name/directional/south{ - environ = 0; - equipment = 0; - lighting = 0 - }, -/obj/effect/mapping_helpers/apc/unlocked, -/obj/machinery/light/cold/no_nightlight/directional/south, -/turf/open/floor/circuit/airless, -/area/shuttle/ruin/cyborg_mothership) "pY" = ( /obj/machinery/recharge_station, /obj/structure/sign/warning/vacuum/external/directional/east, @@ -355,6 +337,18 @@ /obj/structure/cable, /turf/open/floor/plating/airless, /area/shuttle/ruin/cyborg_mothership) +"qz" = ( +/obj/machinery/camera/directional/south, +/obj/structure/cable, +/obj/machinery/power/apc/auto_name/directional/south{ + environ = 0; + equipment = 0; + lighting = 0 + }, +/obj/effect/mapping_helpers/apc/unlocked, +/obj/machinery/light/cold/no_nightlight/directional/south, +/turf/open/floor/circuit/airless, +/area/shuttle/ruin/cyborg_mothership) "qV" = ( /obj/structure/spacevine, /obj/machinery/conveyor{ @@ -375,6 +369,15 @@ }, /turf/open/floor/circuit/airless, /area/shuttle/ruin/cyborg_mothership) +"rJ" = ( +/mob/living/basic/hivebot, +/obj/structure/spacevine, +/obj/machinery/conveyor{ + id = "mothership_main" + }, +/obj/structure/cable, +/turf/open/floor/plating/airless, +/area/shuttle/ruin/cyborg_mothership) "so" = ( /obj/structure/lattice, /turf/template_noop, @@ -454,26 +457,6 @@ /obj/structure/cable, /turf/open/floor/plating/airless, /area/shuttle/ruin/cyborg_mothership) -"xs" = ( -/mob/living/basic/hivebot, -/obj/structure/spacevine, -/obj/machinery/conveyor{ - id = "mothership_main" - }, -/obj/structure/cable, -/turf/open/floor/plating/airless, -/area/shuttle/ruin/cyborg_mothership) -"xz" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/window/reinforced/spawner/directional/north{ - layer = 2.9 - }, -/obj/effect/turf_decal/stripes/asteroid/line{ - dir = 4 - }, -/obj/machinery/power/port_gen/pacman, -/turf/open/floor/plating/airless, -/area/shuttle/ruin/cyborg_mothership) "yd" = ( /obj/effect/mapping_helpers/burnt_floor, /obj/effect/turf_decal/stripes/asteroid/line{ @@ -488,6 +471,13 @@ }, /turf/open/floor/circuit/airless, /area/shuttle/ruin/cyborg_mothership) +"yw" = ( +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 1 + }, +/obj/machinery/light/floor/broken, +/turf/open/floor/iron/showroomfloor, +/area/shuttle/ruin/cyborg_mothership) "yA" = ( /obj/structure/spacevine, /obj/machinery/conveyor{ @@ -500,14 +490,9 @@ /obj/machinery/status_display/ai, /turf/closed/wall/mineral/titanium/nodiagonal, /area/shuttle/ruin/cyborg_mothership) -"yI" = ( -/obj/structure/table, -/obj/effect/turf_decal/bot, -/obj/item/clothing/gloves/latex, -/obj/item/clothing/mask/surgical, -/obj/item/razor, -/obj/structure/mirror/directional/west, -/turf/open/floor/iron/dark, +"yG" = ( +/mob/living/basic/hivebot/range, +/turf/open/floor/circuit/airless, /area/shuttle/ruin/cyborg_mothership) "yQ" = ( /obj/item/organ/internal/brain, @@ -546,12 +531,6 @@ /obj/structure/cable, /turf/open/floor/plating/airless, /area/shuttle/ruin/cyborg_mothership) -"Ba" = ( -/mob/living/basic/hivebot, -/obj/item/circuitboard/aicore, -/obj/structure/cable, -/turf/open/floor/circuit/green/airless, -/area/shuttle/ruin/cyborg_mothership) "BD" = ( /obj/structure/cable, /obj/machinery/power/solar, @@ -610,6 +589,11 @@ /obj/machinery/camera/directional/south, /turf/open/floor/iron/showroomfloor, /area/shuttle/ruin/cyborg_mothership) +"FQ" = ( +/obj/structure/lattice, +/mob/living/basic/hivebot/range, +/turf/template_noop, +/area/shuttle/ruin/cyborg_mothership) "Ge" = ( /obj/structure/spacevine, /obj/machinery/conveyor{ @@ -619,6 +603,15 @@ /obj/structure/cable, /turf/open/floor/plating/airless, /area/shuttle/ruin/cyborg_mothership) +"GF" = ( +/obj/structure/lattice/catwalk, +/obj/structure/spacevine, +/obj/machinery/shieldgen{ + anchored = 1; + req_access = null + }, +/turf/template_noop, +/area/shuttle/ruin/cyborg_mothership) "Hg" = ( /obj/machinery/conveyor{ id = "Recycler" @@ -626,6 +619,12 @@ /obj/structure/cable, /turf/open/floor/plating/airless, /area/shuttle/ruin/cyborg_mothership) +"HK" = ( +/mob/living/basic/hivebot, +/obj/item/circuitboard/aicore, +/obj/structure/cable, +/turf/open/floor/circuit/green/airless, +/area/shuttle/ruin/cyborg_mothership) "HM" = ( /obj/machinery/space_heater{ anchored = 1 @@ -637,11 +636,6 @@ /obj/item/wrench, /turf/open/floor/plating, /area/shuttle/ruin/cyborg_mothership) -"HQ" = ( -/obj/structure/lattice, -/mob/living/basic/hivebot/range, -/turf/template_noop, -/area/shuttle/ruin/cyborg_mothership) "IS" = ( /obj/structure/lattice, /obj/machinery/camera/directional/west, @@ -655,6 +649,11 @@ /obj/structure/cable, /turf/open/floor/plating/airless, /area/shuttle/ruin/cyborg_mothership) +"JJ" = ( +/obj/structure/lattice, +/mob/living/basic/hivebot/mechanic, +/turf/template_noop, +/area/shuttle/ruin/cyborg_mothership) "Ks" = ( /obj/structure/cable, /obj/machinery/conveyor/inverted{ @@ -686,11 +685,6 @@ }, /turf/open/floor/circuit/airless, /area/shuttle/ruin/cyborg_mothership) -"LT" = ( -/obj/structure/table/optable, -/obj/effect/turf_decal/bot, -/turf/open/floor/iron/dark, -/area/shuttle/ruin/cyborg_mothership) "MB" = ( /obj/machinery/computer/shuttle/cyborg_mothership{ dir = 1 @@ -721,21 +715,12 @@ /obj/structure/plasticflaps, /turf/open/floor/iron/showroomfloor, /area/shuttle/ruin/cyborg_mothership) -"On" = ( -/obj/structure/lattice, -/mob/living/basic/hivebot/mechanic, -/turf/template_noop, -/area/shuttle/ruin/cyborg_mothership) -"Oq" = ( -/obj/structure/table, -/obj/item/surgery_tray, -/obj/effect/turf_decal/bot, -/obj/structure/sink/directional/east, -/obj/item/toy/figure/borg{ - pixel_x = 7; - pixel_y = 12 +"Nz" = ( +/obj/machinery/button/door/directional/west{ + id = "mothership_left" }, -/turf/open/floor/iron/dark, +/obj/structure/cable, +/turf/open/floor/circuit/airless, /area/shuttle/ruin/cyborg_mothership) "Ou" = ( /obj/machinery/camera/directional/west, @@ -746,14 +731,6 @@ }, /turf/open/floor/plating/airless, /area/shuttle/ruin/cyborg_mothership) -"OA" = ( -/obj/structure/lattice/catwalk, -/obj/machinery/shieldgen{ - anchored = 1; - req_access = null - }, -/turf/template_noop, -/area/shuttle/ruin/cyborg_mothership) "OY" = ( /obj/machinery/power/shuttle_engine/heater, /obj/structure/window/reinforced/spawner/directional/north{ @@ -779,10 +756,6 @@ /obj/machinery/camera/directional/east, /turf/template_noop, /area/shuttle/ruin/cyborg_mothership) -"QO" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/circuit/airless, -/area/shuttle/ruin/cyborg_mothership) "Rv" = ( /obj/structure/window/reinforced/spawner/directional/south, /obj/structure/ore_box, @@ -814,6 +787,13 @@ }, /turf/open/floor/plating/airless, /area/shuttle/ruin/cyborg_mothership) +"Sd" = ( +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 1 + }, +/obj/machinery/light/floor, +/turf/open/floor/iron/showroomfloor, +/area/shuttle/ruin/cyborg_mothership) "SV" = ( /obj/machinery/power/shuttle_engine/heater, /obj/structure/window/reinforced/spawner/directional/north{ @@ -827,6 +807,17 @@ /obj/item/stack/sheet/mineral/titanium, /turf/template_noop, /area/shuttle/ruin/cyborg_mothership) +"TH" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/window/reinforced/spawner/directional/north{ + layer = 2.9 + }, +/obj/effect/turf_decal/stripes/asteroid/line{ + dir = 4 + }, +/obj/machinery/power/port_gen/pacman, +/turf/open/floor/plating/airless, +/area/shuttle/ruin/cyborg_mothership) "TZ" = ( /obj/item/radio/intercom/directional/south, /obj/structure/ai_core, @@ -930,6 +921,14 @@ /obj/structure/cable, /turf/open/floor/plating, /area/shuttle/ruin/cyborg_mothership) +"ZO" = ( +/obj/structure/lattice/catwalk, +/obj/machinery/shieldgen{ + anchored = 1; + req_access = null + }, +/turf/template_noop, +/area/shuttle/ruin/cyborg_mothership) (1,1,1) = {" hR @@ -991,7 +990,7 @@ hR hR hR hR -xz +TH RD wA jx @@ -1011,7 +1010,7 @@ hR hR hR hR -am +GF oe oe oe @@ -1050,7 +1049,7 @@ of oe BD oe -OA +ZO hR hR hR @@ -1115,7 +1114,7 @@ oR eO hR so -On +JJ so kz mp @@ -1161,13 +1160,13 @@ kz zZ zZ mN -yI -Oq +iN +mG zZ kz kz zZ -pe +Nz ww UL Uq @@ -1186,13 +1185,13 @@ yF fB zZ Ey -eQ +Sd Fe yF HM yF yg -Ba +HK vy Dv Ln @@ -1221,7 +1220,7 @@ ks TZ zZ uK -pR +qz zZ VU tr @@ -1236,7 +1235,7 @@ yF pY zZ Ey -iD +yw bE yF hB @@ -1245,7 +1244,7 @@ dA Ng MB ey -oU +yG Uq yF so @@ -1261,16 +1260,16 @@ kz zZ zZ mN -LT +ir hs zZ kz Em no -jl +ms pz Uq -QO +dO zZ kz hR @@ -1338,7 +1337,7 @@ hR hR oe qV -HQ +FQ so so hR @@ -1400,7 +1399,7 @@ MZ BD oe oe -am +GF hR hR hR @@ -1411,14 +1410,14 @@ hR hR hR hR -OA +ZO oe oe oe RV tW tW -xs +rJ Jj tW Sc diff --git a/_maps/shuttles/skyrat/emergency_outpost.dmm b/_maps/shuttles/skyrat/emergency_outpost.dmm index 06358a011a8121..7c210566e08ff7 100644 --- a/_maps/shuttles/skyrat/emergency_outpost.dmm +++ b/_maps/shuttles/skyrat/emergency_outpost.dmm @@ -228,7 +228,7 @@ /area/shuttle/escape) "vD" = ( /obj/structure/table/glass, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /turf/open/floor/mineral/titanium/white, /area/shuttle/escape) "vI" = ( diff --git a/_maps/shuttles/skyrat/emergency_skyrat.dmm b/_maps/shuttles/skyrat/emergency_skyrat.dmm index 0cd803cda03d6d..fee55c936e99c9 100644 --- a/_maps/shuttles/skyrat/emergency_skyrat.dmm +++ b/_maps/shuttles/skyrat/emergency_skyrat.dmm @@ -96,7 +96,7 @@ /area/shuttle/escape) "gI" = ( /obj/structure/table/reinforced/rglass, -/obj/item/surgery_tray{ +/obj/item/surgery_tray/full{ pixel_y = 8 }, /turf/open/floor/iron/dark/textured_large, diff --git a/_maps/shuttles/whiteship_birdshot.dmm b/_maps/shuttles/whiteship_birdshot.dmm index 51db46c9b8c620..25dc64ed0fc01c 100644 --- a/_maps/shuttles/whiteship_birdshot.dmm +++ b/_maps/shuttles/whiteship_birdshot.dmm @@ -149,7 +149,7 @@ pixel_y = 3 }, /obj/item/reagent_containers/blood, -/obj/item/surgery_tray{ +/obj/item/surgery_tray/full{ pixel_x = 2; pixel_y = 9 }, diff --git a/_maps/shuttles/whiteship_box.dmm b/_maps/shuttles/whiteship_box.dmm index 72c843587f727d..48d47820df2754 100644 --- a/_maps/shuttles/whiteship_box.dmm +++ b/_maps/shuttles/whiteship_box.dmm @@ -104,7 +104,7 @@ }, /obj/machinery/airalarm/directional/north, /obj/effect/mapping_helpers/airalarm/all_access, -/obj/item/surgery_tray{ +/obj/item/surgery_tray/full{ pixel_y = 4 }, /obj/item/clothing/suit/apron/surgical, diff --git a/_maps/shuttles/whiteship_delta.dmm b/_maps/shuttles/whiteship_delta.dmm index 36df707a668261..2ee3a6e691e6e0 100644 --- a/_maps/shuttles/whiteship_delta.dmm +++ b/_maps/shuttles/whiteship_delta.dmm @@ -1623,7 +1623,7 @@ /area/shuttle/abandoned/medbay) "dO" = ( /obj/structure/table, -/obj/item/surgery_tray{ +/obj/item/surgery_tray/full{ pixel_y = 4 }, /obj/effect/decal/cleanable/dirt, diff --git a/_maps/skyrat/automapper/automapper_config.toml b/_maps/skyrat/automapper/automapper_config.toml index a007accbad914c..6c45d2a3955a96 100644 --- a/_maps/skyrat/automapper/automapper_config.toml +++ b/_maps/skyrat/automapper/automapper_config.toml @@ -359,7 +359,7 @@ trait_name = "Station" map_files = ["northstar_supermatter.dmm"] directory = "_maps/skyrat/automapper/templates/northstar/" required_map = "north_star.dmm" -coordinates = [174, 129, 1] +coordinates = [171, 129, 1] trait_name = "Station" # Tannhauser Gate Overrides go below this line diff --git a/_maps/skyrat/automapper/templates/birdshot/birdshot_ntrep_office.dmm b/_maps/skyrat/automapper/templates/birdshot/birdshot_ntrep_office.dmm index b815c4676696a6..41608333fd3b3a 100644 --- a/_maps/skyrat/automapper/templates/birdshot/birdshot_ntrep_office.dmm +++ b/_maps/skyrat/automapper/templates/birdshot/birdshot_ntrep_office.dmm @@ -10,29 +10,29 @@ name = "Nanotrasen Consultant's Fax Machine" }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "aU" = ( /obj/machinery/light/directional/west, /obj/machinery/light_switch/directional/west, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "bD" = ( /obj/structure/closet/secure_closet/nanotrasen_consultant/station, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "ca" = ( /obj/structure/chair/comfy/black{ dir = 4 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "cP" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, /obj/machinery/light/directional/south, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "eD" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -65,7 +65,7 @@ /obj/structure/cable, /obj/machinery/light_switch/directional/south, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "iC" = ( /obj/effect/mapping_helpers/broken_floor, /obj/structure/cable, @@ -96,7 +96,7 @@ dir = 8 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "lJ" = ( /obj/machinery/power/apc/auto_name/directional/north, /obj/structure/cable, @@ -112,7 +112,7 @@ }, /obj/structure/sign/calendar/directional/west, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "nw" = ( /turf/template_noop, /area/template_noop) @@ -128,18 +128,18 @@ dir = 1 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "rA" = ( /obj/machinery/modular_computer/preset/command, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "sZ" = ( /turf/closed/wall/r_wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "ti" = ( /obj/structure/filingcabinet/chestdrawer, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "vK" = ( /obj/structure/extinguisher_cabinet/directional/east, /obj/machinery/camera/autoname/directional/east, @@ -148,7 +148,7 @@ }, /obj/effect/landmark/start/nanotrasen_consultant, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "wx" = ( /obj/structure/cable, /turf/open/floor/plating, @@ -176,7 +176,7 @@ }, /obj/item/radio/intercom/directional/north, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "xL" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, @@ -184,10 +184,10 @@ dir = 8 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "yC" = ( /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Ab" = ( /turf/closed/wall, /area/station/maintenance/hallway/abandoned_command) @@ -234,7 +234,7 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /obj/machinery/newscaster/directional/north, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "FF" = ( /obj/structure/cable, /turf/template_noop, @@ -273,18 +273,18 @@ pixel_y = 7 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Ll" = ( /obj/machinery/firealarm/directional/north, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Nt" = ( /turf/open/floor/iron, /area/station/maintenance/hallway/abandoned_command) "OS" = ( /obj/structure/filingcabinet/employment, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Pd" = ( /obj/structure/disposalpipe/segment{ dir = 5 @@ -308,14 +308,14 @@ dir = 8 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Rk" = ( /turf/closed/wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "TT" = ( /obj/machinery/photocopier, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "VM" = ( /obj/structure/table/wood, /obj/item/stamp/centcom{ @@ -323,7 +323,7 @@ pixel_x = -7 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Yp" = ( /turf/closed/wall/r_wall, /area/station/maintenance/fore/lesser) diff --git a/_maps/skyrat/automapper/templates/birdshot/birdshot_supermatter.dmm b/_maps/skyrat/automapper/templates/birdshot/birdshot_supermatter.dmm index 33005aba421194..fc0d26771fb0a5 100644 --- a/_maps/skyrat/automapper/templates/birdshot/birdshot_supermatter.dmm +++ b/_maps/skyrat/automapper/templates/birdshot/birdshot_supermatter.dmm @@ -14,7 +14,7 @@ /turf/template_noop, /area/template_noop) "v" = ( -/obj/item/folder/biscuit/confidential/delam, +/obj/structure/sign/delam_procedure, /turf/template_noop, /area/template_noop) "B" = ( diff --git a/_maps/skyrat/automapper/templates/deltastation/deltastation_ntrep_office.dmm b/_maps/skyrat/automapper/templates/deltastation/deltastation_ntrep_office.dmm index 65763878a52bfe..2ce018e9314514 100644 --- a/_maps/skyrat/automapper/templates/deltastation/deltastation_ntrep_office.dmm +++ b/_maps/skyrat/automapper/templates/deltastation/deltastation_ntrep_office.dmm @@ -1,7 +1,7 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE "a" = ( /turf/closed/wall/r_wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "b" = ( /obj/structure/table/wood, /obj/item/stamp{ @@ -14,7 +14,7 @@ pixel_y = 8 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "c" = ( /obj/structure/sign/directions/engineering, /obj/structure/sign/directions/evac{ @@ -24,7 +24,7 @@ pixel_y = 8 }, /turf/closed/wall/r_wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "f" = ( /obj/structure/table/wood, /obj/item/camera_film{ @@ -40,7 +40,7 @@ }, /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "i" = ( /turf/template_noop, /area/template_noop) @@ -48,24 +48,24 @@ /obj/machinery/light/directional/east, /obj/machinery/photocopier, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "k" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 }, /obj/effect/landmark/start/nanotrasen_consultant, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "m" = ( /obj/structure/extinguisher_cabinet/directional/north, /obj/effect/turf_decal/siding/wood, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "n" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "o" = ( /obj/machinery/button/door/directional/south{ id = "nt_rep_priv"; @@ -77,13 +77,13 @@ dir = 4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "q" = ( /obj/structure/chair/office{ dir = 8 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "s" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/door/airlock/maintenance_hatch{ @@ -103,13 +103,13 @@ /obj/structure/sign/poster/official/random/directional/north, /obj/item/radio/intercom/directional/west, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "u" = ( /obj/structure/cable, /obj/structure/filingcabinet/chestdrawer, /obj/machinery/power/apc/auto_name/directional/west, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "v" = ( /obj/machinery/newscaster/directional/west, /obj/structure/chair/office{ @@ -117,7 +117,7 @@ }, /obj/effect/landmark/start/nanotrasen_consultant, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "w" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/door/poddoor/preopen{ @@ -125,7 +125,7 @@ name = "Privacy Shutter" }, /turf/open/floor/plating, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "x" = ( /obj/structure/sign/poster/official/random/directional/south, /obj/structure/disposalpipe/segment{ @@ -143,13 +143,13 @@ pixel_x = -8 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "y" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "z" = ( /obj/structure/cable, /obj/effect/turf_decal/siding/wood{ @@ -158,10 +158,10 @@ /obj/effect/landmark/start/nanotrasen_consultant, /obj/machinery/airalarm/directional/north, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "B" = ( /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "C" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/siding/wood{ @@ -169,18 +169,18 @@ }, /obj/structure/cable, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "D" = ( /obj/structure/closet/secure_closet/nanotrasen_consultant/station, /obj/item/storage/briefcase, /obj/item/assembly/flash/handheld, /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "E" = ( /obj/structure/filingcabinet/employment, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "F" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/siding/wood/corner{ @@ -189,7 +189,7 @@ /obj/structure/cable, /obj/machinery/holopad, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "I" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -199,7 +199,7 @@ }, /obj/effect/landmark/start/nanotrasen_consultant, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "J" = ( /obj/structure/table/wood, /obj/item/paper_bin{ @@ -207,7 +207,7 @@ }, /obj/item/pen/fountain, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "K" = ( /obj/machinery/light_switch/directional/north, /obj/structure/disposalpipe/segment{ @@ -217,7 +217,7 @@ dir = 4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "L" = ( /obj/machinery/door/airlock/corporate{ name = "NT Consultant's Office" @@ -228,14 +228,14 @@ /obj/effect/mapping_helpers/airlock/access/all/cent_com/rep_door, /obj/machinery/door/firedoor, /turf/open/floor/iron, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "M" = ( /obj/machinery/status_display/ai/directional/south, /obj/machinery/modular_computer/preset/command{ dir = 1 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "P" = ( /obj/machinery/airalarm/directional/south, /obj/effect/turf_decal/siding/wood{ @@ -247,7 +247,7 @@ }, /obj/structure/cable, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Q" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -258,7 +258,7 @@ name = "Nanotrasen Consultant's Fax Machine" }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "S" = ( /obj/machinery/disposal/bin, /obj/structure/disposalpipe/trunk{ @@ -266,12 +266,12 @@ }, /obj/machinery/firealarm/directional/south, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "U" = ( /obj/structure/fireplace, /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "V" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /obj/effect/turf_decal/siding/wood/corner{ @@ -280,17 +280,17 @@ /obj/structure/cable, /obj/effect/landmark/start/nanotrasen_consultant, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "W" = ( /obj/structure/disposalpipe/segment{ dir = 6 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Y" = ( /obj/effect/turf_decal/siding/wood, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) (1,1,1) = {" i diff --git a/_maps/skyrat/automapper/templates/deltastation/deltastation_supermatter.dmm b/_maps/skyrat/automapper/templates/deltastation/deltastation_supermatter.dmm index 3ede0c69f005dc..3a91788fd6a208 100644 --- a/_maps/skyrat/automapper/templates/deltastation/deltastation_supermatter.dmm +++ b/_maps/skyrat/automapper/templates/deltastation/deltastation_supermatter.dmm @@ -7,7 +7,7 @@ /turf/template_noop, /area/template_noop) "j" = ( -/obj/item/folder/biscuit/confidential/delam, +/obj/structure/sign/delam_procedure, /turf/template_noop, /area/template_noop) "l" = ( @@ -69,7 +69,7 @@ a a a M -a +j a "} (6,1,1) = {" @@ -87,6 +87,6 @@ a a a a -j +a a "} diff --git a/_maps/skyrat/automapper/templates/icebox/icebox_ntrep_office.dmm b/_maps/skyrat/automapper/templates/icebox/icebox_ntrep_office.dmm index 3bcb075cc9db1c..cbfaddfb20cb6c 100644 --- a/_maps/skyrat/automapper/templates/icebox/icebox_ntrep_office.dmm +++ b/_maps/skyrat/automapper/templates/icebox/icebox_ntrep_office.dmm @@ -13,10 +13,10 @@ pixel_x = -6 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "an" = ( /turf/closed/wall/r_wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "aB" = ( /obj/structure/chair/sofa/bench/left{ dir = 1 @@ -45,7 +45,7 @@ /obj/effect/turf_decal/siding/wood, /obj/structure/filingcabinet/chestdrawer, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "cn" = ( /turf/closed/mineral/random/snow, /area/icemoon/underground/explored) @@ -61,7 +61,7 @@ dir = 4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "dX" = ( /obj/machinery/door/airlock/maintenance, /obj/structure/cable, @@ -134,7 +134,7 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "hX" = ( /obj/structure/flora/rock/icy/style_random, /turf/open/misc/asteroid/snow/icemoon, @@ -148,7 +148,7 @@ dir = 8 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "kL" = ( /turf/open/floor/iron/dark, /area/mine/storage) @@ -164,7 +164,7 @@ "lJ" = ( /obj/structure/fireplace, /turf/open/floor/iron/dark, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "lX" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/broken_floor, @@ -193,7 +193,7 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "oP" = ( /obj/machinery/light/directional/east, /turf/open/misc/asteroid/snow/icemoon, @@ -226,7 +226,7 @@ /obj/machinery/light/directional/north, /obj/machinery/status_display/ai/directional/north, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "qr" = ( /obj/structure/flora/grass/green/style_random, /turf/open/misc/asteroid/snow/icemoon, @@ -240,17 +240,17 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "sV" = ( /obj/structure/chair/office{ dir = 8 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "tw" = ( /obj/structure/filingcabinet/employment, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "tD" = ( /obj/machinery/modular_computer/preset/command{ dir = 4 @@ -266,7 +266,7 @@ pixel_y = -8 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "uu" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -305,7 +305,7 @@ }, /obj/item/pen/fountain, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "vS" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 @@ -323,7 +323,7 @@ }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "yt" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/item/radio/intercom/directional/south, @@ -338,7 +338,7 @@ /obj/machinery/light/directional/west, /obj/item/radio/intercom/directional/west, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "zD" = ( /obj/structure/table/wood, /obj/item/folder/yellow, @@ -353,11 +353,11 @@ }, /obj/machinery/airalarm/directional/east, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "zQ" = ( /obj/effect/landmark/start/nanotrasen_consultant, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Ag" = ( /obj/effect/spawner/random/trash/hobo_squat, /obj/effect/mapping_helpers/broken_floor, @@ -379,7 +379,7 @@ dir = 4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Ct" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 @@ -413,7 +413,7 @@ }, /obj/effect/landmark/start/nanotrasen_consultant, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Fk" = ( /turf/open/genturf/blue, /area/icemoon/underground/unexplored/rivers/deep/shoreline) @@ -422,7 +422,7 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Hy" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/door/poddoor/preopen{ @@ -430,7 +430,7 @@ name = "Privacy Shutter" }, /turf/open/floor/plating, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "HF" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -477,7 +477,7 @@ name = "Nanotrasen Consultant's Fax Machine" }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Kq" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -489,7 +489,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/landmark/start/nanotrasen_consultant, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Lj" = ( /turf/closed/wall/r_wall, /area/mine/storage) @@ -512,7 +512,7 @@ /obj/machinery/light/directional/east, /obj/machinery/light_switch/directional/south, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Nb" = ( /obj/effect/spawner/random/engineering/atmospherics_portable, /turf/open/floor/plating, @@ -564,7 +564,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Qm" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /obj/machinery/light/directional/east, @@ -580,7 +580,7 @@ }, /obj/item/radio/intercom/directional/east, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Rd" = ( /obj/machinery/door/airlock/external{ glass = 1; @@ -611,14 +611,14 @@ "RH" = ( /obj/item/kirbyplants/random, /turf/open/floor/iron/dark, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "RJ" = ( /obj/effect/landmark/start/assistant, /turf/open/floor/iron, /area/station/hallway/primary/central) "RS" = ( /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "ST" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/burnt_floor, @@ -628,7 +628,7 @@ /obj/machinery/power/apc/auto_name/directional/north, /obj/structure/cable, /turf/open/floor/iron/dark, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Uj" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/door/poddoor/preopen{ @@ -636,7 +636,7 @@ name = "Wildlife Observation Shutters" }, /turf/open/floor/plating, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Xo" = ( /obj/structure/sign/warning/directional/north, /turf/open/misc/asteroid/snow/icemoon, @@ -679,7 +679,7 @@ "YS" = ( /obj/machinery/photocopier, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) (1,1,1) = {" qr diff --git a/_maps/skyrat/automapper/templates/icebox/icebox_supermatter.dmm b/_maps/skyrat/automapper/templates/icebox/icebox_supermatter.dmm index 8c6304ec809fa2..077320613000d2 100644 --- a/_maps/skyrat/automapper/templates/icebox/icebox_supermatter.dmm +++ b/_maps/skyrat/automapper/templates/icebox/icebox_supermatter.dmm @@ -2,22 +2,41 @@ "a" = ( /turf/template_noop, /area/template_noop) -"t" = ( +"c" = ( /obj/machinery/button/delam_scram, /turf/template_noop, /area/template_noop) -"x" = ( -/obj/item/folder/biscuit/confidential/delam, -/turf/template_noop, -/area/template_noop) -"H" = ( +"i" = ( /obj/effect/turf_decal/stripes/red/box, /turf/template_noop, /area/template_noop) -"J" = ( +"n" = ( +/obj/effect/spawner/structure/window/reinforced/plasma, +/turf/template_noop, +/area/station/engineering/supermatter/room) +"p" = ( /obj/machinery/atmospherics/components/unary/delam_scram/directional/east, /turf/template_noop, /area/template_noop) +"s" = ( +/obj/structure/sign/delam_procedure, +/turf/closed/wall/r_wall, +/area/station/engineering/supermatter/room) +"y" = ( +/obj/effect/turf_decal/stripes/red/box, +/turf/open/floor/engine, +/area/station/engineering/supermatter/room) +"H" = ( +/obj/structure/table/reinforced, +/obj/item/clothing/suit/utility/radiation, +/obj/item/clothing/head/utility/radiation, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/item/geiger_counter, +/obj/item/clothing/glasses/meson, +/turf/open/floor/engine, +/area/station/engineering/supermatter/room) (1,1,1) = {" a @@ -30,7 +49,7 @@ a a a a -J +p "} (2,1,1) = {" a @@ -46,9 +65,9 @@ a a "} (3,1,1) = {" -H -t -H +i +c +y a a a @@ -60,7 +79,33 @@ a "} (4,1,1) = {" a -x +s +H +a +a +a +a +a +a +a +a +"} +(5,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +"} +(6,1,1) = {" +a +n a a a diff --git a/_maps/skyrat/automapper/templates/kilostation/kilostation_ert_bay.dmm b/_maps/skyrat/automapper/templates/kilostation/kilostation_ert_bay.dmm index 7e94976b7cce4a..34e0fbcad743bc 100644 --- a/_maps/skyrat/automapper/templates/kilostation/kilostation_ert_bay.dmm +++ b/_maps/skyrat/automapper/templates/kilostation/kilostation_ert_bay.dmm @@ -13,7 +13,7 @@ /obj/machinery/newscaster/directional/east, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "bb" = ( /obj/machinery/door/airlock/maintenance/external{ name = "Transit Intersection" @@ -67,7 +67,7 @@ /obj/machinery/airalarm/directional/north, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "cc" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 @@ -82,7 +82,7 @@ "cm" = ( /obj/structure/filingcabinet/employment, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "cW" = ( /obj/structure/fans/tiny/forcefield{ dir = 1 @@ -98,7 +98,7 @@ /obj/item/assembly/flash/handheld, /obj/machinery/status_display/ai/directional/north, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "df" = ( /obj/machinery/disposal/bin, /obj/structure/disposalpipe/trunk{ @@ -241,7 +241,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "fA" = ( /obj/structure/disposalpipe/segment, /obj/structure/window/reinforced/spawner/directional/north, @@ -344,7 +344,7 @@ }, /obj/machinery/holopad, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "ha" = ( /obj/structure/sign/departments/holy{ pixel_y = 30 @@ -492,7 +492,7 @@ id = "nt_rep_priv_2" }, /turf/open/floor/plating, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "kE" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, @@ -568,7 +568,7 @@ /area/station/hallway/primary/fore) "mZ" = ( /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "nc" = ( /obj/effect/turf_decal/sand/plating, /obj/structure/disposalpipe/segment, @@ -657,11 +657,11 @@ id = "nt_rep_priv" }, /turf/open/floor/plating, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "oZ" = ( /obj/effect/decal/cleanable/dirt, /turf/closed/wall/r_wall/rust, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "pf" = ( /turf/closed/wall, /area/station/maintenance/fore) @@ -712,7 +712,7 @@ pixel_x = -2 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "qS" = ( /obj/effect/turf_decal/tile/neutral{ dir = 4 @@ -770,7 +770,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "rT" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, @@ -821,7 +821,7 @@ /obj/effect/landmark/start/nanotrasen_consultant, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "uj" = ( /obj/structure/lattice, /obj/structure/grille/broken, @@ -909,7 +909,7 @@ }, /obj/item/camera_film, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "vV" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line, @@ -961,10 +961,10 @@ }, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "xV" = ( /turf/closed/wall/r_wall/rust, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "yd" = ( /obj/structure/chair/sofa/bench/left{ dir = 1 @@ -984,7 +984,7 @@ /area/space/nearstation) "zb" = ( /turf/closed/wall/r_wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "ze" = ( /obj/machinery/light/directional/south, /obj/effect/turf_decal/stripes/corner{ @@ -1001,7 +1001,7 @@ /obj/machinery/light/directional/east, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "zF" = ( /obj/structure/table/wood, /obj/item/paper_bin{ @@ -1009,7 +1009,7 @@ }, /obj/item/pen/fountain, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "zR" = ( /obj/effect/spawner/structure/window, /obj/structure/curtain/cloth/fancy/mechanical{ @@ -1052,7 +1052,7 @@ }, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Bx" = ( /obj/structure/disposalpipe/segment{ dir = 6 @@ -1091,7 +1091,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/firealarm/directional/south, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Cm" = ( /obj/structure/flora/rock/style_random, /turf/open/misc/asteroid/airless, @@ -1133,7 +1133,7 @@ /area/station/hallway/primary/fore) "DJ" = ( /turf/closed/wall/rust, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Ef" = ( /obj/machinery/light/directional/north, /obj/effect/turf_decal/stripes/line{ @@ -1178,7 +1178,7 @@ /obj/effect/landmark/start/nanotrasen_consultant, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "EG" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -1188,7 +1188,7 @@ }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "EI" = ( /obj/effect/turf_decal/tile/purple/opposingcorners{ dir = 8 @@ -1227,7 +1227,7 @@ }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Fg" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1391,7 +1391,7 @@ pixel_x = -4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Ja" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1414,7 +1414,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Jn" = ( /obj/structure/chair/sofa/bench{ dir = 8 @@ -1446,7 +1446,7 @@ name = "Privacy Shutters Control" }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "KE" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -1522,7 +1522,7 @@ }, /obj/structure/filingcabinet/chestdrawer, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Nu" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -1592,7 +1592,7 @@ dir = 4 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "OY" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1728,7 +1728,7 @@ dir = 1 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Th" = ( /obj/effect/decal/cleanable/dirt, /obj/item/radio/intercom/directional/east, @@ -1831,7 +1831,7 @@ /turf/open/floor/iron/dark/corner{ dir = 4 }, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "WY" = ( /obj/effect/turf_decal/tile/blue{ dir = 4 @@ -1900,7 +1900,7 @@ "YD" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "YS" = ( /obj/effect/turf_decal/sand/plating, /obj/structure/disposalpipe/segment{ @@ -1912,7 +1912,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Ze" = ( /obj/structure/transit_tube/crossing, /obj/effect/turf_decal/sand/plating, @@ -1927,7 +1927,7 @@ "ZN" = ( /obj/structure/table/wood, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) (1,1,1) = {" Gh diff --git a/_maps/skyrat/automapper/templates/metastation/metastation_armory.dmm b/_maps/skyrat/automapper/templates/metastation/metastation_armory.dmm index 9bee58a4be2158..d123d8de9bce72 100644 --- a/_maps/skyrat/automapper/templates/metastation/metastation_armory.dmm +++ b/_maps/skyrat/automapper/templates/metastation/metastation_armory.dmm @@ -37,7 +37,7 @@ /area/station/security/lockers) "j" = ( /obj/machinery/dish_drive/bullet{ - succrange = 2 + suck_distance = 0 }, /obj/machinery/light_switch/directional/east, /turf/open/floor/iron/dark, diff --git a/_maps/skyrat/automapper/templates/metastation/metastation_ntrep_office.dmm b/_maps/skyrat/automapper/templates/metastation/metastation_ntrep_office.dmm index 11fb07a577f1cf..c18d33363e6bef 100644 --- a/_maps/skyrat/automapper/templates/metastation/metastation_ntrep_office.dmm +++ b/_maps/skyrat/automapper/templates/metastation/metastation_ntrep_office.dmm @@ -6,7 +6,7 @@ name = "Privacy Shutter" }, /turf/open/floor/plating, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "b" = ( /obj/structure/table/wood, /obj/item/camera_film{ @@ -17,7 +17,7 @@ pixel_y = 4 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "d" = ( /turf/closed/wall/r_wall, /area/station/maintenance/port) @@ -27,7 +27,7 @@ }, /obj/machinery/holopad, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "f" = ( /obj/machinery/button/door/directional/west{ id = "nt_rep_priv"; @@ -52,14 +52,14 @@ pixel_y = 6 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "g" = ( /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "i" = ( /obj/item/kirbyplants/random, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "j" = ( /obj/structure/sign/poster/official/random/directional/south, /obj/structure/chair/office{ @@ -67,16 +67,16 @@ }, /obj/effect/landmark/start/nanotrasen_consultant, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "k" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "l" = ( /obj/structure/cable, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "p" = ( /obj/effect/turf_decal/tile/neutral{ dir = 8 @@ -85,43 +85,43 @@ /area/station/hallway/primary/port) "q" = ( /turf/closed/wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "s" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 }, /obj/machinery/status_display/ai/directional/west, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "u" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "v" = ( /obj/machinery/camera/directional/west{ c_tag = "NT Consultant's Office"; name = "command camera" }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "w" = ( /obj/structure/table/wood, /obj/item/stamp/centcom{ pixel_x = 8 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "x" = ( /obj/machinery/light/directional/west, /obj/machinery/modular_computer/preset/command{ dir = 4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "y" = ( /obj/machinery/firealarm/directional/east, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "z" = ( /obj/structure/table/wood, /obj/item/paper_bin{ @@ -129,18 +129,18 @@ }, /obj/item/pen/fountain, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "A" = ( /obj/machinery/airalarm/directional/east, /obj/machinery/light/directional/east, /obj/structure/closet/secure_closet/nanotrasen_consultant/station, /obj/item/assembly/flash/handheld, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "B" = ( /obj/structure/filingcabinet/employment, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "C" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -148,7 +148,7 @@ dir = 4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "D" = ( /turf/template_noop, /area/template_noop) @@ -156,14 +156,14 @@ /obj/item/kirbyplants/random, /obj/machinery/airalarm/directional/south, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "F" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/light_switch/directional/east, /obj/effect/turf_decal/siding/wood/corner, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "I" = ( /obj/structure/table/wood, /obj/machinery/fax{ @@ -171,18 +171,18 @@ name = "Nanotrasen Consultant's Fax Machine" }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "L" = ( /obj/structure/chair/office{ dir = 8 }, /obj/effect/landmark/start/nanotrasen_consultant, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "M" = ( /obj/machinery/status_display/ai/directional/east, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "N" = ( /obj/structure/chair/office{ dir = 4 @@ -191,14 +191,14 @@ dir = 4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "O" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 }, /obj/item/radio/intercom/directional/south, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "P" = ( /obj/structure/table/wood, /obj/item/stamp/denied{ @@ -210,7 +210,7 @@ pixel_y = 6 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Q" = ( /obj/machinery/door/airlock/corporate{ name = "NT Consultant's Office" @@ -220,18 +220,18 @@ /obj/effect/mapping_helpers/airlock/access/all/cent_com/rep_door, /obj/machinery/door/firedoor, /turf/open/floor/iron, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "S" = ( /obj/machinery/newscaster/directional/north, /obj/structure/filingcabinet/chestdrawer, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "T" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "V" = ( /obj/machinery/door/airlock/maintenance, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -240,13 +240,13 @@ /area/station/maintenance/port) "Y" = ( /turf/closed/wall/r_wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Z" = ( /obj/structure/cable, /obj/machinery/power/apc/auto_name/directional/west, /obj/machinery/photocopier, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) (1,1,1) = {" D diff --git a/_maps/skyrat/automapper/templates/metastation/metastation_supermatter.dmm b/_maps/skyrat/automapper/templates/metastation/metastation_supermatter.dmm index dae4b01581d383..280a852105db12 100644 --- a/_maps/skyrat/automapper/templates/metastation/metastation_supermatter.dmm +++ b/_maps/skyrat/automapper/templates/metastation/metastation_supermatter.dmm @@ -21,9 +21,9 @@ /turf/open/floor/engine, /area/station/engineering/supermatter/room) "R" = ( -/obj/item/folder/biscuit/confidential/delam, -/turf/template_noop, -/area/template_noop) +/obj/structure/sign/delam_procedure, +/turf/closed/wall/r_wall, +/area/station/engineering/supermatter/room) "V" = ( /obj/machinery/atmospherics/components/unary/delam_scram/directional/west, /turf/template_noop, diff --git a/_maps/skyrat/automapper/templates/northstar/northstar_ntrep_office.dmm b/_maps/skyrat/automapper/templates/northstar/northstar_ntrep_office.dmm index abbfb68334759c..f797c7905a7a44 100644 --- a/_maps/skyrat/automapper/templates/northstar/northstar_ntrep_office.dmm +++ b/_maps/skyrat/automapper/templates/northstar/northstar_ntrep_office.dmm @@ -2,13 +2,13 @@ "a" = ( /obj/structure/filingcabinet/employment, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "b" = ( /obj/machinery/light/warm/directional/south, /obj/machinery/newscaster/directional/south, /obj/effect/landmark/start/nanotrasen_consultant, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "c" = ( /obj/machinery/door/airlock/corporate{ name = "NT Consultant's Office"; @@ -20,7 +20,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/door/firedoor, /turf/open/floor/plating, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "e" = ( /obj/structure/table/wood, /obj/machinery/fax{ @@ -28,12 +28,12 @@ name = "Nanotrasen Consultant's Fax Machine" }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "g" = ( /obj/effect/turf_decal/siding/wood, /obj/structure/chair/comfy/black, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "h" = ( /obj/effect/turf_decal/siding/wood{ dir = 4 @@ -43,17 +43,17 @@ /obj/structure/cable, /obj/machinery/light/warm/directional/north, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "i" = ( /obj/effect/turf_decal/siding/wood, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "j" = ( /obj/structure/chair/comfy/black{ dir = 1 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "k" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -72,7 +72,7 @@ pixel_x = -4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "q" = ( /obj/structure/table/wood, /obj/item/paper_bin/carbon{ @@ -102,7 +102,7 @@ pixel_x = -37 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "r" = ( /obj/structure/table/wood, /obj/item/stamp/centcom{ @@ -111,7 +111,7 @@ }, /obj/item/folder/blue, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "s" = ( /obj/effect/turf_decal/siding/wood/corner{ dir = 4 @@ -119,7 +119,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "t" = ( /obj/machinery/light_switch/directional/north, /obj/machinery/disposal/bin, @@ -127,7 +127,7 @@ dir = 4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "u" = ( /obj/effect/turf_decal/siding/wood{ dir = 8 @@ -136,21 +136,21 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "v" = ( /obj/structure/closet/secure_closet/nanotrasen_consultant/station, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "w" = ( /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "y" = ( /turf/closed/wall/r_wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "z" = ( /obj/structure/filingcabinet/chestdrawer, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "A" = ( /obj/effect/turf_decal/siding/wood/corner{ dir = 8 @@ -160,13 +160,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "B" = ( /obj/effect/turf_decal/siding/wood, /obj/structure/chair/comfy/black, /obj/machinery/airalarm/directional/west, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "D" = ( /turf/template_noop, /area/template_noop) @@ -179,14 +179,14 @@ /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/access/all/cent_com/rep_door, /turf/open/floor/iron, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "F" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 }, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "H" = ( /obj/machinery/camera/autoname/directional/east, /obj/item/radio/intercom/directional/east{ @@ -196,11 +196,11 @@ dir = 8 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "I" = ( /obj/structure/extinguisher_cabinet/directional/east, /turf/open/floor/iron/textured_edge, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "J" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -209,15 +209,15 @@ dir = 1 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "L" = ( /obj/machinery/firealarm/directional/west, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "O" = ( /obj/structure/fireplace, /turf/open/floor/iron/textured_edge, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Q" = ( /obj/structure/table/wood, /obj/item/camera{ @@ -233,7 +233,7 @@ pixel_y = 7 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "R" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/door/poddoor/preopen{ @@ -241,33 +241,33 @@ name = "Privacy Shutter" }, /turf/open/floor/plating, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "V" = ( /obj/structure/sign/flag/nanotrasen/directional/north, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /turf/open/floor/iron/textured_edge, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "W" = ( /obj/item/kirbyplants/monkey, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "X" = ( /obj/structure/disposalpipe/segment{ dir = 9 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Y" = ( /obj/machinery/modular_computer/preset/command{ dir = 4 }, /obj/structure/sign/calendar/directional/west, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Z" = ( /obj/machinery/light_switch/directional/south, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) (1,1,1) = {" y diff --git a/_maps/skyrat/automapper/templates/northstar/northstar_supermatter.dmm b/_maps/skyrat/automapper/templates/northstar/northstar_supermatter.dmm index 2c83fd47def914..a02542f376a7cf 100644 --- a/_maps/skyrat/automapper/templates/northstar/northstar_supermatter.dmm +++ b/_maps/skyrat/automapper/templates/northstar/northstar_supermatter.dmm @@ -1,84 +1,170 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE "a" = ( +/turf/template_noop, +/area/template_noop) +"b" = ( /obj/machinery/atmospherics/components/unary/delam_scram/directional/west, /turf/template_noop, /area/template_noop) +"c" = ( +/obj/effect/spawner/structure/window/reinforced/plasma, +/obj/structure/cable, +/turf/open/floor/plating, +/area/station/engineering/supermatter/room) +"e" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/incident_display/delam/directional/north, +/turf/open/floor/iron, +/area/station/engineering/lobby) +"n" = ( +/obj/machinery/button/door/directional/north{ + id = "Secure Storage"; + req_access = list("engineering") + }, +/turf/template_noop, +/area/template_noop) +"o" = ( +/obj/structure/sign/delam_procedure/directional/west, +/turf/template_noop, +/area/template_noop) "q" = ( /obj/effect/turf_decal/stripes/red/box, /turf/template_noop, /area/template_noop) -"s" = ( +"v" = ( /obj/structure/cable, -/obj/machinery/incident_display/delam/directional/north, /turf/open/floor/iron/half{ dir = 1 }, /area/station/engineering/lobby) -"x" = ( -/turf/template_noop, -/area/template_noop) -"I" = ( -/obj/effect/spawner/structure/window/reinforced/plasma, +"y" = ( +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, -/obj/item/folder/biscuit/confidential/delam, -/turf/open/floor/plating, -/area/station/engineering/supermatter/room) -"O" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron, +/area/station/engineering/lobby) +"A" = ( /obj/machinery/button/delam_scram, /turf/closed/wall/r_wall, /area/station/engineering/supermatter/room) -"S" = ( +"C" = ( /obj/effect/turf_decal/stripes/red/box, /turf/open/floor/iron/half{ dir = 1 }, /area/station/engineering/lobby) +"P" = ( +/obj/structure/sign/delam_procedure, +/turf/template_noop, +/area/template_noop) (1,1,1) = {" -s -S -x -x +n +a +a +a +a +a +a "} (2,1,1) = {" -I -O -x -x +a +a +a +a +a +a +a "} (3,1,1) = {" -x -q -x -x +a +a +a +a +a +a +a "} (4,1,1) = {" -x -x -x -x +e +a +P +v +C +a +a "} (5,1,1) = {" -x -x -x -x +y +a +a +c +A +a +a "} (6,1,1) = {" -x -x -x -x +a +a +a +a +q +o +a "} (7,1,1) = {" -x -x -x -x +a +a +a +a +a +a +a "} (8,1,1) = {" -x -x -x a +a +a +a +a +a +a +"} +(9,1,1) = {" +a +a +a +a +a +a +a +"} +(10,1,1) = {" +a +a +a +a +a +a +a +"} +(11,1,1) = {" +a +a +a +a +a +a +b "} diff --git a/_maps/skyrat/automapper/templates/tramstation/tramstation_ntrep_office.dmm b/_maps/skyrat/automapper/templates/tramstation/tramstation_ntrep_office.dmm index 9cc955b7652fcf..bd1e3e8870cc6a 100644 --- a/_maps/skyrat/automapper/templates/tramstation/tramstation_ntrep_office.dmm +++ b/_maps/skyrat/automapper/templates/tramstation/tramstation_ntrep_office.dmm @@ -1,13 +1,13 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE "a" = ( /turf/closed/wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "b" = ( /obj/machinery/modular_computer/preset/command{ dir = 1 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "c" = ( /obj/structure/table/wood, /obj/item/paper_bin/carbon{ @@ -28,11 +28,11 @@ /obj/machinery/newscaster/directional/south, /obj/item/radio/intercom/directional/west, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "e" = ( /obj/structure/closet/secure_closet/nanotrasen_consultant/station, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "f" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/door/poddoor/preopen{ @@ -41,21 +41,21 @@ }, /obj/structure/cable, /turf/open/floor/plating, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "g" = ( /obj/effect/turf_decal/siding/wood{ dir = 4 }, /obj/machinery/firealarm/directional/north, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "h" = ( /obj/effect/turf_decal/siding/wood, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "i" = ( /obj/structure/cable, /obj/machinery/power/apc/auto_name/directional/north, @@ -64,20 +64,20 @@ dir = 8 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "j" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "k" = ( /obj/effect/turf_decal/siding/wood{ dir = 8 }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "l" = ( /obj/structure/cable, /obj/structure/chair/comfy/black{ @@ -87,12 +87,12 @@ dir = 1 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "m" = ( /obj/effect/turf_decal/siding/wood, /obj/structure/sign/flag/nanotrasen/directional/north, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "n" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -101,7 +101,7 @@ dir = 4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "o" = ( /obj/structure/cable, /obj/structure/table/wood, @@ -109,16 +109,16 @@ dir = 8 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "p" = ( /obj/structure/filingcabinet/employment, /obj/effect/turf_decal/siding/wood, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "q" = ( /obj/structure/table/wood, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "r" = ( /obj/structure/cable, /obj/machinery/door/airlock/corporate{ @@ -128,10 +128,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/door/firedoor, /turf/open/floor/iron/dark/textured_large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "s" = ( /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "t" = ( /obj/structure/table/wood, /obj/item/stamp/centcom{ @@ -139,23 +139,23 @@ pixel_x = -7 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "u" = ( /obj/machinery/button/door/directional/west{ id = "nt_rep_priv"; name = "Privacy Shutters Control" }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "v" = ( /obj/item/kirbyplants/random, /obj/machinery/airalarm/directional/north, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "w" = ( /obj/item/radio/intercom/directional/east, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "x" = ( /obj/effect/turf_decal/siding/wood/corner{ dir = 4 @@ -165,12 +165,12 @@ }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "y" = ( /obj/effect/turf_decal/siding/wood, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "A" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -179,10 +179,10 @@ dir = 8 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "B" = ( /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "C" = ( /obj/structure/table/wood, /obj/item/camera{ @@ -198,7 +198,7 @@ pixel_y = 7 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "E" = ( /obj/structure/table/wood, /obj/machinery/fax{ @@ -206,13 +206,13 @@ name = "Nanotrasen Consultant's Fax Machine" }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "F" = ( /obj/item/kirbyplants/random, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/light_switch/directional/south, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "G" = ( /obj/effect/turf_decal/siding/wood{ dir = 4 @@ -222,27 +222,27 @@ }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "H" = ( /obj/machinery/light/warm/directional/west, /obj/structure/sign/calendar/directional/west, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "J" = ( /obj/machinery/status_display/evac/directional/north, /obj/machinery/light/warm/directional/north, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "K" = ( /obj/machinery/photocopier, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "M" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "N" = ( /obj/effect/turf_decal/siding/wood{ dir = 4 @@ -252,12 +252,12 @@ }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "O" = ( /obj/structure/chair/office, /obj/effect/landmark/start/nanotrasen_consultant, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Q" = ( /obj/structure/cable, /obj/effect/turf_decal/siding/wood{ @@ -266,18 +266,18 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "T" = ( /obj/structure/sign/clock/directional/east, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "U" = ( /obj/machinery/status_display/ai/directional/east, /obj/structure/chair/comfy/black{ dir = 8 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "V" = ( /obj/structure/filingcabinet/chestdrawer, /obj/effect/turf_decal/siding/wood{ @@ -286,18 +286,18 @@ /obj/machinery/light/warm/directional/east, /obj/structure/extinguisher_cabinet/directional/east, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "W" = ( /obj/structure/chair/comfy/black, /obj/machinery/newscaster/directional/north, /obj/machinery/light/warm/directional/north, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "Z" = ( /obj/machinery/holopad, /obj/effect/turf_decal/bot, /turf/open/floor/iron/dark/textured_large, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) (1,1,1) = {" a diff --git a/_maps/skyrat/automapper/templates/tramstation/tramstation_supermatter.dmm b/_maps/skyrat/automapper/templates/tramstation/tramstation_supermatter.dmm index a8b22dcfaa5cc3..ca7e23d65dfa69 100644 --- a/_maps/skyrat/automapper/templates/tramstation/tramstation_supermatter.dmm +++ b/_maps/skyrat/automapper/templates/tramstation/tramstation_supermatter.dmm @@ -3,9 +3,10 @@ /turf/template_noop, /area/template_noop) "k" = ( -/obj/item/folder/biscuit/confidential/delam, -/turf/template_noop, -/area/template_noop) +/obj/effect/turf_decal/stripes/red/box, +/obj/structure/sign/delam_procedure, +/turf/closed/wall/r_wall, +/area/station/engineering/supermatter/room) "l" = ( /obj/machinery/power/apc/auto_name/directional/east, /obj/structure/cable, diff --git a/_maps/skyrat/lazy_templates/reebe.dmm b/_maps/skyrat/lazy_templates/reebe.dmm index 05c0f545f8bae7..852d14d41c5a7a 100644 --- a/_maps/skyrat/lazy_templates/reebe.dmm +++ b/_maps/skyrat/lazy_templates/reebe.dmm @@ -64,6 +64,10 @@ /obj/structure/fluff/clockwork/blind_eye, /turf/open/floor/bronze, /area/ruin/powered/reebe) +"hU" = ( +/obj/structure/fluff/clockwork/alloy_shards, +/turf/open/floor/bronze/flat, +/area/ruin/powered/reebe) "iJ" = ( /turf/open/floor/bronze, /area/ruin/powered/reebe) @@ -97,6 +101,10 @@ }, /turf/open/floor/bronze/filled, /area/ruin/powered/reebe) +"mj" = ( +/obj/structure/destructible/clockwork/gear_base/powered/prosperity_prism, +/turf/open/floor/bronze/flat, +/area/ruin/powered/reebe) "mx" = ( /obj/effect/rune/convert, /turf/open/floor/bronze/flat, @@ -179,19 +187,25 @@ "vA" = ( /obj/structure/table/bronze, /obj/item/gun/ballistic/rifle/lionhunter/clockwork, -/obj/item/ammo_box/strilka310/lionhunter/clock{ +/obj/item/ammo_box/a762/lionhunter/clock{ pixel_x = 12; pixel_y = 9 }, -/obj/item/ammo_box/strilka310/lionhunter/clock{ +/obj/item/ammo_box/a762/lionhunter/clock{ pixel_x = -12; pixel_y = 9 }, -/obj/item/ammo_box/strilka310/lionhunter/clock{ +/obj/item/ammo_box/a762/lionhunter/clock{ pixel_y = 9 }, /turf/open/floor/bronze/flat, /area/ruin/powered/reebe) +"vV" = ( +/obj/effect/rune/teleport{ + cultist_name = "Reebe" + }, +/turf/open/floor/bronze/flat, +/area/ruin/powered/reebe) "wu" = ( /obj/structure/fluff/clockwork/alloy_shards/small{ pixel_x = -4; @@ -214,8 +228,8 @@ /turf/open/floor/bronze/flat, /area/ruin/powered/reebe) "xm" = ( -/obj/structure/destructible/clockwork/gear_base/powered/interdiction_lens/free, /obj/effect/decal/cleanable/dirt, +/obj/structure/destructible/clockwork/gear_base/powered/interdiction_lens, /turf/open/floor/bronze/filled, /area/ruin/powered/reebe) "yd" = ( @@ -248,6 +262,10 @@ }, /turf/open/floor/bronze, /area/ruin/powered/reebe) +"Cj" = ( +/obj/structure/door_assembly/door_assembly_bronze/clock, +/turf/open/floor/bronze/flat, +/area/ruin/powered/reebe) "FD" = ( /obj/effect/portal/permanent/one_way/reebe/leaving, /turf/open/floor/bronze/filled, @@ -256,6 +274,10 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/bronze/flat, /area/ruin/powered/reebe) +"Go" = ( +/obj/structure/table/bronze, +/turf/open/floor/bronze, +/area/ruin/powered/reebe) "HU" = ( /obj/effect/decal/cleanable/blood/footprints{ dir = 4 @@ -299,6 +321,14 @@ /obj/structure/fluff/clockwork/blind_eye, /turf/open/floor/bronze, /area/ruin/powered/reebe) +"Nh" = ( +/obj/item/ectoplasm, +/turf/open/indestructible/reebe_void, +/area/ruin/powered/reebe/space) +"Nw" = ( +/obj/structure/door_assembly/door_assembly_bronze/clock, +/turf/open/floor/bronze, +/area/ruin/powered/reebe) "Os" = ( /obj/item/stack/sheet/mineral/wood, /turf/open/floor/bronze/filled, @@ -326,11 +356,19 @@ /turf/open/floor/bronze/filled, /area/ruin/powered/reebe) "Pv" = ( -/obj/machinery/door/airlock/bronze/clock/glass, +/obj/machinery/door/airlock/bronze, /turf/open/floor/bronze, /area/ruin/powered/reebe) "PD" = ( -/obj/structure/girder/bronze, +/obj/structure/destructible/clockwork/gear_base/powered/tinkerers_cache, +/turf/open/floor/bronze/flat, +/area/ruin/powered/reebe) +"PZ" = ( +/obj/structure/destructible/clockwork/gear_base/technologists_lectern, +/turf/open/floor/bronze/flat, +/area/ruin/powered/reebe) +"QR" = ( +/obj/machinery/door/airlock/bronze, /turf/open/floor/bronze/flat, /area/ruin/powered/reebe) "QX" = ( @@ -373,6 +411,24 @@ /obj/effect/decal/cleanable/blood/splatter, /turf/open/floor/bronze, /area/ruin/powered/reebe) +"UF" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/table/bronze, +/obj/item/stack/sheet/bronze/thirty{ + pixel_y = 10; + pixel_x = 10 + }, +/obj/item/stack/sheet/bronze/thirty{ + pixel_y = 5; + pixel_x = 5 + }, +/obj/item/stack/sheet/bronze/thirty, +/obj/item/clockwork/replica_fabricator{ + pixel_x = -10; + pixel_y = 10 + }, +/turf/open/floor/bronze, +/area/ruin/powered/reebe) "UI" = ( /obj/structure/table/bronze, /obj/item/clockwork/weapon/brass_spear{ @@ -387,8 +443,8 @@ /turf/open/floor/bronze/filled, /area/ruin/powered/reebe) "UJ" = ( -/obj/effect/rune/teleport, -/turf/open/floor/bronze, +/obj/item/ectoplasm, +/turf/open/floor/bronze/flat, /area/ruin/powered/reebe) "Vv" = ( /obj/structure/fluff/clockwork/clockgolem_remains, @@ -406,6 +462,10 @@ /obj/structure/fluff/clockwork/blind_eye, /turf/open/floor/bronze/flat, /area/ruin/powered/reebe) +"Ym" = ( +/obj/effect/decal/cleanable/blood/splatter/over_window, +/turf/closed/wall/mineral/bronze, +/area/ruin/powered/reebe) (1,1,1) = {" ok @@ -1106,7 +1166,7 @@ ve My yd qS -iJ +Nw xd Pi xd @@ -1219,7 +1279,7 @@ qS iJ xd pM -xd +UJ Pi ve ve @@ -1265,7 +1325,7 @@ qS qS iJ xd -UJ +iJ qS qS ve @@ -1410,7 +1470,7 @@ QX QX ve yL -xd +Cj xd iJ ve @@ -1462,7 +1522,7 @@ QX QX ve Pi -xd +UJ iJ ve ve @@ -1523,9 +1583,9 @@ QX QX qS qS -ve +qS Pv -ve +qS qS qS QX @@ -1578,7 +1638,7 @@ PD Bm Pi Pi -PD +PZ qS qS ve @@ -1587,7 +1647,7 @@ ve qS aj xd -iJ +Nw aj qS qS @@ -1625,13 +1685,13 @@ Bm Pi Pi iJ -Iw +qS Pi -xd +hU iJ xd Pi -ve +qS iJ Pi Pi @@ -1729,13 +1789,13 @@ kZ yd Pi iJ -ve +qS Pi xd iJ -xd +hU Pi -Iw +Ym oh Pi Pi @@ -1782,7 +1842,7 @@ ve ve qS qS -PD +mj Pi Pi Pi @@ -1835,9 +1895,9 @@ QX QX qS qS -ve +qS Pv -ve +qS qS qS QX @@ -1930,7 +1990,7 @@ QX QX ve iJ -xd +vV FM iJ ve @@ -2091,7 +2151,7 @@ et xd xd iJ -UJ +iJ ve qS qS @@ -2197,13 +2257,13 @@ iJ Pi FM xd -xd +QR xd xd Pd xd xd -xd +QR xd xd Pi @@ -2407,9 +2467,9 @@ QX QX QX qS -yL +UF Pi -iJ +Go qS QX QX @@ -2865,7 +2925,7 @@ mL mL mL mL -mL +Nh mL mL mL diff --git a/_maps/templates/lazy_templates/abductor_ships.dmm b/_maps/templates/lazy_templates/abductor_ships.dmm index 0e33b8d39224af..4c7d2e172ff260 100644 --- a/_maps/templates/lazy_templates/abductor_ships.dmm +++ b/_maps/templates/lazy_templates/abductor_ships.dmm @@ -1,4 +1,10 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/turf/open/water, +/area/awaymission/beach) +"ab" = ( +/turf/open/lava, +/area/awaymission/caves) "bX" = ( /turf/closed/indestructible/abductor{ icon_state = "alien11" @@ -592,3 +598,515 @@ bX Zf Xy "} + +(1,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(2,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(3,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(4,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(5,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(6,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(7,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(8,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(9,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(10,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(11,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(12,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(13,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(14,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(15,1,2) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} + +(1,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(2,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(3,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(4,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(5,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(6,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(7,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(8,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(9,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(10,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(11,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(12,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(13,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(14,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} +(15,1,3) = {" +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +"} diff --git a/_maps/templates/heretic_sacrifice_template.dmm b/_maps/templates/lazy_templates/heretic_sacrifice.dmm similarity index 82% rename from _maps/templates/heretic_sacrifice_template.dmm rename to _maps/templates/lazy_templates/heretic_sacrifice.dmm index d0277a1e71204f..cbabb4c6485822 100644 --- a/_maps/templates/heretic_sacrifice_template.dmm +++ b/_maps/templates/lazy_templates/heretic_sacrifice.dmm @@ -40,6 +40,14 @@ /obj/structure/cable, /turf/open/floor/plating, /area/centcom/heretic_sacrifice/rust) +"fL" = ( +/obj/effect/decal/cleanable/blood/old, +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/indestructible/plating, +/area/centcom/heretic_sacrifice/knock) +"fO" = ( +/turf/open/indestructible, +/area/space) "gJ" = ( /obj/effect/decal/remains/human, /turf/open/misc/dirt/jungle/dark{ @@ -47,6 +55,11 @@ slowdown = 0 }, /area/centcom/heretic_sacrifice/ash) +"hE" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/storage/toolbox/mechanical/old, +/turf/open/indestructible/plating, +/area/centcom/heretic_sacrifice/knock) "hZ" = ( /obj/effect/decal/cleanable/blood/old, /turf/open/indestructible/necropolis/air, @@ -56,6 +69,9 @@ /obj/structure/cable, /turf/open/floor/plating/rust, /area/centcom/heretic_sacrifice/rust) +"jt" = ( +/turf/closed/indestructible/reinforced, +/area/centcom/heretic_sacrifice/knock) "jB" = ( /obj/machinery/light/very_dim/directional/south, /turf/open/misc/asteroid, @@ -85,6 +101,11 @@ }, /turf/open/floor/plating, /area/centcom/heretic_sacrifice/rust) +"mW" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/spear, +/turf/open/indestructible/plating, +/area/centcom/heretic_sacrifice/knock) "mZ" = ( /obj/effect/decal/fakelattice{ density = 0 @@ -150,6 +171,12 @@ /obj/effect/decal/remains/human, /turf/open/misc/asteroid, /area/centcom/heretic_sacrifice/void) +"qo" = ( +/obj/effect/decal/cleanable/blood/old, +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/storage/toolbox/mechanical/old, +/turf/open/indestructible/plating, +/area/centcom/heretic_sacrifice/knock) "qu" = ( /obj/effect/turf_decal/weather/dirt, /turf/open/misc/ashplanet/wateryrock{ @@ -202,6 +229,12 @@ }, /turf/open/floor/plating/rust, /area/centcom/heretic_sacrifice/rust) +"uM" = ( +/obj/effect/decal/cleanable/blood/old, +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/clothing/under/color/grey/ancient, +/turf/open/indestructible/plating, +/area/centcom/heretic_sacrifice/knock) "uT" = ( /obj/structure/cable, /turf/open/floor/plating/rust, @@ -225,6 +258,9 @@ slowdown = 0 }, /area/centcom/heretic_sacrifice/ash) +"wo" = ( +/turf/closed/indestructible/grille, +/area/centcom/heretic_sacrifice/knock) "wt" = ( /obj/structure/stone_tile/block{ dir = 1 @@ -240,6 +276,16 @@ slowdown = 0 }, /area/centcom/heretic_sacrifice/ash) +"wP" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/flashlight/flare{ + fuel = 1e+031; + randomize_fuel = 0; + icon_state = "flare-on"; + on = 1 + }, +/turf/open/indestructible/plating, +/area/centcom/heretic_sacrifice/knock) "wS" = ( /turf/open/misc/dirt/jungle/dark{ planetary_atmos = 0; @@ -252,6 +298,9 @@ name = "void glass floor" }, /area/centcom/heretic_sacrifice/void) +"xc" = ( +/turf/open/indestructible/white, +/area/space) "yC" = ( /obj/effect/turf_decal/trimline/brown/line{ dir = 1 @@ -273,6 +322,11 @@ }, /turf/open/floor/plating/rust, /area/centcom/heretic_sacrifice/rust) +"Aw" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/clothing/mask/gas, +/turf/open/indestructible/plating, +/area/centcom/heretic_sacrifice/knock) "AH" = ( /obj/effect/turf_decal/trimline/brown/corner, /turf/open/floor/plating/rust, @@ -287,6 +341,15 @@ "AO" = ( /turf/open/floor/fakespace, /area/centcom/heretic_sacrifice/void) +"AW" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/clothing/mask/gas/tiki_mask/yalp_elor, +/turf/open/indestructible/plating, +/area/centcom/heretic_sacrifice/knock) +"AY" = ( +/obj/effect/decal/cleanable/dirt/dust, +/turf/open/indestructible/plating, +/area/centcom/heretic_sacrifice/knock) "Bv" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/trimline/brown/line, @@ -340,6 +403,9 @@ slowdown = 0 }, /area/centcom/heretic_sacrifice/ash) +"En" = ( +/turf/closed/indestructible/fakedoor/maintenance, +/area/centcom/heretic_sacrifice/knock) "ER" = ( /turf/open/misc/ironsand, /area/centcom/heretic_sacrifice/rust) @@ -467,6 +533,17 @@ /obj/machinery/light/very_dim/directional/west, /turf/open/floor/fakespace, /area/centcom/heretic_sacrifice/void) +"MZ" = ( +/obj/effect/decal/cleanable/blood/old, +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/flashlight/flare{ + fuel = 1e+031; + randomize_fuel = 0; + icon_state = "flare-on"; + on = 1 + }, +/turf/open/indestructible/plating, +/area/centcom/heretic_sacrifice/knock) "Nh" = ( /obj/effect/turf_decal/trimline/brown/line{ dir = 1 @@ -508,6 +585,11 @@ slowdown = 0 }, /area/centcom/heretic_sacrifice/ash) +"OW" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/item/clothing/under/color/grey/ancient, +/turf/open/indestructible/plating, +/area/centcom/heretic_sacrifice/knock) "Pl" = ( /obj/effect/turf_decal/weather/dirt{ dir = 6 @@ -627,6 +709,12 @@ /obj/effect/decal/cleanable/dirt, /turf/open/indestructible/necropolis/air, /area/centcom/heretic_sacrifice/flesh) +"Zw" = ( +/obj/effect/decal/cleanable/blood/old, +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/landmark/heretic/knock, +/turf/open/indestructible/plating, +/area/centcom/heretic_sacrifice/knock) "ZA" = ( /turf/closed/indestructible/riveted/boss, /area/centcom/heretic_sacrifice/ash) @@ -661,9 +749,37 @@ ab ab ab ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab "} (2,1,1) = {" ab +ab +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd Fd Fd Fd @@ -695,6 +811,20 @@ ab "} (3,1,1) = {" ab +ab +Fd +jt +jt +wo +wo +jt +En +En +jt +wo +wo +jt +jt Fd ZA ZA @@ -726,6 +856,20 @@ ab "} (4,1,1) = {" ab +ab +Fd +jt +AY +AY +AY +AY +AY +AY +AY +AY +fL +AY +jt Fd ZA Pl @@ -757,6 +901,20 @@ ab "} (5,1,1) = {" ab +ab +Fd +wo +AY +fL +uM +AY +AY +qo +fL +AY +mW +MZ +wo Fd ZA wS @@ -788,6 +946,20 @@ ab "} (6,1,1) = {" ab +ab +Fd +wo +AY +Aw +fL +AY +wP +fL +fL +AY +qo +AY +wo Fd ZA OG @@ -819,6 +991,20 @@ ab "} (7,1,1) = {" ab +ab +Fd +jt +AY +fL +fL +AY +AY +fL +AY +AY +fL +Aw +jt Fd ZA Bw @@ -850,6 +1036,20 @@ ab "} (8,1,1) = {" ab +ab +Fd +En +AY +MZ +fL +AY +Zw +OW +AY +AY +AY +fL +En Fd ZA Bw @@ -881,6 +1081,20 @@ ab "} (9,1,1) = {" ab +ab +Fd +En +fL +AY +AY +AY +fL +fL +AY +AY +fL +AY +En Fd ZA Bw @@ -912,6 +1126,20 @@ ab "} (10,1,1) = {" ab +ab +Fd +jt +AY +AY +fL +AY +fL +AY +fL +AY +AW +fL +jt Fd ZA Bw @@ -943,6 +1171,20 @@ ab "} (11,1,1) = {" ab +ab +Fd +wo +fL +AY +hE +MZ +AY +AY +hE +fL +wP +AY +wo Fd ZA Pl @@ -974,6 +1216,20 @@ ab "} (12,1,1) = {" ab +ab +Fd +wo +AY +fL +AY +AY +AY +fL +AY +OW +fL +fL +wo Fd ZA wS @@ -1005,6 +1261,20 @@ ab "} (13,1,1) = {" ab +ab +Fd +jt +AY +AY +fL +fL +AY +AY +AY +AY +AY +AY +jt Fd ZA OG @@ -1036,6 +1306,20 @@ ab "} (14,1,1) = {" ab +ab +Fd +jt +jt +wo +wo +jt +En +En +jt +wo +wo +jt +jt Fd ZA ZA @@ -1067,6 +1351,20 @@ ab "} (15,1,1) = {" ab +ab +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd Fd Fd Fd @@ -1098,6 +1396,20 @@ ab "} (16,1,1) = {" ab +ab +Fd +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO Fd WD WD @@ -1129,6 +1441,20 @@ ab "} (17,1,1) = {" ab +ab +Fd +fO +fO +fO +fO +fO +fO +xc +xc +xc +xc +xc +fO Fd WD dZ @@ -1160,6 +1486,20 @@ ab "} (18,1,1) = {" ab +ab +Fd +fO +fO +fO +fO +fO +fO +fO +fO +xc +fO +fO +fO Fd WD dZ @@ -1191,6 +1531,20 @@ ab "} (19,1,1) = {" ab +ab +Fd +fO +fO +fO +fO +fO +fO +xc +xc +xc +xc +xc +fO Fd WD ER @@ -1222,6 +1576,20 @@ ab "} (20,1,1) = {" ab +ab +Fd +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO Fd WD Se @@ -1253,6 +1621,20 @@ ab "} (21,1,1) = {" ab +ab +Fd +fO +fO +fO +fO +fO +fO +xc +fO +xc +xc +xc +fO Fd WD Xr @@ -1284,6 +1666,20 @@ ab "} (22,1,1) = {" ab +ab +Fd +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO Fd WD Se @@ -1315,6 +1711,20 @@ ab "} (23,1,1) = {" ab +ab +Fd +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO Fd WD Xr @@ -1346,6 +1756,20 @@ ab "} (24,1,1) = {" ab +ab +Fd +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO Fd WD ps @@ -1377,6 +1801,20 @@ ab "} (25,1,1) = {" ab +ab +Fd +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO Fd WD Je @@ -1408,6 +1846,20 @@ ab "} (26,1,1) = {" ab +ab +Fd +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO Fd WD ER @@ -1439,6 +1891,20 @@ ab "} (27,1,1) = {" ab +ab +Fd +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO +fO Fd WD WD @@ -1470,6 +1936,20 @@ ab "} (28,1,1) = {" ab +ab +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd Fd Fd Fd @@ -1529,4 +2009,18 @@ ab ab ab ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab +ab "} diff --git a/_maps/templates/lazy_templates/ninja_den.dmm b/_maps/templates/lazy_templates/ninja_den.dmm index a364024c345e56..40efeb77e7f207 100644 --- a/_maps/templates/lazy_templates/ninja_den.dmm +++ b/_maps/templates/lazy_templates/ninja_den.dmm @@ -1,22 +1,52 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"al" = ( +"af" = ( /obj/effect/turf_decal/siding/wood{ - dir = 8 + dir = 4 + }, +/obj/structure/chair/sofa/corp/left{ + dir = 4; + pixel_x = -4 }, +/obj/machinery/light/small/directional/north, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) -"aq" = ( -/obj/structure/table/wood, -/obj/item/toy/plush/goatplushie, -/obj/machinery/light/small/directional/north, +"al" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) -"aw" = ( -/obj/item/kirbyplants/organic/plant10, -/obj/machinery/light/small/directional/north, -/obj/structure/sign/painting/library{ - pixel_y = 32 +"au" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/structure/rack, +/obj/item/toy/gun{ + pixel_y = 2 + }, +/obj/item/toy/balloon/syndicate{ + pixel_x = 8; + pixel_y = 2 + }, +/obj/item/toy/balloon/syndicate{ + pixel_x = 8; + pixel_y = 2 + }, +/obj/item/toy/balloon/syndicate{ + pixel_x = 8; + pixel_y = 2 + }, +/obj/item/clothing/under/misc/syndicate_souvenir{ + pixel_y = -5 + }, +/obj/item/clothing/under/misc/syndicate_souvenir{ + pixel_y = -5 + }, +/obj/item/clothing/under/misc/syndicate_souvenir{ + pixel_y = -5 }, +/obj/effect/turf_decal/tile/dark/fourcorners, +/obj/machinery/light/small/directional/east, /turf/open/floor/iron/sepia, /area/centcom/central_command_areas/holding) "ay" = ( @@ -36,6 +66,12 @@ }, /turf/open/floor/vault/rock, /area/centcom/central_command_areas/holding) +"be" = ( +/obj/structure/chair/comfy/black{ + dir = 4 + }, +/turf/open/floor/carpet/black, +/area/centcom/central_command_areas/holding) "bl" = ( /turf/open/floor/bamboo/tatami/purple, /area/centcom/central_command_areas/holding) @@ -43,6 +79,15 @@ /obj/machinery/photocopier, /turf/open/floor/catwalk_floor, /area/centcom/central_command_areas/holding) +"bO" = ( +/obj/structure/flora/rock/pile/jungle/style_random{ + pixel_x = -12; + pixel_y = 15 + }, +/turf/open/misc/ashplanet/wateryrock{ + initial_gas_mix = "o2=22;n2=82;TEMP=293.15" + }, +/area/centcom/central_command_areas/holding) "bP" = ( /obj/structure/table/reinforced/plastitaniumglass, /obj/item/paper_bin, @@ -83,12 +128,9 @@ }, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) -"cv" = ( -/obj/effect/turf_decal/siding/wood, -/obj/structure/chair/sofa/corp/left{ - pixel_y = 6 - }, -/obj/machinery/light/small/directional/east, +"cK" = ( +/obj/structure/table/wood, +/obj/item/flashlight/lamp/green, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) "cQ" = ( @@ -113,25 +155,6 @@ }, /turf/open/floor/iron/sepia, /area/centcom/central_command_areas/holding) -"cV" = ( -/obj/structure/closet/secure_closet/freezer/fridge/open, -/obj/item/food/grown/chili, -/obj/item/food/grown/chili, -/obj/item/food/grown/chili, -/obj/item/food/grown/chili, -/obj/item/food/grown/chili, -/obj/item/reagent_containers/condiment/milk, -/obj/item/reagent_containers/condiment/milk, -/obj/item/reagent_containers/condiment/soymilk, -/obj/item/reagent_containers/condiment/soymilk, -/obj/item/storage/fancy/egg_box, -/obj/item/food/grown/citrus/lime, -/obj/item/food/grown/citrus/orange, -/obj/item/food/grown/citrus/lemon, -/obj/item/food/grown/watermelon, -/obj/machinery/light/small/directional/west, -/turf/open/floor/carpet/black, -/area/centcom/central_command_areas/holding) "cW" = ( /obj/effect/turf_decal/siding/wood{ dir = 8 @@ -151,6 +174,11 @@ "dg" = ( /turf/closed/wall/mineral/wood, /area/centcom/central_command_areas/holding) +"dv" = ( +/obj/item/kirbyplants/organic/plant10, +/obj/machinery/light/small/directional/south, +/turf/open/floor/iron/sepia, +/area/centcom/central_command_areas/holding) "dy" = ( /obj/machinery/light/small/directional/west, /turf/open/floor/wood/tile, @@ -185,46 +213,11 @@ /obj/effect/turf_decal/siding/wood, /turf/open/floor/wood/large, /area/centcom/central_command_areas/holding) -"eC" = ( -/obj/structure/table/wood, -/obj/machinery/microwave{ - pixel_y = 6 - }, +"eo" = ( +/obj/item/kirbyplants/organic/plant10, +/obj/machinery/duct, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) -"eN" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/structure/rack, -/obj/item/toy/gun{ - pixel_y = 2 - }, -/obj/item/toy/balloon/syndicate{ - pixel_x = 8; - pixel_y = 2 - }, -/obj/item/toy/balloon/syndicate{ - pixel_x = 8; - pixel_y = 2 - }, -/obj/item/toy/balloon/syndicate{ - pixel_x = 8; - pixel_y = 2 - }, -/obj/item/clothing/under/misc/syndicate_souvenir{ - pixel_y = -5 - }, -/obj/item/clothing/under/misc/syndicate_souvenir{ - pixel_y = -5 - }, -/obj/item/clothing/under/misc/syndicate_souvenir{ - pixel_y = -5 - }, -/obj/effect/turf_decal/tile/dark/fourcorners, -/obj/machinery/light/small/directional/east, -/turf/open/floor/iron/sepia, -/area/centcom/central_command_areas/holding) "fu" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -234,21 +227,6 @@ }, /turf/open/floor/eighties/red, /area/centcom/central_command_areas/holding) -"fx" = ( -/obj/structure/bookcase/random/fiction, -/obj/machinery/light/small/directional/east, -/turf/open/floor/carpet/black, -/area/centcom/central_command_areas/holding) -"fG" = ( -/obj/item/kirbyplants/organic/plant10, -/turf/open/floor/wood/parquet, -/area/centcom/central_command_areas/holding) -"fV" = ( -/obj/effect/turf_decal/siding/wood, -/obj/item/kirbyplants/organic/plant10, -/obj/effect/turf_decal/tile/dark/opposingcorners, -/turf/open/floor/iron/sepia, -/area/centcom/central_command_areas/holding) "ga" = ( /obj/structure/table/reinforced/plastitaniumglass, /obj/item/toy/mecha/phazon, @@ -290,6 +268,12 @@ }, /turf/open/floor/iron/sepia, /area/centcom/central_command_areas/holding) +"ha" = ( +/obj/machinery/light/directional/north, +/turf/open/floor/bamboo/tatami/purple{ + dir = 8 + }, +/area/centcom/central_command_areas/holding) "hi" = ( /obj/structure/bed, /obj/item/bedsheet/syndie, @@ -297,17 +281,14 @@ dir = 4 }, /area/centcom/central_command_areas/holding) -"hl" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/item/kirbyplants/organic/plant10, -/turf/open/floor/carpet/black, -/area/centcom/central_command_areas/holding) "hm" = ( /obj/machinery/vending/clothing, /turf/open/floor/wood/parquet, /area/centcom/central_command_areas/holding) +"hn" = ( +/obj/machinery/light/directional/north, +/turf/open/floor/wood/large, +/area/centcom/central_command_areas/holding) "ho" = ( /obj/structure/chair/pew/left{ dir = 8 @@ -318,11 +299,12 @@ /obj/machinery/duct, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) -"hr" = ( -/obj/machinery/light/directional/north, -/turf/open/floor/bamboo/tatami/purple{ - dir = 8 +"hs" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 1 }, +/obj/item/kirbyplants/organic/plant10, +/turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) "ht" = ( /obj/effect/turf_decal/siding/wood{ @@ -335,16 +317,17 @@ /obj/machinery/computer/libraryconsole/bookmanagement, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) +"hw" = ( +/obj/item/kirbyplants/organic/plant10, +/obj/structure/sign/painting/library{ + pixel_y = 32 + }, +/turf/open/floor/carpet/black, +/area/centcom/central_command_areas/holding) "hH" = ( /obj/item/flashlight/lantern, /turf/open/misc/sandy_dirt, /area/centcom/central_command_areas/holding) -"hJ" = ( -/obj/structure/chair/comfy/black{ - dir = 4 - }, -/turf/open/floor/carpet/black, -/area/centcom/central_command_areas/holding) "hO" = ( /turf/open/floor/wood/tile, /area/centcom/central_command_areas/holding) @@ -378,6 +361,10 @@ /obj/machinery/gibber, /turf/open/floor/catwalk_floor, /area/centcom/central_command_areas/holding) +"iW" = ( +/obj/machinery/light/small/directional/west, +/turf/open/floor/iron/stairs/medium, +/area/centcom/central_command_areas/holding) "jb" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -440,12 +427,6 @@ /obj/item/food/meat/slab/synthmeat, /turf/open/floor/catwalk_floor, /area/centcom/central_command_areas/holding) -"jK" = ( -/obj/machinery/light/small/directional/north, -/turf/open/floor/bamboo/tatami/black{ - dir = 1 - }, -/area/centcom/central_command_areas/holding) "jR" = ( /obj/structure/chair/wood{ dir = 4 @@ -532,31 +513,34 @@ "lP" = ( /turf/open/floor/bamboo/tatami/black, /area/centcom/central_command_areas/holding) +"lV" = ( +/obj/structure/table/wood/fancy/royalblack, +/obj/item/book/bible, +/obj/machinery/light/directional/north, +/turf/open/floor/wood/large, +/area/centcom/central_command_areas/holding) "mj" = ( /obj/effect/turf_decal/siding/wood, /turf/open/floor/iron/sepia, /area/centcom/central_command_areas/holding) +"mr" = ( +/obj/item/kirbyplants/organic/plant10, +/turf/open/floor/wood/parquet, +/area/centcom/central_command_areas/holding) "mw" = ( /turf/open/floor/wood/large, /area/centcom/central_command_areas/holding) -"mN" = ( -/obj/structure/chair/comfy/black{ - dir = 8 - }, -/turf/open/floor/carpet/black, -/area/centcom/central_command_areas/holding) -"nm" = ( -/obj/machinery/light/directional/south, +"ni" = ( /obj/structure/rack, -/obj/item/nullrod/vibro{ +/obj/item/nullrod/claymore/saber/red{ damtype = "stamina"; - force = 30; - pixel_x = 5; - pixel_y = -2 + force = 30 }, -/obj/item/nullrod/claymore/glowing{ +/obj/item/nullrod/claymore/katana{ damtype = "stamina"; - force = 30 + force = 30; + pixel_x = -8; + pixel_y = -1 }, /turf/open/floor/wood/parquet, /area/centcom/central_command_areas/holding) @@ -571,6 +555,41 @@ /obj/structure/sink/kitchen/directional/west, /turf/open/floor/iron/cafeteria, /area/centcom/central_command_areas/holding) +"nR" = ( +/obj/machinery/light/small/directional/east, +/turf/open/floor/iron/stairs/medium, +/area/centcom/central_command_areas/holding) +"nW" = ( +/obj/machinery/light/warm/directional/west, +/turf/open/water{ + initial_gas_mix = "o2=22;n2=82;TEMP=293.15" + }, +/area/centcom/central_command_areas/holding) +"od" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/structure/table/reinforced/plastitaniumglass, +/obj/item/storage/basket, +/obj/effect/turf_decal/tile/dark/fourcorners, +/obj/machinery/light/small/directional/west, +/turf/open/floor/iron/sepia, +/area/centcom/central_command_areas/holding) +"oh" = ( +/obj/machinery/light/directional/south, +/obj/structure/rack, +/obj/item/nullrod/vibro{ + damtype = "stamina"; + force = 30; + pixel_x = 5; + pixel_y = -2 + }, +/obj/item/nullrod/claymore/glowing{ + damtype = "stamina"; + force = 30 + }, +/turf/open/floor/wood/parquet, +/area/centcom/central_command_areas/holding) "os" = ( /obj/machinery/shower/directional/south, /obj/item/soap/syndie, @@ -600,10 +619,6 @@ /obj/machinery/biogenerator, /turf/open/floor/wood/tile, /area/centcom/central_command_areas/holding) -"oP" = ( -/obj/machinery/light/small/directional/south, -/turf/open/floor/carpet/black, -/area/centcom/central_command_areas/holding) "oT" = ( /obj/effect/turf_decal/siding/wood, /obj/effect/turf_decal/siding/wood{ @@ -649,6 +664,23 @@ }, /turf/open/floor/catwalk_floor, /area/centcom/central_command_areas/holding) +"pB" = ( +/obj/structure/rack, +/obj/item/nullrod/claymore{ + damtype = "stamina"; + force = 30; + pixel_x = 4; + pixel_y = -1 + }, +/obj/item/nullrod/claymore/darkblade{ + damtype = "stamina"; + force = 30; + pixel_x = -3; + pixel_y = 3 + }, +/obj/machinery/light/directional/north, +/turf/open/floor/wood/parquet, +/area/centcom/central_command_areas/holding) "pK" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -674,6 +706,35 @@ initial_gas_mix = "TEMP=2.7" }, /area/centcom/central_command_areas/holding) +"pU" = ( +/obj/structure/closet, +/obj/item/surgery_tray/full, +/obj/machinery/iv_drip, +/obj/item/emergency_bed, +/obj/item/storage/medkit/regular, +/obj/item/reagent_containers/medigel/synthflesh, +/obj/item/reagent_containers/medigel/synthflesh, +/obj/item/reagent_containers/medigel/synthflesh, +/obj/item/organ/internal/heart/cybernetic/tier2, +/obj/item/organ/internal/heart/cybernetic/tier2, +/obj/item/defibrillator, +/turf/open/floor/iron/sepia, +/area/centcom/central_command_areas/holding) +"pX" = ( +/obj/machinery/light/small/directional/north, +/turf/open/floor/bamboo/tatami/black{ + dir = 1 + }, +/area/centcom/central_command_areas/holding) +"qg" = ( +/obj/machinery/light/warm/directional/east, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/effect/turf_decal/siding/wood, +/obj/item/kirbyplants/organic/plant10, +/turf/open/floor/stone, +/area/centcom/central_command_areas/holding) "qi" = ( /obj/machinery/hydroponics/constructable, /turf/open/floor/grass, @@ -733,15 +794,6 @@ }, /turf/open/floor/catwalk_floor, /area/centcom/central_command_areas/holding) -"qW" = ( -/obj/item/kirbyplants/organic/plant10, -/turf/open/floor/bamboo/tatami/purple, -/area/centcom/central_command_areas/holding) -"ri" = ( -/obj/effect/turf_decal/siding/wood, -/obj/machinery/light/small/directional/south, -/turf/open/floor/wood/tile, -/area/centcom/central_command_areas/holding) "rj" = ( /obj/effect/turf_decal/siding/wood{ dir = 8 @@ -754,6 +806,20 @@ }, /turf/open/floor/iron/sepia, /area/centcom/central_command_areas/holding) +"rn" = ( +/obj/structure/table/wood, +/obj/machinery/chem_dispenser/drinks/beer{ + dir = 4; + pixel_x = -8; + pixel_y = 1 + }, +/obj/item/reagent_containers/cup/beaker{ + pixel_x = 7; + pixel_y = -4 + }, +/obj/machinery/light/small/directional/west, +/turf/open/floor/carpet/black, +/area/centcom/central_command_areas/holding) "rz" = ( /obj/structure/flora/bush/flowers_yw/style_random, /obj/structure/flora/bush/flowers_br/style_random, @@ -776,10 +842,6 @@ dir = 8 }, /area/centcom/central_command_areas/holding) -"rV" = ( -/obj/item/kirbyplants/organic/plant10, -/turf/open/floor/carpet/black, -/area/centcom/central_command_areas/holding) "sc" = ( /obj/structure/sink/directional/west, /obj/structure/mirror/directional/east, @@ -840,10 +902,6 @@ }, /turf/open/floor/wood/tile, /area/centcom/central_command_areas/holding) -"uP" = ( -/obj/machinery/light/small/directional/north, -/turf/open/floor/carpet/black, -/area/centcom/central_command_areas/holding) "uQ" = ( /obj/structure/chair/wood{ dir = 8 @@ -852,45 +910,43 @@ dir = 4 }, /area/centcom/central_command_areas/holding) -"uT" = ( -/obj/structure/flora/rock/pile/jungle/style_random{ - pixel_x = -12; - pixel_y = 15 - }, -/turf/open/misc/ashplanet/wateryrock{ - initial_gas_mix = "o2=22;n2=82;TEMP=293.15" - }, -/area/centcom/central_command_areas/holding) "vr" = ( -/obj/machinery/light/warm/directional/west, -/turf/open/water{ - initial_gas_mix = "o2=22;n2=82;TEMP=293.15" +/obj/structure/rack, +/obj/item/nullrod/claymore/saber{ + damtype = "stamina"; + force = 30; + pixel_x = 5; + pixel_y = -3 }, -/area/centcom/central_command_areas/holding) -"vv" = ( -/obj/item/kirbyplants/organic/plant10, -/turf/open/floor/wood/large, +/obj/item/nullrod/claymore/katana{ + damtype = "stamina"; + force = 30 + }, +/turf/open/floor/wood/parquet, /area/centcom/central_command_areas/holding) "vA" = ( /obj/machinery/seed_extractor, /turf/open/floor/wood/tile, /area/centcom/central_command_areas/holding) -"vH" = ( -/obj/item/kirbyplants/organic/plant10, -/obj/machinery/light/small/directional/south, -/turf/open/floor/iron/sepia, -/area/centcom/central_command_areas/holding) "vS" = ( /obj/structure/table/wood, /obj/item/paper_bin, /obj/item/pen/fountain, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) -"wS" = ( -/obj/structure/bookcase/random/reference, -/obj/machinery/light/small/directional/west, +"wc" = ( +/obj/effect/turf_decal/siding/wood, +/obj/structure/chair/sofa/corp/left{ + pixel_y = 6 + }, +/obj/machinery/light/small/directional/east, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) +"wq" = ( +/obj/structure/closet/crate/freezer/blood, +/obj/machinery/light/small/directional/north, +/turf/open/floor/iron/sepia, +/area/centcom/central_command_areas/holding) "wU" = ( /turf/open/floor/wood/parquet, /area/centcom/central_command_areas/holding) @@ -961,37 +1017,38 @@ dir = 4 }, /obj/structure/mineral_door/paperframe{ - name = "Electrical Room" - }, -/turf/open/floor/iron/sepia, -/area/centcom/central_command_areas/holding) -"yo" = ( -/obj/structure/table/wood, -/obj/machinery/chem_dispenser/drinks/beer{ - dir = 4; - pixel_x = -8; - pixel_y = 1 - }, -/obj/item/reagent_containers/cup/beaker{ - pixel_x = 7; - pixel_y = -4 + name = "Electrical Room" }, -/obj/machinery/light/small/directional/west, -/turf/open/floor/carpet/black, +/turf/open/floor/iron/sepia, /area/centcom/central_command_areas/holding) "yz" = ( /obj/structure/chair/stool/directional/west, /turf/open/misc/beach/sand, /area/centcom/central_command_areas/holding) -"ze" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 4 - }, -/obj/structure/chair/sofa/corp/left{ - dir = 4; - pixel_x = -4 +"zc" = ( +/obj/structure/table/wood, +/obj/machinery/microwave{ + pixel_y = 6 }, -/obj/machinery/light/small/directional/north, +/turf/open/floor/carpet/black, +/area/centcom/central_command_areas/holding) +"zh" = ( +/obj/structure/closet/secure_closet/freezer/fridge/open, +/obj/item/food/grown/chili, +/obj/item/food/grown/chili, +/obj/item/food/grown/chili, +/obj/item/food/grown/chili, +/obj/item/food/grown/chili, +/obj/item/reagent_containers/condiment/milk, +/obj/item/reagent_containers/condiment/milk, +/obj/item/reagent_containers/condiment/soymilk, +/obj/item/reagent_containers/condiment/soymilk, +/obj/item/storage/fancy/egg_box, +/obj/item/food/grown/citrus/lime, +/obj/item/food/grown/citrus/orange, +/obj/item/food/grown/citrus/lemon, +/obj/item/food/grown/watermelon, +/obj/machinery/light/small/directional/west, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) "zB" = ( @@ -1014,15 +1071,11 @@ /obj/structure/window/reinforced/fulltile, /turf/open/floor/grass, /area/centcom/central_command_areas/holding) -"zQ" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/structure/table/reinforced/plastitaniumglass, -/obj/item/storage/basket, -/obj/effect/turf_decal/tile/dark/fourcorners, -/obj/machinery/light/small/directional/west, -/turf/open/floor/iron/sepia, +"zU" = ( +/obj/structure/table/wood, +/obj/item/toy/plush/goatplushie, +/obj/machinery/light/small/directional/north, +/turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) "Af" = ( /obj/effect/turf_decal/siding/wood{ @@ -1072,6 +1125,12 @@ dir = 1 }, /area/centcom/central_command_areas/holding) +"AP" = ( +/obj/item/kirbyplants/organic/plant10, +/turf/open/floor/bamboo/tatami/purple{ + dir = 1 + }, +/area/centcom/central_command_areas/holding) "Bn" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -1087,10 +1146,6 @@ /obj/item/food/chawanmushi, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) -"Bt" = ( -/obj/machinery/light/small/directional/east, -/turf/open/floor/iron/stairs/medium, -/area/centcom/central_command_areas/holding) "Bw" = ( /turf/open/misc/beach/sand, /area/centcom/central_command_areas/holding) @@ -1161,8 +1216,13 @@ }, /turf/open/floor/grass, /area/centcom/central_command_areas/holding) -"Dy" = ( +"DF" = ( /obj/item/kirbyplants/organic/plant10, +/turf/open/floor/bamboo/tatami/purple, +/area/centcom/central_command_areas/holding) +"DG" = ( +/obj/structure/closet/crate/freezer/blood, +/obj/machinery/light/small/directional/south, /turf/open/floor/iron/sepia, /area/centcom/central_command_areas/holding) "DI" = ( @@ -1213,6 +1273,10 @@ initial_gas_mix = "o2=22;n2=82;TEMP=293.15" }, /area/centcom/central_command_areas/holding) +"EC" = ( +/obj/item/kirbyplants/organic/plant10, +/turf/open/floor/carpet/black, +/area/centcom/central_command_areas/holding) "EJ" = ( /obj/item/mop, /obj/structure/sink/kitchen/directional/west, @@ -1227,6 +1291,13 @@ dir = 4 }, /area/centcom/central_command_areas/holding) +"FB" = ( +/obj/machinery/modular_computer/preset/research{ + dir = 4 + }, +/obj/machinery/light/directional/west, +/turf/open/floor/catwalk_floor, +/area/centcom/central_command_areas/holding) "FE" = ( /turf/open/floor/catwalk_floor, /area/centcom/central_command_areas/holding) @@ -1293,6 +1364,19 @@ }, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) +"GN" = ( +/obj/structure/bed/dogbed/cayenne{ + name = "Paprika's bed" + }, +/mob/living/basic/carp/pet/cayenne{ + desc = "It's Paprika! One of the Spider Clan's lovable Space Carp!"; + faction = list("neutral"); + name = "Paprika"; + real_name = "Paprika" + }, +/obj/machinery/light/warm/directional/south, +/turf/open/floor/carpet/black, +/area/centcom/central_command_areas/holding) "GO" = ( /obj/effect/turf_decal/siding/wood{ dir = 8 @@ -1329,11 +1413,6 @@ }, /turf/open/floor/stone, /area/centcom/central_command_areas/holding) -"Hf" = ( -/obj/machinery/vending/dinnerware, -/obj/machinery/light/warm/directional/north, -/turf/open/floor/iron/sepia, -/area/centcom/central_command_areas/holding) "Ho" = ( /obj/effect/turf_decal/siding/wood{ dir = 4 @@ -1353,34 +1432,6 @@ /obj/effect/turf_decal/siding/wood, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) -"Hw" = ( -/obj/structure/rack, -/obj/item/nullrod/claymore{ - damtype = "stamina"; - force = 30; - pixel_x = 4; - pixel_y = -1 - }, -/obj/item/nullrod/claymore/darkblade{ - damtype = "stamina"; - force = 30; - pixel_x = -3; - pixel_y = 3 - }, -/obj/machinery/light/directional/north, -/turf/open/floor/wood/parquet, -/area/centcom/central_command_areas/holding) -"HL" = ( -/obj/structure/closet/crate/freezer/blood, -/obj/machinery/light/small/directional/north, -/turf/open/floor/iron/sepia, -/area/centcom/central_command_areas/holding) -"HP" = ( -/obj/structure/table/wood/fancy/royalblack, -/obj/item/book/bible, -/obj/machinery/light/directional/north, -/turf/open/floor/wood/large, -/area/centcom/central_command_areas/holding) "HU" = ( /turf/open/misc/asteroid/basalt/wasteland{ initial_gas_mix = "TEMP=2.7" @@ -1438,19 +1489,6 @@ /obj/item/paper/guides/jobs/hydroponics, /turf/open/floor/wood/tile, /area/centcom/central_command_areas/holding) -"IY" = ( -/obj/machinery/light/small/directional/south, -/turf/open/floor/bamboo/tatami/black{ - dir = 4 - }, -/area/centcom/central_command_areas/holding) -"Je" = ( -/obj/item/kirbyplants/organic/plant10, -/obj/structure/sign/painting/library{ - pixel_y = 32 - }, -/turf/open/floor/carpet/black, -/area/centcom/central_command_areas/holding) "Jf" = ( /obj/structure/table/reinforced/rglass, /obj/item/wrench{ @@ -1528,6 +1566,11 @@ }, /turf/open/floor/wood/tile, /area/centcom/central_command_areas/holding) +"JL" = ( +/obj/effect/turf_decal/siding/wood, +/obj/machinery/light/small/directional/south, +/turf/open/floor/wood/tile, +/area/centcom/central_command_areas/holding) "JR" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -1587,6 +1630,11 @@ dir = 8 }, /area/centcom/central_command_areas/holding) +"LE" = ( +/obj/machinery/vending/dinnerware, +/obj/machinery/light/warm/directional/north, +/turf/open/floor/iron/sepia, +/area/centcom/central_command_areas/holding) "LK" = ( /turf/closed/indestructible/weeb, /area/centcom/central_command_areas/holding) @@ -1607,18 +1655,11 @@ }, /turf/open/floor/iron/cafeteria, /area/centcom/central_command_areas/holding) -"Mz" = ( -/obj/structure/closet, -/obj/item/surgery_tray, -/obj/machinery/iv_drip, -/obj/item/emergency_bed, -/obj/item/storage/medkit/regular, -/obj/item/reagent_containers/medigel/synthflesh, -/obj/item/reagent_containers/medigel/synthflesh, -/obj/item/reagent_containers/medigel/synthflesh, -/obj/item/organ/internal/heart/cybernetic/tier2, -/obj/item/organ/internal/heart/cybernetic/tier2, -/obj/item/defibrillator, +"My" = ( +/obj/item/kirbyplants/organic/plant10, +/obj/structure/sign/painting/library{ + pixel_y = 32 + }, /turf/open/floor/iron/sepia, /area/centcom/central_command_areas/holding) "ML" = ( @@ -1642,11 +1683,6 @@ /obj/item/food/grown/soybeans, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) -"Nh" = ( -/obj/item/kirbyplants/organic/plant10, -/obj/machinery/duct, -/turf/open/floor/carpet/black, -/area/centcom/central_command_areas/holding) "Nt" = ( /obj/structure/table/wood, /obj/machinery/chem_dispenser/drinks{ @@ -1667,6 +1703,10 @@ }, /turf/open/misc/sandy_dirt, /area/centcom/central_command_areas/holding) +"ND" = ( +/obj/item/kirbyplants/organic/plant10, +/turf/open/floor/wood/large, +/area/centcom/central_command_areas/holding) "NF" = ( /turf/open/floor/bamboo/tatami/black{ dir = 4 @@ -1678,20 +1718,6 @@ }, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) -"NP" = ( -/obj/structure/rack, -/obj/item/nullrod/claymore/saber/red{ - damtype = "stamina"; - force = 30 - }, -/obj/item/nullrod/claymore/katana{ - damtype = "stamina"; - force = 30; - pixel_x = -8; - pixel_y = -1 - }, -/turf/open/floor/wood/parquet, -/area/centcom/central_command_areas/holding) "NR" = ( /obj/structure/bookcase/random/fiction, /turf/open/floor/carpet/black, @@ -1707,6 +1733,14 @@ dir = 1 }, /area/centcom/central_command_areas/holding) +"Od" = ( +/obj/item/kirbyplants/organic/plant10, +/obj/machinery/light/small/directional/north, +/obj/structure/sign/painting/library{ + pixel_y = 32 + }, +/turf/open/floor/iron/sepia, +/area/centcom/central_command_areas/holding) "Ok" = ( /obj/effect/turf_decal/siding/wood{ dir = 8 @@ -1716,16 +1750,15 @@ }, /turf/open/floor/stone, /area/centcom/central_command_areas/holding) -"Oy" = ( +"Oo" = ( /obj/item/kirbyplants/organic/plant10, /obj/machinery/light/directional/south, /turf/open/floor/wood/large, /area/centcom/central_command_areas/holding) -"OA" = ( -/obj/item/kirbyplants/organic/plant10, -/turf/open/floor/bamboo/tatami/purple{ - dir = 1 - }, +"Op" = ( +/obj/structure/bookcase/random/fiction, +/obj/machinery/light/small/directional/east, +/turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) "OC" = ( /obj/effect/turf_decal/siding/wood{ @@ -1733,9 +1766,10 @@ }, /turf/open/misc/sandy_dirt, /area/centcom/central_command_areas/holding) -"Pf" = ( -/obj/machinery/light/directional/north, -/turf/open/floor/wood/large, +"OQ" = ( +/obj/structure/bookcase/random/reference, +/obj/machinery/light/small/directional/west, +/turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) "Pl" = ( /obj/structure/flora/bush/flowers_yw/style_random, @@ -1746,6 +1780,12 @@ /obj/structure/sign/poster/contraband/syndicate_recruitment/directional/south, /turf/open/floor/wood/large, /area/centcom/central_command_areas/holding) +"PH" = ( +/obj/structure/chair/comfy/black{ + dir = 8 + }, +/turf/open/floor/carpet/black, +/area/centcom/central_command_areas/holding) "PK" = ( /obj/structure/table/reinforced/rglass, /obj/item/shovel/spade{ @@ -1760,33 +1800,20 @@ /obj/item/instrument/saxophone, /turf/open/floor/wood/parquet, /area/centcom/central_command_areas/holding) -"Qh" = ( -/obj/structure/rack, -/obj/item/nullrod/claymore/saber{ - damtype = "stamina"; - force = 30; - pixel_x = 5; - pixel_y = -3 - }, -/obj/item/nullrod/claymore/katana{ - damtype = "stamina"; - force = 30 - }, -/turf/open/floor/wood/parquet, +"Qt" = ( +/obj/machinery/light/small/directional/north, +/turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) "Qu" = ( /obj/machinery/defibrillator_mount/directional/south, /obj/machinery/stasis, /turf/open/floor/iron/sepia, /area/centcom/central_command_areas/holding) -"QR" = ( -/obj/machinery/light/warm/directional/east, -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, +"QJ" = ( /obj/effect/turf_decal/siding/wood, /obj/item/kirbyplants/organic/plant10, -/turf/open/floor/stone, +/obj/effect/turf_decal/tile/dark/opposingcorners, +/turf/open/floor/iron/sepia, /area/centcom/central_command_areas/holding) "QW" = ( /obj/structure/table/wood/fancy/royalblack, @@ -1858,11 +1885,6 @@ "Sc" = ( /turf/open/floor/stone, /area/centcom/central_command_areas/holding) -"Si" = ( -/obj/structure/table/wood, -/obj/item/flashlight/lamp/green, -/turf/open/floor/carpet/black, -/area/centcom/central_command_areas/holding) "Tc" = ( /obj/effect/turf_decal/siding/wood, /obj/structure/chair/sofa/corp/right{ @@ -1914,6 +1936,14 @@ /obj/structure/chair/stool/directional/south, /turf/open/floor/wood/parquet, /area/centcom/central_command_areas/holding) +"Uj" = ( +/obj/item/kirbyplants/organic/plant10, +/turf/open/floor/iron/sepia, +/area/centcom/central_command_areas/holding) +"Ul" = ( +/obj/machinery/light/small/directional/south, +/turf/open/floor/carpet/black, +/area/centcom/central_command_areas/holding) "UB" = ( /obj/structure/table/reinforced/plastitaniumglass, /obj/item/toy/figure/ninja, @@ -1957,13 +1987,6 @@ /obj/machinery/light/directional/west, /turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) -"Vg" = ( -/obj/item/kirbyplants/organic/plant10, -/obj/structure/sign/painting/library{ - pixel_y = 32 - }, -/turf/open/floor/iron/sepia, -/area/centcom/central_command_areas/holding) "Vi" = ( /obj/machinery/defibrillator_mount/directional/north, /obj/machinery/stasis, @@ -1980,19 +2003,6 @@ }, /turf/open/floor/wood/tile, /area/centcom/central_command_areas/holding) -"Vu" = ( -/obj/structure/bed/dogbed/cayenne{ - name = "Paprika's bed" - }, -/mob/living/basic/carp/pet/cayenne{ - desc = "It's Paprika! One of the Spider Clan's lovable Space Carp!"; - faction = list("neutral"); - name = "Paprika"; - real_name = "Paprika" - }, -/obj/machinery/light/warm/directional/south, -/turf/open/floor/carpet/black, -/area/centcom/central_command_areas/holding) "VC" = ( /obj/structure/closet/crate/bin, /obj/item/soap/syndie, @@ -2036,13 +2046,6 @@ /obj/item/food/grown/redbeet, /turf/open/floor/catwalk_floor, /area/centcom/central_command_areas/holding) -"Wc" = ( -/obj/machinery/modular_computer/preset/research{ - dir = 4 - }, -/obj/machinery/light/directional/west, -/turf/open/floor/catwalk_floor, -/area/centcom/central_command_areas/holding) "We" = ( /obj/machinery/vending/cigarette/syndicate, /obj/machinery/light/small/directional/south, @@ -2056,6 +2059,12 @@ }, /turf/open/floor/iron/sepia, /area/centcom/central_command_areas/holding) +"WD" = ( +/obj/machinery/light/small/directional/south, +/turf/open/floor/bamboo/tatami/black{ + dir = 4 + }, +/area/centcom/central_command_areas/holding) "WS" = ( /obj/effect/turf_decal/siding/wood/corner{ dir = 4 @@ -2107,9 +2116,9 @@ initial_gas_mix = "o2=22;n2=82;TEMP=293.15" }, /area/centcom/central_command_areas/holding) -"Xj" = ( -/obj/machinery/light/small/directional/west, -/turf/open/floor/iron/stairs/medium, +"Xn" = ( +/obj/structure/reagent_dispensers/plumbed, +/turf/open/floor/carpet/black, /area/centcom/central_command_areas/holding) "Xt" = ( /obj/effect/turf_decal/siding/wood, @@ -2146,11 +2155,6 @@ /obj/item/toy/spinningtoy, /turf/open/floor/wood/parquet, /area/centcom/central_command_areas/holding) -"Yf" = ( -/obj/structure/closet/crate/freezer/blood, -/obj/machinery/light/small/directional/south, -/turf/open/floor/iron/sepia, -/area/centcom/central_command_areas/holding) "YQ" = ( /turf/open/floor/bamboo/tatami{ dir = 4 @@ -2177,10 +2181,6 @@ }, /turf/open/floor/iron/sepia, /area/centcom/central_command_areas/holding) -"Zp" = ( -/obj/structure/reagent_dispensers/plumbed, -/turf/open/floor/carpet/black, -/area/centcom/central_command_areas/holding) "Zq" = ( /obj/structure/bookcase/random/adult, /turf/open/floor/carpet/black, @@ -2428,12 +2428,12 @@ gy wV Ea dg -eC -yo +zc +rn Nt JV -cV -Zp +zh +Xn dg ts FE @@ -2503,10 +2503,10 @@ rQ wV dg zL -Nh +eo Am Am -rV +EC VC dg dg @@ -2547,7 +2547,7 @@ MR dg dg oG -vr +nW oG LK Ed @@ -2576,12 +2576,12 @@ CG CG Ho dg -aq +zU AE Gy Bo iF -Si +cK dg oG oG @@ -2722,7 +2722,7 @@ Zj HU Zj CG -Hf +LE zN hO hO @@ -2804,7 +2804,7 @@ pt pN hO hO -QR +qg Bw yz Bw @@ -2873,7 +2873,7 @@ Vj mw DL ht -ri +JL dg ic mw @@ -2941,7 +2941,7 @@ MM ML mw mw -hl +hs dg dg iH @@ -2985,7 +2985,7 @@ mw mw ht kl -fx +Op XP mw mw @@ -3016,7 +3016,7 @@ ML mw mw FU -Bt +nR lI mw mw @@ -3086,15 +3086,15 @@ LK lh qx dg -fV +QJ mw mw -zQ +od Gw XP xw Am -mN +PH Am VO XP @@ -3130,10 +3130,10 @@ Ey Dh XP xw -oP +Ul dg -uP -Vu +Qt +GN dg iH mw @@ -3160,15 +3160,15 @@ LK os sc dg -fV +QJ mw mw -eN +au GX XP xw Am -hJ +be Am NU XP @@ -3238,7 +3238,7 @@ ML mw mw FU -Xj +iW lI mw mw @@ -3281,7 +3281,7 @@ mw mw ZV kl -wS +OQ XP mw mw @@ -3387,7 +3387,7 @@ pp pp cn XP -cv +wc mw mw ht @@ -3457,8 +3457,8 @@ aB xq Zc ML -vv -vv +ND +ND dg uv Zk @@ -3499,7 +3499,7 @@ LK CG CG CG -Pf +hn mw zN VD @@ -3513,7 +3513,7 @@ Zj CG bH qr -Wc +FB bP Xd CG @@ -3577,7 +3577,7 @@ mw mw zN VD -uT +bO zN mw mw @@ -3619,7 +3619,7 @@ dg iH GU dg -ze +af QZ dg rj @@ -3634,7 +3634,7 @@ Ed (39,1,1) = {" Ed CG -HP +lV mw mw mw @@ -3661,7 +3661,7 @@ mw mw mw mw -Oy +Oo dg lx Jg @@ -3749,24 +3749,24 @@ hH Zb hH dg -OA +AP bl xM -qW +DF dg -Mz +pU DI -vH +dv dg -Je +hw NU Vf NU -rV +EC dg -aw +Od Wm -Mz +pU dg uL hO @@ -3786,7 +3786,7 @@ Zb gp Zb dg -hr +ha xM bl CL @@ -3828,9 +3828,9 @@ CL CL rR dg -HL +wq DI -Dy +Uj dg jR NU @@ -3838,9 +3838,9 @@ NU NU NU dg -Vg +My DI -Yf +DG dg VE qi @@ -3904,7 +3904,7 @@ rR dg ed wU -fG +mr oY Rf Oa @@ -3912,7 +3912,7 @@ lP Oa lP oY -fG +mr wU ed dg @@ -3939,7 +3939,7 @@ bl xM ee dg -Hw +pB wU wU WX @@ -3951,7 +3951,7 @@ Rf oY Uf wU -nm +oh dg qi ZU @@ -3976,7 +3976,7 @@ Yd PV Tj dg -NP +ni wU Uf oY @@ -3988,7 +3988,7 @@ NF oY Uf wU -Qh +vr dg Ez Ez @@ -4054,11 +4054,11 @@ LK LK LK CG -jK +pX lP Oa lP -IY +WD CG LK LK diff --git a/_maps/templates/lazy_templates/nukie_base.dmm b/_maps/templates/lazy_templates/nukie_base.dmm index 6a1115b432b036..68913efe70dbf3 100644 --- a/_maps/templates/lazy_templates/nukie_base.dmm +++ b/_maps/templates/lazy_templates/nukie_base.dmm @@ -111,7 +111,7 @@ dir = 5 }, /obj/structure/table/reinforced/plasmarglass, -/obj/item/surgery_tray{ +/obj/item/surgery_tray/full{ pixel_y = -11 }, /obj/item/storage/belt/medical, diff --git a/code/__DEFINES/achievements.dm b/code/__DEFINES/achievements.dm index b5efdb76f1a3fd..4a0299d835ac32 100644 --- a/code/__DEFINES/achievements.dm +++ b/code/__DEFINES/achievements.dm @@ -46,6 +46,7 @@ #define MEDAL_VOID_ASCENSION "Void" #define MEDAL_BLADE_ASCENSION "Blade" #define MEDAL_COSMOS_ASCENSION "Cosmos" +#define MEDAL_KNOCK_ASCENSION "Knock" #define MEDAL_TOOLBOX_SOUL "Toolsoul" #define MEDAL_CHEM_TUT "Beginner Chemist" #define MEDAL_HOT_DAMN "Hot Damn!" diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index 289f75862229e3..c71b1a4acd540e 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -44,6 +44,8 @@ /// Generic key for a non-specific targetted action #define BB_TARGETTED_ACTION "BB_targetted_action" +/// Generic key for a non-specific action +#define BB_GENERIC_ACTION "BB_generic_action" ///How long have we spent with no target? #define BB_TARGETLESS_TIME "BB_targetless_time" @@ -83,3 +85,6 @@ #define BB_MOD_IMPLANT "BB_mod_implant" ///Range for a MOD AI controller. #define MOD_AI_RANGE 200 + +///should we skip the faction check for the targetting datum? +#define BB_BASIC_MOB_SKIP_FACTION_CHECK "BB_basic_mob_skip_faction_check" diff --git a/code/__DEFINES/ai/monsters.dm b/code/__DEFINES/ai/monsters.dm index 4040bdb23a84f5..ebb924e42e19aa 100644 --- a/code/__DEFINES/ai/monsters.dm +++ b/code/__DEFINES/ai/monsters.dm @@ -59,11 +59,6 @@ /// We increment this counter every time we try to move while dragging an arm and if we go too long we'll give up trying to get out of line of sight and just eat the fingers #define BB_LOBSTROSITY_FINGER_LUST "BB_lobstrosity_finger_lust" -/// Key containing overwatch ability information -#define BB_WATCHER_OVERWATCH "BB_watcher_overwatch" -/// Key containing gazae ability information -#define BB_WATCHER_GAZE "BB_watcher_gaze" - // eyeball keys ///the death glare ability #define BB_GLARE_ABILITY "BB_glare_ability" diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 7c530b3970e993..e74cd6a58bd2c2 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -80,6 +80,7 @@ #define PATH_VOID "Void Path" #define PATH_BLADE "Blade Path" #define PATH_COSMIC "Cosmic Path" +#define PATH_KNOCK "Knock Path" /// Defines are used in /proc/has_living_heart() to report if the heretic has no heart period, no living heart, or has a living heart. #define HERETIC_NO_HEART_ORGAN -1 diff --git a/code/__DEFINES/bodyparts.dm b/code/__DEFINES/bodyparts.dm index 5c575184273983..87995d46abb87c 100644 --- a/code/__DEFINES/bodyparts.dm +++ b/code/__DEFINES/bodyparts.dm @@ -1,2 +1,25 @@ ///The standard amount of bodyparts a carbon has. Currently 6, HEAD/L_ARM/R_ARM/CHEST/L_LEG/R_LEG #define BODYPARTS_DEFAULT_MAXIMUM 6 + +/// The max HP of surplus prosthetics. +#define PROSTHESIS_MAX_HP 20 + +// EMP +// Note most of these values are doubled on heavy EMP + +/// The brute damage an augged limb takes from an EMP. +#define AUGGED_LIMB_EMP_BRUTE_DAMAGE 2 +/// The brute damage an augged limb takes from an EMP. +#define AUGGED_LIMB_EMP_BURN_DAMAGE 1.5 + +/// When hit by an EMP, the time an augged limb will be paralyzed for if its above the damage threshold. +#define AUGGED_LIMB_EMP_PARALYZE_TIME 3 SECONDS + +/// When hit by an EMP, the time an augged leg will be knocked down for. +#define AUGGED_LEG_EMP_KNOCKDOWN_TIME 3 SECONDS +/// When hit by an EMP, the time a augged chest will cause a hardstun for if its above the damage threshold. +#define AUGGED_CHEST_EMP_STUN_TIME 3 SECONDS +/// When hit by an EMP, the time an augged chest will cause the mob to shake() for. +#define AUGGED_CHEST_EMP_SHAKE_TIME 5 SECONDS +/// When hit by an EMP, the time an augged head will make vision fucky for. +#define AUGGED_HEAD_EMP_GLITCH_DURATION 6 SECONDS diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm index d47833f84c0d98..a2198cfb63c184 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm @@ -64,3 +64,6 @@ #define ATTACKER_SHOVING (1<<1) /// The attack is a damaging-type attack #define ATTACKER_DAMAGING_ATTACK (1<<2) + +/// Called on the atom being hit, from /datum/component/anti_magic/on_attack() : (obj/item/weapon, mob/user, antimagic_flags) +#define COMSIG_ATOM_HOLYATTACK "atom_holyattacked" diff --git a/code/__DEFINES/dcs/signals/signals_lazy_templates.dm b/code/__DEFINES/dcs/signals/signals_lazy_templates.dm new file mode 100644 index 00000000000000..1c6ce7926ea5c9 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_lazy_templates.dm @@ -0,0 +1,2 @@ +/// Fired on the lazy template datum when the template is finished loading. (list/loaded_atom_movables, list/loaded_turfs, list/loaded_areas) +#define COMSIG_LAZY_TEMPLATE_LOADED "lazy_template_loaded" diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm index dd5b38113d3d8c..677a65a7be1736 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm @@ -25,6 +25,8 @@ // /mob/living/carbon physiology signals #define COMSIG_CARBON_GAIN_WOUND "carbon_gain_wound" //from /datum/wound/proc/apply_wound() (/mob/living/carbon/C, /datum/wound/W, /obj/item/bodypart/L) #define COMSIG_CARBON_LOSE_WOUND "carbon_lose_wound" //from /datum/wound/proc/remove_wound() (/mob/living/carbon/C, /datum/wound/W, /obj/item/bodypart/L) +/// Called after limb AND victim has been unset +#define COMSIG_CARBON_POST_LOSE_WOUND "carbon_post_lose_wound" //from /datum/wound/proc/remove_wound() (/datum/wound/lost_wound, /obj/item/bodypart/part, ignore_limb, replaced) ///from base of /obj/item/bodypart/proc/can_attach_limb(): (new_limb, special) allows you to fail limb attachment #define COMSIG_ATTEMPT_CARBON_ATTACH_LIMB "attempt_carbon_attach_limb" #define COMPONENT_NO_ATTACH (1<<0) diff --git a/code/__DEFINES/dcs/signals/signals_mod.dm b/code/__DEFINES/dcs/signals/signals_mod.dm index 2533b698528495..c4007d1296910c 100644 --- a/code/__DEFINES/dcs/signals/signals_mod.dm +++ b/code/__DEFINES/dcs/signals/signals_mod.dm @@ -25,6 +25,8 @@ #define MOD_ABORT_USE (1<<0) /// Called when a module activates, after all checks have passed and cooldown started. #define COMSIG_MODULE_ACTIVATED "mod_module_activated" +/// Called when a module starts a cooldown until its next activation. Passed the cooldown time. +#define COMSIG_MODULE_COOLDOWN_STARTED "mod_module_cooldown_started" /// Called when a module deactivates, after all checks have passed. #define COMSIG_MODULE_DEACTIVATED "mod_module_deactivated" /// Called when a module is used, after all checks have passed and cooldown started. diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index fee0ca52781f79..19286859e9e4dd 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -50,6 +50,8 @@ // /obj/machinery/computer/teleporter /// from /obj/machinery/computer/teleporter/proc/set_target(target, old_target) #define COMSIG_TELEPORTER_NEW_TARGET "teleporter_new_target" +/// from /obj/item/beacon/proc/turn_off() +#define COMSIG_BEACON_DISABLED "beacon_disabled" // /obj/machinery/power/supermatter_crystal /// from /obj/machinery/power/supermatter_crystal/process_atmos(); when the SM sounds an audible alarm @@ -246,6 +248,8 @@ /// Called on component/uplink/OnAttackBy(..) #define COMSIG_ITEM_ATTEMPT_TC_REIMBURSE "item_attempt_tc_reimburse" +///Called when a holoparasite/guardiancreator is used. +#define COMSIG_TRAITOR_ITEM_USED(type) "traitor_item_used_[type]" // /obj/item/clothing signals diff --git a/code/__DEFINES/dcs/signals/signals_saboteur.dm b/code/__DEFINES/dcs/signals/signals_saboteur.dm new file mode 100644 index 00000000000000..5b0fef52aee666 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_saboteur.dm @@ -0,0 +1,5 @@ +// Light disruptor. Not to be confused with the light eater, which permanently disables lights. + +/// from /obj/projectile/energy/fisher/on_hit() or /obj/item/gun/energy/recharge/fisher when striking a target +#define COMSIG_HIT_BY_SABOTEUR "HIT_BY_SABOTEUR" + #define COMSIG_SABOTEUR_SUCCESS (1<<0) diff --git a/code/__DEFINES/fishing.dm b/code/__DEFINES/fishing.dm index 2481f0ae3e7222..dc73623f27cabf 100644 --- a/code/__DEFINES/fishing.dm +++ b/code/__DEFINES/fishing.dm @@ -51,14 +51,10 @@ /// Much like FISHING_HOOK_ENSNARE but for the reel. #define FISHING_LINE_BOUNCY (1 << 2) -#define FISHING_MINIGAME_RULE_HEAVY_FISH "heavy" -#define FISHING_MINIGAME_RULE_LUBED_FISH "lubed" -#define FISHING_MINIGAME_RULE_WEIGHTED_BAIT "weighted" -#define FISHING_MINIGAME_RULE_LIMIT_LOSS "limit_loss" -#define FISHING_MINIGAME_RULE_BIDIRECTIONAL "bidirectional" -#define FISHING_MINIGAME_RULE_NO_ESCAPE "no_escape" -#define FISHING_MINIGAME_RULE_KILL "kill" -#define FISHING_MINIGAME_RULE_NO_EXP "no_exp" +#define FISHING_MINIGAME_RULE_BIDIRECTIONAL (1 << 2) +#define FISHING_MINIGAME_RULE_NO_ESCAPE (1 << 3) +#define FISHING_MINIGAME_RULE_KILL (1 << 4) +#define FISHING_MINIGAME_RULE_NO_EXP (1 << 5) /// The default additive value for fishing hook catch weight modifiers. #define FISHING_DEFAULT_HOOK_BONUS_ADDITIVE 0 diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index f509b740d26999..849b3a28b9c624 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -88,7 +88,10 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 //TURF FLAGS /// If a turf cant be jaunted through. #define NOJAUNT (1<<0) +/// If a turf is an usused reservation turf awaiting assignment #define UNUSED_RESERVATION_TURF (1<<1) +/// If a turf is a reserved turf +#define RESERVATION_TURF (1<<2) /// Blocks lava rivers being generated on the turf. #define NO_LAVA_GEN (1<<3) /// Blocks ruins spawning on the turf. diff --git a/code/__DEFINES/holiday.dm b/code/__DEFINES/holiday.dm new file mode 100644 index 00000000000000..1c35940e718870 --- /dev/null +++ b/code/__DEFINES/holiday.dm @@ -0,0 +1 @@ +#define HOLIDAY_HAT_CHANCE 20 diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index 71fc835d25ee58..44e67226604f85 100644 --- a/code/__DEFINES/jobs.dm +++ b/code/__DEFINES/jobs.dm @@ -135,6 +135,11 @@ #define JOB_SOLFED_LIASON "SolFed Liason" // SKYRAT EDIT ADDITION END +#define JOB_GROUP_ENGINEERS list( \ + JOB_STATION_ENGINEER, \ + JOB_ATMOSPHERIC_TECHNICIAN, \ +) + #define JOB_DISPLAY_ORDER_ASSISTANT 1 #define JOB_DISPLAY_ORDER_CAPTAIN 2 diff --git a/code/__DEFINES/keybinding.dm b/code/__DEFINES/keybinding.dm index 0f05c0fe12b62c..33178bc7c8be8f 100644 --- a/code/__DEFINES/keybinding.dm +++ b/code/__DEFINES/keybinding.dm @@ -49,6 +49,8 @@ #define COMSIG_KB_LIVING_TOGGLE_COMBAT_DOWN "keybinding_living_toggle_combat_down" #define COMSIG_KB_LIVING_ENABLE_COMBAT_DOWN "keybinding_living_enable_combat_down" #define COMSIG_KB_LIVING_DISABLE_COMBAT_DOWN "keybinding_living_disable_combat_down" +#define COMSIG_KB_LIVING_TOGGLEMOVEINTENT_DOWN "keybinding_mob_togglemoveintent_down" +#define COMSIG_KB_LIVING_TOGGLEMOVEINTENTALT_DOWN "keybinding_mob_togglemoveintentalt_down" //Mob #define COMSIG_KB_MOB_FACENORTH_DOWN "keybinding_mob_facenorth_down" @@ -61,8 +63,6 @@ #define COMSIG_KB_MOB_SWAPHANDS_DOWN "keybinding_mob_swaphands_down" #define COMSIG_KB_MOB_ACTIVATEINHAND_DOWN "keybinding_mob_activateinhand_down" #define COMSIG_KB_MOB_DROPITEM_DOWN "keybinding_mob_dropitem_down" -#define COMSIG_KB_MOB_TOGGLEMOVEINTENT_DOWN "keybinding_mob_togglemoveintent_down" -#define COMSIG_KB_MOB_TOGGLEMOVEINTENTALT_DOWN "keybinding_mob_togglemoveintentalt_down" #define COMSIG_KB_MOB_TARGETCYCLEHEAD_DOWN "keybinding_mob_targetcyclehead_down" #define COMSIG_KB_MOB_TARGETEYES_DOWN "keybinding_mob_targeteyes_down" #define COMSIG_KB_MOB_TARGETMOUTH_DOWN "keybinding_mob_targetmouth_down" diff --git a/code/__DEFINES/lazy_templates.dm b/code/__DEFINES/lazy_templates.dm index d075b1e681a672..1e8fab8d92cd0f 100644 --- a/code/__DEFINES/lazy_templates.dm +++ b/code/__DEFINES/lazy_templates.dm @@ -2,11 +2,13 @@ #define LAZY_TEMPLATE_KEY_WIZARDDEN "LT_WIZARDDEN" #define LAZY_TEMPLATE_KEY_NINJA_HOLDING_FACILITY "LT_NINJAHOLDING" #define LAZY_TEMPLATE_KEY_ABDUCTOR_SHIPS "LT_ABDUCTORSHIPS" +#define LAZY_TEMPLATE_KEY_HERETIC_SACRIFICE "LT_HERETICSACRIFICE" #define LAZY_TEMPLATE_KEY_LIST_ALL(...) list( \ "Nukie Base" = LAZY_TEMPLATE_KEY_NUKIEBASE, \ "Wizard Den" = LAZY_TEMPLATE_KEY_WIZARDDEN, \ "Ninja Holding" = LAZY_TEMPLATE_KEY_NINJA_HOLDING_FACILITY, \ "Abductor Ships" = LAZY_TEMPLATE_KEY_ABDUCTOR_SHIPS, \ + "Heretic Sacrifice Level" = LAZY_TEMPLATE_KEY_HERETIC_SACRIFICE, \ "Outpost of Cogs" = LAZY_TEMPLATE_KEY_OUTPOST_OF_COGS, \ ) // SKYRAT EDIT ABOVE - OUTPOST OF COGS diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm index c40f3c4f59c6a7..eb1b2ecce51e69 100644 --- a/code/__DEFINES/maths.dm +++ b/code/__DEFINES/maths.dm @@ -240,6 +240,9 @@ #define SPT_PROB(prob_per_second_percent, seconds_per_tick) (prob(100*SPT_PROB_RATE((prob_per_second_percent)/100, (seconds_per_tick)))) // ) +// This value per these many units. Very unnecessary but helpful for readability (For example wanting 30 units of synthflesh to heal 50 damage - VALUE_PER(50, 30)) +#define VALUE_PER(value, per) (value / per) + #define GET_TRUE_DIST(a, b) (a == null || b == null) ? -1 : max(abs(a.x -b.x), abs(a.y-b.y), abs(a.z-b.z)) //We used to use linear regression to approximate the answer, but Mloc realized this was actually faster. @@ -248,3 +251,6 @@ /// The number of cells in a taxicab circle (rasterized diamond) of radius X. #define DIAMOND_AREA(X) (1 + 2*(X)*((X)+1)) + +/// Returns a random decimal between x and y. +#define RANDOM_DECIMAL(x, y) LERP((x), (y), rand()) diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 8ef3f2809e5d27..bca259b0dc17d5 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -42,18 +42,29 @@ #define VENTCRAWLER_ALWAYS 2 //Mob bio-types flags -///The mob is organic, can can heal from medical sutures. +///The mob is organic, can heal from medical sutures. #define MOB_ORGANIC (1 << 0) +///The mob is of a rocky make, most likely a golem. Iron within, iron without! #define MOB_MINERAL (1 << 1) +///The mob is a synthetic lifeform, like station borgs. #define MOB_ROBOTIC (1 << 2) +///The mob is an shambling undead corpse. Or a halloween species. Pick your poison. #define MOB_UNDEAD (1 << 3) +///The mob is a human-sized human-like human-creature. #define MOB_HUMANOID (1 << 4) +///The mob is a bug/insect/arachnid/some other kind of scuttly thing. #define MOB_BUG (1 << 5) +///The mob is a wild animal. Domestication may apply. #define MOB_BEAST (1 << 6) -#define MOB_EPIC (1 << 7) //megafauna +///The mob is some kind of a creature that should be exempt from certain **fun** interactions for balance reasons, i.e. megafauna or a headslug. +#define MOB_SPECIAL (1 << 7) +///The mob is some kind of a scaly reptile creature #define MOB_REPTILE (1 << 8) +///The mob is a spooky phantasm or an evil ghast of such nature. #define MOB_SPIRIT (1 << 9) +///The mob is a plant-based species, benefitting from light but suffering from darkness and plantkillers. #define MOB_PLANT (1 << 10) +///The mob is a goopy creature, probably coming from xenobiology. #define MOB_SLIME (1 << 11) //Lung respiration type flags @@ -878,12 +889,26 @@ GLOBAL_LIST_INIT(layers_to_offset, list( /// Get the client from the var #define CLIENT_FROM_VAR(I) (ismob(I) ? I:client : (istype(I, /client) ? I : (istype(I, /datum/mind) ? I:current?:client : null))) -/// The mob will vomit a green color -#define VOMIT_TOXIC 1 -/// The mob will vomit a purple color -#define VOMIT_PURPLE 2 -/// The mob will vomit a nebula color -#define VOMIT_NEBULA 3 +// Various flags for carbon mob vomiting +/// Flag which makes a message send about the vomiting. +#define MOB_VOMIT_MESSAGE (1<<0) +/// Flag which makes the mob get stunned upon vomiting. +#define MOB_VOMIT_STUN (1<<1) +/// Flag which makes the mob incur damage upon vomiting. +#define MOB_VOMIT_HARM (1<<2) +/// Flag which makes the mob vomit blood +#define MOB_VOMIT_BLOOD (1<<3) +/// Flag which will cause the mob to fall over when vomiting. +#define MOB_VOMIT_KNOCKDOWN (1<<4) +/// Flag which will make the proc skip certain checks when it comes to forcing a vomit. +#define MOB_VOMIT_FORCE (1<<5) + +/// The default. Gives you might typically expect to happen when you vomit. +#define VOMIT_CATEGORY_DEFAULT (MOB_VOMIT_MESSAGE | MOB_VOMIT_HARM | MOB_VOMIT_STUN) +/// The vomit you've all come to know and love, but with a little extra "spice" (blood) +#define VOMIT_CATEGORY_BLOOD (VOMIT_CATEGORY_DEFAULT | MOB_VOMIT_BLOOD) +/// Another vomit variant that causes you to get knocked down instead of just only getting a stun. Standard otherwise. +#define VOMIT_CATEGORY_KNOCKDOWN (VOMIT_CATEGORY_DEFAULT | MOB_VOMIT_KNOCKDOWN) /// Possible value of [/atom/movable/buckle_lying]. If set to a different (positive-or-zero) value than this, the buckling thing will force a lying angle on the buckled. #define NO_BUCKLE_LYING -1 diff --git a/code/__DEFINES/multiz.dm b/code/__DEFINES/multiz.dm index 9d167495fa88ef..370eaa8ba45938 100644 --- a/code/__DEFINES/multiz.dm +++ b/code/__DEFINES/multiz.dm @@ -1,4 +1,8 @@ /// Attempt to get the turf below the provided one according to Z traits -#define GET_TURF_BELOW(turf) ((!(turf) || !length(SSmapping.multiz_levels) || !SSmapping.multiz_levels[(turf).z][Z_LEVEL_DOWN]) ? null : get_step((turf), DOWN)) +#define GET_TURF_BELOW(turf) ( \ + (turf.turf_flags & RESERVATION_TURF) ? SSmapping.get_reservation_from_turf(turf)?.get_turf_below(turf) : \ + (!(turf) || !length(SSmapping.multiz_levels) || !SSmapping.multiz_levels[(turf).z][Z_LEVEL_DOWN]) ? null : get_step((turf), DOWN)) /// Attempt to get the turf above the provided one according to Z traits -#define GET_TURF_ABOVE(turf) ((!(turf) || !length(SSmapping.multiz_levels) || !SSmapping.multiz_levels[(turf).z][Z_LEVEL_UP]) ? null : get_step((turf), UP)) +#define GET_TURF_ABOVE(turf) ( \ + (turf.turf_flags & RESERVATION_TURF) ? SSmapping.get_reservation_from_turf(turf)?.get_turf_above(turf) : \ + (!(turf) || !length(SSmapping.multiz_levels) || !SSmapping.multiz_levels[(turf).z][Z_LEVEL_UP]) ? null : get_step((turf), UP)) diff --git a/code/__DEFINES/projectiles.dm b/code/__DEFINES/projectiles.dm index eec9472c2bfb9d..3bc745756aae35 100644 --- a/code/__DEFINES/projectiles.dm +++ b/code/__DEFINES/projectiles.dm @@ -60,6 +60,9 @@ /// For gunpoints, how many tiles around the target the shooter can roam without losing their shot #define GUNPOINT_SHOOTER_STRAY_RANGE 2 +/// A spark will be generated for each THIS amount of damage dealt to a robotic limb by a projectile. +#define PROJECTILE_DAMAGE_PER_ROBOTIC_SPARK 20 + //Designed for things that need precision trajectories like projectiles. //Don't use this for anything that you don't absolutely have to use this with (like projectiles!) because it isn't worth using a datum unless you need accuracy down to decimal places in pixels. diff --git a/code/__DEFINES/reagents.dm b/code/__DEFINES/reagents.dm index e874b68f02bd84..a6ba5c0ed38ae0 100644 --- a/code/__DEFINES/reagents.dm +++ b/code/__DEFINES/reagents.dm @@ -115,6 +115,8 @@ #define REAGENT_NO_RANDOM_RECIPE (1<<7) ///Does this reagent clean things? #define REAGENT_CLEANS (1<<8) +///Does this reagent affect wounds? Used to check if some procs should be ran. +#define REAGENT_AFFECTS_WOUNDS (1<<9) //Chemical reaction flags, for determining reaction specialties ///Convert into impure/pure on reaction completion diff --git a/code/__DEFINES/shuttles.dm b/code/__DEFINES/shuttles.dm index 3649bc4a6b079a..6f15ea65216386 100644 --- a/code/__DEFINES/shuttles.dm +++ b/code/__DEFINES/shuttles.dm @@ -63,6 +63,14 @@ #define ENGINE_COEFF_MAX 2 #define ENGINE_DEFAULT_MAXSPEED_ENGINES 5 +// Alert level related +#define ALERT_COEFF_AUTOEVAC_NORMAL 2.5 +#define ALERT_COEFF_GREEN 2 +#define ALERT_COEFF_BLUE 1 +#define ALERT_COEFF_RED 0.5 +#define ALERT_COEFF_AUTOEVAC_CRITICAL 0.4 +#define ALERT_COEFF_DELTA 0.25 + //Docking error flags #define DOCKING_SUCCESS 0 #define DOCKING_BLOCKED (1<<0) diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 4262472475a4e8..50b33eb4c75ef7 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -34,10 +34,9 @@ // Grouped effect sources, see also code/__DEFINES/traits.dm #define STASIS_MACHINE_EFFECT "stasis_machine" - #define STASIS_CHEMICAL_EFFECT "stasis_chemical" - #define STASIS_SHAPECHANGE_EFFECT "stasis_shapechange" +#define STASIS_ADMIN "stasis_admin" /// Causes the mob to become blind via the passed source #define become_blind(source) apply_status_effect(/datum/status_effect/grouped/blindness, source) diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index da2a1dfadc6d2f..2f452345ef9eab 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -326,6 +326,9 @@ #define SSMOBS_DT (SSmobs.wait/10) #define SSOBJ_DT (SSobj.wait/10) +// The change in the world's time from the subsystem's last fire in seconds. +#define DELTA_WORLD_TIME(ss) ((world.time - ss.last_fire) * 0.1) + /// The timer key used to know how long subsystem initialization takes #define SS_INIT_TIMER_KEY "ss_init" diff --git a/code/__DEFINES/supermatter.dm b/code/__DEFINES/supermatter.dm index ac7a1f67b292ef..bac35207fb537c 100644 --- a/code/__DEFINES/supermatter.dm +++ b/code/__DEFINES/supermatter.dm @@ -51,7 +51,10 @@ #define VORTEX_ANOMALY "vortex_anomaly" #define DIMENSIONAL_ANOMALY "dimensional_anomaly" -#define SUPERMATTER_COUNTDOWN_TIME (30 SECONDS) +/// How long it takes for the supermatter to delaminate after hitting 0 integrity +#define SUPERMATTER_COUNTDOWN_TIME (15 SECONDS) +/// How long it takes for the supermatter to delaminate after hitting 0 integrity if a sliver has been removed +#define SUPERMATTER_SLIVER_REMOVED_COUNTDOWN_TIME (5 SECONDS) ///to prevent accent sounds from layering #define SUPERMATTER_ACCENT_SOUND_MIN_COOLDOWN (2 SECONDS) @@ -60,6 +63,8 @@ #define SLIGHTLY_CHARGED_ZAP_ICON_STATE "sm_arc_supercharged" #define OVER_9000_ZAP_ICON_STATE "sm_arc_dbz_referance" //Witty I know +#define SUPERMATTER_DEFAULT_BULLET_ENERGY 2 + #define SUPERMATTER_CASCADE_PERCENT 80 /// The divisor scaling value for cubic power loss. diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index fa29b69bb02302..571f67f5b7d33c 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -1183,6 +1183,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define STATION_TRAIT_RADIOACTIVE_NEBULA "station_trait_radioactive_nebula" #define STATION_TRAIT_FORESTED "station_trait_forested" #define STATION_TRAIT_VENDING_SHORTAGE "station_trait_vending_shortage" +#define STATION_TRAIT_MEDBOT_MANIA "station_trait_medbot_mania" +#define STATION_TRAIT_LOANER_SHUTTLE "station_trait_loaner_shuttle" +#define STATION_TRAIT_SHUTTLE_SALE "station_trait_shuttle_sale" ///From the market_crash event #define MARKET_CRASH_EVENT_TRAIT "crashed_market_event" @@ -1193,6 +1196,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_MAGNETIC_ID_CARD "magnetic_id_card" /// ID cards with this trait have special appraisal text. #define TRAIT_TASTEFULLY_THICK_ID_CARD "impressive_very_nice" +/// things with this trait are treated as having no access in /obj/proc/check_access(obj/item) +#define TRAIT_ALWAYS_NO_ACCESS "alwaysnoaccess" /// Traits granted to items due to their chameleon properties. #define CHAMELEON_ITEM_TRAIT "chameleon_item_trait" diff --git a/code/__DEFINES/wires.dm b/code/__DEFINES/wires.dm index d4f0cb748e12a8..6f618ac8240326 100644 --- a/code/__DEFINES/wires.dm +++ b/code/__DEFINES/wires.dm @@ -9,6 +9,8 @@ #define WIRE_ACCEPT "Scan Success" #define WIRE_ACTIVATE "Activate" +#define WIRE_LAUNCH "Launch" +#define WIRE_SAFETIES "Safeties" #define WIRE_AGELIMIT "Age Limit" #define WIRE_AI "AI Connection" #define WIRE_ALARM "Alarm" diff --git a/code/__DEFINES/wounds.dm b/code/__DEFINES/wounds.dm index 5529ee1f0c6b12..19ccd843dd43ad 100644 --- a/code/__DEFINES/wounds.dm +++ b/code/__DEFINES/wounds.dm @@ -1,4 +1,3 @@ - // ~wound damage/rolling defines /// the cornerstone of the wound threshold system, your base wound roll for any attack is rand(1, damage^this), after armor reduces said damage. See [/obj/item/bodypart/proc/check_wounding] #define WOUND_DAMAGE_EXPONENT 1.4 @@ -13,6 +12,10 @@ /// set wound_bonus on an item or attack to this to disable checking wounding for the attack #define CANT_WOUND -100 +/// If there are multiple possible and valid wounds for the same type and severity, weight will be used to pick among them. See _wound_pregen_data.dm for more details +/// This is used in pick_weight, so use integers +#define WOUND_DEFAULT_WEIGHT 50 + // ~wound severities /// for jokey/meme wounds like stubbed toe, no standard messages/sounds or second winds #define WOUND_SEVERITY_TRIVIAL 0 @@ -22,16 +25,26 @@ /// outright dismemberment of limb #define WOUND_SEVERITY_LOSS 4 +/// A "chronological" list of wound severities, starting at the least severe. +GLOBAL_LIST_INIT(wound_severities_chronological, list( + "[WOUND_SEVERITY_TRIVIAL]", + "[WOUND_SEVERITY_MODERATE]", + "[WOUND_SEVERITY_SEVERE]", + "[WOUND_SEVERITY_CRITICAL]" +)) -// ~wound categories +// ~wound categories: wounding_types /// any brute weapon/attack that doesn't have sharpness. rolls for blunt bone wounds -#define WOUND_BLUNT 1 +#define WOUND_BLUNT "wound_blunt" /// any brute weapon/attack with sharpness = SHARP_EDGED. rolls for slash wounds -#define WOUND_SLASH 2 +#define WOUND_SLASH "wound_slash" /// any brute weapon/attack with sharpness = SHARP_POINTY. rolls for piercing wounds -#define WOUND_PIERCE 3 +#define WOUND_PIERCE "wound_pierce" /// any concentrated burn attack (lasers really). rolls for burning wounds -#define WOUND_BURN 4 +#define WOUND_BURN "wound_burn" + +/// Mainly a define used for wound_pregen_data, if a pregen data instance expects this, it will accept any and all wound types, even none at all +#define WOUND_ALL "wound_all" // ~determination second wind defines // How much determination reagent to add each time someone gains a new wound in [/datum/wound/proc/second_wind] @@ -45,6 +58,11 @@ /// While someone has determination in their system, their bleed rate is slightly reduced #define WOUND_DETERMINATION_BLEED_MOD 0.85 +/// Wounds using this competition mode will remove any wounds of a greater severity than itself in a random wound roll. In most cases, you dont want to use this. +#define WOUND_COMPETITION_OVERPOWER_GREATERS "wound_submit" +/// Wounds using this competition mode will remove any wounds of a lower severity than itself in a random wound roll. Used for ensuring the worse case scenario of a given injury_roll. +#define WOUND_COMPETITION_OVERPOWER_LESSERS "wound_dominate" + // ~biology defines // What kind of biology a limb has, and what wounds it can suffer /// Has absolutely fucking nothing, no wounds @@ -53,49 +71,221 @@ #define BIO_BONE (1<<0) /// Has flesh - allows the victim to suffer fleshy slash pierce and burn wounds #define BIO_FLESH (1<<1) -/// Self explanatory -#define BIO_FLESH_BONE (BIO_BONE | BIO_FLESH) /// Has metal - allows the victim to suffer robotic blunt and burn wounds #define BIO_METAL (1<<2) /// Is wired internally - allows the victim to suffer electrical wounds (robotic T1-T3 slash/pierce) #define BIO_WIRED (1<<3) -/// Robotic: shit like cyborg limbs, mostly -#define BIO_ROBOTIC (BIO_METAL|BIO_WIRED) /// Has bloodflow - can suffer bleeding wounds and can bleed #define BIO_BLOODED (1<<4) /// Is connected by a joint - can suffer T1 bone blunt wounds (dislocation) #define BIO_JOINTED (1<<5) -/// Standard humanoid - can suffer all flesh wounds, such as: T1-3 slash/pierce/burn/blunt. Can also bleed -#define BIO_STANDARD (BIO_FLESH_BONE|BIO_BLOODED) - -// "Where" a specific "bio" feature is within a given limb -// Exterior is hard shit, the last line, shit lines bones -// Interior is soft shit, targetted by slashes and pierces (usually), protects exterior -// Yes, it makes no sense -/// The given biostate is on the "exterior" of the limb - hard shit, protected by interior -#define BIO_EXTERIOR (1<<0) -/// The given biostate is on the "exterior" of the limb - soft shit, protects exterior -#define BIO_INTERIOR (1<<1) -#define BIO_EXTERIOR_AND_INTERIOR (BIO_EXTERIOR|BIO_INTERIOR) - -GLOBAL_LIST_INIT(bio_state_states, list( - "[BIO_WIRED]" = BIO_INTERIOR, - "[BIO_METAL]" = BIO_EXTERIOR, - "[BIO_FLESH]" = BIO_INTERIOR, - "[BIO_BONE]" = BIO_EXTERIOR, +/// Robotic - can suffer all metal/wired wounds, such as: UNIMPLEMENTED PLEASE UPDATE ONCE SYNTH WOUNDS 9/5/2023 ~Niko +#define BIO_ROBOTIC (BIO_METAL|BIO_WIRED) +/// Has flesh and bone - See BIO_BONE and BIO_FLESH +#define BIO_FLESH_BONE (BIO_BONE|BIO_FLESH) +/// Standard humanoid - can bleed and suffer all flesh/bone wounds, such as: T1-3 slash/pierce/burn/blunt, except dislocations. Think human heads/chests +#define BIO_STANDARD_UNJOINTED (BIO_FLESH_BONE|BIO_BLOODED) +/// Standard humanoid limbs - can bleed and suffer all flesh/bone wounds, such as: T1-3 slash/pierce/burn/blunt. Can also bleed, and be dislocated. Think human arms and legs +#define BIO_STANDARD_JOINTED (BIO_STANDARD_UNJOINTED|BIO_JOINTED) + +// "Where" a specific biostate is within a given limb +// Interior is hard shit, the last line, shit like bones +// Exterior is soft shit, targetted by slashes and pierces (usually), protects exterior +// A limb needs both mangled interior and exterior to be dismembered, but slash/pierce must mangle exterior to attack the interior +// Not having exterior/interior counts as mangled exterior/interior for the purposes of dismemberment +/// The given biostate is on the "interior" of the limb - hard shit, protected by exterior +#define ANATOMY_INTERIOR (1<<0) +/// The given biostate is on the "exterior" of the limb - soft shit, protects interior +#define ANATOMY_EXTERIOR (1<<1) +#define ANATOMY_EXTERIOR_AND_INTERIOR (ANATOMY_EXTERIOR|ANATOMY_INTERIOR) + +/// A assoc list of BIO_ define to EXTERIOR/INTERIOR defines. +/// This is where the interior/exterior state of a given biostate is set. +/// Note that not all biostates are guaranteed to be one of these - and in fact, many are not +/// IMPORTANT NOTE: All keys are stored as text and must be converted via text2num +GLOBAL_LIST_INIT(bio_state_anatomy, list( + "[BIO_WIRED]" = ANATOMY_EXTERIOR, + "[BIO_METAL]" = ANATOMY_INTERIOR, + "[BIO_FLESH]" = ANATOMY_EXTERIOR, + "[BIO_BONE]" = ANATOMY_INTERIOR, )) // Wound series // A "wound series" is just a family of wounds that logically follow eachother // Multiple wounds in a single series cannot be on a limb - the highest severity will always be prioritized, and lower ones will be skipped /// T1-T3 Bleeding slash wounds. Requires flesh. Can cause bleeding, but doesn't require it. From: slash.dm -#define WOUND_SERIES_FLESH_SLASH_BLEED 1 +#define WOUND_SERIES_FLESH_SLASH_BLEED "wound_series_flesh_slash_bled" /// T1-T3 Basic blunt wounds. T1 requires jointed, but 2-3 require bone. From: bone.dm -#define WOUND_SERIES_BONE_BLUNT_BASIC 2 +#define WOUND_SERIES_BONE_BLUNT_BASIC "wound_series_bone_blunt_basic" /// T1-T3 Basic burn wounds. Requires flesh. From: burns.dm -#define WOUND_SERIES_FLESH_BURN_BASIC 3 -/// T1-3 Bleeding puncture wounds. Requires flesh. Can cause bleeding, but doesn't require it. From: pierce.dm -#define WOUND_SERIES_FLESH_PUNCTURE_BLEED 4 +#define WOUND_SERIES_FLESH_BURN_BASIC "wound_series_flesh_burn_basic" +/// T1-T3 Bleeding puncture wounds. Requires flesh. Can cause bleeding, but doesn't require it. From: pierce.dm +#define WOUND_SERIES_FLESH_PUNCTURE_BLEED "wound_series_flesh_puncture_bleed" +/// Generic loss wounds. See loss.dm +#define WOUND_SERIES_LOSS_BASIC "wound_series_loss_basic" + +// SKYRAT EDIT ADDITION BEGIN - MUSCLE WOUNDS +// Have to put it here so I can use it in the global list of wound series +/// See muscle.dm +#define WOUND_SERIES_MUSCLE_DAMAGE "skyrat_wound_series_muscle_damage" // We use a super high number as realistically speaking TG will never increment to this amount of wound series +// SKYRAT EDIT ADDITION END + +/// A assoc list of (wound typepath -> wound_pregen_data instance). Every wound should have a pregen data. +GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate_wound_static_data()) + +/// Constructs [GLOB.all_wound_pregen_data] by iterating through a typecache of pregen data, ignoring abstract types, and instantiating the rest. +/proc/generate_wound_static_data() + RETURN_TYPE(/list/datum/wound_pregen_data) + + var/list/datum/wound_pregen_data/all_pregen_data = list() + + for (var/datum/wound_pregen_data/iterated_path as anything in typecacheof(path = /datum/wound_pregen_data, ignore_root_path = TRUE)) + if (initial(iterated_path.abstract)) + continue + + if (!isnull(all_pregen_data[initial(iterated_path.wound_path_to_generate)])) + stack_trace("pre-existing pregen data for [initial(iterated_path.wound_path_to_generate)] when [iterated_path] was being considered: [all_pregen_data[initial(iterated_path.wound_path_to_generate)]]. \ + this is definitely a bug, and is probably because one of the two pregen data have the wrong wound typepath defined. [iterated_path] will not be instantiated") + + continue + + var/datum/wound_pregen_data/pregen_data = new iterated_path + all_pregen_data[pregen_data.wound_path_to_generate] = pregen_data + + return all_pregen_data + +// A wound series "collection" is merely a way for us to track what is in what series, and what their types are. +// Without this, we have no centralized way to determine what type is in what series outside of iterating over every pregen data. + +/// A branching assoc list of (series -> list(severity -> list(typepath -> weight))). Allows you to say "I want a generic slash wound", +/// then "Of severity 2", and get a wound of that description - via get_corresponding_wound_type() +/// Series: A generic wound_series, such as WOUND_SERIES_BONE_BLUNT_BASIC +/// Severity: Any wounds held within this will be of this severity. +/// Typepath, Weight: Merely a pairing of a given typepath to its weight, held for convenience in pickweight. +GLOBAL_LIST_INIT(wound_series_collections, generate_wound_series_collection()) + +// Series -> severity -> type -> weight +/// Generates [wound_series_collections] by iterating through all pregen_data. Refer to the mentioned list for documentation +/proc/generate_wound_series_collection() + RETURN_TYPE(/list/datum/wound) + + var/list/datum/wound/wound_collection = list() + + for (var/datum/wound/wound_typepath as anything in typecacheof(/datum/wound, FALSE, TRUE)) + var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[wound_typepath] + if (!pregen_data) + continue + + if (pregen_data.abstract) + stack_trace("somehow, a abstract wound_pregen_data instance ([pregen_data.type]) was instantiated and made it to generate_wound_series_collection()! \ + i literally have no idea how! please fix this!") + continue + + var/series = pregen_data.wound_series + var/list/datum/wound/series_list = wound_collection[series] + if (isnull(series_list)) + wound_collection[series] = list() + series_list = wound_collection[series] + + var/severity = "[(initial(wound_typepath.severity))]" + var/list/datum/wound/severity_list = series_list[severity] + if (isnull(severity_list)) + series_list[severity] = list() + severity_list = series_list[severity] + + severity_list[wound_typepath] = pregen_data.weight + + return wound_collection + +/// A branching assoc list of (wounding_type -> list(wound_series)). +/// Allows for determining of which wound series are caused by what. +GLOBAL_LIST_INIT(wounding_types_to_series, list( + WOUND_BLUNT = list( + WOUND_SERIES_BONE_BLUNT_BASIC, + WOUND_SERIES_MUSCLE_DAMAGE, // SKYRAT EDIT -- MUSCLE WOUNDS + ), + WOUND_SLASH = list( + WOUND_SERIES_FLESH_SLASH_BLEED, + WOUND_SERIES_MUSCLE_DAMAGE, // SKYRAT EDIT -- MUSCLE WOUNDS + ), + WOUND_BURN = list( + WOUND_SERIES_FLESH_BURN_BASIC, + ), + WOUND_PUNCTURE = list( + WOUND_SERIES_FLESH_PUNCTURE_BLEED, + WOUND_SERIES_MUSCLE_DAMAGE, // SKYRAT EDIT -- MUSCLE WOUNDS + ), +)) + +/// Used in get_corresponding_wound_type(): Will pick the highest severity wound out of severity_min and severity_max +#define WOUND_PICK_HIGHEST_SEVERITY 1 +/// Used in get_corresponding_wound_type(): Will pick the lowest severity wound out of severity_min and severity_max +#define WOUND_PICK_LOWEST_SEVERITY 2 + +/** + * Searches through all wounds for any of proper type, series, and biostate, and then returns a single one via pickweight. + * Is able to discern between, say, a flesh slash wound, and a metallic slash wound, and will return the respective one for the provided limb. + * + * The severity_max and severity_pick_mode args mostly exist in case you want a wound in a series that may not have your ideal severity wound, as it lets you + * essentially set a "fallback", where if your ideal wound doesnt exist, it'll still return something, trying to get closest to your ideal severity. + * + * Generally speaking, if you want a critical/severe/moderate wound, you should set severity_min to WOUND_SEVERITY_MODERATE, severity_max to your ideal wound, + * and severity_pick_mode to WOUND_PICK_HIGHEST_SEVERITY - UNLESS you for some reason want the LOWEST severity, in which case you should set + * severity_max to the highest wound you're willing to tolerate, and severity_pick_mode to WOUND_PICK_LOWEST_SEVERITY. + * + * Args: + * * list/wounding_types: A list of wounding_types. Only wounds that accept these wound types will be considered. + * * obj/item/bodypart/part: The limb we are considering. Extremely important for biostates. + * * severity_min: The minimum wound severity we will search for. + * * severity_max = severity_min: The maximum wound severity we will search for. + * * severity_pick_mode = WOUND_PICK_HIGHEST_SEVERITY: The "pick mode" we will use when considering multiple wounds of acceptable severity. See the above defines. + * * random_roll = TRUE: If this is considered a "random" consideration. If true, only wounds that can be randomly generated will be considered. + * * duplicates_allowed = FALSE: If exact duplicates of a given wound on part are tolerated. Useful for simply getting a path and not instantiating. + * * care_about_existing_wounds = TRUE: If we iterate over wounds to see if any are above or at a given wounds severity, and disregard it if any are. Useful for simply getting a path and not instantiating. + * + * Returns: + * A randomly picked wound typepath meeting all the above criteria and being applicable to the part's biotype - or null if there were none. + */ +/proc/get_corresponding_wound_type(list/wounding_types, obj/item/bodypart/part, severity_min, severity_max = severity_min, severity_pick_mode = WOUND_PICK_HIGHEST_SEVERITY, random_roll = TRUE, duplicates_allowed = FALSE, care_about_existing_wounds = TRUE) + RETURN_TYPE(/datum/wound) // note that just because its set to return this doesnt mean its non-nullable + + var/list/wounding_type_list = list() + for (var/wounding_type as anything in wounding_types) + wounding_type_list += GLOB.wounding_types_to_series[wounding_type] + if (!length(wounding_type_list)) + return null + + var/list/datum/wound/paths_to_pick_from = list() + for (var/series as anything in shuffle(wounding_type_list)) + var/list/severity_list = GLOB.wound_series_collections[series] + if (!length(severity_list)) + continue + + var/picked_severity + for (var/severity_text as anything in shuffle(GLOB.wound_severities_chronological)) + var/severity = text2num(severity_text) + if (severity > severity_min || severity < severity_max) + continue + + if (isnull(picked_severity) || ((severity_pick_mode == WOUND_PICK_HIGHEST_SEVERITY && severity > picked_severity) || (severity_pick_mode == WOUND_PICK_LOWEST_SEVERITY && severity < picked_severity))) + picked_severity = severity + + var/list/wound_typepaths = severity_list["[picked_severity]"] + if (!length(wound_typepaths)) + continue + + for (var/datum/wound/iterated_path as anything in wound_typepaths) + var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[iterated_path] + if (pregen_data.can_be_applied_to(part, wounding_types, random_roll = random_roll, duplicates_allowed = duplicates_allowed, care_about_existing_wounds = care_about_existing_wounds)) + paths_to_pick_from[iterated_path] = wound_typepaths[iterated_path] + + return pick_weight(paths_to_pick_from) // we found our winners! + +/// Assoc list of biotype -> ideal scar file to be used and grab stuff from. +GLOBAL_LIST_INIT(biotypes_to_scar_file, list( + "[BIO_FLESH]" = FLESH_SCAR_FILE, + "[BIO_BONE]" = BONE_SCAR_FILE +)) // ~burn wound infection defines // Thresholds for infection for burn wounds, once infestation hits each threshold, things get steadily worse @@ -123,22 +313,25 @@ GLOBAL_LIST_INIT(bio_state_states, list( // ~mangling defines -// With the wounds pt. 2 update, general dismemberment now requires 2 things for a limb to be dismemberable (bone only creatures just need the second): -// 1. Flesh is mangled: A critical slash or pierce wound on that limb -// 2. Bone is mangled: At least a severe bone wound on that limb -// see [/obj/item/bodypart/proc/get_mangled_state] for more information +// With the wounds pt. 2 update, general dismemberment now requires 2 things for a limb to be dismemberable (exterior/bone only creatures just need the second): +// 1. Exterior is mangled: A critical slash or pierce wound on that limb +// 2. Interior is mangled: At least a severe bone wound on that limb +// Lack of exterior or interior count as mangled exterior/interior respectively +// see [/obj/item/bodypart/proc/get_mangled_state] for more information, as well as GLOB.bio_state_anatomy #define BODYPART_MANGLED_NONE NONE -#define BODYPART_MANGLED_BONE (1<<0) -#define BODYPART_MANGLED_FLESH (1<<1) -#define BODYPART_MANGLED_BOTH (BODYPART_MANGLED_BONE | BODYPART_MANGLED_FLESH) +#define BODYPART_MANGLED_INTERIOR (1<<0) +#define BODYPART_MANGLED_EXTERIOR (1<<1) +#define BODYPART_MANGLED_BOTH (BODYPART_MANGLED_INTERIOR | BODYPART_MANGLED_EXTERIOR) // ~wound flag defines -/// If having this wound counts as mangled flesh for dismemberment -#define MANGLES_FLESH (1<<0) -/// If having this wound counts as mangled bone for dismemberment -#define MANGLES_BONE (1<<1) +/// If having this wound counts as mangled exterior for dismemberment +#define MANGLES_EXTERIOR (1<<0) +/// If having this wound counts as mangled interior for dismemberment +#define MANGLES_INTERIOR (1<<1) /// If this wound marks the limb as being allowed to have gauze applied #define ACCEPTS_GAUZE (1<<2) +/// If this wound allows the victim to grasp it +#define CAN_BE_GRASPED (1<<3) // ~scar persistence defines // The following are the order placements for persistent scar save formats diff --git a/code/__DEFINES/~skyrat_defines/_organ_defines.dm b/code/__DEFINES/~skyrat_defines/_organ_defines.dm index 4571ca57af2e36..78bed9213e32fb 100644 --- a/code/__DEFINES/~skyrat_defines/_organ_defines.dm +++ b/code/__DEFINES/~skyrat_defines/_organ_defines.dm @@ -8,6 +8,9 @@ #define ORGAN_SLOT_BREASTS "breasts" #define ORGAN_SLOT_ANUS "anus" #define ORGAN_SLOT_NIPPLES "nipples" -#define ORGAN_ERP_LIST list(ORGAN_SLOT_PENIS, ORGAN_SLOT_WOMB, ORGAN_SLOT_VAGINA, ORGAN_SLOT_TESTICLES, ORGAN_SLOT_BREASTS, ORGAN_SLOT_ANUS, ORGAN_SLOT_NIPPLES) +#define ORGAN_SLOT_TAIL "tail" +#define ORGAN_SLOT_SLIT "slit" +#define ORGAN_SLOT_SHEATH "sheath" +#define ORGAN_ERP_LIST list(ORGAN_SLOT_PENIS, ORGAN_SLOT_WOMB, ORGAN_SLOT_VAGINA, ORGAN_SLOT_TESTICLES, ORGAN_SLOT_BREASTS, ORGAN_SLOT_ANUS, ORGAN_SLOT_NIPPLES, ORGAN_SLOT_TAIL, ORGAN_SLOT_SLIT, ORGAN_SLOT_SHEATH) #define ORGAN_SLOT_WINGS "wings" diff --git a/code/__DEFINES/~skyrat_defines/flavor_defines.dm b/code/__DEFINES/~skyrat_defines/flavor_defines.dm index ccc055f0da0eba..c7804a0d9560d4 100644 --- a/code/__DEFINES/~skyrat_defines/flavor_defines.dm +++ b/code/__DEFINES/~skyrat_defines/flavor_defines.dm @@ -7,3 +7,5 @@ /// The message displayed when someone received the View Crew Exploitables verb. #define VIEW_CREW_EXPLOITABLES_GAIN_TEXT "You now have access to the View Crew Exploitables verb, which shows all crew who currently have exploitable info and a link to view it!" +/// How many characters will be displayed in the temporary flavor text preview before we cut it off? +#define TEMPORARY_FLAVOR_PREVIEW_LIMIT 110 diff --git a/code/__DEFINES/~skyrat_defines/jobs.dm b/code/__DEFINES/~skyrat_defines/jobs.dm index 92af0760c94a8c..f00d0a72a662e8 100644 --- a/code/__DEFINES/~skyrat_defines/jobs.dm +++ b/code/__DEFINES/~skyrat_defines/jobs.dm @@ -4,6 +4,7 @@ #define JOB_UNAVAILABLE_SPECIES (JOB_UNAVAILABLE_QUIRK + 1) #define JOB_UNAVAILABLE_LANGUAGE (JOB_UNAVAILABLE_SPECIES + 1) #define JOB_UNAVAILABLE_FLAVOUR (JOB_UNAVAILABLE_LANGUAGE + 1) +#define JOB_UNAVAILABLE_AUGMENT (JOB_UNAVAILABLE_FLAVOUR + 1) #define SEC_RESTRICTED_QUIRKS "Blind" = TRUE, "Brain Tumor" = TRUE, "Deaf" = TRUE, "Paraplegic" = TRUE, "Hemiplegic" = TRUE, "Mute" = TRUE, "Foreigner" = TRUE, "Pacifist" = TRUE, "Chunky Fingers" = TRUE, "No Guns" = TRUE, "Illiterate" = TRUE, "Nerve Stapled" = TRUE #define HEAD_RESTRICTED_QUIRKS "Blind" = TRUE, "Deaf" = TRUE, "Mute" = TRUE, "Foreigner" = TRUE, "Chunky Fingers" = TRUE, "Brain Tumor" = TRUE, "Illiterate" = TRUE @@ -11,3 +12,6 @@ #define GUARD_RESTRICTED_QUIRKS "Blind" = TRUE, "Deaf" = TRUE, "Foreigner" = TRUE, "Pacifist" = TRUE, "Nerve Stapled" = TRUE #define RESTRICTED_QUIRKS_EXCEPTIONS list("Mute" = "Signer") + +#define HEAD_RESTRICTED_AUGMENTS /obj/item/bodypart/arm/left/self_destruct, /obj/item/bodypart/arm/right/self_destruct, /obj/item/bodypart/leg/left/self_destruct, /obj/item/bodypart/leg/right/self_destruct +#define SEC_RESTRICTED_AUGMENTS /obj/item/bodypart/arm/left/self_destruct, /obj/item/bodypart/arm/right/self_destruct, /obj/item/bodypart/leg/left/self_destruct, /obj/item/bodypart/leg/right/self_destruct diff --git a/code/__DEFINES/~skyrat_defines/medical_defines.dm b/code/__DEFINES/~skyrat_defines/medical_defines.dm index 098c801a1014c8..c32d18bbd4f981 100644 --- a/code/__DEFINES/~skyrat_defines/medical_defines.dm +++ b/code/__DEFINES/~skyrat_defines/medical_defines.dm @@ -2,9 +2,3 @@ #define DAMAGED_BODYPART_BONUS_WOUNDING_BONUS 30 //After this threshold we dont get any wounding bonuses form damaged bodyparts #define DAMAGED_BODYPART_BONUS_WOUNDING_THRESHOLD 0.5 //How much extra % of wounding dmg we'll have if a bodypart is damaged enough #define DAMAGED_BODYPART_BONUS_WOUNDING_COEFF 15 //This is multiplied by the sustained damage %. Keep in mind the % limit //Currently: 15/0.5=7.5 - -#define GAUZE_STAIN_BLOOD 1 -#define GAUZE_STAIN_PUS 2 - -#define COMSIG_BODYPART_SPLINTED "bodypart_splinted" // from /obj/item/bodypart/proc/apply_gauze(/obj/item/stack/gauze) -#define COMSIG_BODYPART_SPLINT_DESTROYED "bodypart_desplinted" // from [/obj/item/bodypart/proc/seep_gauze] when it runs out of absorption diff --git a/code/__DEFINES/~skyrat_defines/mobs.dm b/code/__DEFINES/~skyrat_defines/mobs.dm index dc32d8e3b661ac..d02f0d7108e3e7 100644 --- a/code/__DEFINES/~skyrat_defines/mobs.dm +++ b/code/__DEFINES/~skyrat_defines/mobs.dm @@ -6,9 +6,6 @@ #define HUMAN_MAXHEALTH MAX_LIVING_HEALTH * HUMAN_HEALTH_MODIFIER -/// Used for Nanite Slurry vomit. The mob will vomit a nanite puddle. -#define VOMIT_NANITE 3 - #define UNDERWEAR_HIDE_SOCKS (1<<0) #define UNDERWEAR_HIDE_SHIRT (1<<1) #define UNDERWEAR_HIDE_UNDIES (1<<2) diff --git a/code/__DEFINES/~skyrat_defines/wounds.dm b/code/__DEFINES/~skyrat_defines/wounds.dm index 4c29cd6a642226..f6a9275db8e244 100644 --- a/code/__DEFINES/~skyrat_defines/wounds.dm +++ b/code/__DEFINES/~skyrat_defines/wounds.dm @@ -1,5 +1,2 @@ -/// See muscle.dm -#define WOUND_SERIES_MUSCLE_DAMAGE 10000 // We use a super high number as realistically speaking TG will never increment to this amount of wound series - /// If this wound, when bandaged, will cause a splint overlay to generate rather than a bandage overlay. #define SPLINT_OVERLAY (1<<200) // we use a big number since tg realistically wouldnt go to it diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 4a4bc828cf8f2f..34512b95952120 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -17,6 +17,37 @@ ///Remove an untyped item to a list, taking care to handle list items by wrapping them in a list to remove the footgun #define UNTYPED_LIST_REMOVE(list, item) (list -= LIST_VALUE_WRAP_LISTS(item)) +/* + * ## Lazylists + * + * * What is a lazylist? + * + * True to its name a lazylist is a lazy instantiated list. + * It is a list that is only created when necessary (when it has elements) and is null when empty. + * + * * Why use a lazylist? + * + * Lazylists save memory - an empty list that is never used takes up more memory than just `null`. + * + * * When to use a lazylist? + * + * Lazylists are best used on hot types when making lists that are not always used. + * + * For example, if you were adding a list to all atoms that tracks the names of people who touched it, + * you would want to use a lazylist because most atoms will never be touched by anyone. + * + * * How do I use a lazylist? + * + * A lazylist is just a list you defined as `null` rather than `list()`. + * Then, you use the LAZY* macros to interact with it, which are essentially null-safe ways to interact with a list. + * + * Note that you probably should not be using these macros if your list is not a lazylist. + * This will obfuscate the code and make it a bit harder to read and debug. + * + * Generally speaking you shouldn't be checking if your lazylist is `null` yourself, the macros will do that for you. + * Remember that LAZYLEN (and by extension, length) will return 0 if the list is null. + */ + ///Initialize the lazylist #define LAZYINITLIST(L) if (!L) { L = list(); } ///If the provided list is empty, set it to null @@ -60,14 +91,14 @@ #define LAZYCLEARLIST(L) if(L) L.Cut() ///Returns the list if it's actually a valid list, otherwise will initialize it #define SANITIZE_LIST(L) ( islist(L) ? L : list() ) -#define reverseList(L) reverse_range(L.Copy()) - /// Performs an insertion on the given lazy list with the given key and value. If the value already exists, a new one will not be made. #define LAZYORASSOCLIST(lazy_list, key, value) \ LAZYINITLIST(lazy_list); \ LAZYINITLIST(lazy_list[key]); \ lazy_list[key] |= value; +#define reverseList(L) reverse_range(L.Copy()) + /// Passed into BINARY_INSERT to compare keys #define COMPARE_KEY __BIN_LIST[__BIN_MID] /// Passed into BINARY_INSERT to compare values diff --git a/code/__HELPERS/byond_status.dm b/code/__HELPERS/byond_status.dm deleted file mode 100644 index 1985080418c4d1..00000000000000 --- a/code/__HELPERS/byond_status.dm +++ /dev/null @@ -1,7 +0,0 @@ -/// Returns the debug status, including sleeping procs. -/// If this blame is older than a month, please revert the PR that added it. -/proc/byond_status() - if (world.system_type == UNIX) - return LIBCALL("libbyond_sleeping_procs.so", "get_status")() - else - return "byond_status is not supported on [world.system_type]" diff --git a/code/__HELPERS/hallucinations.dm b/code/__HELPERS/hallucinations.dm index 9deb27b90400a6..525114cea28bce 100644 --- a/code/__HELPERS/hallucinations.dm +++ b/code/__HELPERS/hallucinations.dm @@ -10,7 +10,7 @@ GLOBAL_LIST_EMPTY(all_ongoing_hallucinations) #define HALLUCINATION_ARGLIST 3 /// Biotypes which cannot hallucinate for balance and logic reasons (not code) -#define NO_HALLUCINATION_BIOTYPES (MOB_ROBOTIC|MOB_SPIRIT|MOB_EPIC) +#define NO_HALLUCINATION_BIOTYPES (MOB_ROBOTIC|MOB_SPIRIT|MOB_SPECIAL) // Macro wrapper for _cause_hallucination so we can cheat in named arguments, like AddComponent. /** diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 6bb147721fdfec..9c355ca4e72fea 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -110,7 +110,7 @@ "moth_wings" = pick(GLOB.moth_wings_list), "moth_antennae" = pick(GLOB.moth_antennae_list), "moth_markings" = pick(GLOB.moth_markings_list), - "tail_monkey" = "None", + "tail_monkey" = "Monkey", "pod_hair" = pick(GLOB.pod_hair_list), )) */ diff --git a/code/__HELPERS/mouse_control.dm b/code/__HELPERS/mouse_control.dm index 8896afb3ec6290..0c99e53e7a0cdc 100644 --- a/code/__HELPERS/mouse_control.dm +++ b/code/__HELPERS/mouse_control.dm @@ -1,18 +1,22 @@ -/proc/mouse_angle_from_client(client/client) - var/list/modifiers = params2list(client.mouseParams) - if(LAZYACCESS(modifiers, SCREEN_LOC) && client) - var/list/screen_loc_params = splittext(LAZYACCESS(modifiers, SCREEN_LOC), ",") - var/list/screen_loc_X = splittext(screen_loc_params[1],":") - var/list/screen_loc_Y = splittext(screen_loc_params[2],":") - var/x = (text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32) - var/y = (text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32) - var/list/screenview = getviewsize(client.view) - var/screenviewX = screenview[1] * world.icon_size - var/screenviewY = screenview[2] * world.icon_size - var/ox = round(screenviewX/2) - client.pixel_x //"origin" x - var/oy = round(screenviewY/2) - client.pixel_y //"origin" y - var/angle = SIMPLIFY_DEGREES(ATAN2(y - oy, x - ox)) - return angle +///Returns an angle in degrees relative to the position of the mouse and that of the client eye. +/proc/mouse_angle_from_client(client/client, params) + if(!client) + return + var/list/modifiers = params2list(params) + if(!LAZYACCESS(modifiers, SCREEN_LOC)) + return + var/list/screen_loc_params = splittext(LAZYACCESS(modifiers, SCREEN_LOC), ",") + var/list/screen_loc_X = splittext(screen_loc_params[1],":") + var/list/screen_loc_Y = splittext(screen_loc_params[2],":") + var/x = (text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32) + var/y = (text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32) + var/list/screenview = getviewsize(client.view) + var/screenviewX = screenview[1] * world.icon_size + var/screenviewY = screenview[2] * world.icon_size + var/ox = round(screenviewX/2) - client.pixel_x //"origin" x + var/oy = round(screenviewY/2) - client.pixel_y //"origin" y + var/angle = SIMPLIFY_DEGREES(ATAN2(y - oy, x - ox)) + return angle //Wow, specific name! /proc/mouse_absolute_datum_map_position_from_client(client/client) diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index 0d61a7efb13481..7c8fb23f4c3718 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -190,16 +190,27 @@ GLOBAL_LIST_INIT(achievements_unlocked, list()) if(!human_mob.hardcore_survival_score) ///no score no glory return FALSE - if(human_mob.mind && (human_mob.mind.special_role || length(human_mob.mind.antag_datums) > 0)) + if(human_mob.mind && (length(human_mob.mind.antag_datums) > 0)) for(var/datum/antagonist/antag_datums as anything in human_mob.mind.antag_datums) + if(!antag_datums.hardcore_random_bonus) //dont give bonusses to dumb stuff like revs or hypnos + continue if(initial(antag_datums.can_assign_self_objectives) && !antag_datums.can_assign_self_objectives) - return FALSE // You don't get a prize if you picked your own objective, you can't fail those + continue // You don't get a prize if you picked your own objective, you can't fail those + + var/greentexted = TRUE for(var/datum/objective/objective_datum as anything in antag_datums.objectives) if(!objective_datum.check_completion()) - return FALSE - player_client.give_award(/datum/award/score/hardcore_random, human_mob, round(human_mob.hardcore_survival_score * 2)) - else if(considered_escaped(human_mob.mind)) + greentexted = FALSE + break + if(greentexted) + var/score = round(human_mob.hardcore_survival_score * 2) + player_client.give_award(/datum/award/score/hardcore_random, human_mob, score) + log_admin("[player_client] gained [score] hardcore random points, including greentext bonus!") + return + + if(considered_escaped(human_mob.mind)) player_client.give_award(/datum/award/score/hardcore_random, human_mob, round(human_mob.hardcore_survival_score)) + log_admin("[player_client] gained [round(human_mob.hardcore_survival_score)] hardcore random points.") /datum/controller/subsystem/ticker/proc/declare_completion(was_forced = END_ROUND_AS_NORMAL) set waitfor = FALSE @@ -588,7 +599,7 @@ GLOBAL_LIST_INIT(achievements_unlocked, list()) if(!ishuman(i)) continue var/mob/living/carbon/human/human_player = i - if(!human_player.hardcore_survival_score || !human_player.onCentCom() || human_player.stat == DEAD) ///gotta escape nerd + if(!human_player.hardcore_survival_score || !considered_escaped(human_player.mind) || human_player.stat == DEAD) ///gotta escape nerd continue if(!human_player.mind) continue diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 80d9d3e9b09026..fad0deb0bd89f1 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -75,6 +75,7 @@ DEFINE_BITFIELD(turf_flags, list( "NOJAUNT" = NOJAUNT, "IS_SOLID" = IS_SOLID, "UNUSED_RESERVATION_TURF" = UNUSED_RESERVATION_TURF, + "RESERVATION_TURF" = RESERVATION_TURF, )) DEFINE_BITFIELD(car_traits, list( @@ -249,16 +250,16 @@ DEFINE_BITFIELD(mecha_flags, list( DEFINE_BITFIELD(mob_biotypes, list( "MOB_BEAST" = MOB_BEAST, "MOB_BUG" = MOB_BUG, - "MOB_EPIC" = MOB_EPIC, "MOB_HUMANOID" = MOB_HUMANOID, "MOB_MINERAL" = MOB_MINERAL, "MOB_ORGANIC" = MOB_ORGANIC, + "MOB_PLANT" = MOB_PLANT, "MOB_REPTILE" = MOB_REPTILE, "MOB_ROBOTIC" = MOB_ROBOTIC, + "MOB_SLIME" = MOB_SLIME, + "MOB_SPECIAL" = MOB_SPECIAL, "MOB_SPIRIT" = MOB_SPIRIT, "MOB_UNDEAD" = MOB_UNDEAD, - "MOB_PLANT" = MOB_PLANT, - "MOB_SLIME" = MOB_SLIME, )) DEFINE_BITFIELD(mob_respiration_type, list( @@ -552,3 +553,11 @@ DEFINE_BITFIELD(gun_flags, list( "TOY_FIREARM_OVERLAY" = TOY_FIREARM_OVERLAY, "TURRET_INCOMPATIBLE" = TURRET_INCOMPATIBLE, )) + +DEFINE_BITFIELD(bot_mode_flags, list( + "POWER_ON" = BOT_MODE_ON, + "AUTO_PATROL" = BOT_MODE_AUTOPATROL, + "REMOTE_CONTROL" = BOT_MODE_REMOTE_ENABLED, + "SAPIENCE_ALLOWED" = BOT_MODE_CAN_BE_SAPIENT, + "STARTS_POSSESSABLE" = BOT_MODE_ROUNDSTART_POSSESSION, +)) diff --git a/code/_globalvars/lists/mapping.dm b/code/_globalvars/lists/mapping.dm index be439d8217fc2c..8ac2f0d3ddfe5a 100644 --- a/code/_globalvars/lists/mapping.dm +++ b/code/_globalvars/lists/mapping.dm @@ -127,6 +127,9 @@ GLOBAL_LIST_EMPTY(emergencyresponseteamspawn) GLOBAL_LIST_EMPTY(ruin_landmarks) GLOBAL_LIST_EMPTY(bar_areas) +/// List of all the maps that have been cached for /proc/load_map +GLOBAL_LIST_EMPTY(cached_maps) + /// Away missions GLOBAL_LIST_EMPTY(vr_spawnpoints) diff --git a/code/_globalvars/phobias.dm b/code/_globalvars/phobias.dm index 309b31ceb37b9d..a6cb2dedb324f7 100644 --- a/code/_globalvars/phobias.dm +++ b/code/_globalvars/phobias.dm @@ -366,8 +366,10 @@ GLOBAL_LIST_INIT(phobia_objs, list( "heresy" = typecacheof(list( /obj/effect/floating_blade, /obj/effect/forcefield/cosmic_field, - /obj/effect/heretic_rune, + /obj/effect/forcefield/wizard/heretic, /obj/effect/heretic_influence, + /obj/effect/heretic_rune, + /obj/effect/knock_portal, /obj/effect/visible_heretic_influence, /obj/item/ammo_box/strilka310/lionhunter, /obj/item/ammo_casing/strilka310/lionhunter, @@ -379,6 +381,7 @@ GLOBAL_LIST_INIT(phobia_objs, list( /obj/item/codex_cicatrix, /obj/item/coin/eldritch, /obj/item/gun/ballistic/rifle/lionhunter, + /obj/item/heretic_lintel, /obj/item/melee/rune_carver, /obj/item/melee/sickly_blade, /obj/item/melee/touch_attack/mansus_fist, @@ -387,6 +390,7 @@ GLOBAL_LIST_INIT(phobia_objs, list( /obj/item/toy/reality_pierce, /obj/projectile/curse_hand, /obj/structure/destructible/eldritch_crucible, + /obj/structure/knock_tear, )), "insects" = typecacheof(list( /obj/item/clothing/mask/animal/small/bee, diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm index c4f8de8e63bc4f..edecd0ba78f649 100644 --- a/code/_onclick/drag_drop.dm +++ b/code/_onclick/drag_drop.dm @@ -96,9 +96,6 @@ while(selected_target[1]) Click(selected_target[1], location, control, selected_target[2]) sleep(delay) - active_mousedown_item = mob.canMobMousedown(object, location, params) - if(active_mousedown_item) - active_mousedown_item.onMouseDown(object, location, params, mob) /client/MouseUp(object, location, control, params) if(SEND_SIGNAL(src, COMSIG_CLIENT_MOUSEUP, object, location, control, params) & COMPONENT_CLIENT_MOUSEUP_INTERCEPT) @@ -106,9 +103,6 @@ if(mouse_up_icon) mouse_pointer_icon = mouse_up_icon selected_target[1] = null - if(active_mousedown_item) - active_mousedown_item.onMouseUp(object, location, params, mob) - active_mousedown_item = null /mob/proc/CanMobAutoclick(object, location, params) @@ -119,25 +113,8 @@ if(h) . = h.CanItemAutoclick(object, location, params) -/mob/proc/canMobMousedown(atom/object, location, params) - -/mob/living/carbon/canMobMousedown(atom/object, location, params) - var/obj/item/H = get_active_held_item() - if(H) - . = H.canItemMouseDown(object, location, params) - /obj/item/proc/CanItemAutoclick(object, location, params) -/obj/item/proc/canItemMouseDown(object, location, params) - if(canMouseDown) - return src - -/obj/item/proc/onMouseDown(object, location, params, mob) - return - -/obj/item/proc/onMouseUp(object, location, params, mob) - return - /atom/proc/IsAutoclickable() return TRUE @@ -165,14 +142,9 @@ if(selected_target[1] && over_object?.IsAutoclickable()) selected_target[1] = over_object selected_target[2] = params - if(active_mousedown_item) - active_mousedown_item.onMouseDrag(src_object, over_object, src_location, over_location, params, mob) SEND_SIGNAL(src, COMSIG_CLIENT_MOUSEDRAG, src_object, over_object, src_location, over_location, src_control, over_control, params) return ..() -/obj/item/proc/onMouseDrag(src_object, over_object, src_location, over_location, params, mob) - return - /client/MouseDrop(atom/src_object, atom/over_object, atom/src_location, atom/over_location, src_control, over_control, params) if (IS_WEAKREF_OF(src_object, middle_drag_atom_ref)) middragtime = 0 diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 9b85f6e464ce9b..fc5d0fe8d4e746 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -961,6 +961,10 @@ SUBSYSTEM_DEF(job) JobDebug("[debug_prefix] Error: [get_job_unavailable_error_message(JOB_UNAVAILABLE_FLAVOUR)], Player: [player][add_job_to_log ? ", Job: [possible_job]" : ""]") return JOB_UNAVAILABLE_FLAVOUR + if(possible_job.has_banned_augment(player.client.prefs)) + JobDebug("[debug_prefix] Error: [get_job_unavailable_error_message(JOB_UNAVAILABLE_AUGMENT)], Player: [player][add_job_to_log ? ", Job: [possible_job]" : ""]") + return JOB_UNAVAILABLE_AUGMENT + //SKYRAT EDIT END @@ -973,4 +977,27 @@ SUBSYSTEM_DEF(job) return JOB_AVAILABLE +/** + * Check if the station manifest has at least a certain amount of this staff type. + * If a matching head of staff is on the manifest, automatically passes (returns TRUE) + * + * Arguments: + * * crew_threshold - amount of crew to meet the requirement + * * jobs - a list of jobs that qualify the requirement + * * head_jobs - a list of head jobs that qualify the requirement + * +*/ +/datum/controller/subsystem/job/proc/has_minimum_jobs(crew_threshold, list/jobs = list(), list/head_jobs = list()) + var/employees = 0 + for(var/datum/record/crew/target in GLOB.manifest.general) + if(target.trim in head_jobs) + return TRUE + if(target.trim in jobs) + employees++ + + if(employees > crew_threshold) + return TRUE + + return FALSE + #undef VERY_LATE_ARRIVAL_TOAST_PROB diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index 396d736ac3f2c7..681658caa3b9e6 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -190,7 +190,7 @@ SUBSYSTEM_DEF(mapping) unused_turfs["[T.z]"] |= T var/area/old_area = T.loc old_area.turfs_to_uncontain += T - T.flags_1 |= UNUSED_RESERVATION_TURF + T.turf_flags = UNUSED_RESERVATION_TURF world_contents += T world_turf_contents += T packet.len-- @@ -309,6 +309,10 @@ SUBSYSTEM_DEF(mapping) returning += M qdel(T, TRUE) +/datum/controller/subsystem/mapping/proc/get_reservation_from_turf(turf/T) + RETURN_TYPE(/datum/turf_reservation) + return used_turfs[T] + /* Nuke threats, for making the blue tiles on the station go RED Used by the AI doomsday and the self-destruct nuke. */ @@ -695,26 +699,34 @@ GLOBAL_LIST_EMPTY(the_station_areas) num_of_res_levels++ return add_new_zlevel("Transit/Reserved #[num_of_res_levels]", list(ZTRAIT_RESERVED = TRUE)) -/datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override) - UNTIL((!z || reservation_ready["[z]"]) && !clearing_reserved_turfs) - var/datum/turf_reservation/reserve = new type - if(turf_type_override) +/// Requests a /datum/turf_reservation based on the given width, height, and z_size. You can specify a z_reservation to use a specific z level, or leave it null to use any z level. +/datum/controller/subsystem/mapping/proc/request_turf_block_reservation( + width, + height, + z_size = 1, + z_reservation = null, + reservation_type = /datum/turf_reservation, + turf_type_override = null, +) + UNTIL((!z_reservation || reservation_ready["[z_reservation]"]) && !clearing_reserved_turfs) + var/datum/turf_reservation/reserve = new reservation_type + if(!isnull(turf_type_override)) reserve.turf_type = turf_type_override - if(!z) + if(!z_reservation) for(var/i in levels_by_trait(ZTRAIT_RESERVED)) - if(reserve.Reserve(width, height, i)) + if(reserve.reserve(width, height, z_size, i)) return reserve //If we didn't return at this point, theres a good chance we ran out of room on the exisiting reserved z levels, so lets try a new one var/datum/space_level/newReserved = add_reservation_zlevel() initialize_reserved_level(newReserved.z_value) - if(reserve.Reserve(width, height, newReserved.z_value)) + if(reserve.reserve(width, height, z_size, newReserved.z_value)) return reserve else - if(!level_trait(z, ZTRAIT_RESERVED)) + if(!level_trait(z_reservation, ZTRAIT_RESERVED)) qdel(reserve) return else - if(reserve.Reserve(width, height, z)) + if(reserve.reserve(width, height, z_size, z_reservation)) return reserve QDEL_NULL(reserve) @@ -732,7 +744,7 @@ GLOBAL_LIST_EMPTY(the_station_areas) var/block = block(A, B) for(var/turf/T as anything in block) // No need to empty() these, because they just got created and are already /turf/open/space/basic. - T.flags_1 |= UNUSED_RESERVATION_TURF + T.turf_flags = UNUSED_RESERVATION_TURF CHECK_TICK // Gotta create these suckers if we've not done so already diff --git a/code/controllers/subsystem/processing/fishing.dm b/code/controllers/subsystem/processing/fishing.dm new file mode 100644 index 00000000000000..da10d3d631aeff --- /dev/null +++ b/code/controllers/subsystem/processing/fishing.dm @@ -0,0 +1,7 @@ +/** + * So far, only used by the fishing minigame. Feel free to rename it to something like veryfastprocess + * if you need one that fires 10 times a second + */ +PROCESSING_SUBSYSTEM_DEF(fishing) + name = "Fishing" + wait = 0.1 SECONDS diff --git a/code/controllers/subsystem/security_level.dm b/code/controllers/subsystem/security_level.dm index 9bd803602df24d..d4fb13d99889f8 100644 --- a/code/controllers/subsystem/security_level.dm +++ b/code/controllers/subsystem/security_level.dm @@ -41,8 +41,6 @@ SUBSYSTEM_DEF(security_level) announce_security_level(selected_level) // We want to announce BEFORE updating to the new level - var/old_shuttle_call_time_mod = current_security_level.shuttle_call_time_mod // Need this before we set the new one - SSsecurity_level.current_security_level = selected_level if(selected_level.looping_sound) @@ -52,9 +50,7 @@ SUBSYSTEM_DEF(security_level) can_fire = FALSE if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) // By god this is absolutely shit - old_shuttle_call_time_mod = 1 / old_shuttle_call_time_mod - SSshuttle.emergency.modTimer(old_shuttle_call_time_mod) - SSshuttle.emergency.modTimer(selected_level.shuttle_call_time_mod) + SSshuttle.emergency.alert_coeff_change(selected_level.shuttle_call_time_mod) SEND_SIGNAL(src, COMSIG_SECURITY_LEVEL_CHANGED, selected_level.number_level) SSnightshift.check_nightshift() diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 661c1de25744b3..0e5ed6ca685d48 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -266,8 +266,8 @@ SUBSYSTEM_DEF(shuttle) log_shuttle("[msg] Alive: [alive], Roundstart: [total], Threshold: [threshold]") emergency_no_recall = TRUE priority_announce("Catastrophic casualties detected: crisis shuttle protocols activated - jamming recall signals across all frequencies.") - if(emergency.timeLeft(1) > emergency_call_time * 0.4) - emergency.request(null, set_coefficient = 0.4) + if(emergency.timeLeft(1) > emergency_call_time * ALERT_COEFF_AUTOEVAC_CRITICAL) + emergency.request(null, set_coefficient = ALERT_COEFF_AUTOEVAC_CRITICAL) /datum/controller/subsystem/shuttle/proc/block_recall(lockout_timer) if(admin_emergency_no_recall) @@ -473,7 +473,7 @@ SUBSYSTEM_DEF(shuttle) if(callShuttle) if(EMERGENCY_IDLE_OR_RECALLED) - emergency.request(null, set_coefficient = 2.5) + emergency.request(null, set_coefficient = ALERT_COEFF_AUTOEVAC_NORMAL) log_shuttle("There is no means of calling the emergency shuttle anymore. Shuttle automatically called.") message_admins("All the communications consoles were destroyed and all AIs are inactive. Shuttle called.") @@ -617,12 +617,18 @@ SUBSYSTEM_DEF(shuttle) if(WEST) transit_path = /turf/open/space/transit/west - var/datum/turf_reservation/proposal = SSmapping.RequestBlockReservation(transit_width, transit_height, null, /datum/turf_reservation/transit, transit_path) + var/datum/turf_reservation/proposal = SSmapping.request_turf_block_reservation( + transit_width, + transit_height, + 1, + reservation_type = /datum/turf_reservation/transit, + turf_type_override = transit_path, + ) if(!istype(proposal)) return FALSE - var/turf/bottomleft = locate(proposal.bottom_left_coords[1], proposal.bottom_left_coords[2], proposal.bottom_left_coords[3]) + var/turf/bottomleft = proposal.bottom_left_turfs[1] // Then create a transit docking port in the middle var/coords = M.return_coords(0, 0, dock_dir) /* 0------2 @@ -893,10 +899,15 @@ SUBSYSTEM_DEF(shuttle) /datum/controller/subsystem/shuttle/proc/load_template(datum/map_template/shuttle/loading_template) . = FALSE // Load shuttle template to a fresh block reservation. - preview_reservation = SSmapping.RequestBlockReservation(loading_template.width, loading_template.height, type = /datum/turf_reservation/transit) + preview_reservation = SSmapping.request_turf_block_reservation( + loading_template.width, + loading_template.height, + 1, + reservation_type = /datum/turf_reservation/transit, + ) if(!preview_reservation) CRASH("failed to reserve an area for shuttle template loading") - var/turf/bottom_left = TURF_FROM_COORDS_LIST(preview_reservation.bottom_left_coords) + var/turf/bottom_left = preview_reservation.bottom_left_turfs[1] loading_template.load(bottom_left, centered = FALSE, register = FALSE) var/affected = loading_template.get_affected_turfs(bottom_left, centered=FALSE) diff --git a/code/datums/achievements/misc_achievements.dm b/code/datums/achievements/misc_achievements.dm index 8240ebbf62e71c..f83f2cde7b0a18 100644 --- a/code/datums/achievements/misc_achievements.dm +++ b/code/datums/achievements/misc_achievements.dm @@ -135,6 +135,12 @@ database_id = MEDAL_COSMOS_ASCENSION icon = "cosmicascend" +/datum/award/achievement/misc/knock_ascension + name = "Secrets behind the Spider Door" + desc = "You managed to open a gate into the mansus." + database_id = MEDAL_KNOCK_ASCENSION + icon = "knockascend" + /datum/award/achievement/misc/grand_ritual_finale name = "Archmage" desc = "Made a big impression on the station with your phenomenal cosmic power." diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm index 480aa68984d5a3..a27d881a4372db 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm @@ -1,5 +1,5 @@ /datum/ai_behavior/basic_melee_attack - action_cooldown = 2 SECONDS + action_cooldown = 0.2 SECONDS // We gotta check unfortunately often because we're in a race condition with nextmove behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION /datum/ai_behavior/basic_melee_attack/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) @@ -16,6 +16,11 @@ set_movement_target(controller, target) /datum/ai_behavior/basic_melee_attack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) + if (isliving(controller.pawn)) + var/mob/living/pawn = controller.pawn + if (world.time < pawn.next_move) + return + . = ..() var/mob/living/basic/basic_mob = controller.pawn //targetting datum will kill the action if not real anymore @@ -41,9 +46,6 @@ if(!succeeded) controller.clear_blackboard_key(target_key) -/datum/ai_behavior/basic_melee_attack/average_speed - action_cooldown = 1 SECONDS - /datum/ai_behavior/basic_ranged_attack action_cooldown = 0.6 SECONDS behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_MOVE_AND_PERFORM diff --git a/code/datums/ai/basic_mobs/basic_subtrees/maintain_distance.dm b/code/datums/ai/basic_mobs/basic_subtrees/maintain_distance.dm index b80a28836a0614..61631178163896 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/maintain_distance.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/maintain_distance.dm @@ -11,6 +11,9 @@ /datum/ai_planning_subtree/maintain_distance/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() + var/mob/living/living_pawn = controller.pawn + if(LAZYLEN(living_pawn.do_afters)) + return var/atom/target = controller.blackboard[target_key] if (!isliving(target) || !can_see(controller.pawn, target, view_distance)) return // Don't run away from cucumbers, they're not snakes diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_attack_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_attack_target.dm index 90379fcac0a715..ed45de512ac2f1 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/simple_attack_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_attack_target.dm @@ -9,9 +9,6 @@ controller.queue_behavior(melee_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) return SUBTREE_RETURN_FINISH_PLANNING //we are going into battle...no distractions. -/datum/ai_planning_subtree/basic_melee_attack_subtree/average_speed - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/average_speed - /datum/ai_planning_subtree/basic_ranged_attack_subtree operational_datums = list(/datum/component/ranged_attacks) var/datum/ai_behavior/basic_ranged_attack/ranged_attack_behavior = /datum/ai_behavior/basic_ranged_attack diff --git a/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm index 2d553fe4b2f77f..6133759183ded8 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm @@ -7,10 +7,15 @@ var/target_key = BB_BASIC_MOB_CURRENT_TARGET /// Blackboard key in which to store selected target's hiding place var/hiding_place_key = BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION + /// do we check for faction? + var/check_faction = FALSE /datum/ai_planning_subtree/target_retaliate/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() - controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list, BB_BASIC_MOB_RETALIATE_LIST, target_key, targetting_datum_key, hiding_place_key) + controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list, BB_BASIC_MOB_RETALIATE_LIST, target_key, targetting_datum_key, hiding_place_key, check_faction) + +/datum/ai_planning_subtree/target_retaliate/check_faction + check_faction = TRUE /// Places a mob which you can see and who has recently attacked you into some 'run away from this' AI keys /// Can use a different targetting datum than you use to select attack targets @@ -29,20 +34,28 @@ /// How far can we see stuff? var/vision_range = 9 -/datum/ai_behavior/target_from_retaliate_list/perform(seconds_per_tick, datum/ai_controller/controller, shitlist_key, target_key, targetting_datum_key, hiding_location_key) +/datum/ai_behavior/target_from_retaliate_list/perform(seconds_per_tick, datum/ai_controller/controller, shitlist_key, target_key, targetting_datum_key, hiding_location_key, check_faction) . = ..() var/mob/living/living_mob = controller.pawn var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key] if(!targetting_datum) CRASH("No target datum was supplied in the blackboard for [controller.pawn]") - var/list/enemies_list = controller.blackboard[shitlist_key] - if (!length(enemies_list)) - finish_action(controller, succeeded = FALSE) + + var/list/enemies_list = list() + + for(var/mob/living/potential_target as anything in controller.blackboard[shitlist_key]) + if(!targetting_datum.can_attack(living_mob, potential_target, vision_range, check_faction)) + continue + enemies_list += potential_target + + + if(!length(enemies_list)) + finish_action(controller, succeeded = FALSE, check_faction = check_faction) return if (controller.blackboard[target_key] in enemies_list) // Don't bother changing - finish_action(controller, succeeded = FALSE) + finish_action(controller, succeeded = TRUE, check_faction = check_faction) return var/atom/new_target = pick_final_target(controller, enemies_list) @@ -53,18 +66,15 @@ if(potential_hiding_location) //If they're hiding inside of something, we need to know so we can go for that instead initially. controller.set_blackboard_key(hiding_location_key, potential_hiding_location) - finish_action(controller, succeeded = TRUE) - -/// Returns true if this target is valid for attacking based on current conditions -/datum/ai_behavior/target_from_retaliate_list/proc/can_attack_target(mob/living/living_mob, atom/target, datum/targetting_datum/targetting_datum) - if (!target) - return FALSE - if (target == living_mob) - return FALSE - if (!can_see(living_mob, target, vision_range)) - return FALSE - return targetting_datum.can_attack(living_mob, target) + finish_action(controller, succeeded = TRUE, check_faction = check_faction) /// Returns the desired final target from the filtered list of enemies /datum/ai_behavior/target_from_retaliate_list/proc/pick_final_target(datum/ai_controller/controller, list/enemies_list) return pick(enemies_list) + + +/datum/ai_behavior/target_from_retaliate_list/finish_action(datum/ai_controller/controller, succeeded, target_key, check_faction) + . = ..() + if(check_faction) + return + controller.set_blackboard_key(BB_BASIC_MOB_SKIP_FACTION_CHECK, succeeded) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/use_mob_ability.dm b/code/datums/ai/basic_mobs/basic_subtrees/use_mob_ability.dm index 2c618e98e72b13..1d7bfd62ad777d 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/use_mob_ability.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/use_mob_ability.dm @@ -4,7 +4,7 @@ */ /datum/ai_planning_subtree/use_mob_ability /// Blackboard key for the ability - var/ability_key + var/ability_key = BB_GENERIC_ACTION /// Behaviour to perform using ability var/use_ability_behaviour = /datum/ai_behavior/use_mob_ability /// If true we terminate planning after trying to use the ability. diff --git a/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm b/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm index 643089bb5eae4e..43b974219e2640 100644 --- a/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm +++ b/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm @@ -20,7 +20,12 @@ ///Whether we care for seeing the target or not var/ignore_sight = FALSE -/datum/targetting_datum/basic/can_attack(mob/living/living_mob, atom/the_target, vision_range) +/datum/targetting_datum/basic/can_attack(mob/living/living_mob, atom/the_target, vision_range, check_faction = TRUE) + var/datum/ai_controller/basic_controller/our_controller = living_mob.ai_controller + + if(isnull(our_controller)) + return FALSE + if(isturf(the_target) || !the_target) // bail out on invalids return FALSE @@ -44,9 +49,13 @@ return FALSE if(isliving(the_target)) //Targeting vs living mobs - var/mob/living/L = the_target - if(faction_check(living_mob, L) || (L.stat > stat_attack)) + var/mob/living/living_target = the_target + var/bypass_faction_check = !check_faction || our_controller.blackboard[BB_BASIC_MOB_SKIP_FACTION_CHECK] + if(faction_check(living_mob, living_target) && !bypass_faction_check) return FALSE + if(living_target.stat > stat_attack) + return FALSE + return TRUE if(ismecha(the_target)) //Targeting vs mechas diff --git a/code/datums/ai/dog/dog_behaviors.dm b/code/datums/ai/dog/dog_behaviors.dm index 7bd0d5824a1119..6c9cb779bb3bd7 100644 --- a/code/datums/ai/dog/dog_behaviors.dm +++ b/code/datums/ai/dog/dog_behaviors.dm @@ -4,7 +4,6 @@ * Adds a floor to the melee damage of the dog, as most pet dogs don't actually have any melee strength */ /datum/ai_behavior/basic_melee_attack/dog - action_cooldown = 0.8 SECONDS behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_MOVE_AND_PERFORM required_distance = 3 diff --git a/code/datums/brain_damage/mild.dm b/code/datums/brain_damage/mild.dm index 5275ff97150731..52731852c11311 100644 --- a/code/datums/brain_damage/mild.dm +++ b/code/datums/brain_damage/mild.dm @@ -89,7 +89,7 @@ if(SPT_PROB(2.5, seconds_per_tick)) switch(rand(1,11)) if(1) - owner.vomit() + owner.vomit(VOMIT_CATEGORY_DEFAULT) if(2,3) owner.adjust_dizzy(20 SECONDS) if(4,5) diff --git a/code/datums/components/anti_magic.dm b/code/datums/components/anti_magic.dm index d3d53237777e1d..059bc2f787d41d 100644 --- a/code/datums/components/anti_magic.dm +++ b/code/datums/components/anti_magic.dm @@ -44,6 +44,7 @@ if(isitem(parent)) RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip)) RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop)) + RegisterSignals(parent, list(COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_ATOM), PROC_REF(on_attack)) else if(ismob(parent)) register_antimagic_signals(parent) else @@ -131,3 +132,7 @@ return COMPONENT_MAGIC_BLOCKED return NONE + +/datum/component/anti_magic/proc/on_attack(atom/movable/source, atom/target, mob/user) + SIGNAL_HANDLER + SEND_SIGNAL(target, COMSIG_ATOM_HOLYATTACK, source, user, antimagic_flags) diff --git a/code/datums/components/bakeable.dm b/code/datums/components/bakeable.dm index 1088205d3572d1..5aa60cd89a7096 100644 --- a/code/datums/components/bakeable.dm +++ b/code/datums/components/bakeable.dm @@ -66,11 +66,8 @@ /datum/component/bakeable/proc/finish_baking(atom/used_oven) var/atom/original_object = parent var/obj/item/plate/oven_tray/used_tray = original_object.loc - var/atom/baked_result = new bake_result( - used_tray, - /* starting_reagent_purity = */ null, - /* no_base_reagents = */ TRUE, - ) + var/atom/baked_result = new bake_result(used_tray) + baked_result.reagents.clear_reagents() original_object.reagents?.trans_to(baked_result, original_object.reagents.total_volume) if(who_baked_us) diff --git a/code/datums/components/basic_mob_attack_telegraph.dm b/code/datums/components/basic_mob_attack_telegraph.dm index 6467fbd7bbc21c..5473dbd0fa00f4 100644 --- a/code/datums/components/basic_mob_attack_telegraph.dm +++ b/code/datums/components/basic_mob_attack_telegraph.dm @@ -73,7 +73,7 @@ return ADD_TRAIT(source, TRAIT_BASIC_ATTACK_FORECAST, REF(src)) forget_target(target) - source.melee_attack(target) + source.melee_attack(target, ignore_cooldown = TRUE) // We already started the cooldown when we triggered the forecast /// The guy we're trying to attack moved, is he still in range? /datum/component/basic_mob_attack_telegraph/proc/target_moved(atom/target) diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm index 3a360c012f6cb4..0ed00e7dd94ef6 100644 --- a/code/datums/components/butchering.dm +++ b/code/datums/components/butchering.dm @@ -91,11 +91,8 @@ log_combat(user, H, "wounded via throat slitting", source) H.apply_damage(source.force, BRUTE, BODY_ZONE_HEAD, wound_bonus=CANT_WOUND) // easy tiger, we'll get to that in a sec var/obj/item/bodypart/slit_throat = H.get_bodypart(BODY_ZONE_HEAD) - if(slit_throat) - var/datum/wound/slash/flesh/critical/screaming_through_a_slit_throat = new - if (!screaming_through_a_slit_throat.apply_wound(slit_throat, wound_source = "throat slit")) - qdel(screaming_through_a_slit_throat) - H.apply_status_effect(/datum/status_effect/neck_slice) + if (H.cause_wound_of_type_and_severity(WOUND_SLASH, slit_throat, WOUND_SEVERITY_CRITICAL)) + H.apply_status_effect(/datum/status_effect/neck_slice) /** * Handles a user butchering a target diff --git a/code/datums/components/chasm.dm b/code/datums/components/chasm.dm index 12dff2b6aa9a42..fc93123921c0dd 100644 --- a/code/datums/components/chasm.dm +++ b/code/datums/components/chasm.dm @@ -29,6 +29,7 @@ /obj/effect/wisp, /obj/effect/ebeam, /obj/effect/fishing_lure, + /obj/effect/constructing_effect, )) /datum/component/chasm/Initialize(turf/target, mapload) @@ -235,13 +236,13 @@ GLOBAL_LIST_EMPTY(chasm_fallen_mobs) /obj/effect/abstract/chasm_storage/Entered(atom/movable/arrived) . = ..() - if (isliving(arrived)) + if(isliving(arrived)) RegisterSignal(arrived, COMSIG_LIVING_REVIVE, PROC_REF(on_revive)) GLOB.chasm_fallen_mobs += arrived /obj/effect/abstract/chasm_storage/Exited(atom/movable/gone) . = ..() - if (isliving(gone)) + if(isliving(gone)) UnregisterSignal(gone, COMSIG_LIVING_REVIVE) GLOB.chasm_fallen_mobs -= gone diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm index 1c46052140d21b..9f17b3d1d7e665 100644 --- a/code/datums/components/crafting/crafting.dm +++ b/code/datums/components/crafting/crafting.dm @@ -205,17 +205,13 @@ var/atom/movable/result if(ispath(recipe.result, /obj/item/stack)) result = new recipe.result(get_turf(crafter.loc), recipe.result_amount || 1) - else if (ispath(recipe.result, /obj/item/food)) - result = new recipe.result( - get_turf(crafter.loc), - /* starting_reagent_purity = */ null, - /* no_base_reagents = */ TRUE, - ) else result = new recipe.result(get_turf(crafter.loc)) if(result.atom_storage && recipe.delete_contents) for(var/obj/item/thing in result) qdel(thing) + if (IsEdible(result)) + result.reagents?.clear_reagents() result.CheckParts(parts, recipe) if(send_feedback) SSblackbox.record_feedback("tally", "object_crafted", 1, result.type) diff --git a/code/datums/components/crafting/furniture.dm b/code/datums/components/crafting/furniture.dm index bdd7372f17030d..6cfe215a4b7bd2 100644 --- a/code/datums/components/crafting/furniture.dm +++ b/code/datums/components/crafting/furniture.dm @@ -36,3 +36,14 @@ /obj/item/stack/sheet/mineral/silver = 2, ) category = CAT_FURNITURE + +/datum/crafting_recipe/surgery_tray + name = "Surgery Tray" + reqs = list( + /obj/item/stack/sheet/mineral/silver = 1, + /obj/item/stack/rods = 2 + ) + result = /obj/item/surgery_tray + tool_behaviors = list(TOOL_SCREWDRIVER) + category = CAT_FURNITURE + time = 5 SECONDS diff --git a/code/datums/components/crafting/ranged_weapon.dm b/code/datums/components/crafting/ranged_weapon.dm index ac7b6eb39affea..a8d631c6266e0e 100644 --- a/code/datums/components/crafting/ranged_weapon.dm +++ b/code/datums/components/crafting/ranged_weapon.dm @@ -45,14 +45,12 @@ /datum/crafting_recipe/advancedegun name = "Advanced Energy Gun" - tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) result = /obj/item/gun/energy/e_gun/nuclear reqs = list( /obj/item/gun/energy/e_gun = 1, - /obj/item/stack/cable_coil = 5, /obj/item/weaponcrafting/gunkit/nuclear = 1, ) - time = 20 SECONDS + time = 10 SECONDS category = CAT_WEAPON_RANGED /datum/crafting_recipe/advancedegun/New() @@ -61,14 +59,12 @@ /datum/crafting_recipe/tempgun name = "Temperature Gun" - tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) result = /obj/item/gun/energy/temperature reqs = list( - /obj/item/gun/energy/e_gun = 1, - /obj/item/stack/cable_coil = 5, + /obj/item/gun/energy/disabler = 1, /obj/item/weaponcrafting/gunkit/temperature = 1, ) - time = 20 SECONDS + time = 10 SECONDS category = CAT_WEAPON_RANGED /datum/crafting_recipe/tempgun/New() @@ -77,16 +73,14 @@ /datum/crafting_recipe/beam_rifle name = "Particle Acceleration Rifle" - tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) result = /obj/item/gun/energy/beam_rifle reqs = list( /obj/item/gun/energy/e_gun = 1, /obj/item/assembly/signaler/anomaly/flux = 1, /obj/item/assembly/signaler/anomaly/grav = 1, - /obj/item/stack/cable_coil = 5, /obj/item/weaponcrafting/gunkit/beam_rifle = 1, ) - time = 20 SECONDS + time = 10 SECONDS category = CAT_WEAPON_RANGED /datum/crafting_recipe/beam_rifle/New() @@ -95,27 +89,23 @@ /datum/crafting_recipe/ebow name = "Energy Crossbow" - tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) result = /obj/item/gun/energy/recharge/ebow/large reqs = list( /obj/item/gun/energy/recharge/kinetic_accelerator = 1, - /obj/item/stack/cable_coil = 5, /obj/item/weaponcrafting/gunkit/ebow = 1, /datum/reagent/uranium/radium = 15, ) - time = 20 SECONDS + time = 10 SECONDS category = CAT_WEAPON_RANGED /datum/crafting_recipe/xraylaser name = "X-ray Laser Gun" - tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) result = /obj/item/gun/energy/xray reqs = list( /obj/item/gun/energy/laser = 1, - /obj/item/stack/cable_coil = 5, /obj/item/weaponcrafting/gunkit/xray = 1, ) - time = 20 SECONDS + time = 10 SECONDS category = CAT_WEAPON_RANGED /datum/crafting_recipe/xraylaser/New() @@ -124,14 +114,12 @@ /datum/crafting_recipe/hellgun name = "Hellfire Laser Gun" - tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) result = /obj/item/gun/energy/laser/hellgun reqs = list( /obj/item/gun/energy/laser = 1, - /obj/item/stack/cable_coil = 5, /obj/item/weaponcrafting/gunkit/hellgun = 1, ) - time = 20 SECONDS + time = 10 SECONDS category = CAT_WEAPON_RANGED /datum/crafting_recipe/hellgun/New() @@ -140,14 +128,12 @@ /datum/crafting_recipe/ioncarbine name = "Ion Carbine" - tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) result = /obj/item/gun/energy/ionrifle/carbine reqs = list( /obj/item/gun/energy/laser = 1, - /obj/item/stack/cable_coil = 5, /obj/item/weaponcrafting/gunkit/ion = 1, ) - time = 20 SECONDS + time = 10 SECONDS category = CAT_WEAPON_RANGED /datum/crafting_recipe/ioncarbine/New() @@ -156,16 +142,14 @@ /datum/crafting_recipe/decloner name = "Biological Demolecularisor" - tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) result = /obj/item/gun/energy/decloner reqs = list( /obj/item/gun/energy/laser = 1, - /obj/item/stack/cable_coil = 5, /obj/item/weaponcrafting/gunkit/decloner = 1, /datum/reagent/baldium = 30, /datum/reagent/toxin/mutagen = 4, ) - time = 20 SECONDS + time = 10 SECONDS category = CAT_WEAPON_RANGED /datum/crafting_recipe/decloner/New() @@ -174,14 +158,12 @@ /datum/crafting_recipe/teslacannon name = "Tesla Cannon" - tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) result = /obj/item/gun/energy/tesla_cannon reqs = list( /obj/item/assembly/signaler/anomaly/flux = 1, - /obj/item/stack/cable_coil = 5, /obj/item/weaponcrafting/gunkit/tesla = 1, ) - time = 20 SECONDS + time = 10 SECONDS category = CAT_WEAPON_RANGED /datum/crafting_recipe/improvised_pneumatic_cannon //Pretty easy to obtain but diff --git a/code/datums/components/crafting/weapon_ammo.dm b/code/datums/components/crafting/weapon_ammo.dm index fd6993220ec969..206adbaefb1c4e 100644 --- a/code/datums/components/crafting/weapon_ammo.dm +++ b/code/datums/components/crafting/weapon_ammo.dm @@ -65,6 +65,7 @@ reqs = list( /obj/item/stack/sheet/iron = 2, /obj/item/stack/cable_coil = 1, + /obj/item/shard = 1, /datum/reagent/fuel = 10, ) tool_behaviors = list(TOOL_SCREWDRIVER) diff --git a/code/datums/components/embedded.dm b/code/datums/components/embedded.dm index 433784e845ea0f..f4d7b5d7369c80 100644 --- a/code/datums/components/embedded.dm +++ b/code/datums/components/embedded.dm @@ -93,7 +93,8 @@ if(harmful) victim.throw_alert(ALERT_EMBEDDED_OBJECT, /atom/movable/screen/alert/embeddedobject) playsound(victim,'sound/weapons/bladeslice.ogg', 40) - weapon.add_mob_blood(victim)//it embedded itself in you, of course it's bloody! + if (limb.can_bleed()) + weapon.add_mob_blood(victim)//it embedded itself in you, of course it's bloody! damage += weapon.w_class * impact_pain_mult victim.add_mood_event("embedded", /datum/mood_event/embedded) @@ -206,14 +207,18 @@ qdel(src) return if(harmful) - var/damage = weapon.w_class * remove_pain_mult - limb.receive_damage(brute=(1-pain_stam_pct) * damage, sharpness=SHARP_EDGED) //It hurts to rip it out, get surgery you dingus. unlike the others, this CAN wound + increase slash bloodflow - victim.adjustStaminaLoss(pain_stam_pct * damage) - victim.emote("scream") + damaging_removal(victim, I, limb) victim.visible_message(span_notice("[victim] successfully rips [weapon] [harmful ? "out" : "off"] of [victim.p_their()] [limb.plaintext_zone]!"), span_notice("You successfully remove [weapon] from your [limb.plaintext_zone].")) safeRemove(victim) +/// Proc that actually does the damage associated with ripping something out of yourself. Call this before safeRemove. +/datum/component/embedded/proc/damaging_removal(mob/living/carbon/victim, obj/item/removed, obj/item/bodypart/limb, ouch_multiplier = 1) + var/damage = weapon.w_class * remove_pain_mult * ouch_multiplier + limb.receive_damage(brute=(1-pain_stam_pct) * damage, sharpness=SHARP_EDGED) //It hurts to rip it out, get surgery you dingus. unlike the others, this CAN wound + increase slash bloodflow + victim.adjustStaminaLoss(pain_stam_pct * damage) + victim.emote("scream") + /// This proc handles the final step and actual removal of an embedded/stuck item from a carbon, whether or not it was actually removed safely. /// If you want the thing to go into someone's hands rather than the floor, pass them in to_hands /datum/component/embedded/proc/safeRemove(mob/to_hands) @@ -248,7 +253,7 @@ /datum/component/embedded/proc/checkTweeze(mob/living/carbon/victim, obj/item/possible_tweezers, mob/user) SIGNAL_HANDLER - if(!istype(victim) || possible_tweezers.tool_behaviour != TOOL_HEMOSTAT || user.zone_selected != limb.body_zone) + if(!istype(victim) || (possible_tweezers.tool_behaviour != TOOL_HEMOSTAT && possible_tweezers.tool_behaviour != TOOL_WIRECUTTER) || user.zone_selected != limb.body_zone) return if(weapon != limb.embedded_objects[1]) // just pluck the first one, since we can't easily coordinate with other embedded components affecting this limb who is highest priority @@ -265,18 +270,21 @@ /// The actual action for pulling out an embedded object with a hemostat /datum/component/embedded/proc/tweezePluck(obj/item/possible_tweezers, mob/user) var/mob/living/carbon/victim = parent - var/self_pluck = (user == victim) + // quality of the tool we're using + var/tweezer_speed = possible_tweezers.toolspeed + // is this an actual piece of medical equipment + var/tweezer_safe = (possible_tweezers.tool_behaviour == TOOL_HEMOSTAT) + var/pluck_time = rip_time * (weapon.w_class * 0.3) * (self_pluck ? 1.5 : 1) * tweezer_speed * (tweezer_safe ? 1 : 1.5) if(self_pluck) - user.visible_message(span_danger("[user] begins plucking [weapon] from [user.p_their()] [limb.plaintext_zone]"), span_notice("You start plucking [weapon] from your [limb.plaintext_zone]..."),\ + user.visible_message(span_danger("[user] begins plucking [weapon] from [user.p_their()] [limb.plaintext_zone] with [possible_tweezers]..."), span_notice("You start plucking [weapon] from your [limb.plaintext_zone] with [possible_tweezers]... (It will take [DisplayTimeText(pluck_time)].)"),\ vision_distance=COMBAT_MESSAGE_RANGE, ignored_mobs=victim) else - user.visible_message(span_danger("[user] begins plucking [weapon] from [victim]'s [limb.plaintext_zone]"),span_notice("You start plucking [weapon] from [victim]'s [limb.plaintext_zone]..."), \ + user.visible_message(span_danger("[user] begins plucking [weapon] from [victim]'s [limb.plaintext_zone] with [possible_tweezers]..."),span_notice("You start plucking [weapon] from [victim]'s [limb.plaintext_zone] with [possible_tweezers]... (It will take [DisplayTimeText(pluck_time)]."), \ vision_distance=COMBAT_MESSAGE_RANGE, ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] begins plucking [weapon] from your [limb.plaintext_zone]...")) + to_chat(victim, span_userdanger("[user] begins plucking [weapon] from your [limb.plaintext_zone] with [possible_tweezers]... (It will take [DisplayTimeText(pluck_time)].")) - var/pluck_time = 2.5 SECONDS * weapon.w_class * (self_pluck ? 2 : 1) if(!do_after(user, pluck_time, victim)) if(self_pluck) to_chat(user, span_danger("You fail to pluck [weapon] from your [limb.plaintext_zone].")) @@ -285,8 +293,11 @@ to_chat(victim, span_danger("[user] fails to pluck [weapon] from your [limb.plaintext_zone].")) return - to_chat(user, span_notice("You successfully pluck [weapon] from [victim]'s [limb.plaintext_zone].")) - to_chat(victim, span_notice("[user] plucks [weapon] from your [limb.plaintext_zone].")) + to_chat(user, span_notice("You successfully pluck [weapon] from [victim]'s [limb.plaintext_zone][tweezer_safe ? "." : ", but hurt [victim.p_them()] in the process."]")) + to_chat(victim, span_notice("[user] plucks [weapon] from your [limb.plaintext_zone][tweezer_safe ? "." : ", but it's not perfect."]")) + if(!tweezer_safe) + // sure it still hurts but it sucks less + damaging_removal(victim, weapon, limb, (0.4 * possible_tweezers.w_class)) safeRemove(user) /// Called when an object is ripped out of someone's body by magic or other abnormal means @@ -303,7 +314,7 @@ return var/damage = weapon.w_class * remove_pain_mult limb.receive_damage(brute=(1-pain_stam_pct) * damage * 1.5, sharpness=SHARP_EDGED) // Performs exit wounds and flings the user to the caster if nearby - limb.force_wound_upwards(/datum/wound/pierce/bleed/moderate) + victim.cause_wound_of_type_and_severity(WOUND_PIERCE, limb, WOUND_SEVERITY_MODERATE) victim.adjustStaminaLoss(pain_stam_pct * damage) playsound(get_turf(victim), 'sound/effects/wounds/blood2.ogg', 50, TRUE) diff --git a/code/datums/components/food/ghost_edible.dm b/code/datums/components/food/ghost_edible.dm new file mode 100644 index 00000000000000..25207800a7426f --- /dev/null +++ b/code/datums/components/food/ghost_edible.dm @@ -0,0 +1,59 @@ +/** + * Allows ghosts to eat this by orbiting it + * They do this by consuming the reagents in the object, so if it doesn't have any then it won't work + */ +/datum/component/ghost_edible + /// Amount of reagents which will be consumed by each bite + var/bite_consumption + /// Chance per ghost that a bite will be taken + var/bite_chance + /// Minimum size the food will display as before being deleted + var/minimum_scale + /// How many reagents this had on initialisation, used to figure out how eaten we are + var/initial_reagent_volume = 0 + +/datum/component/ghost_edible/Initialize(bite_consumption = 3, bite_chance = 20, minimum_scale = 0.6) + . = ..() + if (!isatom(parent)) + return COMPONENT_INCOMPATIBLE + var/atom/atom_parent = parent + if (isnull(atom_parent.reagents) || atom_parent.reagents.total_volume == 0) + return COMPONENT_INCOMPATIBLE + src.bite_consumption = bite_consumption + src.bite_chance = bite_chance + src.minimum_scale = minimum_scale + initial_reagent_volume = atom_parent.reagents.total_volume + notify_ghosts("[parent] is edible by ghosts!", source = parent, action = NOTIFY_ORBIT, header="Something Tasty!") + +/datum/component/ghost_edible/RegisterWithParent() + START_PROCESSING(SSdcs, src) + +/datum/component/ghost_edible/UnregisterFromParent() + STOP_PROCESSING(SSdcs, src) + +/datum/component/ghost_edible/Destroy(force, silent) + STOP_PROCESSING(SSdcs, src) + return ..() + +/datum/component/ghost_edible/process(seconds_per_tick) + var/atom/atom_parent = parent + // Ghosts can eat this burger + var/munch_chance = 0 + for(var/mob/dead/observer/ghost in atom_parent.orbiters?.orbiter_list) + munch_chance += bite_chance + if (munch_chance >= 100) + break + if (!prob(munch_chance)) + return + playsound(atom_parent.loc,'sound/items/eatfood.ogg', vol = rand(10,50), vary = TRUE) + atom_parent.reagents.remove_any(bite_consumption) + if (atom_parent.reagents.total_volume <= 0) + atom_parent.visible_message(span_notice("[atom_parent] disappears completely!")) + new /obj/item/ectoplasm(atom_parent.loc) + qdel(parent) + return + + var/final_transform = matrix().Scale(LERP(minimum_scale, 1, atom_parent.reagents.total_volume / initial_reagent_volume)) + var/animate_transform = matrix(final_transform).Scale(0.8) + animate(parent, transform = animate_transform, time = 0.1 SECONDS) + animate(transform = final_transform, time = 0.1 SECONDS) diff --git a/code/datums/components/food/golem_food.dm b/code/datums/components/food/golem_food.dm index d79fcabb11a20f..c2540f54cc1cb7 100644 --- a/code/datums/components/food/golem_food.dm +++ b/code/datums/components/food/golem_food.dm @@ -53,14 +53,12 @@ /// Creates our golem snack atom instance /datum/component/golem_food/proc/create_golem_snack(atom/source) - golem_snack = new( - /* loc = */ null, - /* starting_reagent_purity = */ null, - /* no_base_reagents = */ FALSE, - /* name = */ source.name, - /* consume_food = */ consume_on_eat, - /* food_buff = */ snack_type, - /* owner = */ parent, + golem_snack = new(null) + golem_snack.setup( + name = source.name, + consume_food = consume_on_eat, + food_buff = snack_type, + owner = parent, ) RegisterSignal(golem_snack, COMSIG_QDELETING, PROC_REF(on_food_destroyed)) @@ -90,21 +88,17 @@ /// Golem food buff to apply on consumption var/datum/golem_food_buff/food_buff -/obj/item/food/golem_food/Initialize( - mapload, - starting_reagent_purity, - no_base_reagents = FALSE, +/// Set up some properties based on a passed-in item that the golem will pretend to eat +/obj/item/food/golem_food/proc/setup( name, - consume_food, + consume_food = TRUE, datum/golem_food_buff/food_buff, atom/owner, ) - . = ..() src.name = name src.consume_food = consume_food src.food_buff = food_buff src.owner = owner - RegisterSignal(owner, COMSIG_QDELETING, PROC_REF(on_parent_destroyed)) /// Clean ourselves up if our parent dies diff --git a/code/datums/components/grillable.dm b/code/datums/components/grillable.dm index b43d45f7c7015a..f1fe80fe9fb536 100644 --- a/code/datums/components/grillable.dm +++ b/code/datums/components/grillable.dm @@ -104,16 +104,13 @@ grilled_result = new cook_result(original_object.loc, stack_parent.amount) else - grilled_result = new cook_result( - original_object.loc, - /* starting_reagent_purity = */ null, - /* no_base_reagents = */ TRUE, - ) + grilled_result = new cook_result(original_object.loc) if(original_object.custom_materials) grilled_result.set_custom_materials(original_object.custom_materials) - if(IS_EDIBLE(grilled_result)) + if(IsEdible(grilled_result)) BLACKBOX_LOG_FOOD_MADE(grilled_result.type) + grilled_result.reagents.clear_reagents() original_object.reagents?.trans_to(grilled_result, original_object.reagents.total_volume) SEND_SIGNAL(parent, COMSIG_ITEM_GRILLED, grilled_result) diff --git a/code/datums/components/itembound.dm b/code/datums/components/itembound.dm index ae29949961b8e8..f742c1233fd116 100644 --- a/code/datums/components/itembound.dm +++ b/code/datums/components/itembound.dm @@ -11,19 +11,39 @@ if(QDELETED(passed_container)) return containerref = WEAKREF(passed_container) + RegisterSignal(passed_container, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(on_examined)) move_tracker = new(parent, CALLBACK(src, PROC_REF(verify_containment))) + +/datum/component/itembound/RegisterWithParent() + . = ..() ADD_TRAIT(parent, TRAIT_INCAPACITATED, SMITE_TRAIT) + if (isliving(parent)) + var/mob/living/living_parent = parent + living_parent.apply_status_effect(/datum/status_effect/grouped/stasis, STASIS_ADMIN) + +/datum/component/itembound/UnregisterFromParent() + REMOVE_TRAIT(parent, TRAIT_INCAPACITATED, SMITE_TRAIT) + if (isliving(parent)) + var/mob/living/living_parent = parent + living_parent.remove_status_effect(/datum/status_effect/grouped/stasis, STASIS_ADMIN) + return ..() + +/datum/component/itembound/proc/on_examined(atom/source, mob/user, list/examine_list) + SIGNAL_HANDLER + examine_list += span_notice("If you hold it up to your ear, you can hear the screams of the damned.") /// Ensure that when we move, we still are in the container. If not in the container, remove all the traits. /datum/component/itembound/proc/verify_containment() var/atom/movable/container = containerref.resolve() if(!QDELETED(container) && container.contains(parent)) return - REMOVE_TRAIT(parent, TRAIT_INCAPACITATED, SMITE_TRAIT) qdel(src) /datum/component/itembound/Destroy(force, silent) + var/atom/movable/container = containerref?.resolve() + if (!QDELETED(container)) + UnregisterSignal(container, COMSIG_ATOM_EXAMINE_MORE) containerref = null QDEL_NULL(move_tracker) return ..() diff --git a/code/datums/components/material/remote_materials.dm b/code/datums/components/material/remote_materials.dm index c9677ecec440c8..17561581083140 100644 --- a/code/datums/components/material/remote_materials.dm +++ b/code/datums/components/material/remote_materials.dm @@ -145,16 +145,27 @@ handles linking back and forth. if(!check_z_level(M.buffer)) to_chat(user, span_warning("[parent] is too far away to get a connection signal!")) return COMPONENT_BLOCK_TOOL_ATTACK + + var/obj/machinery/ore_silo/new_silo = M.buffer + var/datum/component/material_container/new_container = new_silo.GetComponent(/datum/component/material_container) if (silo) silo.ore_connected_machines -= src silo.holds -= src silo.updateUsrDialog() else if (mat_container) + //transfer all mats to silo. whatever cannot be transfered is dumped out as sheets + if(mat_container.total_amount()) + for(var/datum/material/mat as anything in mat_container.materials) + var/mat_amount = mat_container.materials[mat] + if(!mat_amount || !new_container.has_space(mat_amount) || !new_container.can_hold_material(mat)) + continue + new_container.materials[mat] += mat_amount + mat_container.materials[mat] = 0 qdel(mat_container) - silo = M.buffer + silo = new_silo silo.ore_connected_machines += src silo.updateUsrDialog() - mat_container = silo.GetComponent(/datum/component/material_container) + mat_container = new_container RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, TYPE_PROC_REF(/datum/component/remote_materials, SiloAttackBy)) to_chat(user, span_notice("You connect [parent] to [silo] from the multitool's buffer.")) return COMPONENT_BLOCK_TOOL_ATTACK diff --git a/code/datums/components/pellet_cloud.dm b/code/datums/components/pellet_cloud.dm index 40381df8e86235..fbd32fe5e4fbc1 100644 --- a/code/datums/components/pellet_cloud.dm +++ b/code/datums/components/pellet_cloud.dm @@ -311,7 +311,7 @@ var/damage_dealt = wound_info_by_part[hit_part][CLOUD_POSITION_DAMAGE] var/w_bonus = wound_info_by_part[hit_part][CLOUD_POSITION_W_BONUS] var/bw_bonus = wound_info_by_part[hit_part][CLOUD_POSITION_BW_BONUS] - var/wound_type = (initial(P.damage_type) == BRUTE) ? WOUND_BLUNT : WOUND_BURN // sharpness is handled in the wound rolling + var/wounding_type = (initial(P.damage_type) == BRUTE) ? WOUND_BLUNT : WOUND_BURN // sharpness is handled in the wound rolling wound_info_by_part -= hit_part // technically this only checks armor worn the moment that all the pellets resolve rather than as each one hits you, @@ -324,7 +324,7 @@ armor_factor *= ARMOR_WEAKENED_MULTIPLIER damage_dealt *= max(0, 1 - armor_factor*0.01) - hit_part.painless_wound_roll(wound_type, damage_dealt, w_bonus, bw_bonus, initial(P.sharpness)) + hit_part.painless_wound_roll(wounding_type, damage_dealt, w_bonus, bw_bonus, initial(P.sharpness)) var/limb_hit_text = "" if(hit_part) diff --git a/code/datums/components/pet_commands/pet_commands_basic.dm b/code/datums/components/pet_commands/pet_commands_basic.dm index a07a94fff3fc47..ff29b8f37d2df4 100644 --- a/code/datums/components/pet_commands/pet_commands_basic.dm +++ b/code/datums/components/pet_commands/pet_commands_basic.dm @@ -111,7 +111,7 @@ pointed_reaction = "and growls" /// Balloon alert to display if providing an invalid target var/refuse_reaction = "shakes head" - /// Attack behaviour to use, generally you will want to override this to add some kind of cooldown + /// Attack behaviour to use var/attack_behaviour = /datum/ai_behavior/basic_melee_attack // Refuse to target things we can't target, chiefly other friends diff --git a/code/datums/components/ranged_attacks.dm b/code/datums/components/ranged_attacks.dm index aecaa2c1808627..f75d29a10f4549 100644 --- a/code/datums/components/ranged_attacks.dm +++ b/code/datums/components/ranged_attacks.dm @@ -66,6 +66,7 @@ /// Actually fire the damn thing /datum/component/ranged_attacks/proc/async_fire_ranged_attack(mob/living/basic/firer, atom/target, modifiers) + firer.face_atom(target) if(projectile_type) firer.fire_projectile(projectile_type, target, projectile_sound) SEND_SIGNAL(parent, COMSIG_BASICMOB_POST_ATTACK_RANGED, target, modifiers) diff --git a/code/datums/components/seclight_attachable.dm b/code/datums/components/seclight_attachable.dm index 56761cfd1bfb56..b3f36fe041ad0a 100644 --- a/code/datums/components/seclight_attachable.dm +++ b/code/datums/components/seclight_attachable.dm @@ -98,6 +98,7 @@ RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(on_parent_deleted)) + RegisterSignal(parent, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) /datum/component/seclite_attachable/UnregisterFromParent() UnregisterSignal(parent, list( @@ -156,12 +157,10 @@ if(!light) return FALSE - light.on = !light.on - light.update_brightness() - if(user) - user.balloon_alert(user, "[light.name] toggled [light.on ? "on":"off"]") - - playsound(light, 'sound/weapons/empty.ogg', 100, TRUE) + var/successful_toggle = light.toggle_light(user) + if(!successful_toggle) + return TRUE + user.balloon_alert(user, "[light.name] toggled [light.on ? "on":"off"]") update_light() return TRUE @@ -296,3 +295,9 @@ // Yes, this might mess with other icon state alterations, // but that's the downside of using icon states over overlays. source.icon_state = base_state + +/// Signal proc for [COMSIG_HIT_BY_SABOTEUR] that turns the light off for a few seconds. +/datum/component/seclite_attachable/proc/on_saboteur(datum/source, disrupt_duration) + SIGNAL_HANDLER + . = light.on_saboteur(source, disrupt_duration) + update_light() diff --git a/code/datums/components/spawner.dm b/code/datums/components/spawner.dm index abb931540992d3..3f660d5fcbdf69 100644 --- a/code/datums/components/spawner.dm +++ b/code/datums/components/spawner.dm @@ -38,6 +38,8 @@ /// Try to create a new mob /datum/component/spawner/proc/try_spawn_mob() + if(!length(spawn_types)) + return if(!COOLDOWN_FINISHED(src, spawn_delay)) return validate_references() diff --git a/code/datums/components/twohanded.dm b/code/datums/components/twohanded.dm index 3b015c953839d6..37df730821762e 100644 --- a/code/datums/components/twohanded.dm +++ b/code/datums/components/twohanded.dm @@ -63,7 +63,7 @@ return ..() // Inherit the new values passed to the component -/datum/component/two_handed/InheritComponent(datum/component/two_handed/new_comp, original, require_twohands, wieldsound, unwieldsound, \ +/datum/component/two_handed/InheritComponent(datum/component/two_handed/new_comp, original, require_twohands, wieldsound, unwieldsound, attacksound, \ force_multiplier, force_wielded, force_unwielded, icon_wielded, \ datum/callback/wield_callback, datum/callback/unwield_callback) if(!original) diff --git a/code/datums/components/wall_mounted.dm b/code/datums/components/wall_mounted.dm new file mode 100644 index 00000000000000..6164d39b001663 --- /dev/null +++ b/code/datums/components/wall_mounted.dm @@ -0,0 +1,78 @@ +// This element should be applied to wall-mounted machines/structures, so that if the wall it's "hanging" from is broken or deconstructed, the wall-hung structure will deconstruct. +/datum/component/wall_mounted + dupe_mode = COMPONENT_DUPE_ALLOWED + /// The wall our object is currently linked to. + var/turf/hanging_wall_turf + /// Callback to the parent's proc to call on the linked object when the wall disappear's or changes. + var/datum/callback/on_drop + +/datum/component/wall_mounted/Initialize(target_wall, on_drop_callback) + . = ..() + if(!isobj(parent)) + return COMPONENT_INCOMPATIBLE + if(!isturf(target_wall)) + return COMPONENT_INCOMPATIBLE + hanging_wall_turf = target_wall + on_drop = on_drop_callback + +/datum/component/wall_mounted/RegisterWithParent() + RegisterSignal(hanging_wall_turf, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(hanging_wall_turf, COMSIG_TURF_CHANGE, PROC_REF(drop_wallmount)) + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(drop_wallmount)) + RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(on_linked_destroyed)) + +/datum/component/wall_mounted/UnregisterFromParent() + UnregisterSignal(hanging_wall_turf, list(COMSIG_ATOM_EXAMINE, COMSIG_TURF_CHANGE)) + UnregisterSignal(parent, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED)) + hanging_wall_turf = null + +/** + * Basic reference handling if the hanging/linked object is destroyed first. + */ +/datum/component/wall_mounted/proc/on_linked_destroyed() + SIGNAL_HANDLER + if(!QDELING(src)) + qdel(src) + +/** + * When the wall is examined, explains that it's supporting the linked object. + */ +/datum/component/wall_mounted/proc/on_examine(datum/source, mob/user, list/examine_list) + SIGNAL_HANDLER + examine_list += span_notice("\The [hanging_wall_turf] is currently supporting [span_bold("[parent]")]. Deconstruction or excessive damage would cause it to [span_bold("fall to the ground")].") + +/** + * Handles the dropping of the linked object. This is done via deconstruction, as that should be the most sane way to handle it for most objects. + * Except for intercoms, which are handled by creating a new wallframe intercom, as they're apparently items. + */ +/datum/component/wall_mounted/proc/drop_wallmount() + SIGNAL_HANDLER + var/obj/hanging_parent = parent + + if(on_drop) + hanging_parent.visible_message(message = span_warning("\The [hanging_parent] falls off the wall!"), vision_distance = 5) + on_drop.Invoke(hanging_parent) + else + hanging_parent.visible_message(message = span_warning("\The [hanging_parent] falls apart!"), vision_distance = 5) + hanging_parent.deconstruct() + + if(!QDELING(src)) + qdel(src) //Well, we fell off the wall, so we're done here. +/** + * Checks object direction and then verifies if there's a wall in that direction. Finally, applies a wall_mounted component to the object. + * + * @param directional If TRUE, will use the direction of the object to determine the wall to attach to. If FALSE, will use the object's loc. + * @param custom_drop_callback If set, will use this callback instead of the default deconstruct callback. + */ +/obj/proc/find_and_hang_on_wall(directional = TRUE, custom_drop_callback) + if(istype(get_area(src), /area/shuttle)) + return FALSE //For now, we're going to keep the component off of shuttles to avoid the turf changing issue. We'll hit that later really; + var/turf/attachable_wall + if(directional) + attachable_wall = get_step(src, dir) + else + attachable_wall = loc ///Pull from the curent object loc + if(!iswallturf(attachable_wall)) + return FALSE//Nothing to latch onto, or not the right thing. + src.AddComponent(/datum/component/wall_mounted, attachable_wall, custom_drop_callback) + return TRUE diff --git a/code/datums/diseases/advance/symptoms/heal.dm b/code/datums/diseases/advance/symptoms/heal.dm index d9345d0107c7da..8754eb3b71d43b 100644 --- a/code/datums/diseases/advance/symptoms/heal.dm +++ b/code/datums/diseases/advance/symptoms/heal.dm @@ -75,7 +75,7 @@ /datum/symptom/heal/starlight/proc/CanTileHealDirectional(turf/turf_to_check, direction) if(direction == UP) - turf_to_check = turf_to_check.above() + turf_to_check = GET_TURF_ABOVE(turf_to_check) if(!turf_to_check) return STARLIGHT_CANNOT_HEAL var/area/area_to_check = get_area(turf_to_check) @@ -98,9 +98,9 @@ if(istransparentturf(turf_to_check) || istype(turf_to_check, /turf/open/openspace)) // Check above or below us if(direction == UP) - turf_to_check = turf_to_check.above() + turf_to_check = GET_TURF_ABOVE(turf_to_check) else - turf_to_check = turf_to_check.below() + turf_to_check = GET_TURF_BELOW(turf_to_check) // If we found a turf above or below us, // then we can rerun the loop on the newly found turf / area diff --git a/code/datums/diseases/advance/symptoms/vomit.dm b/code/datums/diseases/advance/symptoms/vomit.dm index 72558f69ba9131..ee695ffd5bcafd 100644 --- a/code/datums/diseases/advance/symptoms/vomit.dm +++ b/code/datums/diseases/advance/symptoms/vomit.dm @@ -53,11 +53,21 @@ and your disease can spread via people walking on vomit. else vomit(M) -/datum/symptom/vomit/proc/vomit(mob/living/carbon/M) +/datum/symptom/vomit/proc/vomit(mob/living/carbon/vomiter) + var/deductable_nutrition = 0 + var/constructed_flags = (MOB_VOMIT_MESSAGE | MOB_VOMIT_HARM) + var/type_of_vomit = /obj/effect/decal/cleanable/vomit/toxic if(vomit_nebula) - M.vomit(lost_nutrition = 10, blood = vomit_blood, vomit_type = VOMIT_NEBULA, stun = FALSE, distance = proj_vomit) + type_of_vomit = /obj/effect/decal/cleanable/vomit/nebula + deductable_nutrition = 10 else - M.vomit(lost_nutrition = 20, blood = vomit_blood, distance = proj_vomit) + constructed_flags |= MOB_VOMIT_STUN + deductable_nutrition = 20 + + if(vomit_blood) + constructed_flags |= MOB_VOMIT_BLOOD + + vomiter.vomit(vomit_flags = constructed_flags, vomit_type = type_of_vomit, lost_nutrition = deductable_nutrition, distance = proj_vomit) /datum/symptom/vomit/nebula name = "Nebula Vomiting" diff --git a/code/datums/diseases/chronic_illness.dm b/code/datums/diseases/chronic_illness.dm index f3c2285cd7e830..77c162d6d85c30 100644 --- a/code/datums/diseases/chronic_illness.dm +++ b/code/datums/diseases/chronic_illness.dm @@ -34,7 +34,7 @@ if(SPT_PROB(0.5, seconds_per_tick)) to_chat(affected_mob, span_danger("You feel a very sharp pain in your chest!")) if(prob(45)) - affected_mob.vomit(20,TRUE) + affected_mob.vomit(VOMIT_CATEGORY_BLOOD, lost_nutrition = 20) if(SPT_PROB(0.5, seconds_per_tick)) to_chat(affected_mob, span_userdanger("[pick("You feel your heart slowing...", "You relax and slow your heartbeat.")]")) affected_mob.adjustStaminaLoss(70, FALSE) @@ -49,7 +49,7 @@ if(SPT_PROB(1, seconds_per_tick)) to_chat(affected_mob, span_danger("You feel a gruesome pain in your chest!")) if(prob(75)) - affected_mob.vomit(45,TRUE) + affected_mob.vomit(VOMIT_CATEGORY_BLOOD, lost_nutrition = 45) if(SPT_PROB(1, seconds_per_tick)) affected_mob.adjustStaminaLoss(100, FALSE) affected_mob.visible_message(span_warning("[affected_mob] collapses!")) diff --git a/code/datums/diseases/death_sandwich_poisoning.dm b/code/datums/diseases/death_sandwich_poisoning.dm index 5d52ac7281c2eb..f865f4fb5be6ad 100644 --- a/code/datums/diseases/death_sandwich_poisoning.dm +++ b/code/datums/diseases/death_sandwich_poisoning.dm @@ -47,7 +47,7 @@ if(SPT_PROB(10, seconds_per_tick)) affected_mob.emote("gasp") if(SPT_PROB(2.5, seconds_per_tick)) - affected_mob.vomit(20, TRUE) + affected_mob.vomit(VOMIT_CATEGORY_BLOOD, lost_nutrition = 20) if(SPT_PROB(2.5, seconds_per_tick)) to_chat(affected_mob, span_danger("Your body feels hot!")) if(prob(60)) diff --git a/code/datums/diseases/heart_failure.dm b/code/datums/diseases/heart_failure.dm index 1a4f05bfb8a5eb..45d4e6672fb699 100644 --- a/code/datums/diseases/heart_failure.dm +++ b/code/datums/diseases/heart_failure.dm @@ -48,7 +48,7 @@ if(SPT_PROB(1.5, seconds_per_tick)) to_chat(affected_mob, span_danger("You feel a sharp pain in your chest!")) if(prob(25)) - affected_mob.vomit(95) + affected_mob.vomit(VOMIT_CATEGORY_DEFAULT, lost_nutrition = 95) affected_mob.emote("cough") affected_mob.Paralyze(40) affected_mob.losebreath += 4 diff --git a/code/datums/diseases/parasitic_infection.dm b/code/datums/diseases/parasitic_infection.dm index 8eb7f9f2b19e98..64bb59f01fd968 100644 --- a/code/datums/diseases/parasitic_infection.dm +++ b/code/datums/diseases/parasitic_infection.dm @@ -41,7 +41,7 @@ affected_mob.adjust_nutrition(-12) else to_chat(affected_mob, span_warning("You feel much, MUCH lighter!")) - affected_mob.vomit(20, TRUE) + affected_mob.vomit(VOMIT_CATEGORY_BLOOD, lost_nutrition = 20) // disease code already checks if the liver exists otherwise it is cured var/obj/item/organ/internal/liver/affected_liver = affected_mob.get_organ_slot(ORGAN_SLOT_LIVER) affected_liver.Remove(affected_mob) diff --git a/code/datums/diseases/tuberculosis.dm b/code/datums/diseases/tuberculosis.dm index 16ce69fc18166f..dd75ea7cc62c7b 100644 --- a/code/datums/diseases/tuberculosis.dm +++ b/code/datums/diseases/tuberculosis.dm @@ -51,7 +51,7 @@ to_chat(affected_mob, span_userdanger("You feel your mind relax and your thoughts drift!")) affected_mob.adjust_confusion_up_to(8 SECONDS, 100 SECONDS) if(SPT_PROB(5, seconds_per_tick)) - affected_mob.vomit(20) + affected_mob.vomit(VOMIT_CATEGORY_DEFAULT, lost_nutrition = 20) if(SPT_PROB(1.5, seconds_per_tick)) to_chat(affected_mob, span_warning("[pick("Your stomach silently rumbles...", "Your stomach seizes up and falls limp, muscles dead and lifeless.", "You could eat a crayon")]")) affected_mob.overeatduration = max(affected_mob.overeatduration - (200 SECONDS), 0) diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 8261718dc3c9de..5034a863f5619c 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -912,7 +912,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) var/list/elligible_organs = list() for(var/obj/item/organ/internal/internal_organ in organs) //make sure we dont get an implant or cavity item elligible_organs += internal_organ - vomit(20, TRUE) + vomit(VOMIT_CATEGORY_DEFAULT, lost_nutrition = 10) if(elligible_organs.len) var/obj/item/organ/O = pick(elligible_organs) O.Remove(src) diff --git a/code/datums/dog_fashion.dm b/code/datums/dog_fashion.dm index 84913c234bef07..c2154736cc0f05 100644 --- a/code/datums/dog_fashion.dm +++ b/code/datums/dog_fashion.dm @@ -236,3 +236,10 @@ speak = list() //they're very patient and focused on holding the butter on 'em emote_see = list("shakes a little.", "looks around.") emote_hear = list("licks a trickle of the butter up.", "smiles.") + +/datum/dog_fashion/head/eyepatch + name = "Punished %REAL_NAME%" + desc = "%REAL_NAME% has really been going through it today." + obj_icon_state = "eyepatch" + emote_hear = list("sighs gruffly.", "groans.") + emote_see = list("considers their own mortality.", "stares bleakly into the middle distance.", "ponders the horrors of warfare.") diff --git a/code/datums/elements/bombable_turf.dm b/code/datums/elements/bombable_turf.dm new file mode 100644 index 00000000000000..11a83c79340f90 --- /dev/null +++ b/code/datums/elements/bombable_turf.dm @@ -0,0 +1,45 @@ +/** + * Apply this to a turf (usually a wall) and it will be destroyed instantly by any explosion. + * Most walls can already be destroyed by explosions so this is largely for usually indestructible ones. + * For applying it in a map editor, use /obj/effect/mapping_helpers/bombable_wall + */ +/datum/element/bombable_turf + +/datum/element/bombable_turf/Attach(turf/target) + . = ..() + if(!isturf(target)) + return ELEMENT_INCOMPATIBLE + target.explosive_resistance = 1 + + RegisterSignal(target, COMSIG_ATOM_EX_ACT, PROC_REF(detonate)) + RegisterSignal(target, COMSIG_TURF_CHANGE, PROC_REF(turf_changed)) + RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_update_overlays)) + RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(on_examined)) + + target.update_appearance(UPDATE_OVERLAYS) + +/datum/element/bombable_turf/Detach(turf/source) + UnregisterSignal(source, list(COMSIG_ATOM_EX_ACT, COMSIG_TURF_CHANGE, COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_ATOM_EXAMINE)) + source.explosive_resistance = initial(source.explosive_resistance) + source.update_appearance(UPDATE_OVERLAYS) + return ..() + +/// If we get blowed up, move to the next turf +/datum/element/bombable_turf/proc/detonate(turf/source) + SIGNAL_HANDLER + source.ScrapeAway() + +/// If this turf becomes something else we either just went off or regardless don't want this any more +/datum/element/bombable_turf/proc/turf_changed(turf/source) + SIGNAL_HANDLER + Detach(source) + +/// Show a little crack on here +/datum/element/bombable_turf/proc/on_update_overlays(turf/source, list/overlays) + SIGNAL_HANDLER + overlays += mutable_appearance('icons/turf/overlays.dmi', "explodable", source.layer + 0.1) + +/// Show a little extra on examine +/datum/element/bombable_turf/proc/on_examined(turf/source, mob/user, list/examine_list) + SIGNAL_HANDLER + examine_list += span_notice("It seems to be slightly cracked...") diff --git a/code/datums/elements/can_barricade.dm b/code/datums/elements/can_barricade.dm index 49be7f5aafdfd2..175738be5f62ea 100644 --- a/code/datums/elements/can_barricade.dm +++ b/code/datums/elements/can_barricade.dm @@ -11,23 +11,18 @@ return ELEMENT_INCOMPATIBLE RegisterSignal(target, COMSIG_ATOM_ATTACKBY, PROC_REF(on_start_barricade)) - RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) target.flags_1 |= HAS_CONTEXTUAL_SCREENTIPS_1 RegisterSignal(target, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context_from_item)) /datum/element/can_barricade/Detach(atom/target) - UnregisterSignal(target, list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_EXAMINE, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM)) + UnregisterSignal(target, list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM)) // We don't remove HAS_CONTEXTUAL_SCREENTIPS_1, since there could be other stuff still hooked to it, // and being set without signals is not dangerous, just less performant. // A lot of things don't do this, perhaps make a proc that checks if any signals are still set, and if not, // remove the flag. return ..() -/datum/element/can_barricade/proc/on_examine(atom/source, mob/user, list/examine_texts) - SIGNAL_HANDLER - examine_texts += span_notice("This looks like it can be barricaded with planks of wood.") - /datum/element/can_barricade/proc/on_start_barricade(atom/source, obj/item/stack/sheet/mineral/wood/plank, mob/living/user, params) SIGNAL_HANDLER diff --git a/code/datums/elements/content_barfer.dm b/code/datums/elements/content_barfer.dm index 7e26d3f7753735..e30294bc08a7ff 100644 --- a/code/datums/elements/content_barfer.dm +++ b/code/datums/elements/content_barfer.dm @@ -4,9 +4,8 @@ * Used for morphs and bileworms! */ /datum/element/content_barfer - argument_hash_start_idx = 2 -/datum/element/content_barfer/Attach(datum/target, tally_string) +/datum/element/content_barfer/Attach(datum/target) . = ..() if(!isliving(target)) diff --git a/code/datums/elements/dryable.dm b/code/datums/elements/dryable.dm index 72e048b7908d33..c17547971b5179 100644 --- a/code/datums/elements/dryable.dm +++ b/code/datums/elements/dryable.dm @@ -38,11 +38,8 @@ return else if(istype(source, /obj/item/food) && ispath(dry_result, /obj/item/food)) var/obj/item/food/source_food = source - var/obj/item/food/resulting_food = new dry_result( - source.drop_location(), - /* starting_reagent_purity = */ null, - /* no_base_reagents = */ TRUE, - ) + var/obj/item/food/resulting_food = new dry_result(source.drop_location()) + resulting_food.reagents.clear_reagents() source_food.reagents.trans_to(resulting_food, source_food.reagents.total_volume) ADD_TRAIT(resulting_food, TRAIT_DRIED, ELEMENT_TRAIT(type)) qdel(source) diff --git a/code/datums/elements/embed.dm b/code/datums/elements/embed.dm index 0ba3a581d9a460..1bc70dc500fc4e 100644 --- a/code/datums/elements/embed.dm +++ b/code/datums/elements/embed.dm @@ -76,6 +76,9 @@ if(blocked || !istype(victim) || HAS_TRAIT(victim, TRAIT_PIERCEIMMUNE)) return FALSE + + if(victim.status_flags & GODMODE) + return FALSE var/flying_speed = throwingdatum?.speed || weapon.throw_speed diff --git a/code/datums/elements/food/microwavable.dm b/code/datums/elements/food/microwavable.dm index 1a177b03ab35b0..3ad3e272d345dd 100644 --- a/code/datums/elements/food/microwavable.dm +++ b/code/datums/elements/food/microwavable.dm @@ -36,11 +36,7 @@ var/obj/item/stack/stack_source = source result = new result_typepath(result_loc, stack_source.amount) else - result = new result_typepath( - result_loc, - /* starting_reagent_purity = */ null, - /* no_base_reagents = */ TRUE, - ) + result = new result_typepath(result_loc) var/efficiency = istype(used_microwave) ? used_microwave.efficiency : 1 SEND_SIGNAL(result, COMSIG_ITEM_MICROWAVE_COOKED, source, efficiency) @@ -48,7 +44,7 @@ if(IS_EDIBLE(result)) if(microwaver && microwaver.mind) ADD_TRAIT(result, TRAIT_FOOD_CHEF_MADE, REF(microwaver.mind)) - + result.reagents.clear_reagents() source.reagents?.trans_to(result, source.reagents.total_volume) BLACKBOX_LOG_FOOD_MADE(result.type) diff --git a/code/datums/elements/kneecapping.dm b/code/datums/elements/kneecapping.dm index 217c11d4361dad..340938c430c35d 100644 --- a/code/datums/elements/kneecapping.dm +++ b/code/datums/elements/kneecapping.dm @@ -80,9 +80,11 @@ if(do_after(attacker, 3 SECONDS, target, interaction_key = weapon)) attacker.visible_message(span_warning("[attacker] swings [attacker.p_their()] [weapon] at [target]'s kneecaps!"), span_danger("You swing \the [weapon] at [target]'s kneecaps!")) - var/datum/wound/blunt/bone/severe/severe_wound_type = /datum/wound/blunt/bone/severe - var/datum/wound/blunt/bone/critical/critical_wound_type = /datum/wound/blunt/bone/critical - leg.receive_damage(brute = weapon.force, wound_bonus = rand(initial(severe_wound_type.threshold_minimum), initial(critical_wound_type.threshold_minimum) + 10), damage_source = "kneecapping") + + var/min_wound = leg.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_SEVERE, return_value_if_no_wound = 30, wound_source = weapon) + var/max_wound = leg.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_CRITICAL, return_value_if_no_wound = 50, wound_source = weapon) + + leg.receive_damage(brute = weapon.force, wound_bonus = rand(min_wound, max_wound + 10), damage_source = "kneecapping") target.emote("scream") log_combat(attacker, target, "broke the kneecaps of", weapon) target.update_damage_overlays() diff --git a/code/datums/elements/light_eater.dm b/code/datums/elements/light_eater.dm index f60a922b9d7059..b4f7cf1042f3d4 100644 --- a/code/datums/elements/light_eater.dm +++ b/code/datums/elements/light_eater.dm @@ -83,6 +83,9 @@ * - [eater][/datum]: The light eater eating the morsel. This is the datum that the element is attached to that started this chain. */ /datum/element/light_eater/proc/devour(atom/morsel, datum/eater) + var/static/list/undevourable = typecacheof(list(/turf/open/space)) + if(is_type_in_typecache(morsel, undevourable)) + return FALSE if(morsel.light_power <= 0 || morsel.light_range <= 0 || !morsel.light_on) return FALSE if(SEND_SIGNAL(morsel, COMSIG_LIGHT_EATER_ACT, eater) & COMPONENT_BLOCK_LIGHT_EATER) diff --git a/code/datums/elements/mob_grabber.dm b/code/datums/elements/mob_grabber.dm new file mode 100644 index 00000000000000..a85c5dc48b25ab --- /dev/null +++ b/code/datums/elements/mob_grabber.dm @@ -0,0 +1,30 @@ +/// Grab onto mobs we attack +/datum/element/mob_grabber + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 2 + /// What state must the mob be in to be grabbed? + var/minimum_stat + /// If someone else is already grabbing this, will we take it? + var/steal_from_others + +/datum/element/mob_grabber/Attach(datum/target, minimum_stat = SOFT_CRIT, steal_from_others = TRUE) + . = ..() + if (!isliving(target)) + return ELEMENT_INCOMPATIBLE + src.minimum_stat = minimum_stat + src.steal_from_others = steal_from_others + RegisterSignals(target, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET), PROC_REF(grab_mob)) + +/datum/element/mob_grabber/Detach(datum/source) + UnregisterSignal(source, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)) + . = ..() + +/// Try and grab something we attacked +/datum/element/mob_grabber/proc/grab_mob(mob/living/source, mob/living/target) + SIGNAL_HANDLER + if (!isliving(target) || !source.Adjacent(target) || target.stat < minimum_stat) + return + var/atom/currently_pulled = target.pulledby + if (!isnull(currently_pulled) && (!steal_from_others || currently_pulled == source)) + return + INVOKE_ASYNC(target, TYPE_PROC_REF(/mob/living, grabbedby), source) diff --git a/code/datums/elements/openspace_item_click_handler.dm b/code/datums/elements/openspace_item_click_handler.dm index 43c7a60d1efb5e..c9de01f381cd91 100644 --- a/code/datums/elements/openspace_item_click_handler.dm +++ b/code/datums/elements/openspace_item_click_handler.dm @@ -21,7 +21,7 @@ return var/turf/checked_turf = get_turf(target) while(!isnull(checked_turf)) - checked_turf = checked_turf.above() + checked_turf = GET_TURF_ABOVE(checked_turf) if(checked_turf?.z == user.z) INVOKE_ASYNC(source, TYPE_PROC_REF(/obj/item, handle_openspace_click), checked_turf, user, user.CanReach(checked_turf, source), click_parameters) break diff --git a/code/datums/elements/turf_transparency.dm b/code/datums/elements/turf_transparency.dm index ab3a17dc40d51a..b050dd0866f0e0 100644 --- a/code/datums/elements/turf_transparency.dm +++ b/code/datums/elements/turf_transparency.dm @@ -103,7 +103,7 @@ GLOBAL_LIST_EMPTY(pillars_by_z) if(!holding) return - var/turf/visual_target = to_display.above() + var/turf/visual_target = GET_TURF_ABOVE(to_display) /// Basically, if we used to be under a non transparent turf, but are no longer in that position /// Then we add to the transparent turf we're now under, and nuke the old object if(!istransparentturf(visual_target)) @@ -120,7 +120,7 @@ GLOBAL_LIST_EMPTY(pillars_by_z) turf_sources[to_display] = sources sources |= source - var/turf/visual_target = to_display.above() + var/turf/visual_target = GET_TURF_ABOVE(to_display) if(istransparentturf(visual_target) || isopenspaceturf(visual_target)) visual_target.vis_contents += to_display else @@ -142,7 +142,7 @@ GLOBAL_LIST_EMPTY(pillars_by_z) if(holding) qdel(holding) else - var/turf/visual_target = to_hide.above() + var/turf/visual_target = GET_TURF_ABOVE(to_hide) visual_target.vis_contents -= to_hide if(!length(turf_sources) && !QDELETED(src)) @@ -201,7 +201,7 @@ GLOBAL_LIST_EMPTY(pillars_by_z) ///Updates the viscontents or underlays below this tile. /datum/element/turf_z_transparency/proc/update_multi_z(turf/our_turf) - var/turf/below_turf = our_turf.below() + var/turf/below_turf = GET_TURF_BELOW(our_turf) if(below_turf) // If we actually have something below us, display it. for(var/turf/partner in range(1, below_turf)) // We use our z here to ensure the pillar is actually on our level @@ -228,7 +228,7 @@ GLOBAL_LIST_EMPTY(pillars_by_z) return TRUE /datum/element/turf_z_transparency/proc/clear_multiz(turf/our_turf) - var/turf/below_turf = our_turf.below() + var/turf/below_turf = GET_TURF_BELOW(our_turf) if(below_turf) // If we actually have something below us, we need to clear ourselves from it for(var/turf/partner in range(1, below_turf)) // We use our z here to ensure the pillar is actually on our level diff --git a/code/datums/elements/uplink_reimburse.dm b/code/datums/elements/uplink_reimburse.dm index 5387f245d8c347..3ff182ec2314dd 100644 --- a/code/datums/elements/uplink_reimburse.dm +++ b/code/datums/elements/uplink_reimburse.dm @@ -1,5 +1,5 @@ /** - * Uplinik Reimburse element. + * Uplink Reimburse element. * When element is applied onto items, it allows them to be reimbursed if an user pokes an item with a uplink component with them. * * Element is only compatible with items. @@ -21,9 +21,11 @@ RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) RegisterSignal(target, COMSIG_ITEM_ATTEMPT_TC_REIMBURSE, PROC_REF(reimburse)) - + RegisterSignal(target,COMSIG_TRAITOR_ITEM_USED(target.type), PROC_REF(used)) + /datum/element/uplink_reimburse/Detach(datum/target) - UnregisterSignal(target, list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_EXAMINE)) + UnregisterSignal(target, list(COMSIG_ATOM_EXAMINE, COMSIG_TRAITOR_ITEM_USED(target.type), COMSIG_ITEM_ATTEMPT_TC_REIMBURSE)) + return ..() @@ -47,3 +49,8 @@ do_sparks(2, source = uplink_comp.uplink_handler) uplink_comp.add_telecrystals(refundable_tc) qdel(refund_item) +/// If the item is used, it needs to no longer be refundable +/datum/element/uplink_reimburse/proc/used(datum/target) + SIGNAL_HANDLER + + Detach(target) diff --git a/code/datums/keybinding/living.dm b/code/datums/keybinding/living.dm index f0f306344b51b6..84e3685f5f890e 100644 --- a/code/datums/keybinding/living.dm +++ b/code/datums/keybinding/living.dm @@ -119,3 +119,38 @@ return var/mob/living/user_mob = user.mob user_mob.set_combat_mode(FALSE, silent = FALSE) + +/datum/keybinding/living/toggle_move_intent + hotkey_keys = list("Alt") //SKYRAT EDIT CHANGE - C IS FOR COMBAT INDICATOR - ORIGINAL: hotkey_keys = list("C") + name = "toggle_move_intent" + full_name = "Hold to toggle move intent" + description = "Held down to cycle to the other move intent, release to cycle back" + keybind_signal = COMSIG_KB_LIVING_TOGGLEMOVEINTENT_DOWN + +/datum/keybinding/living/toggle_move_intent/down(client/user) + . = ..() + if(.) + return + var/mob/living/M = user.mob + M.toggle_move_intent() + return TRUE + +/datum/keybinding/living/toggle_move_intent/up(client/user) + var/mob/living/M = user.mob + M.toggle_move_intent() + return TRUE + +/datum/keybinding/living/toggle_move_intent_alternative + hotkey_keys = list("Unbound") + name = "toggle_move_intent_alt" + full_name = "press to cycle move intent" + description = "Pressing this cycle to the opposite move intent, does not cycle back" + keybind_signal = COMSIG_KB_LIVING_TOGGLEMOVEINTENTALT_DOWN + +/datum/keybinding/living/toggle_move_intent_alternative/down(client/user) + . = ..() + if(.) + return + var/mob/living/M = user.mob + M.toggle_move_intent() + return TRUE diff --git a/code/datums/keybinding/mob.dm b/code/datums/keybinding/mob.dm index a53e3390e1270f..def4ec36fb2c1a 100644 --- a/code/datums/keybinding/mob.dm +++ b/code/datums/keybinding/mob.dm @@ -71,41 +71,6 @@ user.mob.dropItemToGround(I) return TRUE -/datum/keybinding/mob/toggle_move_intent - hotkey_keys = list("Alt") //SKYRAT EDIT CHANGE - COMBAT_INDICATOR - name = "toggle_move_intent" - full_name = "Hold to toggle move intent" - description = "Held down to cycle to the other move intent, release to cycle back" - keybind_signal = COMSIG_KB_MOB_TOGGLEMOVEINTENT_DOWN - -/datum/keybinding/mob/toggle_move_intent/down(client/user) - . = ..() - if(.) - return - var/mob/living/M = user.mob - M.toggle_move_intent() - return TRUE - -/datum/keybinding/mob/toggle_move_intent/up(client/user) - var/mob/living/M = user.mob - M.toggle_move_intent() - return TRUE - -/datum/keybinding/mob/toggle_move_intent_alternative - hotkey_keys = list("Unbound") - name = "toggle_move_intent_alt" - full_name = "press to cycle move intent" - description = "Pressing this cycle to the opposite move intent, does not cycle back" - keybind_signal = COMSIG_KB_MOB_TOGGLEMOVEINTENTALT_DOWN - -/datum/keybinding/mob/toggle_move_intent_alternative/down(client/user) - . = ..() - if(.) - return - var/mob/living/M = user.mob - M.toggle_move_intent() - return TRUE - /datum/keybinding/mob/target/down(client/user) . = ..() if(.) diff --git a/code/datums/lazy_template.dm b/code/datums/lazy_template.dm index af6df50e96f8c1..0b8b2999f69938 100644 --- a/code/datums/lazy_template.dm +++ b/code/datums/lazy_template.dm @@ -10,8 +10,6 @@ var/key var/map_dir = "_maps/templates/lazy_templates" var/map_name - var/map_width - var/map_height /datum/lazy_template/New() reservations = list() @@ -46,25 +44,53 @@ if(!load_path || !fexists(load_path)) CRASH("lazy template [type] has an invalid load_path: '[load_path]', check directory and map name!") - var/datum/map_template/loading = new(path = load_path, cache = TRUE) - if(!loading.cached_map) + var/datum/parsed_map/parsed_template = load_map( + file(load_path), + measure_only = TRUE, + ) + if(isnull(parsed_template.parsed_bounds)) CRASH("Failed to cache lazy template for loading: '[key]'") - var/datum/turf_reservation/reservation = SSmapping.RequestBlockReservation(loading.width, loading.height) + var/width = parsed_template.parsed_bounds[MAP_MAXX] - parsed_template.parsed_bounds[MAP_MINX] + 1 + var/height = parsed_template.parsed_bounds[MAP_MAXY] - parsed_template.parsed_bounds[MAP_MINY] + 1 + var/datum/turf_reservation/reservation = SSmapping.request_turf_block_reservation( + width, + height, + parsed_template.parsed_bounds[MAP_MAXZ], + ) if(!reservation) CRASH("Failed to reserve a block for lazy template: '[key]'") - if(!loading.load(coords2turf(reservation.bottom_left_coords))) - CRASH("Failed to load lazy template: '[key]'") - reservations += reservation + var/list/loaded_atom_movables = list() + var/list/loaded_turfs = list() + var/list/loaded_areas = list() + for(var/z_idx in parsed_template.parsed_bounds[MAP_MAXZ] to 1 step -1) + var/turf/bottom_left = reservation.bottom_left_turfs[z_idx] + var/turf/top_right = reservation.top_right_turfs[z_idx] + load_map( + file(load_path), + bottom_left.x, + bottom_left.y, + bottom_left.z, + z_upper = z_idx, + z_lower = z_idx, + ) + for(var/turf/turf as anything in block(bottom_left, top_right)) + loaded_turfs += turf + loaded_areas |= get_area(turf) + for(var/thing in turf.get_all_contents()) + // atoms can actually be in the contents of two or more turfs based on its icon/bound size + // see https://www.byond.com/docs/ref/index.html#/atom/var/contents + loaded_atom_movables |= thing + SSatoms.InitializeAtoms(loaded_atom_movables + loaded_turfs + loaded_areas) + SEND_SIGNAL(src, COMSIG_LAZY_TEMPLATE_LOADED, loaded_atom_movables, loaded_turfs, loaded_areas) + reservations += reservation return reservation /datum/lazy_template/nukie_base key = LAZY_TEMPLATE_KEY_NUKIEBASE map_name = "nukie_base" - map_width = 89 - map_height = 100 /datum/lazy_template/wizard_dem key = LAZY_TEMPLATE_KEY_WIZARDDEN @@ -77,3 +103,7 @@ /datum/lazy_template/abductor_ship key = LAZY_TEMPLATE_KEY_ABDUCTOR_SHIPS map_name = "abductor_ships" + +/datum/lazy_template/heretic_sacrifice_room + key = LAZY_TEMPLATE_KEY_HERETIC_SACRIFICE + map_name = "heretic_sacrifice" diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 68bd8798560f25..a5aa648ecee3e9 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -48,7 +48,7 @@ timeout = 4 MINUTES /datum/mood_event/cascade // Big boi delamination - description = "The engineers have finally done it, we are all going to die..." + description = "I never thought I'd see a resonance cascade, let alone experience one..." mood_change = -8 timeout = 5 MINUTES diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm index 28b88c246e3a91..9ab5d4b86ef3ba 100644 --- a/code/datums/mutations/hulk.dm +++ b/code/datums/mutations/hulk.dm @@ -63,13 +63,19 @@ *arg1 is the arm to evaluate damage of and possibly break. */ /datum/mutation/human/hulk/proc/break_an_arm(obj/item/bodypart/arm) + var/severity switch(arm.brute_dam) if(45 to 50) - arm.force_wound_upwards(/datum/wound/blunt/bone/critical, wound_source = "hulk smashing") + severity = WOUND_SEVERITY_CRITICAL if(41 to 45) - arm.force_wound_upwards(/datum/wound/blunt/bone/severe, wound_source = "hulk smashing") + severity = WOUND_SEVERITY_SEVERE if(35 to 41) - arm.force_wound_upwards(/datum/wound/blunt/bone/moderate, wound_source = "hulk smashing") + severity = WOUND_SEVERITY_MODERATE + + if (isnull(severity)) + return + + owner.cause_wound_of_type_and_severity(WOUND_BLUNT, arm, severity, wound_source = "hulk smashing") /datum/mutation/human/hulk/on_life(seconds_per_tick, times_fired) if(owner.health < owner.crit_threshold) diff --git a/code/datums/quirks/negative_quirks/allergic.dm b/code/datums/quirks/negative_quirks/allergic.dm new file mode 100644 index 00000000000000..d6a510f62b6a23 --- /dev/null +++ b/code/datums/quirks/negative_quirks/allergic.dm @@ -0,0 +1,71 @@ +/datum/quirk/item_quirk/allergic + name = "Extreme Medicine Allergy" + desc = "Ever since you were a kid, you've been allergic to certain chemicals..." + icon = FA_ICON_PRESCRIPTION_BOTTLE + value = -6 + gain_text = span_danger("You feel your immune system shift.") + lose_text = span_notice("You feel your immune system phase back into perfect shape.") + medical_record_text = "Patient's immune system responds violently to certain chemicals." + hardcore_value = 3 + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES + mail_goodies = list(/obj/item/reagent_containers/hypospray/medipen) // epinephrine medipen stops allergic reactions + var/list/allergies = list() + var/list/blacklist = list( + /datum/reagent/medicine/c2, + /datum/reagent/medicine/epinephrine, + /datum/reagent/medicine/adminordrazine, + /datum/reagent/medicine/adminordrazine/quantum_heal, + /datum/reagent/medicine/omnizine/godblood, + /datum/reagent/medicine/cordiolis_hepatico, + /datum/reagent/medicine/synaphydramine, + /datum/reagent/medicine/diphenhydramine, + /datum/reagent/medicine/sansufentanyl + ) + var/allergy_string + +/datum/quirk/item_quirk/allergic/add_unique(client/client_source) + var/list/chem_list = subtypesof(/datum/reagent/medicine) - blacklist + var/list/allergy_chem_names = list() + for(var/i in 0 to 5) + var/datum/reagent/medicine/chem_type = pick_n_take(chem_list) + allergies += chem_type + allergy_chem_names += initial(chem_type.name) + + allergy_string = allergy_chem_names.Join(", ") + name = "Extreme [allergy_string] Allergies" + medical_record_text = "Patient's immune system responds violently to [allergy_string]" + + var/mob/living/carbon/human/human_holder = quirk_holder + var/obj/item/clothing/accessory/dogtag/allergy/dogtag = new(get_turf(human_holder), allergy_string) + + give_item_to_holder(dogtag, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS), flavour_text = "Make sure medical staff can see this...") + +/datum/quirk/item_quirk/allergic/post_add() + quirk_holder.add_mob_memory(/datum/memory/key/quirk_allergy, allergy_string = allergy_string) + to_chat(quirk_holder, span_boldnotice("You are allergic to [allergy_string], make sure not to consume any of these!")) + +/datum/quirk/item_quirk/allergic/process(seconds_per_tick) + if(!iscarbon(quirk_holder)) + return + + if(IS_IN_STASIS(quirk_holder)) + return + + if(quirk_holder.stat == DEAD) + return + + var/mob/living/carbon/carbon_quirk_holder = quirk_holder + for(var/allergy in allergies) + var/datum/reagent/instantiated_med = carbon_quirk_holder.reagents.has_reagent(allergy) + if(!instantiated_med) + continue + //Just halts the progression, I'd suggest you run to medbay asap to get it fixed + if(carbon_quirk_holder.reagents.has_reagent(/datum/reagent/medicine/epinephrine)) + instantiated_med.reagent_removal_skip_list |= ALLERGIC_REMOVAL_SKIP + return //intentionally stops the entire proc so we avoid the organ damage after the loop + instantiated_med.reagent_removal_skip_list -= ALLERGIC_REMOVAL_SKIP + carbon_quirk_holder.adjustToxLoss(3 * seconds_per_tick) + carbon_quirk_holder.reagents.add_reagent(/datum/reagent/toxin/histamine, 3 * seconds_per_tick) + if(SPT_PROB(10, seconds_per_tick)) + carbon_quirk_holder.vomit(VOMIT_CATEGORY_DEFAULT) + carbon_quirk_holder.adjustOrganLoss(pick(ORGAN_SLOT_BRAIN,ORGAN_SLOT_APPENDIX,ORGAN_SLOT_LUNGS,ORGAN_SLOT_HEART,ORGAN_SLOT_LIVER,ORGAN_SLOT_STOMACH),10) diff --git a/code/datums/quirks/negative_quirks/bad_back.dm b/code/datums/quirks/negative_quirks/bad_back.dm new file mode 100644 index 00000000000000..b7c406361596f8 --- /dev/null +++ b/code/datums/quirks/negative_quirks/bad_back.dm @@ -0,0 +1,50 @@ +/datum/quirk/badback + name = "Bad Back" + desc = "Thanks to your poor posture, backpacks and other bags never sit right on your back. More evenly weighted objects are fine, though." + icon = FA_ICON_HIKING + value = -8 + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED + gain_text = span_danger("Your back REALLY hurts!") + lose_text = span_notice("Your back feels better.") + medical_record_text = "Patient scans indicate severe and chronic back pain." + hardcore_value = 4 + mail_goodies = list(/obj/item/cane) + var/datum/weakref/backpack + +/datum/quirk/badback/add(client/client_source) + var/mob/living/carbon/human/human_holder = quirk_holder + var/obj/item/storage/backpack/equipped_backpack = human_holder.back + if(istype(equipped_backpack)) + quirk_holder.add_mood_event("back_pain", /datum/mood_event/back_pain) + RegisterSignal(human_holder.back, COMSIG_ITEM_POST_UNEQUIP, PROC_REF(on_unequipped_backpack)) + else + RegisterSignal(quirk_holder, COMSIG_MOB_EQUIPPED_ITEM, PROC_REF(on_equipped_item)) + +/datum/quirk/badback/remove() + UnregisterSignal(quirk_holder, COMSIG_MOB_EQUIPPED_ITEM) + + var/obj/item/storage/equipped_backpack = backpack?.resolve() + if(equipped_backpack) + UnregisterSignal(equipped_backpack, COMSIG_ITEM_POST_UNEQUIP) + quirk_holder.clear_mood_event("back_pain") + +/// Signal handler for when the quirk_holder equips an item. If it's a backpack, adds the back_pain mood event. +/datum/quirk/badback/proc/on_equipped_item(mob/living/source, obj/item/equipped_item, slot) + SIGNAL_HANDLER + + if(!(slot & ITEM_SLOT_BACK) || !istype(equipped_item, /obj/item/storage/backpack)) + return + + quirk_holder.add_mood_event("back_pain", /datum/mood_event/back_pain) + RegisterSignal(equipped_item, COMSIG_ITEM_POST_UNEQUIP, PROC_REF(on_unequipped_backpack)) + UnregisterSignal(quirk_holder, COMSIG_MOB_EQUIPPED_ITEM) + backpack = WEAKREF(equipped_item) + +/// Signal handler for when the quirk_holder unequips an equipped backpack. Removes the back_pain mood event. +/datum/quirk/badback/proc/on_unequipped_backpack(obj/item/source, force, atom/newloc, no_move, invdrop, silent) + SIGNAL_HANDLER + + UnregisterSignal(source, COMSIG_ITEM_POST_UNEQUIP) + quirk_holder.clear_mood_event("back_pain") + backpack = null + RegisterSignal(quirk_holder, COMSIG_MOB_EQUIPPED_ITEM, PROC_REF(on_equipped_item)) diff --git a/code/datums/quirks/negative_quirks/bad_touch.dm b/code/datums/quirks/negative_quirks/bad_touch.dm new file mode 100644 index 00000000000000..f3a5d967a01944 --- /dev/null +++ b/code/datums/quirks/negative_quirks/bad_touch.dm @@ -0,0 +1,31 @@ +/datum/quirk/bad_touch + name = "Bad Touch" + desc = "You don't like hugs. You'd really prefer if people just left you alone." + icon = "tg-bad-touch" + mob_trait = TRAIT_BADTOUCH + value = -1 + gain_text = span_danger("You just want people to leave you alone.") + lose_text = span_notice("You could use a big hug.") + medical_record_text = "Patient has disdain for being touched. Potentially has undiagnosed haphephobia." + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED + hardcore_value = 1 + mail_goodies = list(/obj/item/reagent_containers/spray/pepper) // show me on the doll where the bad man touched you + +/datum/quirk/bad_touch/add(client/client_source) + RegisterSignals(quirk_holder, list(COMSIG_LIVING_GET_PULLED, COMSIG_CARBON_HELP_ACT), PROC_REF(uncomfortable_touch)) + +/datum/quirk/bad_touch/remove() + UnregisterSignal(quirk_holder, list(COMSIG_LIVING_GET_PULLED, COMSIG_CARBON_HELP_ACT)) + +/// Causes a negative moodlet to our quirk holder on signal +/datum/quirk/bad_touch/proc/uncomfortable_touch(datum/source) + SIGNAL_HANDLER + + if(quirk_holder.stat == DEAD) + return + + new /obj/effect/temp_visual/annoyed(quirk_holder.loc) + if(quirk_holder.mob_mood.sanity <= SANITY_NEUTRAL) + quirk_holder.add_mood_event("bad_touch", /datum/mood_event/very_bad_touch) + else + quirk_holder.add_mood_event("bad_touch", /datum/mood_event/bad_touch) diff --git a/code/datums/quirks/negative_quirks/big_hands.dm b/code/datums/quirks/negative_quirks/big_hands.dm new file mode 100644 index 00000000000000..778ea6af8c3700 --- /dev/null +++ b/code/datums/quirks/negative_quirks/big_hands.dm @@ -0,0 +1,10 @@ +/datum/quirk/bighands + name = "Big Hands" + desc = "You have big hands, it sure does make it hard to use a lot of things." + icon = FA_ICON_HAND_DOTS + value = -6 + mob_trait = TRAIT_CHUNKYFINGERS + gain_text = span_danger("Your hands are huge! You can't use small things anymore!") + lose_text = span_notice("Your hands are back to normal.") + medical_record_text = "Patient has unusually large hands. Made me question my masculinity..." + hardcore_value = 5 diff --git a/code/datums/quirks/negative_quirks/blindness.dm b/code/datums/quirks/negative_quirks/blindness.dm new file mode 100644 index 00000000000000..ce57e946fe92ec --- /dev/null +++ b/code/datums/quirks/negative_quirks/blindness.dm @@ -0,0 +1,20 @@ +/datum/quirk/item_quirk/blindness + name = "Blind" + desc = "You are completely blind, nothing can counteract this." + icon = FA_ICON_EYE_SLASH + value = -16 + gain_text = span_danger("You can't see anything.") + lose_text = span_notice("You miraculously gain back your vision.") + medical_record_text = "Patient has permanent blindness." + hardcore_value = 15 + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE + mail_goodies = list(/obj/item/clothing/glasses/sunglasses, /obj/item/cane/white) + +/datum/quirk/item_quirk/blindness/add_unique(client/client_source) + give_item_to_holder(/obj/item/clothing/glasses/blindfold/white, list(LOCATION_EYES = ITEM_SLOT_EYES, LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) + +/datum/quirk/item_quirk/blindness/add(client/client_source) + quirk_holder.become_blind(QUIRK_TRAIT) + +/datum/quirk/item_quirk/blindness/remove() + quirk_holder.cure_blind(QUIRK_TRAIT) diff --git a/code/datums/quirks/negative_quirks/blood_deficiency.dm b/code/datums/quirks/negative_quirks/blood_deficiency.dm new file mode 100644 index 00000000000000..c75007bacc20c8 --- /dev/null +++ b/code/datums/quirks/negative_quirks/blood_deficiency.dm @@ -0,0 +1,39 @@ +/datum/quirk/blooddeficiency + name = "Blood Deficiency" + desc = "Your body can't produce enough blood to sustain itself." + icon = FA_ICON_TINT + value = -8 + mob_trait = TRAIT_BLOOD_DEFICIENCY + gain_text = span_danger("You feel your vigor slowly fading away.") + lose_text = span_notice("You feel vigorous again.") + medical_record_text = "Patient requires regular treatment for blood loss due to low production of blood." + hardcore_value = 8 + mail_goodies = list(/obj/item/reagent_containers/blood/o_minus) // universal blood type that is safe for all + var/min_blood = BLOOD_VOLUME_SAFE - 25 // just barely survivable without treatment + +/datum/quirk/blooddeficiency/post_add() + if(!ishuman(quirk_holder)) + return + + // for making sure the roundstart species has the right blood pack sent to them + var/mob/living/carbon/human/carbon_target = quirk_holder + carbon_target.dna.species.update_quirk_mail_goodies(carbon_target, src) + +/** + * Makes the mob lose blood from having the blood deficiency quirk, if possible + * + * Arguments: + * * seconds_per_tick + */ +/datum/quirk/blooddeficiency/proc/lose_blood(seconds_per_tick) + if(quirk_holder.stat == DEAD) + return + + var/mob/living/carbon/human/carbon_target = quirk_holder + if(HAS_TRAIT(carbon_target, TRAIT_NOBLOOD) && isnull(carbon_target.dna.species.exotic_blood)) //can't lose blood if your species doesn't have any + return + + if (carbon_target.blood_volume <= min_blood) + return + // Ensures that we don't reduce total blood volume below min_blood. + carbon_target.blood_volume = max(min_blood, carbon_target.blood_volume - carbon_target.dna.species.blood_deficiency_drain_rate * seconds_per_tick) diff --git a/code/datums/quirks/negative_quirks/body_purist.dm b/code/datums/quirks/negative_quirks/body_purist.dm new file mode 100644 index 00000000000000..6350a7108820ba --- /dev/null +++ b/code/datums/quirks/negative_quirks/body_purist.dm @@ -0,0 +1,69 @@ +/datum/quirk/body_purist + name = "Body Purist" + desc = "You believe your body is a temple and its natural form is an embodiment of perfection. Accordingly, you despise the idea of ever augmenting it with unnatural parts, cybernetic, prosthetic, or anything like it." + icon = FA_ICON_PERSON_RAYS + value = -2 + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED + gain_text = span_danger("You now begin to hate the idea of having cybernetic implants.") + lose_text = span_notice("Maybe cybernetics aren't so bad. You now feel okay with augmentations and prosthetics.") + medical_record_text = "This patient has disclosed an extreme hatred for unnatural bodyparts and augmentations." + hardcore_value = 3 + mail_goodies = list(/obj/item/paper/pamphlet/cybernetics) + var/cybernetics_level = 0 + +/datum/quirk/body_purist/add(client/client_source) + check_cybernetics() + RegisterSignal(quirk_holder, COMSIG_CARBON_GAIN_ORGAN, PROC_REF(on_organ_gain)) + RegisterSignal(quirk_holder, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(on_organ_lose)) + RegisterSignal(quirk_holder, COMSIG_CARBON_ATTACH_LIMB, PROC_REF(on_limb_gain)) + RegisterSignal(quirk_holder, COMSIG_CARBON_REMOVE_LIMB, PROC_REF(on_limb_lose)) + +/datum/quirk/body_purist/remove() + UnregisterSignal(quirk_holder, list( + COMSIG_CARBON_GAIN_ORGAN, + COMSIG_CARBON_LOSE_ORGAN, + COMSIG_CARBON_ATTACH_LIMB, + COMSIG_CARBON_REMOVE_LIMB, + )) + quirk_holder.clear_mood_event("body_purist") + +/datum/quirk/body_purist/proc/check_cybernetics() + var/mob/living/carbon/owner = quirk_holder + if(!istype(owner)) + return + for(var/obj/item/bodypart/limb as anything in owner.bodyparts) + if(IS_ROBOTIC_LIMB(limb)) + cybernetics_level++ + for(var/obj/item/organ/organ as anything in owner.organs) + if(IS_ROBOTIC_ORGAN(organ) && !(organ.organ_flags & ORGAN_HIDDEN)) + cybernetics_level++ + update_mood() + +/datum/quirk/body_purist/proc/update_mood() + quirk_holder.clear_mood_event("body_purist") + if(cybernetics_level) + quirk_holder.add_mood_event("body_purist", /datum/mood_event/body_purist, -cybernetics_level * 10) + +/datum/quirk/body_purist/proc/on_organ_gain(datum/source, obj/item/organ/new_organ, special) + SIGNAL_HANDLER + if(IS_ROBOTIC_ORGAN(new_organ) && !(new_organ.organ_flags & ORGAN_HIDDEN)) //why the fuck are there 2 of them + cybernetics_level++ + update_mood() + +/datum/quirk/body_purist/proc/on_organ_lose(datum/source, obj/item/organ/old_organ, special) + SIGNAL_HANDLER + if(IS_ROBOTIC_ORGAN(old_organ) && !(old_organ.organ_flags & ORGAN_HIDDEN)) + cybernetics_level-- + update_mood() + +/datum/quirk/body_purist/proc/on_limb_gain(datum/source, obj/item/bodypart/new_limb, special) + SIGNAL_HANDLER + if(IS_ROBOTIC_LIMB(new_limb)) + cybernetics_level++ + update_mood() + +/datum/quirk/body_purist/proc/on_limb_lose(datum/source, obj/item/bodypart/old_limb, special) + SIGNAL_HANDLER + if(IS_ROBOTIC_LIMB(old_limb)) + cybernetics_level-- + update_mood() diff --git a/code/datums/quirks/negative_quirks/brain_problems.dm b/code/datums/quirks/negative_quirks/brain_problems.dm new file mode 100644 index 00000000000000..15cc0128020cf4 --- /dev/null +++ b/code/datums/quirks/negative_quirks/brain_problems.dm @@ -0,0 +1,37 @@ + /* A couple of brain tumor stats for anyone curious / looking at this quirk for balancing: + * - It takes less 16 minute 40 seconds to die from brain death due to a brain tumor. + * - It takes 1 minutes 40 seconds to take 10% (20 organ damage) brain damage. + * - 5u mannitol will heal 12.5% (25 organ damage) brain damage + */ +/datum/quirk/item_quirk/brainproblems + name = "Brain Tumor" + desc = "You have a little friend in your brain that is slowly destroying it. Better bring some mannitol!" + icon = FA_ICON_BRAIN + value = -12 + gain_text = span_danger("You feel smooth.") + lose_text = span_notice("You feel wrinkled again.") + medical_record_text = "Patient has a tumor in their brain that is slowly driving them to brain death." + hardcore_value = 12 + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES + mail_goodies = list(/obj/item/storage/pill_bottle/mannitol/braintumor) + +/datum/quirk/item_quirk/brainproblems/add_unique(client/client_source) + give_item_to_holder( + /obj/item/storage/pill_bottle/mannitol/braintumor, + list( + LOCATION_LPOCKET = ITEM_SLOT_LPOCKET, + LOCATION_RPOCKET = ITEM_SLOT_RPOCKET, + LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, + LOCATION_HANDS = ITEM_SLOT_HANDS, + ), + flavour_text = "These will keep you alive until you can secure a supply of medication. Don't rely on them too much!", + ) + +/datum/quirk/item_quirk/brainproblems/process(seconds_per_tick) + if(quirk_holder.stat == DEAD) + return + + if(HAS_TRAIT(quirk_holder, TRAIT_TUMOR_SUPPRESSED)) + return + + quirk_holder.adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.2 * seconds_per_tick) diff --git a/code/datums/quirks/negative_quirks/chronic_illness.dm b/code/datums/quirks/negative_quirks/chronic_illness.dm new file mode 100644 index 00000000000000..663d41381987e3 --- /dev/null +++ b/code/datums/quirks/negative_quirks/chronic_illness.dm @@ -0,0 +1,16 @@ +/datum/quirk/item_quirk/chronic_illness + name = "Chronic Illness" + desc = "You have a chronic illness that requires constant medication to keep under control." + icon = FA_ICON_DISEASE + value = -12 + gain_text = span_danger("You feel a bit off today.") + lose_text = span_notice("You feel a bit better today.") + medical_record_text = "Patient has a chronic illness that requires constant medication to keep under control." + hardcore_value = 12 + mail_goodies = list(/obj/item/storage/pill_bottle/sansufentanyl) + +/datum/quirk/item_quirk/chronic_illness/add_unique(client/client_source) + var/datum/disease/chronic_illness/hms = new /datum/disease/chronic_illness() + quirk_holder.ForceContractDisease(hms) + give_item_to_holder(/obj/item/storage/pill_bottle/sansufentanyl, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK),flavour_text = "You've been provided with medication to help manage your condition. Take it regularly to avoid complications.") + give_item_to_holder(/obj/item/healthanalyzer/simple/disease, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK)) diff --git a/code/datums/quirks/negative_quirks/claustrophobia.dm b/code/datums/quirks/negative_quirks/claustrophobia.dm new file mode 100644 index 00000000000000..e0207d227dd3c0 --- /dev/null +++ b/code/datums/quirks/negative_quirks/claustrophobia.dm @@ -0,0 +1,54 @@ +/datum/quirk/claustrophobia + name = "Claustrophobia" + desc = "You are terrified of small spaces and certain jolly figures. If you are placed inside any container, locker, or machinery, a panic attack sets in and you struggle to breathe." + icon = FA_ICON_BOX_OPEN + value = -4 + medical_record_text = "Patient demonstrates a fear of tight spaces." + hardcore_value = 5 + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES + mail_goodies = list(/obj/item/reagent_containers/syringe/convermol) // to help breathing + +/datum/quirk/claustrophobia/remove() + quirk_holder.clear_mood_event("claustrophobia") + +/datum/quirk/claustrophobia/process(seconds_per_tick) + if(quirk_holder.stat != CONSCIOUS || quirk_holder.IsSleeping() || quirk_holder.IsUnconscious()) + return + + if(HAS_TRAIT(quirk_holder, TRAIT_FEARLESS)) + return + + var/nick_spotted = FALSE + + for(var/mob/living/carbon/human/possible_claus in view(5, quirk_holder)) + if(evaluate_jolly_levels(possible_claus)) + nick_spotted = TRUE + break + + if(!nick_spotted && isturf(quirk_holder.loc)) + quirk_holder.clear_mood_event("claustrophobia") + return + + quirk_holder.add_mood_event("claustrophobia", /datum/mood_event/claustrophobia) + quirk_holder.losebreath += 0.25 // miss a breath one in four times + if(SPT_PROB(25, seconds_per_tick)) + if(nick_spotted) + to_chat(quirk_holder, span_warning("Santa Claus is here! I gotta get out of here!")) + else + to_chat(quirk_holder, span_warning("You feel trapped! Must escape... can't breathe...")) + +///investigates whether possible_saint_nick possesses a high level of christmas cheer +/datum/quirk/claustrophobia/proc/evaluate_jolly_levels(mob/living/carbon/human/possible_saint_nick) + if(!istype(possible_saint_nick)) + return FALSE + + if(istype(possible_saint_nick.back, /obj/item/storage/backpack/santabag)) + return TRUE + + if(istype(possible_saint_nick.head, /obj/item/clothing/head/costume/santa) || istype(possible_saint_nick.head, /obj/item/clothing/head/helmet/space/santahat)) + return TRUE + + if(istype(possible_saint_nick.wear_suit, /obj/item/clothing/suit/space/santa)) + return TRUE + + return FALSE diff --git a/code/datums/quirks/negative_quirks/clumsy.dm b/code/datums/quirks/negative_quirks/clumsy.dm new file mode 100644 index 00000000000000..8cf363753d4b28 --- /dev/null +++ b/code/datums/quirks/negative_quirks/clumsy.dm @@ -0,0 +1,9 @@ +/datum/quirk/clumsy + name = "Clumsy" + desc = "You're clumsy, a goofball, a silly dude. You big loveable himbo/bimbo you! Hope you weren't planning on using your hands for anything that takes even a LICK of dexterity." + icon = FA_ICON_FACE_DIZZY + value = -8 + mob_trait = TRAIT_CLUMSY + gain_text = span_danger("You feel your IQ sink like your brain is liquid.") + lose_text = span_notice("You feel like your IQ went up to at least average.") + medical_record_text = "Patient has demonstrated an extreme difficulty with high motor skill paired with an inability to demonstrate critical thinking." diff --git a/code/datums/quirks/negative_quirks/cursed.dm b/code/datums/quirks/negative_quirks/cursed.dm new file mode 100644 index 00000000000000..4b99ff850b843b --- /dev/null +++ b/code/datums/quirks/negative_quirks/cursed.dm @@ -0,0 +1,17 @@ +/* +// SKYRAT EDIT REMOVAL +/datum/quirk/cursed + name = "Cursed" + desc = "You are cursed with bad luck. You are much more likely to suffer from accidents and mishaps. When it rains, it pours." + icon = FA_ICON_CLOUD_SHOWERS_HEAVY + value = -8 + mob_trait = TRAIT_CURSED + gain_text = span_danger("You feel like you're going to have a bad day.") + lose_text = span_notice("You feel like you're going to have a good day.") + medical_record_text = "Patient is cursed with bad luck." + hardcore_value = 8 + +/datum/quirk/cursed/add(client/client_source) + quirk_holder.AddComponent(/datum/component/omen/quirk) +*/ +// SKYRAT EDIT REMOVAL END diff --git a/code/datums/quirks/negative_quirks/deafness.dm b/code/datums/quirks/negative_quirks/deafness.dm new file mode 100644 index 00000000000000..077bbe72aa5c62 --- /dev/null +++ b/code/datums/quirks/negative_quirks/deafness.dm @@ -0,0 +1,14 @@ +/datum/quirk/item_quirk/deafness + name = "Deaf" + desc = "You are incurably deaf." + icon = FA_ICON_DEAF + value = -8 + mob_trait = TRAIT_DEAF + gain_text = span_danger("You can't hear anything.") + lose_text = span_notice("You're able to hear again!") + medical_record_text = "Patient's cochlear nerve is incurably damaged." + hardcore_value = 12 + mail_goodies = list(/obj/item/clothing/mask/whistle) + +/datum/quirk/item_quirk/deafness/add_unique(client/client_source) + give_item_to_holder(/obj/item/clothing/accessory/deaf_pin, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) diff --git a/code/datums/quirks/negative_quirks/depression.dm b/code/datums/quirks/negative_quirks/depression.dm new file mode 100644 index 00000000000000..0bf15516105818 --- /dev/null +++ b/code/datums/quirks/negative_quirks/depression.dm @@ -0,0 +1,12 @@ +/datum/quirk/depression + name = "Depression" + desc = "You sometimes just hate life." + icon = FA_ICON_FROWN + mob_trait = TRAIT_DEPRESSION + value = -3 + gain_text = span_danger("You start feeling depressed.") + lose_text = span_notice("You no longer feel depressed.") //if only it were that easy! + medical_record_text = "Patient has a mild mood disorder causing them to experience acute episodes of depression." + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED + hardcore_value = 2 + mail_goodies = list(/obj/item/storage/pill_bottle/happinesspsych) diff --git a/code/datums/quirks/negative_quirks/family_heirloom.dm b/code/datums/quirks/negative_quirks/family_heirloom.dm new file mode 100644 index 00000000000000..0fd08c68f21785 --- /dev/null +++ b/code/datums/quirks/negative_quirks/family_heirloom.dm @@ -0,0 +1,72 @@ +/datum/quirk/item_quirk/family_heirloom + name = "Family Heirloom" + desc = "You are the current owner of an heirloom, passed down for generations. You have to keep it safe!" + icon = FA_ICON_TOOLBOX + value = -2 + medical_record_text = "Patient demonstrates an unnatural attachment to a family heirloom." + hardcore_value = 1 + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES|QUIRK_MOODLET_BASED + /// A weak reference to our heirloom. + var/datum/weakref/heirloom + mail_goodies = list(/obj/item/storage/secure/briefcase) + +/datum/quirk/item_quirk/family_heirloom/add_unique(client/client_source) + var/mob/living/carbon/human/human_holder = quirk_holder + var/obj/item/heirloom_type + + // The quirk holder's species - we have a 50% chance, if we have a species with a set heirloom, to choose a species heirloom. + var/datum/species/holder_species = human_holder.dna?.species + if(holder_species && LAZYLEN(holder_species.family_heirlooms) && prob(50)) + heirloom_type = pick(holder_species.family_heirlooms) + else + // Our quirk holder's job + var/datum/job/holder_job = human_holder.last_mind?.assigned_role + if(holder_job && LAZYLEN(holder_job.family_heirlooms)) + heirloom_type = pick(holder_job.family_heirlooms) + + // If we didn't find an heirloom somehow, throw them a generic one + if(!heirloom_type) + heirloom_type = pick(/obj/item/toy/cards/deck, /obj/item/lighter, /obj/item/dice/d20) + + var/obj/new_heirloom = new heirloom_type(get_turf(human_holder)) + heirloom = WEAKREF(new_heirloom) + + give_item_to_holder( + new_heirloom, + list( + LOCATION_LPOCKET = ITEM_SLOT_LPOCKET, + LOCATION_RPOCKET = ITEM_SLOT_RPOCKET, + LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, + LOCATION_HANDS = ITEM_SLOT_HANDS, + ), + flavour_text = "This is a precious family heirloom, passed down from generation to generation. Keep it safe!", + ) + +/datum/quirk/item_quirk/family_heirloom/post_add() + var/list/names = splittext(quirk_holder.real_name, " ") + var/family_name = names[names.len] + + var/obj/family_heirloom = heirloom?.resolve() + if(!family_heirloom) + to_chat(quirk_holder, span_boldnotice("A wave of existential dread runs over you as you realize your precious family heirloom is missing. Perhaps the Gods will show mercy on your cursed soul?")) + return + family_heirloom.AddComponent(/datum/component/heirloom, quirk_holder.mind, family_name) + + return ..() + +/datum/quirk/item_quirk/family_heirloom/process() + if(quirk_holder.stat == DEAD) + return + + var/obj/family_heirloom = heirloom?.resolve() + + if(family_heirloom && (family_heirloom in quirk_holder.get_all_contents())) + quirk_holder.clear_mood_event("family_heirloom_missing") + quirk_holder.add_mood_event("family_heirloom", /datum/mood_event/family_heirloom) + else + quirk_holder.clear_mood_event("family_heirloom") + quirk_holder.add_mood_event("family_heirloom_missing", /datum/mood_event/family_heirloom_missing) + +/datum/quirk/item_quirk/family_heirloom/remove() + quirk_holder.clear_mood_event("family_heirloom_missing") + quirk_holder.clear_mood_event("family_heirloom") diff --git a/code/datums/quirks/negative_quirks/frail.dm b/code/datums/quirks/negative_quirks/frail.dm new file mode 100644 index 00000000000000..6b806875ea24c7 --- /dev/null +++ b/code/datums/quirks/negative_quirks/frail.dm @@ -0,0 +1,11 @@ +/datum/quirk/frail + name = "Frail" + desc = "You have skin of paper and bones of glass! You suffer wounds much more easily than most." + icon = FA_ICON_SKULL + value = -6 + mob_trait = TRAIT_EASILY_WOUNDED + gain_text = span_danger("You feel frail.") + lose_text = span_notice("You feel sturdy again.") + medical_record_text = "Patient is absurdly easy to injure. Please take all due diligence to avoid possible malpractice suits." + hardcore_value = 4 + mail_goodies = list(/obj/effect/spawner/random/medical/minor_healing) diff --git a/code/datums/quirks/negative_quirks/glass_jaw.dm b/code/datums/quirks/negative_quirks/glass_jaw.dm new file mode 100644 index 00000000000000..33ad19add6ddbf --- /dev/null +++ b/code/datums/quirks/negative_quirks/glass_jaw.dm @@ -0,0 +1,52 @@ +/datum/quirk/glass_jaw + name = "Glass Jaw" + desc = "You have a very fragile jaw. Any sufficiently hard blow to your head might knock you out." + icon = FA_ICON_HAND_FIST + value = -4 + gain_text = span_danger("Your jaw feels loose.") + lose_text = span_notice("Your jaw feels fitting again.") + medical_record_text = "Patient is absurdly easy to knock out. Do not allow them near a boxing ring." + hardcore_value = 4 + mail_goodies = list( + /obj/item/clothing/gloves/boxing, + /obj/item/clothing/mask/luchador/rudos, + ) + +/datum/quirk/glass_jaw/New() + . = ..() + //randomly picks between blue or red equipment for goodies + if(prob(50)) + mail_goodies = list( + /obj/item/clothing/gloves/boxing, + /obj/item/clothing/mask/luchador/rudos, + ) + else + mail_goodies = list( + /obj/item/clothing/gloves/boxing/blue, + /obj/item/clothing/mask/luchador/tecnicos, + ) + +/datum/quirk/glass_jaw/add(client/client_source) + RegisterSignal(quirk_holder, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(punch_out)) + +/datum/quirk/glass_jaw/remove() + UnregisterSignal(quirk_holder, COMSIG_MOB_APPLY_DAMAGE) + +/datum/quirk/glass_jaw/proc/punch_out(mob/living/carbon/source, damage, damagetype, def_zone, blocked, wound_bonus, bare_wound_bonus, sharpness, attack_direction, attacking_item) + SIGNAL_HANDLER + if((damagetype != BRUTE) || (def_zone != BODY_ZONE_HEAD)) + return + var/actual_damage = damage - (damage * blocked/100) + //only roll for knockouts at 5 damage or more + if(actual_damage < 5) + return + //blunt items are more likely to knock out, but sharp ones are still capable of doing it + if(prob(CEILING(actual_damage * (sharpness & (SHARP_EDGED|SHARP_POINTY) ? 0.65 : 1), 1))) + //don't display the message if little mac is already KO'd + if(!source.IsUnconscious()) + source.visible_message( + span_warning("[source] gets knocked out!"), + span_userdanger("You get knocked out!"), + vision_distance = COMBAT_MESSAGE_RANGE, + ) + source.Unconscious(3 SECONDS) diff --git a/code/datums/quirks/negative_quirks/heavy_sleeper.dm b/code/datums/quirks/negative_quirks/heavy_sleeper.dm new file mode 100644 index 00000000000000..dea79683915bb1 --- /dev/null +++ b/code/datums/quirks/negative_quirks/heavy_sleeper.dm @@ -0,0 +1,19 @@ +/datum/quirk/heavy_sleeper + name = "Heavy Sleeper" + desc = "You sleep like a rock! Whenever you're put to sleep or knocked unconscious, you take a little bit longer to wake up." + icon = FA_ICON_BED + value = -2 + mob_trait = TRAIT_HEAVY_SLEEPER + gain_text = span_danger("You feel sleepy.") + lose_text = span_notice("You feel awake again.") + medical_record_text = "Patient has abnormal sleep study results and is difficult to wake up." + hardcore_value = 2 + mail_goodies = list( + /obj/item/clothing/glasses/blindfold, + /obj/item/bedsheet/random, + /obj/item/clothing/under/misc/pj/red, + /obj/item/clothing/head/costume/nightcap/red, + /obj/item/clothing/under/misc/pj/blue, + /obj/item/clothing/head/costume/nightcap/blue, + /obj/item/pillow/random, + ) diff --git a/code/datums/quirks/negative_quirks/hemiplegic.dm b/code/datums/quirks/negative_quirks/hemiplegic.dm new file mode 100644 index 00000000000000..459b880fad2d1d --- /dev/null +++ b/code/datums/quirks/negative_quirks/hemiplegic.dm @@ -0,0 +1,22 @@ +/datum/quirk/hemiplegic + name = "Hemiplegic" + desc = "Half of your body doesn't work. Nothing will ever fix this." + icon = FA_ICON_CIRCLE_HALF_STROKE + value = -10 // slightly more bearable than paraplegic but not by much + gain_text = null // Handled by trauma. + lose_text = null + medical_record_text = "Patient has an untreatable impairment in motor function on half of their body." + hardcore_value = 10 + mail_goodies = list( + /obj/item/stack/sheet/mineral/uranium/half, //half a stack of a material that has a half life + /obj/item/reagent_containers/cup/glass/drinkingglass/filled/half_full, + ) + +/datum/quirk/hemiplegic/add(client/client_source) + var/mob/living/carbon/human/human_holder = quirk_holder + var/trauma_type = pick(/datum/brain_trauma/severe/paralysis/hemiplegic/left, /datum/brain_trauma/severe/paralysis/hemiplegic/right) + human_holder.gain_trauma(trauma_type, TRAUMA_RESILIENCE_ABSOLUTE) + +/datum/quirk/hemiplegic/remove() + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.cure_trauma_type(/datum/brain_trauma/severe/paralysis/hemiplegic, TRAUMA_RESILIENCE_ABSOLUTE) diff --git a/code/datums/quirks/negative_quirks/hypersensitive.dm b/code/datums/quirks/negative_quirks/hypersensitive.dm new file mode 100644 index 00000000000000..f51e72fc2560be --- /dev/null +++ b/code/datums/quirks/negative_quirks/hypersensitive.dm @@ -0,0 +1,18 @@ +/datum/quirk/hypersensitive + name = "Hypersensitive" + desc = "For better or worse, everything seems to affect your mood more than it should." + icon = FA_ICON_FLUSHED + value = -2 + gain_text = span_danger("You seem to make a big deal out of everything.") + lose_text = span_notice("You don't seem to make a big deal out of everything anymore.") + medical_record_text = "Patient demonstrates a high level of emotional volatility." + hardcore_value = 3 + mail_goodies = list(/obj/effect/spawner/random/entertainment/plushie_delux) + +/datum/quirk/hypersensitive/add(client/client_source) + if (quirk_holder.mob_mood) + quirk_holder.mob_mood.mood_modifier += 0.5 + +/datum/quirk/hypersensitive/remove() + if (quirk_holder.mob_mood) + quirk_holder.mob_mood.mood_modifier -= 0.5 diff --git a/code/datums/quirks/negative_quirks/illiterate.dm b/code/datums/quirks/negative_quirks/illiterate.dm new file mode 100644 index 00000000000000..8101985f8f7efb --- /dev/null +++ b/code/datums/quirks/negative_quirks/illiterate.dm @@ -0,0 +1,9 @@ +/datum/quirk/illiterate + name = "Illiterate" + desc = "You dropped out of school and are unable to read or write. This affects reading, writing, using computers and other electronics." + icon = FA_ICON_GRADUATION_CAP + value = -8 + mob_trait = TRAIT_ILLITERATE + medical_record_text = "Patient is not literate." + hardcore_value = 8 + mail_goodies = list(/obj/item/pai_card) // can read things for you diff --git a/code/datums/quirks/negative_quirks/indebted.dm b/code/datums/quirks/negative_quirks/indebted.dm new file mode 100644 index 00000000000000..1e30e7800d6d3d --- /dev/null +++ b/code/datums/quirks/negative_quirks/indebted.dm @@ -0,0 +1,40 @@ +/datum/quirk/indebted + name = "Indebted" + desc = "Bad life decisions, medical bills, student loans, whatever it may be, you've incurred quite the debt. A portion of all you receive will go towards extinguishing it." + icon = FA_ICON_DOLLAR + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_HIDE_FROM_SCAN + value = -2 + medical_record_text = "Alas, the patient struggled to scrape together enough money to pay the checkup bill." + hardcore_value = 2 + +/datum/quirk/indebted/add_unique(client/client_source) + var/mob/living/carbon/human/human_holder = quirk_holder + if(!human_holder.account_id) + return + var/datum/bank_account/account = SSeconomy.bank_accounts_by_id["[human_holder.account_id]"] + var/debt = PAYCHECK_CREW * rand(275, 325) + account.account_debt += debt + RegisterSignal(account, COMSIG_BANK_ACCOUNT_DEBT_PAID, PROC_REF(on_debt_paid)) + to_chat(client_source.mob, span_warning("You remember, you've a hefty, [debt] credits debt to pay...")) + +///Once the debt is extinguished, award an achievement and a pin for actually taking care of it. +/datum/quirk/indebted/proc/on_debt_paid(datum/bank_account/source) + SIGNAL_HANDLER + if(source.account_debt) + return + UnregisterSignal(source, COMSIG_BANK_ACCOUNT_DEBT_PAID) + ///The debt was extinguished while the quirk holder was logged out, so let's kindly award it once they come back. + if(!quirk_holder.client) + RegisterSignal(quirk_holder, COMSIG_MOB_LOGIN, PROC_REF(award_on_login)) + else + quirk_holder.client.give_award(/datum/award/achievement/misc/debt_extinguished, quirk_holder) + podspawn(list( + "target" = get_turf(quirk_holder), + "style" = STYLE_BLUESPACE, + "spawn" = /obj/item/clothing/accessory/debt_payer_pin, + )) + +/datum/quirk/indebted/proc/award_on_login(mob/source) + SIGNAL_HANDLER + quirk_holder.client.give_award(/datum/award/achievement/misc/debt_extinguished, quirk_holder) + UnregisterSignal(source, COMSIG_MOB_LOGIN) diff --git a/code/datums/quirks/negative_quirks/insanity.dm b/code/datums/quirks/negative_quirks/insanity.dm new file mode 100644 index 00000000000000..56b56a53812166 --- /dev/null +++ b/code/datums/quirks/negative_quirks/insanity.dm @@ -0,0 +1,41 @@ +/datum/quirk/insanity + name = "Reality Dissociation Syndrome" + desc = "You suffer from a severe disorder that causes very vivid hallucinations. \ + Mindbreaker toxin can suppress its effects, and you are immune to mindbreaker's hallucinogenic properties. \ + THIS IS NOT A LICENSE TO GRIEF." + icon = FA_ICON_GRIN_TONGUE_WINK + value = -8 + gain_text = span_userdanger("...") + lose_text = span_notice("You feel in tune with the world again.") + medical_record_text = "Patient suffers from acute Reality Dissociation Syndrome and experiences vivid hallucinations." + hardcore_value = 6 + mail_goodies = list(/obj/item/storage/pill_bottle/lsdpsych) + /// Weakref to the trauma we give out + var/datum/weakref/added_trama_ref + +/datum/quirk/insanity/add(client/client_source) + if(!iscarbon(quirk_holder)) + return + var/mob/living/carbon/carbon_quirk_holder = quirk_holder + + // Setup our special RDS mild hallucination. + // Not a unique subtype so not to plague subtypesof, + // also as we inherit the names and values from our quirk. + var/datum/brain_trauma/mild/hallucinations/added_trauma = new() + added_trauma.resilience = TRAUMA_RESILIENCE_ABSOLUTE + added_trauma.name = name + added_trauma.desc = medical_record_text + added_trauma.scan_desc = lowertext(name) + added_trauma.gain_text = null + added_trauma.lose_text = null + + carbon_quirk_holder.gain_trauma(added_trauma) + added_trama_ref = WEAKREF(added_trauma) + +/datum/quirk/insanity/post_add() + var/rds_policy = get_policy("[type]") || "Please note that your [lowertext(name)] does NOT give you any additional right to attack people or cause chaos." + // I don't /think/ we'll need this, but for newbies who think "roleplay as insane" = "license to kill", it's probably a good thing to have. + to_chat(quirk_holder, span_big(span_info(rds_policy))) + +/datum/quirk/insanity/remove() + QDEL_NULL(added_trama_ref) diff --git a/code/datums/quirks/negative_quirks/junkie.dm b/code/datums/quirks/negative_quirks/junkie.dm new file mode 100644 index 00000000000000..269f6d2d96e31f --- /dev/null +++ b/code/datums/quirks/negative_quirks/junkie.dm @@ -0,0 +1,216 @@ +/datum/quirk/item_quirk/junkie + name = "Junkie" + desc = "You can't get enough of hard drugs." + icon = FA_ICON_PILLS + value = -6 + gain_text = span_danger("You suddenly feel the craving for drugs.") + medical_record_text = "Patient has a history of hard drugs." + hardcore_value = 4 + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES + mail_goodies = list(/obj/effect/spawner/random/contraband/narcotics) + var/drug_list = list(/datum/reagent/drug/blastoff, /datum/reagent/drug/krokodil, /datum/reagent/medicine/morphine, /datum/reagent/drug/happiness, /datum/reagent/drug/methamphetamine) //List of possible IDs + var/datum/reagent/reagent_type //!If this is defined, reagent_id will be unused and the defined reagent type will be instead. + var/datum/reagent/reagent_instance //! actual instanced version of the reagent + var/where_drug //! Where the drug spawned + var/obj/item/drug_container_type //! If this is defined before pill generation, pill generation will be skipped. This is the type of the pill bottle. + var/where_accessory //! where the accessory spawned + var/obj/item/accessory_type //! If this is null, an accessory won't be spawned. + var/process_interval = 30 SECONDS //! how frequently the quirk processes + var/next_process = 0 //! ticker for processing + var/drug_flavour_text = "Better hope you don't run out..." + +/datum/quirk/item_quirk/junkie/add_unique(client/client_source) + var/mob/living/carbon/human/human_holder = quirk_holder + + if(!reagent_type) + reagent_type = pick(drug_list) + + reagent_instance = new reagent_type() + + for(var/addiction in reagent_instance.addiction_types) + human_holder.last_mind?.add_addiction_points(addiction, 1000) + + var/current_turf = get_turf(quirk_holder) + + if(!drug_container_type) + drug_container_type = /obj/item/storage/pill_bottle + + var/obj/item/drug_instance = new drug_container_type(current_turf) + if(istype(drug_instance, /obj/item/storage/pill_bottle)) + var/pill_state = "pill[rand(1,20)]" + for(var/i in 1 to 7) + var/obj/item/reagent_containers/pill/pill = new(drug_instance) + pill.icon_state = pill_state + pill.reagents.add_reagent(reagent_type, 3) + + give_item_to_holder( + drug_instance, + list( + LOCATION_LPOCKET = ITEM_SLOT_LPOCKET, + LOCATION_RPOCKET = ITEM_SLOT_RPOCKET, + LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, + LOCATION_HANDS = ITEM_SLOT_HANDS, + ), + flavour_text = drug_flavour_text, + ) + + if(accessory_type) + give_item_to_holder( + accessory_type, + list( + LOCATION_LPOCKET = ITEM_SLOT_LPOCKET, + LOCATION_RPOCKET = ITEM_SLOT_RPOCKET, + LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, + LOCATION_HANDS = ITEM_SLOT_HANDS, + ) + ) + +/datum/quirk/item_quirk/junkie/remove() + if(quirk_holder && reagent_instance) + for(var/addiction_type in subtypesof(/datum/addiction)) + quirk_holder.mind.remove_addiction_points(addiction_type, MAX_ADDICTION_POINTS) + +/datum/quirk/item_quirk/junkie/process(seconds_per_tick) + if(HAS_TRAIT(quirk_holder, TRAIT_LIVERLESS_METABOLISM)) + return + var/mob/living/carbon/human/human_holder = quirk_holder + if(world.time > next_process) + next_process = world.time + process_interval + var/deleted = QDELETED(reagent_instance) + var/missing_addiction = FALSE + for(var/addiction_type in reagent_instance.addiction_types) + if(!LAZYACCESS(human_holder.last_mind?.active_addictions, addiction_type)) + missing_addiction = TRUE + if(deleted || missing_addiction) + if(deleted) + reagent_instance = new reagent_type() + to_chat(quirk_holder, span_danger("You thought you kicked it, but you feel like you're falling back onto bad habits..")) + for(var/addiction in reagent_instance.addiction_types) + human_holder.last_mind?.add_addiction_points(addiction, 1000) ///Max that shit out + +/datum/quirk/item_quirk/junkie/smoker + name = "Smoker" + desc = "Sometimes you just really want a smoke. Probably not great for your lungs." + icon = FA_ICON_SMOKING + value = -4 + gain_text = span_danger("You could really go for a smoke right about now.") + lose_text = span_notice("You don't feel nearly as hooked to nicotine anymore.") + medical_record_text = "Patient is a current smoker." + reagent_type = /datum/reagent/drug/nicotine + accessory_type = /obj/item/lighter/greyscale + mob_trait = TRAIT_SMOKER + hardcore_value = 1 + drug_flavour_text = "Make sure you get your favorite brand when you run out." + mail_goodies = list( + /obj/effect/spawner/random/entertainment/cigarette_pack, + /obj/effect/spawner/random/entertainment/cigar, + /obj/effect/spawner/random/entertainment/lighter, + /obj/item/clothing/mask/cigarette/pipe, + ) + +/datum/quirk/item_quirk/junkie/smoker/New() + drug_container_type = pick(/obj/item/storage/fancy/cigarettes, + /obj/item/storage/fancy/cigarettes/cigpack_midori, + /obj/item/storage/fancy/cigarettes/cigpack_uplift, + /obj/item/storage/fancy/cigarettes/cigpack_robust, + /obj/item/storage/fancy/cigarettes/cigpack_robustgold, + /obj/item/storage/fancy/cigarettes/cigpack_carp) + + return ..() + +/datum/quirk/item_quirk/junkie/smoker/post_add() + . = ..() + quirk_holder.add_mob_memory(/datum/memory/key/quirk_smoker, protagonist = quirk_holder, preferred_brand = initial(drug_container_type.name)) + // smoker lungs have 25% less health and healing + var/mob/living/carbon/carbon_holder = quirk_holder + var/obj/item/organ/internal/lungs/smoker_lungs = null + var/obj/item/organ/internal/lungs/old_lungs = carbon_holder.get_organ_slot(ORGAN_SLOT_LUNGS) + if(old_lungs && IS_ORGANIC_ORGAN(old_lungs)) + if(isplasmaman(carbon_holder)) + smoker_lungs = /obj/item/organ/internal/lungs/plasmaman/plasmaman_smoker + else if(isethereal(carbon_holder)) + smoker_lungs = /obj/item/organ/internal/lungs/ethereal/ethereal_smoker + else + smoker_lungs = /obj/item/organ/internal/lungs/smoker_lungs + if(!isnull(smoker_lungs)) + smoker_lungs = new smoker_lungs + smoker_lungs.Insert(carbon_holder, special = TRUE, drop_if_replaced = FALSE) + +/datum/quirk/item_quirk/junkie/smoker/process(seconds_per_tick) + . = ..() + var/mob/living/carbon/human/human_holder = quirk_holder + var/obj/item/mask_item = human_holder.get_item_by_slot(ITEM_SLOT_MASK) + if(istype(mask_item, /obj/item/clothing/mask/cigarette)) + var/obj/item/storage/fancy/cigarettes/cigarettes = drug_container_type + if(istype(mask_item, initial(cigarettes.spawn_type))) + quirk_holder.clear_mood_event("wrong_cigs") + else + quirk_holder.add_mood_event("wrong_cigs", /datum/mood_event/wrong_brand) + +/datum/quirk/item_quirk/junkie/alcoholic + name = "Alcoholic" + desc = "You just can't live without alcohol. Your liver is a machine that turns ethanol into acetaldehyde." + icon = FA_ICON_WINE_GLASS + value = -4 + gain_text = span_danger("You really need a drink.") + lose_text = span_notice("Alcohol doesn't seem nearly as enticing anymore.") + medical_record_text = "Patient is an alcoholic." + reagent_type = /datum/reagent/consumable/ethanol + drug_container_type = /obj/item/reagent_containers/cup/glass/bottle/whiskey + mob_trait = TRAIT_HEAVY_DRINKER + hardcore_value = 1 + drug_flavour_text = "Make sure you get your favorite type of drink when you run out." + mail_goodies = list( + /obj/effect/spawner/random/food_or_drink/booze, + /obj/item/book/bible/booze, + ) + /// Cached typepath of the owner's favorite alcohol reagent + var/datum/reagent/consumable/ethanol/favorite_alcohol + +/datum/quirk/item_quirk/junkie/alcoholic/New() + drug_container_type = pick( + /obj/item/reagent_containers/cup/glass/bottle/whiskey, + /obj/item/reagent_containers/cup/glass/bottle/vodka, + /obj/item/reagent_containers/cup/glass/bottle/ale, + /obj/item/reagent_containers/cup/glass/bottle/beer, + /obj/item/reagent_containers/cup/glass/bottle/hcider, + /obj/item/reagent_containers/cup/glass/bottle/wine, + /obj/item/reagent_containers/cup/glass/bottle/sake, + ) + + return ..() + +/datum/quirk/item_quirk/junkie/alcoholic/post_add() + . = ..() + RegisterSignal(quirk_holder, COMSIG_MOB_REAGENT_CHECK, PROC_REF(check_brandy)) + + var/obj/item/reagent_containers/brandy_container = GLOB.alcohol_containers[drug_container_type] + if(isnull(brandy_container)) + stack_trace("Alcoholic quirk added while the GLOB.alcohol_containers is (somehow) not initialized!") + brandy_container = new drug_container_type + favorite_alcohol = brandy_container.list_reagents[1] + qdel(brandy_container) + else + favorite_alcohol = brandy_container.list_reagents[1] + + quirk_holder.add_mob_memory(/datum/memory/key/quirk_alcoholic, protagonist = quirk_holder, preferred_brandy = initial(favorite_alcohol.name)) + // alcoholic livers have 25% less health and healing + var/obj/item/organ/internal/liver/alcohol_liver = quirk_holder.get_organ_slot(ORGAN_SLOT_LIVER) + if(alcohol_liver && IS_ORGANIC_ORGAN(alcohol_liver)) // robotic livers aren't affected + alcohol_liver.maxHealth = alcohol_liver.maxHealth * 0.75 + alcohol_liver.healing_factor = alcohol_liver.healing_factor * 0.75 + +/datum/quirk/item_quirk/junkie/alcoholic/remove() + UnregisterSignal(quirk_holder, COMSIG_MOB_REAGENT_CHECK) + +/datum/quirk/item_quirk/junkie/alcoholic/proc/check_brandy(mob/source, datum/reagent/booze) + SIGNAL_HANDLER + + //we don't care if it is not alcohol + if(!istype(booze, /datum/reagent/consumable/ethanol)) + return + + if(istype(booze, favorite_alcohol)) + quirk_holder.clear_mood_event("wrong_alcohol") + else + quirk_holder.add_mood_event("wrong_alcohol", /datum/mood_event/wrong_brandy) diff --git a/code/datums/quirks/negative_quirks/light_drinker.dm b/code/datums/quirks/negative_quirks/light_drinker.dm new file mode 100644 index 00000000000000..5f82e2b9cd7051 --- /dev/null +++ b/code/datums/quirks/negative_quirks/light_drinker.dm @@ -0,0 +1,11 @@ +/datum/quirk/light_drinker + name = "Light Drinker" + desc = "You just can't handle your drinks and get drunk very quickly." + icon = FA_ICON_COCKTAIL + value = -2 + mob_trait = TRAIT_LIGHT_DRINKER + gain_text = span_notice("Just the thought of drinking alcohol makes your head spin.") + lose_text = span_danger("You're no longer severely affected by alcohol.") + medical_record_text = "Patient demonstrates a low tolerance for alcohol. (Wimp)" + hardcore_value = 3 + mail_goodies = list(/obj/item/reagent_containers/cup/glass/waterbottle) diff --git a/code/datums/quirks/negative_quirks/mute.dm b/code/datums/quirks/negative_quirks/mute.dm new file mode 100644 index 00000000000000..44706c4d4346d7 --- /dev/null +++ b/code/datums/quirks/negative_quirks/mute.dm @@ -0,0 +1,10 @@ +/datum/quirk/mute + name = "Mute" + desc = "For some reason you are completely unable to speak." + icon = FA_ICON_VOLUME_XMARK + value = -4 + mob_trait = TRAIT_MUTE + gain_text = span_danger("You find yourself unable to speak!") + lose_text = span_notice("You feel a growing strength in your vocal chords.") + medical_record_text = "The patient is unable to use their voice in any capacity." + hardcore_value = 4 diff --git a/code/datums/quirks/negative_quirks/nearsighted.dm b/code/datums/quirks/negative_quirks/nearsighted.dm new file mode 100644 index 00000000000000..6a5397b6504597 --- /dev/null +++ b/code/datums/quirks/negative_quirks/nearsighted.dm @@ -0,0 +1,30 @@ +/datum/quirk/item_quirk/nearsighted + name = "Nearsighted" + desc = "You are nearsighted without prescription glasses, but spawn with a pair." + icon = FA_ICON_GLASSES + value = -4 + gain_text = span_danger("Things far away from you start looking blurry.") + lose_text = span_notice("You start seeing faraway things normally again.") + medical_record_text = "Patient requires prescription glasses in order to counteract nearsightedness." + hardcore_value = 5 + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE + mail_goodies = list(/obj/item/clothing/glasses/regular) // extra pair if orginal one gets broken by somebody mean + +/datum/quirk/item_quirk/nearsighted/add_unique(client/client_source) + var/glasses_name = client_source?.prefs.read_preference(/datum/preference/choiced/glasses) || "Regular" + var/obj/item/clothing/glasses/glasses_type + + glasses_name = glasses_name == "Random" ? pick(GLOB.nearsighted_glasses) : glasses_name + glasses_type = GLOB.nearsighted_glasses[glasses_name] + + give_item_to_holder(glasses_type, list( + LOCATION_EYES = ITEM_SLOT_EYES, + LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, + LOCATION_HANDS = ITEM_SLOT_HANDS, + )) + +/datum/quirk/item_quirk/nearsighted/add(client/client_source) + quirk_holder.become_nearsighted(QUIRK_TRAIT) + +/datum/quirk/item_quirk/nearsighted/remove() + quirk_holder.cure_nearsighted(QUIRK_TRAIT) diff --git a/code/datums/quirks/negative_quirks/negative_quirks.dm b/code/datums/quirks/negative_quirks/negative_quirks.dm deleted file mode 100644 index 03b4354b9cbd63..00000000000000 --- a/code/datums/quirks/negative_quirks/negative_quirks.dm +++ /dev/null @@ -1,1567 +0,0 @@ -//predominantly negative traits -/datum/quirk/badback - name = "Bad Back" - desc = "Thanks to your poor posture, backpacks and other bags never sit right on your back. More evenly weighted objects are fine, though." - icon = FA_ICON_HIKING - value = -8 - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED - gain_text = span_danger("Your back REALLY hurts!") - lose_text = span_notice("Your back feels better.") - medical_record_text = "Patient scans indicate severe and chronic back pain." - hardcore_value = 4 - mail_goodies = list(/obj/item/cane) - var/datum/weakref/backpack - -/datum/quirk/badback/add(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - var/obj/item/storage/backpack/equipped_backpack = human_holder.back - if(istype(equipped_backpack)) - quirk_holder.add_mood_event("back_pain", /datum/mood_event/back_pain) - RegisterSignal(human_holder.back, COMSIG_ITEM_POST_UNEQUIP, PROC_REF(on_unequipped_backpack)) - else - RegisterSignal(quirk_holder, COMSIG_MOB_EQUIPPED_ITEM, PROC_REF(on_equipped_item)) - -/datum/quirk/badback/remove() - UnregisterSignal(quirk_holder, COMSIG_MOB_EQUIPPED_ITEM) - - var/obj/item/storage/equipped_backpack = backpack?.resolve() - if(equipped_backpack) - UnregisterSignal(equipped_backpack, COMSIG_ITEM_POST_UNEQUIP) - quirk_holder.clear_mood_event("back_pain") - -/// Signal handler for when the quirk_holder equips an item. If it's a backpack, adds the back_pain mood event. -/datum/quirk/badback/proc/on_equipped_item(mob/living/source, obj/item/equipped_item, slot) - SIGNAL_HANDLER - - if(!(slot & ITEM_SLOT_BACK) || !istype(equipped_item, /obj/item/storage/backpack)) - return - - quirk_holder.add_mood_event("back_pain", /datum/mood_event/back_pain) - RegisterSignal(equipped_item, COMSIG_ITEM_POST_UNEQUIP, PROC_REF(on_unequipped_backpack)) - UnregisterSignal(quirk_holder, COMSIG_MOB_EQUIPPED_ITEM) - backpack = WEAKREF(equipped_item) - -/// Signal handler for when the quirk_holder unequips an equipped backpack. Removes the back_pain mood event. -/datum/quirk/badback/proc/on_unequipped_backpack(obj/item/source, force, atom/newloc, no_move, invdrop, silent) - SIGNAL_HANDLER - - UnregisterSignal(source, COMSIG_ITEM_POST_UNEQUIP) - quirk_holder.clear_mood_event("back_pain") - backpack = null - RegisterSignal(quirk_holder, COMSIG_MOB_EQUIPPED_ITEM, PROC_REF(on_equipped_item)) - -/datum/quirk/blooddeficiency - name = "Blood Deficiency" - desc = "Your body can't produce enough blood to sustain itself." - icon = FA_ICON_TINT - value = -8 - mob_trait = TRAIT_BLOOD_DEFICIENCY - gain_text = span_danger("You feel your vigor slowly fading away.") - lose_text = span_notice("You feel vigorous again.") - medical_record_text = "Patient requires regular treatment for blood loss due to low production of blood." - hardcore_value = 8 - mail_goodies = list(/obj/item/reagent_containers/blood/o_minus) // universal blood type that is safe for all - var/min_blood = BLOOD_VOLUME_SAFE - 25 // just barely survivable without treatment - -/datum/quirk/blooddeficiency/post_add() - if(!ishuman(quirk_holder)) - return - - // for making sure the roundstart species has the right blood pack sent to them - var/mob/living/carbon/human/carbon_target = quirk_holder - carbon_target.dna.species.update_quirk_mail_goodies(carbon_target, src) - -/** - * Makes the mob lose blood from having the blood deficiency quirk, if possible - * - * Arguments: - * * seconds_per_tick - */ -/datum/quirk/blooddeficiency/proc/lose_blood(seconds_per_tick) - if(quirk_holder.stat == DEAD) - return - - var/mob/living/carbon/human/carbon_target = quirk_holder - if(HAS_TRAIT(carbon_target, TRAIT_NOBLOOD) && isnull(carbon_target.dna.species.exotic_blood)) //can't lose blood if your species doesn't have any - return - - if (carbon_target.blood_volume <= min_blood) - return - // Ensures that we don't reduce total blood volume below min_blood. - carbon_target.blood_volume = max(min_blood, carbon_target.blood_volume - carbon_target.dna.species.blood_deficiency_drain_rate * seconds_per_tick) - -/datum/quirk/item_quirk/blindness - name = "Blind" - desc = "You are completely blind, nothing can counteract this." - icon = FA_ICON_EYE_SLASH - value = -16 - gain_text = span_danger("You can't see anything.") - lose_text = span_notice("You miraculously gain back your vision.") - medical_record_text = "Patient has permanent blindness." - hardcore_value = 15 - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE - mail_goodies = list(/obj/item/clothing/glasses/sunglasses, /obj/item/cane/white) - -/datum/quirk/item_quirk/blindness/add_unique(client/client_source) - give_item_to_holder(/obj/item/clothing/glasses/blindfold/white, list(LOCATION_EYES = ITEM_SLOT_EYES, LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) - -/datum/quirk/item_quirk/blindness/add(client/client_source) - quirk_holder.become_blind(QUIRK_TRAIT) - -/datum/quirk/item_quirk/blindness/remove() - quirk_holder.cure_blind(QUIRK_TRAIT) - - /* A couple of brain tumor stats for anyone curious / looking at this quirk for balancing: - * - It takes less 16 minute 40 seconds to die from brain death due to a brain tumor. - * - It takes 1 minutes 40 seconds to take 10% (20 organ damage) brain damage. - * - 5u mannitol will heal 12.5% (25 organ damage) brain damage - */ -/datum/quirk/item_quirk/brainproblems - name = "Brain Tumor" - desc = "You have a little friend in your brain that is slowly destroying it. Better bring some mannitol!" - icon = FA_ICON_BRAIN - value = -12 - gain_text = span_danger("You feel smooth.") - lose_text = span_notice("You feel wrinkled again.") - medical_record_text = "Patient has a tumor in their brain that is slowly driving them to brain death." - hardcore_value = 12 - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES - mail_goodies = list(/obj/item/storage/pill_bottle/mannitol/braintumor) - -/datum/quirk/item_quirk/brainproblems/add_unique(client/client_source) - give_item_to_holder( - /obj/item/storage/pill_bottle/mannitol/braintumor, - list( - LOCATION_LPOCKET = ITEM_SLOT_LPOCKET, - LOCATION_RPOCKET = ITEM_SLOT_RPOCKET, - LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, - LOCATION_HANDS = ITEM_SLOT_HANDS, - ), - flavour_text = "These will keep you alive until you can secure a supply of medication. Don't rely on them too much!", - ) - -/datum/quirk/item_quirk/brainproblems/process(seconds_per_tick) - if(quirk_holder.stat == DEAD) - return - - if(HAS_TRAIT(quirk_holder, TRAIT_TUMOR_SUPPRESSED)) - return - - quirk_holder.adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.2 * seconds_per_tick) - -/datum/quirk/item_quirk/deafness - name = "Deaf" - desc = "You are incurably deaf." - icon = FA_ICON_DEAF - value = -8 - mob_trait = TRAIT_DEAF - gain_text = span_danger("You can't hear anything.") - lose_text = span_notice("You're able to hear again!") - medical_record_text = "Patient's cochlear nerve is incurably damaged." - hardcore_value = 12 - mail_goodies = list(/obj/item/clothing/mask/whistle) - -/datum/quirk/item_quirk/deafness/add_unique(client/client_source) - give_item_to_holder(/obj/item/clothing/accessory/deaf_pin, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) - -/datum/quirk/depression - name = "Depression" - desc = "You sometimes just hate life." - icon = FA_ICON_FROWN - mob_trait = TRAIT_DEPRESSION - value = -3 - gain_text = span_danger("You start feeling depressed.") - lose_text = span_notice("You no longer feel depressed.") //if only it were that easy! - medical_record_text = "Patient has a mild mood disorder causing them to experience acute episodes of depression." - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED - hardcore_value = 2 - mail_goodies = list(/obj/item/storage/pill_bottle/happinesspsych) - -/datum/quirk/item_quirk/family_heirloom - name = "Family Heirloom" - desc = "You are the current owner of an heirloom, passed down for generations. You have to keep it safe!" - icon = FA_ICON_TOOLBOX - value = -2 - medical_record_text = "Patient demonstrates an unnatural attachment to a family heirloom." - hardcore_value = 1 - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES|QUIRK_MOODLET_BASED - /// A weak reference to our heirloom. - var/datum/weakref/heirloom - mail_goodies = list(/obj/item/storage/secure/briefcase) - -/datum/quirk/item_quirk/family_heirloom/add_unique(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - var/obj/item/heirloom_type - - // The quirk holder's species - we have a 50% chance, if we have a species with a set heirloom, to choose a species heirloom. - var/datum/species/holder_species = human_holder.dna?.species - if(holder_species && LAZYLEN(holder_species.family_heirlooms) && prob(50)) - heirloom_type = pick(holder_species.family_heirlooms) - else - // Our quirk holder's job - var/datum/job/holder_job = human_holder.last_mind?.assigned_role - if(holder_job && LAZYLEN(holder_job.family_heirlooms)) - heirloom_type = pick(holder_job.family_heirlooms) - - // If we didn't find an heirloom somehow, throw them a generic one - if(!heirloom_type) - heirloom_type = pick(/obj/item/toy/cards/deck, /obj/item/lighter, /obj/item/dice/d20) - - var/obj/new_heirloom = new heirloom_type(get_turf(human_holder)) - heirloom = WEAKREF(new_heirloom) - - give_item_to_holder( - new_heirloom, - list( - LOCATION_LPOCKET = ITEM_SLOT_LPOCKET, - LOCATION_RPOCKET = ITEM_SLOT_RPOCKET, - LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, - LOCATION_HANDS = ITEM_SLOT_HANDS, - ), - flavour_text = "This is a precious family heirloom, passed down from generation to generation. Keep it safe!", - ) - -/datum/quirk/item_quirk/family_heirloom/post_add() - var/list/names = splittext(quirk_holder.real_name, " ") - var/family_name = names[names.len] - - var/obj/family_heirloom = heirloom?.resolve() - if(!family_heirloom) - to_chat(quirk_holder, span_boldnotice("A wave of existential dread runs over you as you realize your precious family heirloom is missing. Perhaps the Gods will show mercy on your cursed soul?")) - return - family_heirloom.AddComponent(/datum/component/heirloom, quirk_holder.mind, family_name) - - return ..() - -/datum/quirk/item_quirk/family_heirloom/process() - if(quirk_holder.stat == DEAD) - return - - var/obj/family_heirloom = heirloom?.resolve() - - if(family_heirloom && (family_heirloom in quirk_holder.get_all_contents())) - quirk_holder.clear_mood_event("family_heirloom_missing") - quirk_holder.add_mood_event("family_heirloom", /datum/mood_event/family_heirloom) - else - quirk_holder.clear_mood_event("family_heirloom") - quirk_holder.add_mood_event("family_heirloom_missing", /datum/mood_event/family_heirloom_missing) - -/datum/quirk/item_quirk/family_heirloom/remove() - quirk_holder.clear_mood_event("family_heirloom_missing") - quirk_holder.clear_mood_event("family_heirloom") - -/datum/quirk/glass_jaw - name = "Glass Jaw" - desc = "You have a very fragile jaw. Any sufficiently hard blow to your head might knock you out." - icon = FA_ICON_HAND_FIST - value = -4 - gain_text = span_danger("Your jaw feels loose.") - lose_text = span_notice("Your jaw feels fitting again.") - medical_record_text = "Patient is absurdly easy to knock out. Do not allow them near a boxing ring." - hardcore_value = 4 - mail_goodies = list( - /obj/item/clothing/gloves/boxing, - /obj/item/clothing/mask/luchador/rudos, - ) - -/datum/quirk/glass_jaw/New() - . = ..() - //randomly picks between blue or red equipment for goodies - if(prob(50)) - mail_goodies = list( - /obj/item/clothing/gloves/boxing, - /obj/item/clothing/mask/luchador/rudos, - ) - else - mail_goodies = list( - /obj/item/clothing/gloves/boxing/blue, - /obj/item/clothing/mask/luchador/tecnicos, - ) - -/datum/quirk/glass_jaw/add(client/client_source) - RegisterSignal(quirk_holder, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(punch_out)) - -/datum/quirk/glass_jaw/remove() - UnregisterSignal(quirk_holder, COMSIG_MOB_APPLY_DAMAGE) - -/datum/quirk/glass_jaw/proc/punch_out(mob/living/carbon/source, damage, damagetype, def_zone, blocked, wound_bonus, bare_wound_bonus, sharpness, attack_direction, attacking_item) - SIGNAL_HANDLER - if((damagetype != BRUTE) || (def_zone != BODY_ZONE_HEAD)) - return - var/actual_damage = damage - (damage * blocked/100) - //only roll for knockouts at 5 damage or more - if(actual_damage < 5) - return - //blunt items are more likely to knock out, but sharp ones are still capable of doing it - if(prob(CEILING(actual_damage * (sharpness & (SHARP_EDGED|SHARP_POINTY) ? 0.65 : 1), 1))) - //don't display the message if little mac is already KO'd - if(!source.IsUnconscious()) - source.visible_message( - span_warning("[source] gets knocked out!"), - span_userdanger("You get knocked out!"), - vision_distance = COMBAT_MESSAGE_RANGE, - ) - source.Unconscious(3 SECONDS) - -/datum/quirk/frail - name = "Frail" - desc = "You have skin of paper and bones of glass! You suffer wounds much more easily than most." - icon = FA_ICON_SKULL - value = -6 - mob_trait = TRAIT_EASILY_WOUNDED - gain_text = span_danger("You feel frail.") - lose_text = span_notice("You feel sturdy again.") - medical_record_text = "Patient is absurdly easy to injure. Please take all due diligence to avoid possible malpractice suits." - hardcore_value = 4 - mail_goodies = list(/obj/effect/spawner/random/medical/minor_healing) - -/datum/quirk/heavy_sleeper - name = "Heavy Sleeper" - desc = "You sleep like a rock! Whenever you're put to sleep or knocked unconscious, you take a little bit longer to wake up." - icon = FA_ICON_BED - value = -2 - mob_trait = TRAIT_HEAVY_SLEEPER - gain_text = span_danger("You feel sleepy.") - lose_text = span_notice("You feel awake again.") - medical_record_text = "Patient has abnormal sleep study results and is difficult to wake up." - hardcore_value = 2 - mail_goodies = list( - /obj/item/clothing/glasses/blindfold, - /obj/item/bedsheet/random, - /obj/item/clothing/under/misc/pj/red, - /obj/item/clothing/head/costume/nightcap/red, - /obj/item/clothing/under/misc/pj/blue, - /obj/item/clothing/head/costume/nightcap/blue, - /obj/item/pillow/random, - ) - -/datum/quirk/hypersensitive - name = "Hypersensitive" - desc = "For better or worse, everything seems to affect your mood more than it should." - icon = FA_ICON_FLUSHED - value = -2 - gain_text = span_danger("You seem to make a big deal out of everything.") - lose_text = span_notice("You don't seem to make a big deal out of everything anymore.") - medical_record_text = "Patient demonstrates a high level of emotional volatility." - hardcore_value = 3 - mail_goodies = list(/obj/effect/spawner/random/entertainment/plushie_delux) - -/datum/quirk/hypersensitive/add(client/client_source) - if (quirk_holder.mob_mood) - quirk_holder.mob_mood.mood_modifier += 0.5 - -/datum/quirk/hypersensitive/remove() - if (quirk_holder.mob_mood) - quirk_holder.mob_mood.mood_modifier -= 0.5 - -/datum/quirk/light_drinker - name = "Light Drinker" - desc = "You just can't handle your drinks and get drunk very quickly." - icon = FA_ICON_COCKTAIL - value = -2 - mob_trait = TRAIT_LIGHT_DRINKER - gain_text = span_notice("Just the thought of drinking alcohol makes your head spin.") - lose_text = span_danger("You're no longer severely affected by alcohol.") - medical_record_text = "Patient demonstrates a low tolerance for alcohol. (Wimp)" - hardcore_value = 3 - mail_goodies = list(/obj/item/reagent_containers/cup/glass/waterbottle) - - -/datum/quirk/item_quirk/nearsighted - name = "Nearsighted" - desc = "You are nearsighted without prescription glasses, but spawn with a pair." - icon = FA_ICON_GLASSES - value = -4 - gain_text = span_danger("Things far away from you start looking blurry.") - lose_text = span_notice("You start seeing faraway things normally again.") - medical_record_text = "Patient requires prescription glasses in order to counteract nearsightedness." - hardcore_value = 5 - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE - mail_goodies = list(/obj/item/clothing/glasses/regular) // extra pair if orginal one gets broken by somebody mean - -/datum/quirk/item_quirk/nearsighted/add_unique(client/client_source) - var/glasses_name = client_source?.prefs.read_preference(/datum/preference/choiced/glasses) || "Regular" - var/obj/item/clothing/glasses/glasses_type - - glasses_name = glasses_name == "Random" ? pick(GLOB.nearsighted_glasses) : glasses_name - glasses_type = GLOB.nearsighted_glasses[glasses_name] - - give_item_to_holder(glasses_type, list( - LOCATION_EYES = ITEM_SLOT_EYES, - LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, - LOCATION_HANDS = ITEM_SLOT_HANDS, - )) - -/datum/quirk/item_quirk/nearsighted/add(client/client_source) - quirk_holder.become_nearsighted(QUIRK_TRAIT) - -/datum/quirk/item_quirk/nearsighted/remove() - quirk_holder.cure_nearsighted(QUIRK_TRAIT) - -/datum/quirk/nyctophobia - name = "Nyctophobia" - desc = "As far as you can remember, you've always been afraid of the dark. While in the dark without a light source, you instinctively act careful, and constantly feel a sense of dread." - icon = FA_ICON_LIGHTBULB - value = -3 - medical_record_text = "Patient demonstrates a fear of the dark. (Seriously?)" - hardcore_value = 5 - mail_goodies = list(/obj/effect/spawner/random/engineering/flashlight) - -/datum/quirk/nyctophobia/add(client/client_source) - RegisterSignal(quirk_holder, COMSIG_MOVABLE_MOVED, PROC_REF(on_holder_moved)) - -/datum/quirk/nyctophobia/remove() - UnregisterSignal(quirk_holder, COMSIG_MOVABLE_MOVED) - quirk_holder.clear_mood_event("nyctophobia") - -/// Called when the quirk holder moves. Updates the quirk holder's mood. -/datum/quirk/nyctophobia/proc/on_holder_moved(mob/living/source, atom/old_loc, dir, forced) - SIGNAL_HANDLER - - if(quirk_holder.stat != CONSCIOUS || quirk_holder.IsSleeping() || quirk_holder.IsUnconscious()) - return - - if(HAS_TRAIT(quirk_holder, TRAIT_FEARLESS)) - return - - var/mob/living/carbon/human/human_holder = quirk_holder - - if(human_holder.dna?.species.id in list(SPECIES_SHADOW, SPECIES_NIGHTMARE)) - return - - if((human_holder.sight & SEE_TURFS) == SEE_TURFS) - return - - var/turf/holder_turf = get_turf(quirk_holder) - - var/lums = holder_turf.get_lumcount() - - if(lums > LIGHTING_TILE_IS_DARK) - quirk_holder.clear_mood_event("nyctophobia") - return - - if(quirk_holder.move_intent == MOVE_INTENT_RUN) - to_chat(quirk_holder, span_warning("Easy, easy, take it slow... you're in the dark...")) - quirk_holder.toggle_move_intent() - quirk_holder.add_mood_event("nyctophobia", /datum/mood_event/nyctophobia) - -#define MOOD_CATEGORY_PHOTOPHOBIA "photophobia" - -/datum/quirk/photophobia - name = "Photophobia" - desc = "Bright lights seem to bother you more than others. Maybe it's a medical condition." - icon = FA_ICON_ARROWS_TO_EYE - value = -4 - gain_text = span_danger("The safety of light feels off...") - lose_text = span_notice("Enlightening.") - medical_record_text = "Patient has acute phobia of light, and insists it is physically harmful." - hardcore_value = 4 - mail_goodies = list( - /obj/item/flashlight/flashdark, - /obj/item/food/grown/mushroom/glowshroom/shadowshroom, - /obj/item/skillchip/light_remover, - ) - -/datum/quirk/photophobia/add(client/client_source) - RegisterSignal(quirk_holder, COMSIG_CARBON_GAIN_ORGAN, PROC_REF(check_eyes)) - RegisterSignal(quirk_holder, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(restore_eyes)) - RegisterSignal(quirk_holder, COMSIG_MOVABLE_MOVED, PROC_REF(on_holder_moved)) - update_eyes(quirk_holder.get_organ_slot(ORGAN_SLOT_EYES)) - -/datum/quirk/photophobia/remove() - UnregisterSignal(quirk_holder, list( - COMSIG_CARBON_GAIN_ORGAN, - COMSIG_CARBON_LOSE_ORGAN, - COMSIG_MOVABLE_MOVED,)) - quirk_holder.clear_mood_event(MOOD_CATEGORY_PHOTOPHOBIA) - var/obj/item/organ/internal/eyes/normal_eyes = quirk_holder.get_organ_slot(ORGAN_SLOT_EYES) - if(istype(normal_eyes)) - normal_eyes.flash_protect = initial(normal_eyes.flash_protect) - -/datum/quirk/photophobia/proc/check_eyes(obj/item/organ/internal/eyes/sensitive_eyes) - SIGNAL_HANDLER - if(!istype(sensitive_eyes)) - return - update_eyes(sensitive_eyes) - -/datum/quirk/photophobia/proc/update_eyes(obj/item/organ/internal/eyes/target_eyes) - if(!istype(target_eyes)) - return - target_eyes.flash_protect = max(target_eyes.flash_protect - 1, FLASH_PROTECTION_HYPER_SENSITIVE) - -/datum/quirk/photophobia/proc/restore_eyes(obj/item/organ/internal/eyes/normal_eyes) - SIGNAL_HANDLER - if(!istype(normal_eyes)) - return - normal_eyes.flash_protect = initial(normal_eyes.flash_protect) - -/datum/quirk/photophobia/proc/on_holder_moved(mob/living/source, atom/old_loc, dir, forced) - SIGNAL_HANDLER - - if(quirk_holder.stat != CONSCIOUS || quirk_holder.IsSleeping() || quirk_holder.IsUnconscious()) - return - - if(HAS_TRAIT(quirk_holder, TRAIT_FEARLESS)) - return - - var/mob/living/carbon/human/human_holder = quirk_holder - - if(human_holder.sight & SEE_TURFS) - return - - var/turf/holder_turf = get_turf(quirk_holder) - - var/lums = holder_turf.get_lumcount() - - var/eye_protection = quirk_holder.get_eye_protection() - if(lums < LIGHTING_TILE_IS_DARK || eye_protection >= FLASH_PROTECTION_NONE) - quirk_holder.clear_mood_event(MOOD_CATEGORY_PHOTOPHOBIA) - return - quirk_holder.add_mood_event(MOOD_CATEGORY_PHOTOPHOBIA, /datum/mood_event/photophobia) - - #undef MOOD_CATEGORY_PHOTOPHOBIA - -/datum/quirk/softspoken - name = "Soft-Spoken" - desc = "You are soft-spoken, and your voice is hard to hear." - icon = FA_ICON_COMMENT - value = -2 - mob_trait = TRAIT_SOFTSPOKEN - gain_text = span_danger("You feel like you're speaking more quietly.") - lose_text = span_notice("You feel like you're speaking louder.") - medical_record_text = "Patient is soft-spoken and difficult to hear." - -/datum/quirk/clumsy - name = "Clumsy" - desc = "You're clumsy, a goofball, a silly dude. You big loveable himbo/bimbo you! Hope you weren't planning on using your hands for anything that takes even a LICK of dexterity." - icon = FA_ICON_FACE_DIZZY - value = -8 - mob_trait = TRAIT_CLUMSY - gain_text = span_danger("You feel your IQ sink like your brain is liquid.") - lose_text = span_notice("You feel like your IQ went up to at least average.") - medical_record_text = "Patient has demonstrated an extreme difficulty with high motor skill paired with an inability to demonstrate critical thinking." - -/datum/quirk/nonviolent - name = "Pacifist" - desc = "The thought of violence makes you sick. So much so, in fact, that you can't hurt anyone." - icon = FA_ICON_PEACE - value = -8 - mob_trait = TRAIT_PACIFISM - gain_text = span_danger("You feel repulsed by the thought of violence!") - lose_text = span_notice("You think you can defend yourself again.") - medical_record_text = "Patient is unusually pacifistic and cannot bring themselves to cause physical harm." - hardcore_value = 6 - mail_goodies = list(/obj/effect/spawner/random/decoration/flower, /obj/effect/spawner/random/contraband/cannabis) // flower power - -/datum/quirk/bighands - name = "Big Hands" - desc = "You have big hands, it sure does make it hard to use a lot of things." - icon = FA_ICON_HAND_DOTS - value = -6 - mob_trait = TRAIT_CHUNKYFINGERS - gain_text = span_danger("Your hands are huge! You can't use small things anymore!") - lose_text = span_notice("Your hands are back to normal.") - medical_record_text = "Patient has unusually large hands. Made me question my masculinity..." - hardcore_value = 5 - -/datum/quirk/paraplegic - name = "Paraplegic" - desc = "Your legs do not function. Nothing will ever fix this. But hey, free wheelchair!" - icon = FA_ICON_WHEELCHAIR - value = -12 - gain_text = null // Handled by trauma. - lose_text = null - medical_record_text = "Patient has an untreatable impairment in motor function in the lower extremities." - hardcore_value = 15 - mail_goodies = list(/obj/vehicle/ridden/wheelchair/motorized) //yes a fullsized unfolded motorized wheelchair does fit - -/datum/quirk/paraplegic/add_unique(client/client_source) - if(quirk_holder.buckled) // Handle late joins being buckled to arrival shuttle chairs. - quirk_holder.buckled.unbuckle_mob(quirk_holder) - - var/turf/holder_turf = get_turf(quirk_holder) - var/obj/structure/chair/spawn_chair = locate() in holder_turf - - var/obj/vehicle/ridden/wheelchair/wheels - if(client_source?.get_award_status(/datum/award/score/hardcore_random) >= 5000) //More than 5k score? you unlock the gamer wheelchair. - wheels = new /obj/vehicle/ridden/wheelchair/gold(holder_turf) - else - wheels = new(holder_turf) - if(spawn_chair) // Makes spawning on the arrivals shuttle more consistent looking - wheels.setDir(spawn_chair.dir) - - wheels.buckle_mob(quirk_holder) - - // During the spawning process, they may have dropped what they were holding, due to the paralysis - // So put the things back in their hands. - for(var/obj/item/dropped_item in holder_turf) - if(dropped_item.fingerprintslast == quirk_holder.ckey) - quirk_holder.put_in_hands(dropped_item) - -/datum/quirk/paraplegic/add(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.gain_trauma(/datum/brain_trauma/severe/paralysis/paraplegic, TRAUMA_RESILIENCE_ABSOLUTE) - -/datum/quirk/paraplegic/remove() - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.cure_trauma_type(/datum/brain_trauma/severe/paralysis/paraplegic, TRAUMA_RESILIENCE_ABSOLUTE) - -/datum/quirk/hemiplegic - name = "Hemiplegic" - desc = "Half of your body doesn't work. Nothing will ever fix this." - icon = FA_ICON_CIRCLE_HALF_STROKE - value = -10 // slightly more bearable than paraplegic but not by much - gain_text = null // Handled by trauma. - lose_text = null - medical_record_text = "Patient has an untreatable impairment in motor function on half of their body." - hardcore_value = 10 - mail_goodies = list( - /obj/item/stack/sheet/mineral/uranium/half, //half a stack of a material that has a half life - /obj/item/reagent_containers/cup/glass/drinkingglass/filled/half_full, - ) - -/datum/quirk/hemiplegic/add(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - var/trauma_type = pick(/datum/brain_trauma/severe/paralysis/hemiplegic/left, /datum/brain_trauma/severe/paralysis/hemiplegic/right) - human_holder.gain_trauma(trauma_type, TRAUMA_RESILIENCE_ABSOLUTE) - -/datum/quirk/hemiplegic/remove() - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.cure_trauma_type(/datum/brain_trauma/severe/paralysis/hemiplegic, TRAUMA_RESILIENCE_ABSOLUTE) - -/datum/quirk/poor_aim - name = "Stormtrooper Aim" - desc = "You've never hit anything you were aiming for in your life." - icon = FA_ICON_BULLSEYE - value = -4 - medical_record_text = "Patient possesses a strong tremor in both hands." - hardcore_value = 3 - mail_goodies = list(/obj/item/cardboard_cutout) // for target practice - -/datum/quirk/poor_aim/add(client/client_source) - RegisterSignal(quirk_holder, COMSIG_MOB_FIRED_GUN, PROC_REF(on_mob_fired_gun)) - -/datum/quirk/poor_aim/remove(client/client_source) - UnregisterSignal(quirk_holder, COMSIG_MOB_FIRED_GUN) - -/datum/quirk/poor_aim/proc/on_mob_fired_gun(mob/user, obj/item/gun/gun_fired, target, params, zone_override, list/bonus_spread_values) - SIGNAL_HANDLER - bonus_spread_values[MIN_BONUS_SPREAD_INDEX] += 10 - bonus_spread_values[MAX_BONUS_SPREAD_INDEX] += 35 - -/datum/quirk/prosopagnosia - name = "Prosopagnosia" - desc = "You have a mental disorder that prevents you from being able to recognize faces at all." - icon = FA_ICON_USER_SECRET - value = -4 - mob_trait = TRAIT_PROSOPAGNOSIA - medical_record_text = "Patient suffers from prosopagnosia and cannot recognize faces." - hardcore_value = 5 - mail_goodies = list(/obj/item/skillchip/appraiser) // bad at recognizing faces but good at recognizing IDs - -/datum/quirk/prosthetic_limb - name = "Prosthetic Limb" - desc = "An accident caused you to lose one of your limbs. Because of this, you now have a surplus prosthetic!" - icon = "tg-prosthetic-leg" - value = -3 - medical_record_text = "During physical examination, patient was found to have a low-budget prosthetic limb." - hardcore_value = 3 - quirk_flags = QUIRK_HUMAN_ONLY // while this technically changes appearance, we don't want it to be shown on the dummy because it's randomized at roundstart - mail_goodies = list(/obj/item/weldingtool/mini, /obj/item/stack/cable_coil/five) - /// The slot to replace, in string form - var/slot_string = "limb" - /// the original limb from before the prosthetic was applied - var/obj/item/bodypart/old_limb - -/datum/quirk/prosthetic_limb/add_unique(client/client_source) - var/limb_slot = pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) - var/mob/living/carbon/human/human_holder = quirk_holder - var/obj/item/bodypart/prosthetic - switch(limb_slot) - if(BODY_ZONE_L_ARM) - prosthetic = new /obj/item/bodypart/arm/left/robot/surplus - slot_string = "left arm" - if(BODY_ZONE_R_ARM) - prosthetic = new /obj/item/bodypart/arm/right/robot/surplus - slot_string = "right arm" - if(BODY_ZONE_L_LEG) - prosthetic = new /obj/item/bodypart/leg/left/robot/surplus - slot_string = "left leg" - if(BODY_ZONE_R_LEG) - prosthetic = new /obj/item/bodypart/leg/right/robot/surplus - slot_string = "right leg" - medical_record_text = "During physical examination, patient was found to have a low-budget prosthetic [slot_string]." - old_limb = human_holder.return_and_replace_bodypart(prosthetic, special = TRUE) - -/datum/quirk/prosthetic_limb/post_add() - to_chat(quirk_holder, span_boldannounce("Your [slot_string] has been replaced with a surplus prosthetic. It is fragile and will easily come apart under duress. Additionally, \ - you need to use a welding tool and cables to repair it, instead of bruise packs and ointment.")) - -/datum/quirk/prosthetic_limb/remove() - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.del_and_replace_bodypart(old_limb, special = TRUE) - old_limb = null - -/datum/quirk/quadruple_amputee - name = "Quadruple Amputee" - desc = "Oops! All Prosthetics! Due to some truly cruel cosmic punishment, all your limbs have been replaced with surplus prosthetics." - icon = "tg-prosthetic-full" - value = -6 - medical_record_text = "During physical examination, patient was found to have all low-budget prosthetic limbs." - hardcore_value = 6 - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE - mail_goodies = list(/obj/item/weldingtool/mini, /obj/item/stack/cable_coil/five) - -/datum/quirk/quadruple_amputee/add_unique(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.del_and_replace_bodypart(new /obj/item/bodypart/arm/left/robot/surplus, special = TRUE) - human_holder.del_and_replace_bodypart(new /obj/item/bodypart/arm/right/robot/surplus, special = TRUE) - human_holder.del_and_replace_bodypart(new /obj/item/bodypart/leg/left/robot/surplus, special = TRUE) - human_holder.del_and_replace_bodypart(new /obj/item/bodypart/leg/right/robot/surplus, special = TRUE) - -/datum/quirk/quadruple_amputee/post_add() - to_chat(quirk_holder, span_boldannounce("All your limbs have been replaced with surplus prosthetics. They are fragile and will easily come apart under duress. \ - Additionally, you need to use a welding tool and cables to repair them, instead of bruise packs and ointment.")) - -/datum/quirk/prosthetic_organ - name = "Prosthetic Organ" - desc = "An accident caused you to lose one of your organs. Because of this, you now have a surplus prosthetic!" - icon = FA_ICON_LUNGS - value = -3 - medical_record_text = "During physical examination, patient was found to have a low-budget prosthetic organ. \ - Removal of these organs is known to be dangerous to the patient as well as the practitioner." - hardcore_value = 3 - mail_goodies = list(/obj/item/storage/organbox) - /// The slot to replace, in string form - var/slot_string = "organ" - /// The original organ from before the prosthetic was applied - var/obj/item/organ/old_organ - -/datum/quirk/prosthetic_organ/add_unique(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - var/static/list/organ_slots = list( - ORGAN_SLOT_HEART, - ORGAN_SLOT_LUNGS, - ORGAN_SLOT_LIVER, - ORGAN_SLOT_STOMACH, - ) - var/list/possible_organ_slots = organ_slots.Copy() - if(HAS_TRAIT(human_holder, TRAIT_NOBLOOD)) - possible_organ_slots -= ORGAN_SLOT_HEART - if(HAS_TRAIT(human_holder, TRAIT_NOBREATH)) - possible_organ_slots -= ORGAN_SLOT_LUNGS - if(HAS_TRAIT(human_holder, TRAIT_LIVERLESS_METABOLISM)) - possible_organ_slots -= ORGAN_SLOT_LIVER - if(HAS_TRAIT(human_holder, TRAIT_NOHUNGER)) - possible_organ_slots -= ORGAN_SLOT_STOMACH - if(!length(organ_slots)) //what the hell - return - var/organ_slot = pick(possible_organ_slots) - var/obj/item/organ/prosthetic - switch(organ_slot) - if(ORGAN_SLOT_HEART) - prosthetic = new /obj/item/organ/internal/heart/cybernetic/surplus - slot_string = "heart" - if(ORGAN_SLOT_LUNGS) - prosthetic = new /obj/item/organ/internal/lungs/cybernetic/surplus - slot_string = "lungs" - if(ORGAN_SLOT_LIVER) - prosthetic = new /obj/item/organ/internal/liver/cybernetic/surplus - slot_string = "liver" - if(ORGAN_SLOT_STOMACH) - prosthetic = new /obj/item/organ/internal/stomach/cybernetic/surplus - slot_string = "stomach" - medical_record_text = "During physical examination, patient was found to have a low-budget prosthetic [slot_string]. \ - Removal of these organs is known to be dangerous to the patient as well as the practitioner." - old_organ = human_holder.get_organ_slot(organ_slot) - if(prosthetic.Insert(human_holder, special = TRUE, drop_if_replaced = TRUE)) - old_organ.moveToNullspace() - STOP_PROCESSING(SSobj, old_organ) - -/datum/quirk/prosthetic_organ/post_add() - to_chat(quirk_holder, span_boldannounce("Your [slot_string] has been replaced with a surplus organ. It is fragile and will easily come apart under duress. \ - Additionally, any EMP will make it stop working entirely.")) - -/datum/quirk/prosthetic_organ/remove() - if(old_organ) - old_organ.Insert(quirk_holder, special = TRUE) - old_organ = null - -/datum/quirk/tin_man - name = "Tin Man" - desc = "Oops! All Prosthetics! Due to some truly cruel cosmic punishment, most of your internal organs have been replaced with surplus prosthetics." - icon = FA_ICON_ROBOT - value = -6 - medical_record_text = "During physical examination, patient was found to have numerous low-budget prosthetic internal organs. \ - Removal of these organs is known to be dangerous to the patient as well as the practitioner." - hardcore_value = 6 - mail_goodies = list(/obj/item/storage/organbox) - -/datum/quirk/tin_man/add_unique(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - var/static/list/organ_slots = list( - ORGAN_SLOT_HEART = /obj/item/organ/internal/heart/cybernetic/surplus, - ORGAN_SLOT_LUNGS = /obj/item/organ/internal/lungs/cybernetic/surplus, - ORGAN_SLOT_LIVER = /obj/item/organ/internal/liver/cybernetic/surplus, - ORGAN_SLOT_STOMACH = /obj/item/organ/internal/stomach/cybernetic/surplus, - ) - var/list/possible_organ_slots = organ_slots.Copy() - if(HAS_TRAIT(human_holder, TRAIT_NOBLOOD)) - possible_organ_slots -= ORGAN_SLOT_HEART - if(HAS_TRAIT(human_holder, TRAIT_NOBREATH)) - possible_organ_slots -= ORGAN_SLOT_LUNGS - if(HAS_TRAIT(human_holder, TRAIT_LIVERLESS_METABOLISM)) - possible_organ_slots -= ORGAN_SLOT_LIVER - if(HAS_TRAIT(human_holder, TRAIT_NOHUNGER)) - possible_organ_slots -= ORGAN_SLOT_STOMACH - if(!length(organ_slots)) //what the hell - return - for(var/organ_slot in possible_organ_slots) - var/organ_path = possible_organ_slots[organ_slot] - var/obj/item/organ/new_organ = new organ_path() - new_organ.Insert(human_holder, special = TRUE, drop_if_replaced = FALSE) - -/datum/quirk/tin_man/post_add() - to_chat(quirk_holder, span_boldannounce("Most of your internal organs have been replaced with surplus prosthetics. They are fragile and will easily come apart under duress. \ - Additionally, any EMP will make them stop working entirely.")) - -/datum/quirk/pushover - name = "Pushover" - desc = "Your first instinct is always to let people push you around. Resisting out of grabs will take conscious effort." - icon = FA_ICON_HANDSHAKE - value = -8 - mob_trait = TRAIT_GRABWEAKNESS - gain_text = span_danger("You feel like a pushover.") - lose_text = span_notice("You feel like standing up for yourself.") - medical_record_text = "Patient presents a notably unassertive personality and is easy to manipulate." - hardcore_value = 4 - mail_goodies = list(/obj/item/clothing/gloves/cargo_gauntlet) - -/datum/quirk/insanity - name = "Reality Dissociation Syndrome" - desc = "You suffer from a severe disorder that causes very vivid hallucinations. \ - Mindbreaker toxin can suppress its effects, and you are immune to mindbreaker's hallucinogenic properties. \ - THIS IS NOT A LICENSE TO GRIEF." - icon = FA_ICON_GRIN_TONGUE_WINK - value = -8 - gain_text = span_userdanger("...") - lose_text = span_notice("You feel in tune with the world again.") - medical_record_text = "Patient suffers from acute Reality Dissociation Syndrome and experiences vivid hallucinations." - hardcore_value = 6 - mail_goodies = list(/obj/item/storage/pill_bottle/lsdpsych) - /// Weakref to the trauma we give out - var/datum/weakref/added_trama_ref - -/datum/quirk/insanity/add(client/client_source) - if(!iscarbon(quirk_holder)) - return - var/mob/living/carbon/carbon_quirk_holder = quirk_holder - - // Setup our special RDS mild hallucination. - // Not a unique subtype so not to plague subtypesof, - // also as we inherit the names and values from our quirk. - var/datum/brain_trauma/mild/hallucinations/added_trauma = new() - added_trauma.resilience = TRAUMA_RESILIENCE_ABSOLUTE - added_trauma.name = name - added_trauma.desc = medical_record_text - added_trauma.scan_desc = lowertext(name) - added_trauma.gain_text = null - added_trauma.lose_text = null - - carbon_quirk_holder.gain_trauma(added_trauma) - added_trama_ref = WEAKREF(added_trauma) - -/datum/quirk/insanity/post_add() - var/rds_policy = get_policy("[type]") || "Please note that your [lowertext(name)] does NOT give you any additional right to attack people or cause chaos." - // I don't /think/ we'll need this, but for newbies who think "roleplay as insane" = "license to kill", it's probably a good thing to have. - to_chat(quirk_holder, span_big(span_info(rds_policy))) - -/datum/quirk/insanity/remove() - QDEL_NULL(added_trama_ref) - -/datum/quirk/social_anxiety - name = "Social Anxiety" - desc = "Talking to people is very difficult for you, and you often stutter or even lock up." - icon = FA_ICON_COMMENT_SLASH - value = -3 - gain_text = span_danger("You start worrying about what you're saying.") - lose_text = span_notice("You feel easier about talking again.") //if only it were that easy! - medical_record_text = "Patient is usually anxious in social encounters and prefers to avoid them." - hardcore_value = 4 - mob_trait = TRAIT_ANXIOUS - mail_goodies = list(/obj/item/storage/pill_bottle/psicodine) - var/dumb_thing = TRUE - -/datum/quirk/social_anxiety/add(client/client_source) - RegisterSignal(quirk_holder, COMSIG_MOB_EYECONTACT, PROC_REF(eye_contact)) - RegisterSignal(quirk_holder, COMSIG_MOB_EXAMINATE, PROC_REF(looks_at_floor)) - RegisterSignal(quirk_holder, COMSIG_MOB_SAY, PROC_REF(handle_speech)) - -/datum/quirk/social_anxiety/remove() - UnregisterSignal(quirk_holder, list(COMSIG_MOB_EYECONTACT, COMSIG_MOB_EXAMINATE, COMSIG_MOB_SAY)) - -/datum/quirk/social_anxiety/proc/handle_speech(datum/source, list/speech_args) - SIGNAL_HANDLER - - if(HAS_TRAIT(quirk_holder, TRAIT_FEARLESS)) - return - - var/moodmod - if(quirk_holder.mob_mood) - moodmod = (1+0.02*(50-(max(50, quirk_holder.mob_mood.mood_level*(7-quirk_holder.mob_mood.sanity_level))))) //low sanity levels are better, they max at 6 - else - moodmod = (1+0.02*(50-(max(50, 0.1*quirk_holder.nutrition)))) - var/nearby_people = 0 - for(var/mob/living/carbon/human/H in oview(3, quirk_holder)) - if(H.client) - nearby_people++ - var/message = speech_args[SPEECH_MESSAGE] - if(message) - var/list/message_split = splittext(message, " ") - var/list/new_message = list() - var/mob/living/carbon/human/quirker = quirk_holder - for(var/word in message_split) - if(prob(max(5,(nearby_people*12.5*moodmod))) && word != message_split[1]) //Minimum 1/20 chance of filler - new_message += pick("uh,","erm,","um,") - if(prob(min(5,(0.05*(nearby_people*12.5)*moodmod)))) //Max 1 in 20 chance of cutoff after a successful filler roll, for 50% odds in a 15 word sentence - quirker.set_silence_if_lower(6 SECONDS) - to_chat(quirker, span_danger("You feel self-conscious and stop talking. You need a moment to recover!")) - break - if(prob(max(5,(nearby_people*12.5*moodmod)))) //Minimum 1/20 chance of stutter - // Add a short stutter, THEN treat our word - quirker.adjust_stutter(0.5 SECONDS) - var/list/message_data = quirker.treat_message(word, capitalize_message = FALSE) - new_message += message_data["message"] - else - new_message += word - - message = jointext(new_message, " ") - var/mob/living/carbon/human/quirker = quirk_holder - if(prob(min(50,(0.50*(nearby_people*12.5)*moodmod)))) //Max 50% chance of not talking - if(dumb_thing) - to_chat(quirker, span_userdanger("You think of a dumb thing you said a long time ago and scream internally.")) - dumb_thing = FALSE //only once per life - if(prob(1)) - new/obj/item/food/spaghetti/pastatomato(get_turf(quirker)) //now that's what I call spaghetti code - else - to_chat(quirk_holder, span_warning("You think that wouldn't add much to the conversation and decide not to say it.")) - if(prob(min(25,(0.25*(nearby_people*12.75)*moodmod)))) //Max 25% chance of silence stacks after successful not talking roll - to_chat(quirker, span_danger("You retreat into yourself. You really don't feel up to talking.")) - quirker.set_silence_if_lower(10 SECONDS) - - speech_args[SPEECH_MESSAGE] = pick("Uh.","Erm.","Um.") - else - speech_args[SPEECH_MESSAGE] = message - -// small chance to make eye contact with inanimate objects/mindless mobs because of nerves -/datum/quirk/social_anxiety/proc/looks_at_floor(datum/source, atom/A) - SIGNAL_HANDLER - - var/mob/living/mind_check = A - if(prob(85) || (istype(mind_check) && mind_check.mind)) - return - - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), quirk_holder, span_smallnotice("You make eye contact with [A].")), 3) - -/datum/quirk/social_anxiety/proc/eye_contact(datum/source, mob/living/other_mob, triggering_examiner) - SIGNAL_HANDLER - - if(prob(75)) - return - var/msg - if(triggering_examiner) - msg = "You make eye contact with [other_mob], " - else - msg = "[other_mob] makes eye contact with you, " - - switch(rand(1,3)) - if(1) - quirk_holder.set_jitter_if_lower(20 SECONDS) - msg += "causing you to start fidgeting!" - if(2) - quirk_holder.set_stutter_if_lower(6 SECONDS) - msg += "causing you to start stuttering!" - if(3) - quirk_holder.Stun(2 SECONDS) - msg += "causing you to freeze up!" - - quirk_holder.add_mood_event("anxiety_eyecontact", /datum/mood_event/anxiety_eyecontact) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), quirk_holder, span_userdanger("[msg]")), 3) // so the examine signal has time to fire and this will print after - return COMSIG_BLOCK_EYECONTACT - -/datum/mood_event/anxiety_eyecontact - description = "Sometimes eye contact makes me so nervous..." - mood_change = -5 - timeout = 3 MINUTES - -/datum/quirk/item_quirk/junkie - name = "Junkie" - desc = "You can't get enough of hard drugs." - icon = FA_ICON_PILLS - value = -6 - gain_text = span_danger("You suddenly feel the craving for drugs.") - medical_record_text = "Patient has a history of hard drugs." - hardcore_value = 4 - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES - mail_goodies = list(/obj/effect/spawner/random/contraband/narcotics) - var/drug_list = list(/datum/reagent/drug/blastoff, /datum/reagent/drug/krokodil, /datum/reagent/medicine/morphine, /datum/reagent/drug/happiness, /datum/reagent/drug/methamphetamine) //List of possible IDs - var/datum/reagent/reagent_type //!If this is defined, reagent_id will be unused and the defined reagent type will be instead. - var/datum/reagent/reagent_instance //! actual instanced version of the reagent - var/where_drug //! Where the drug spawned - var/obj/item/drug_container_type //! If this is defined before pill generation, pill generation will be skipped. This is the type of the pill bottle. - var/where_accessory //! where the accessory spawned - var/obj/item/accessory_type //! If this is null, an accessory won't be spawned. - var/process_interval = 30 SECONDS //! how frequently the quirk processes - var/next_process = 0 //! ticker for processing - var/drug_flavour_text = "Better hope you don't run out..." - -/datum/quirk/item_quirk/junkie/add_unique(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - - if(!reagent_type) - reagent_type = pick(drug_list) - - reagent_instance = new reagent_type() - - for(var/addiction in reagent_instance.addiction_types) - human_holder.last_mind?.add_addiction_points(addiction, 1000) - - var/current_turf = get_turf(quirk_holder) - - if(!drug_container_type) - drug_container_type = /obj/item/storage/pill_bottle - - var/obj/item/drug_instance = new drug_container_type(current_turf) - if(istype(drug_instance, /obj/item/storage/pill_bottle)) - var/pill_state = "pill[rand(1,20)]" - for(var/i in 1 to 7) - var/obj/item/reagent_containers/pill/pill = new(drug_instance) - pill.icon_state = pill_state - pill.reagents.add_reagent(reagent_type, 3) - - give_item_to_holder( - drug_instance, - list( - LOCATION_LPOCKET = ITEM_SLOT_LPOCKET, - LOCATION_RPOCKET = ITEM_SLOT_RPOCKET, - LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, - LOCATION_HANDS = ITEM_SLOT_HANDS, - ), - flavour_text = drug_flavour_text, - ) - - if(accessory_type) - give_item_to_holder( - accessory_type, - list( - LOCATION_LPOCKET = ITEM_SLOT_LPOCKET, - LOCATION_RPOCKET = ITEM_SLOT_RPOCKET, - LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, - LOCATION_HANDS = ITEM_SLOT_HANDS, - ) - ) - -/datum/quirk/item_quirk/junkie/remove() - if(quirk_holder && reagent_instance) - for(var/addiction_type in subtypesof(/datum/addiction)) - quirk_holder.mind.remove_addiction_points(addiction_type, MAX_ADDICTION_POINTS) - -/datum/quirk/item_quirk/junkie/process(seconds_per_tick) - if(HAS_TRAIT(quirk_holder, TRAIT_LIVERLESS_METABOLISM)) - return - var/mob/living/carbon/human/human_holder = quirk_holder - if(world.time > next_process) - next_process = world.time + process_interval - var/deleted = QDELETED(reagent_instance) - var/missing_addiction = FALSE - for(var/addiction_type in reagent_instance.addiction_types) - if(!LAZYACCESS(human_holder.last_mind?.active_addictions, addiction_type)) - missing_addiction = TRUE - if(deleted || missing_addiction) - if(deleted) - reagent_instance = new reagent_type() - to_chat(quirk_holder, span_danger("You thought you kicked it, but you feel like you're falling back onto bad habits..")) - for(var/addiction in reagent_instance.addiction_types) - human_holder.last_mind?.add_addiction_points(addiction, 1000) ///Max that shit out - -/datum/quirk/item_quirk/junkie/smoker - name = "Smoker" - desc = "Sometimes you just really want a smoke. Probably not great for your lungs." - icon = FA_ICON_SMOKING - value = -4 - gain_text = span_danger("You could really go for a smoke right about now.") - lose_text = span_notice("You don't feel nearly as hooked to nicotine anymore.") - medical_record_text = "Patient is a current smoker." - reagent_type = /datum/reagent/drug/nicotine - accessory_type = /obj/item/lighter/greyscale - mob_trait = TRAIT_SMOKER - hardcore_value = 1 - drug_flavour_text = "Make sure you get your favorite brand when you run out." - mail_goodies = list( - /obj/effect/spawner/random/entertainment/cigarette_pack, - /obj/effect/spawner/random/entertainment/cigar, - /obj/effect/spawner/random/entertainment/lighter, - /obj/item/clothing/mask/cigarette/pipe, - ) - -/datum/quirk/item_quirk/junkie/smoker/New() - drug_container_type = pick(/obj/item/storage/fancy/cigarettes, - /obj/item/storage/fancy/cigarettes/cigpack_midori, - /obj/item/storage/fancy/cigarettes/cigpack_uplift, - /obj/item/storage/fancy/cigarettes/cigpack_robust, - /obj/item/storage/fancy/cigarettes/cigpack_robustgold, - /obj/item/storage/fancy/cigarettes/cigpack_carp) - - return ..() - -/datum/quirk/item_quirk/junkie/smoker/post_add() - . = ..() - quirk_holder.add_mob_memory(/datum/memory/key/quirk_smoker, protagonist = quirk_holder, preferred_brand = initial(drug_container_type.name)) - // smoker lungs have 25% less health and healing - var/mob/living/carbon/carbon_holder = quirk_holder - var/obj/item/organ/internal/lungs/smoker_lungs = null - var/obj/item/organ/internal/lungs/old_lungs = carbon_holder.get_organ_slot(ORGAN_SLOT_LUNGS) - if(old_lungs && IS_ORGANIC_ORGAN(old_lungs)) - if(isplasmaman(carbon_holder)) - smoker_lungs = /obj/item/organ/internal/lungs/plasmaman/plasmaman_smoker - else if(isethereal(carbon_holder)) - smoker_lungs = /obj/item/organ/internal/lungs/ethereal/ethereal_smoker - else - smoker_lungs = /obj/item/organ/internal/lungs/smoker_lungs - if(!isnull(smoker_lungs)) - smoker_lungs = new smoker_lungs - smoker_lungs.Insert(carbon_holder, special = TRUE, drop_if_replaced = FALSE) - -/datum/quirk/item_quirk/junkie/smoker/process(seconds_per_tick) - . = ..() - var/mob/living/carbon/human/human_holder = quirk_holder - var/obj/item/mask_item = human_holder.get_item_by_slot(ITEM_SLOT_MASK) - if(istype(mask_item, /obj/item/clothing/mask/cigarette)) - var/obj/item/storage/fancy/cigarettes/cigarettes = drug_container_type - if(istype(mask_item, initial(cigarettes.spawn_type))) - quirk_holder.clear_mood_event("wrong_cigs") - else - quirk_holder.add_mood_event("wrong_cigs", /datum/mood_event/wrong_brand) - -/datum/quirk/item_quirk/junkie/alcoholic - name = "Alcoholic" - desc = "You just can't live without alcohol. Your liver is a machine that turns ethanol into acetaldehyde." - icon = FA_ICON_WINE_GLASS - value = -4 - gain_text = span_danger("You really need a drink.") - lose_text = span_notice("Alcohol doesn't seem nearly as enticing anymore.") - medical_record_text = "Patient is an alcoholic." - reagent_type = /datum/reagent/consumable/ethanol - drug_container_type = /obj/item/reagent_containers/cup/glass/bottle/whiskey - mob_trait = TRAIT_HEAVY_DRINKER - hardcore_value = 1 - drug_flavour_text = "Make sure you get your favorite type of drink when you run out." - mail_goodies = list( - /obj/effect/spawner/random/food_or_drink/booze, - /obj/item/book/bible/booze, - ) - /// Cached typepath of the owner's favorite alcohol reagent - var/datum/reagent/consumable/ethanol/favorite_alcohol - -/datum/quirk/item_quirk/junkie/alcoholic/New() - drug_container_type = pick( - /obj/item/reagent_containers/cup/glass/bottle/whiskey, - /obj/item/reagent_containers/cup/glass/bottle/vodka, - /obj/item/reagent_containers/cup/glass/bottle/ale, - /obj/item/reagent_containers/cup/glass/bottle/beer, - /obj/item/reagent_containers/cup/glass/bottle/hcider, - /obj/item/reagent_containers/cup/glass/bottle/wine, - /obj/item/reagent_containers/cup/glass/bottle/sake, - ) - - return ..() - -/datum/quirk/item_quirk/junkie/alcoholic/post_add() - . = ..() - RegisterSignal(quirk_holder, COMSIG_MOB_REAGENT_CHECK, PROC_REF(check_brandy)) - - var/obj/item/reagent_containers/brandy_container = GLOB.alcohol_containers[drug_container_type] - if(isnull(brandy_container)) - stack_trace("Alcoholic quirk added while the GLOB.alcohol_containers is (somehow) not initialized!") - brandy_container = new drug_container_type - favorite_alcohol = brandy_container.list_reagents[1] - qdel(brandy_container) - else - favorite_alcohol = brandy_container.list_reagents[1] - - quirk_holder.add_mob_memory(/datum/memory/key/quirk_alcoholic, protagonist = quirk_holder, preferred_brandy = initial(favorite_alcohol.name)) - // alcoholic livers have 25% less health and healing - var/obj/item/organ/internal/liver/alcohol_liver = quirk_holder.get_organ_slot(ORGAN_SLOT_LIVER) - if(alcohol_liver && IS_ORGANIC_ORGAN(alcohol_liver)) // robotic livers aren't affected - alcohol_liver.maxHealth = alcohol_liver.maxHealth * 0.75 - alcohol_liver.healing_factor = alcohol_liver.healing_factor * 0.75 - -/datum/quirk/item_quirk/junkie/alcoholic/remove() - UnregisterSignal(quirk_holder, COMSIG_MOB_REAGENT_CHECK) - -/datum/quirk/item_quirk/junkie/alcoholic/proc/check_brandy(mob/source, datum/reagent/booze) - SIGNAL_HANDLER - - //we don't care if it is not alcohol - if(!istype(booze, /datum/reagent/consumable/ethanol)) - return - - if(istype(booze, favorite_alcohol)) - quirk_holder.clear_mood_event("wrong_alcohol") - else - quirk_holder.add_mood_event("wrong_alcohol", /datum/mood_event/wrong_brandy) - -/datum/quirk/item_quirk/chronic_illness - name = "Chronic Illness" - desc = "You have a chronic illness that requires constant medication to keep under control." - icon = FA_ICON_DISEASE - value = -12 - gain_text = span_danger("You feel a bit off today.") - lose_text = span_notice("You feel a bit better today.") - medical_record_text = "Patient has a chronic illness that requires constant medication to keep under control." - hardcore_value = 12 - mail_goodies = list(/obj/item/storage/pill_bottle/sansufentanyl) - -/datum/quirk/item_quirk/chronic_illness/add_unique(client/client_source) - var/datum/disease/chronic_illness/hms = new /datum/disease/chronic_illness() - quirk_holder.ForceContractDisease(hms) - give_item_to_holder(/obj/item/storage/pill_bottle/sansufentanyl, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK),flavour_text = "You've been provided with medication to help manage your condition. Take it regularly to avoid complications.") - give_item_to_holder(/obj/item/healthanalyzer/simple/disease, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK)) - -/datum/quirk/unstable - name = "Unstable" - desc = "Due to past troubles, you are unable to recover your sanity if you lose it. Be very careful managing your mood!" - icon = FA_ICON_ANGRY - value = -10 - mob_trait = TRAIT_UNSTABLE - gain_text = span_danger("There's a lot on your mind right now.") - lose_text = span_notice("Your mind finally feels calm.") - medical_record_text = "Patient's mind is in a vulnerable state, and cannot recover from traumatic events." - hardcore_value = 9 - mail_goodies = list(/obj/effect/spawner/random/entertainment/plushie) - -/datum/quirk/item_quirk/allergic - name = "Extreme Medicine Allergy" - desc = "Ever since you were a kid, you've been allergic to certain chemicals..." - icon = FA_ICON_PRESCRIPTION_BOTTLE - value = -6 - gain_text = span_danger("You feel your immune system shift.") - lose_text = span_notice("You feel your immune system phase back into perfect shape.") - medical_record_text = "Patient's immune system responds violently to certain chemicals." - hardcore_value = 3 - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES - mail_goodies = list(/obj/item/reagent_containers/hypospray/medipen) // epinephrine medipen stops allergic reactions - var/list/allergies = list() - var/list/blacklist = list( - /datum/reagent/medicine/c2, - /datum/reagent/medicine/epinephrine, - /datum/reagent/medicine/adminordrazine, - /datum/reagent/medicine/omnizine/godblood, - /datum/reagent/medicine/cordiolis_hepatico, - /datum/reagent/medicine/synaphydramine, - /datum/reagent/medicine/diphenhydramine, - /datum/reagent/medicine/sansufentanyl - ) - var/allergy_string - -/datum/quirk/item_quirk/allergic/add_unique(client/client_source) - var/list/chem_list = subtypesof(/datum/reagent/medicine) - blacklist - var/list/allergy_chem_names = list() - for(var/i in 0 to 5) - var/datum/reagent/medicine/chem_type = pick_n_take(chem_list) - allergies += chem_type - allergy_chem_names += initial(chem_type.name) - - allergy_string = allergy_chem_names.Join(", ") - name = "Extreme [allergy_string] Allergies" - medical_record_text = "Patient's immune system responds violently to [allergy_string]" - - var/mob/living/carbon/human/human_holder = quirk_holder - var/obj/item/clothing/accessory/dogtag/allergy/dogtag = new(get_turf(human_holder), allergy_string) - - give_item_to_holder(dogtag, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS), flavour_text = "Make sure medical staff can see this...") - -/datum/quirk/item_quirk/allergic/post_add() - quirk_holder.add_mob_memory(/datum/memory/key/quirk_allergy, allergy_string = allergy_string) - to_chat(quirk_holder, span_boldnotice("You are allergic to [allergy_string], make sure not to consume any of these!")) - -/datum/quirk/item_quirk/allergic/process(seconds_per_tick) - if(!iscarbon(quirk_holder)) - return - - if(IS_IN_STASIS(quirk_holder)) - return - - if(quirk_holder.stat == DEAD) - return - - var/mob/living/carbon/carbon_quirk_holder = quirk_holder - for(var/allergy in allergies) - var/datum/reagent/instantiated_med = carbon_quirk_holder.reagents.has_reagent(allergy) - if(!instantiated_med) - continue - //Just halts the progression, I'd suggest you run to medbay asap to get it fixed - if(carbon_quirk_holder.reagents.has_reagent(/datum/reagent/medicine/epinephrine)) - instantiated_med.reagent_removal_skip_list |= ALLERGIC_REMOVAL_SKIP - return //intentionally stops the entire proc so we avoid the organ damage after the loop - instantiated_med.reagent_removal_skip_list -= ALLERGIC_REMOVAL_SKIP - carbon_quirk_holder.adjustToxLoss(3 * seconds_per_tick) - carbon_quirk_holder.reagents.add_reagent(/datum/reagent/toxin/histamine, 3 * seconds_per_tick) - if(SPT_PROB(10, seconds_per_tick)) - carbon_quirk_holder.vomit() - carbon_quirk_holder.adjustOrganLoss(pick(ORGAN_SLOT_BRAIN,ORGAN_SLOT_APPENDIX,ORGAN_SLOT_LUNGS,ORGAN_SLOT_HEART,ORGAN_SLOT_LIVER,ORGAN_SLOT_STOMACH),10) - -/datum/quirk/bad_touch - name = "Bad Touch" - desc = "You don't like hugs. You'd really prefer if people just left you alone." - icon = "tg-bad-touch" - mob_trait = TRAIT_BADTOUCH - value = -1 - gain_text = span_danger("You just want people to leave you alone.") - lose_text = span_notice("You could use a big hug.") - medical_record_text = "Patient has disdain for being touched. Potentially has undiagnosed haphephobia." - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED - hardcore_value = 1 - mail_goodies = list(/obj/item/reagent_containers/spray/pepper) // show me on the doll where the bad man touched you - -/datum/quirk/bad_touch/add(client/client_source) - RegisterSignals(quirk_holder, list(COMSIG_LIVING_GET_PULLED, COMSIG_CARBON_HELP_ACT), PROC_REF(uncomfortable_touch)) - -/datum/quirk/bad_touch/remove() - UnregisterSignal(quirk_holder, list(COMSIG_LIVING_GET_PULLED, COMSIG_CARBON_HELP_ACT)) - -/// Causes a negative moodlet to our quirk holder on signal -/datum/quirk/bad_touch/proc/uncomfortable_touch(datum/source) - SIGNAL_HANDLER - - if(quirk_holder.stat == DEAD) - return - - new /obj/effect/temp_visual/annoyed(quirk_holder.loc) - if(quirk_holder.mob_mood.sanity <= SANITY_NEUTRAL) - quirk_holder.add_mood_event("bad_touch", /datum/mood_event/very_bad_touch) - else - quirk_holder.add_mood_event("bad_touch", /datum/mood_event/bad_touch) - -/datum/quirk/claustrophobia - name = "Claustrophobia" - desc = "You are terrified of small spaces and certain jolly figures. If you are placed inside any container, locker, or machinery, a panic attack sets in and you struggle to breathe." - icon = FA_ICON_BOX_OPEN - value = -4 - medical_record_text = "Patient demonstrates a fear of tight spaces." - hardcore_value = 5 - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES - mail_goodies = list(/obj/item/reagent_containers/syringe/convermol) // to help breathing - -/datum/quirk/claustrophobia/remove() - quirk_holder.clear_mood_event("claustrophobia") - -/datum/quirk/claustrophobia/process(seconds_per_tick) - if(quirk_holder.stat != CONSCIOUS || quirk_holder.IsSleeping() || quirk_holder.IsUnconscious()) - return - - if(HAS_TRAIT(quirk_holder, TRAIT_FEARLESS)) - return - - var/nick_spotted = FALSE - - for(var/mob/living/carbon/human/possible_claus in view(5, quirk_holder)) - if(evaluate_jolly_levels(possible_claus)) - nick_spotted = TRUE - break - - if(!nick_spotted && isturf(quirk_holder.loc)) - quirk_holder.clear_mood_event("claustrophobia") - return - - quirk_holder.add_mood_event("claustrophobia", /datum/mood_event/claustrophobia) - quirk_holder.losebreath += 0.25 // miss a breath one in four times - if(SPT_PROB(25, seconds_per_tick)) - if(nick_spotted) - to_chat(quirk_holder, span_warning("Santa Claus is here! I gotta get out of here!")) - else - to_chat(quirk_holder, span_warning("You feel trapped! Must escape... can't breathe...")) - -///investigates whether possible_saint_nick possesses a high level of christmas cheer -/datum/quirk/claustrophobia/proc/evaluate_jolly_levels(mob/living/carbon/human/possible_saint_nick) - if(!istype(possible_saint_nick)) - return FALSE - - if(istype(possible_saint_nick.back, /obj/item/storage/backpack/santabag)) - return TRUE - - if(istype(possible_saint_nick.head, /obj/item/clothing/head/costume/santa) || istype(possible_saint_nick.head, /obj/item/clothing/head/helmet/space/santahat)) - return TRUE - - if(istype(possible_saint_nick.wear_suit, /obj/item/clothing/suit/space/santa)) - return TRUE - - return FALSE - -/datum/quirk/illiterate - name = "Illiterate" - desc = "You dropped out of school and are unable to read or write. This affects reading, writing, using computers and other electronics." - icon = FA_ICON_GRADUATION_CAP - value = -8 - mob_trait = TRAIT_ILLITERATE - medical_record_text = "Patient is not literate." - hardcore_value = 8 - mail_goodies = list(/obj/item/pai_card) // can read things for you - - -/datum/quirk/mute - name = "Mute" - desc = "For some reason you are completely unable to speak." - icon = FA_ICON_VOLUME_XMARK - value = -4 - mob_trait = TRAIT_MUTE - gain_text = span_danger("You find yourself unable to speak!") - lose_text = span_notice("You feel a growing strength in your vocal chords.") - medical_record_text = "The patient is unable to use their voice in any capacity." - hardcore_value = 4 - -/datum/quirk/body_purist - name = "Body Purist" - desc = "You believe your body is a temple and its natural form is an embodiment of perfection. Accordingly, you despise the idea of ever augmenting it with unnatural parts, cybernetic, prosthetic, or anything like it." - icon = FA_ICON_PERSON_RAYS - value = -2 - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED - gain_text = span_danger("You now begin to hate the idea of having cybernetic implants.") - lose_text = span_notice("Maybe cybernetics aren't so bad. You now feel okay with augmentations and prosthetics.") - medical_record_text = "This patient has disclosed an extreme hatred for unnatural bodyparts and augmentations." - hardcore_value = 3 - mail_goodies = list(/obj/item/paper/pamphlet/cybernetics) - var/cybernetics_level = 0 - -/datum/quirk/body_purist/add(client/client_source) - check_cybernetics() - RegisterSignal(quirk_holder, COMSIG_CARBON_GAIN_ORGAN, PROC_REF(on_organ_gain)) - RegisterSignal(quirk_holder, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(on_organ_lose)) - RegisterSignal(quirk_holder, COMSIG_CARBON_ATTACH_LIMB, PROC_REF(on_limb_gain)) - RegisterSignal(quirk_holder, COMSIG_CARBON_REMOVE_LIMB, PROC_REF(on_limb_lose)) - -/datum/quirk/body_purist/remove() - UnregisterSignal(quirk_holder, list( - COMSIG_CARBON_GAIN_ORGAN, - COMSIG_CARBON_LOSE_ORGAN, - COMSIG_CARBON_ATTACH_LIMB, - COMSIG_CARBON_REMOVE_LIMB, - )) - quirk_holder.clear_mood_event("body_purist") - -/datum/quirk/body_purist/proc/check_cybernetics() - var/mob/living/carbon/owner = quirk_holder - if(!istype(owner)) - return - for(var/obj/item/bodypart/limb as anything in owner.bodyparts) - if(IS_ROBOTIC_LIMB(limb)) - cybernetics_level++ - for(var/obj/item/organ/organ as anything in owner.organs) - if(IS_ROBOTIC_ORGAN(organ) && !(organ.organ_flags & ORGAN_HIDDEN)) - cybernetics_level++ - update_mood() - -/datum/quirk/body_purist/proc/update_mood() - quirk_holder.clear_mood_event("body_purist") - if(cybernetics_level) - quirk_holder.add_mood_event("body_purist", /datum/mood_event/body_purist, -cybernetics_level * 10) - -/datum/quirk/body_purist/proc/on_organ_gain(datum/source, obj/item/organ/new_organ, special) - SIGNAL_HANDLER - if(IS_ROBOTIC_ORGAN(new_organ) && !(new_organ.organ_flags & ORGAN_HIDDEN)) //why the fuck are there 2 of them - cybernetics_level++ - update_mood() - -/datum/quirk/body_purist/proc/on_organ_lose(datum/source, obj/item/organ/old_organ, special) - SIGNAL_HANDLER - if(IS_ROBOTIC_ORGAN(old_organ) && !(old_organ.organ_flags & ORGAN_HIDDEN)) - cybernetics_level-- - update_mood() - -/datum/quirk/body_purist/proc/on_limb_gain(datum/source, obj/item/bodypart/new_limb, special) - SIGNAL_HANDLER - if(IS_ROBOTIC_LIMB(new_limb)) - cybernetics_level++ - update_mood() - -/datum/quirk/body_purist/proc/on_limb_lose(datum/source, obj/item/bodypart/old_limb, special) - SIGNAL_HANDLER - if(IS_ROBOTIC_LIMB(old_limb)) - cybernetics_level-- - update_mood() - -// SKYRAT EDIT REMOVAL BEGIN -/* -/datum/quirk/cursed - name = "Cursed" - desc = "You are cursed with bad luck. You are much more likely to suffer from accidents and mishaps. When it rains, it pours." - icon = FA_ICON_CLOUD_SHOWERS_HEAVY - value = -8 - mob_trait = TRAIT_CURSED - gain_text = span_danger("You feel like you're going to have a bad day.") - lose_text = span_notice("You feel like you're going to have a good day.") - medical_record_text = "Patient is cursed with bad luck." - hardcore_value = 8 - -/datum/quirk/cursed/add(client/client_source) - quirk_holder.AddComponent(/datum/component/omen/quirk) -*/ -// SKYRAT EDIT REMOVAL END - -/datum/quirk/indebted - name = "Indebted" - desc = "Bad life decisions, medical bills, student loans, whatever it may be, you've incurred quite the debt. A portion of all you receive will go towards extinguishing it." - icon = FA_ICON_DOLLAR - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_HIDE_FROM_SCAN - value = -2 - medical_record_text = "Alas, the patient struggled to scrape together enough money to pay the checkup bill." - hardcore_value = 2 - -/datum/quirk/indebted/add_unique(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - if(!human_holder.account_id) - return - var/datum/bank_account/account = SSeconomy.bank_accounts_by_id["[human_holder.account_id]"] - var/debt = PAYCHECK_CREW * rand(275, 325) - account.account_debt += debt - RegisterSignal(account, COMSIG_BANK_ACCOUNT_DEBT_PAID, PROC_REF(on_debt_paid)) - to_chat(client_source.mob, span_warning("You remember, you've a hefty, [debt] credits debt to pay...")) - -///Once the debt is extinguished, award an achievement and a pin for actually taking care of it. -/datum/quirk/indebted/proc/on_debt_paid(datum/bank_account/source) - SIGNAL_HANDLER - if(source.account_debt) - return - UnregisterSignal(source, COMSIG_BANK_ACCOUNT_DEBT_PAID) - ///The debt was extinguished while the quirk holder was logged out, so let's kindly award it once they come back. - if(!quirk_holder.client) - RegisterSignal(quirk_holder, COMSIG_MOB_LOGIN, PROC_REF(award_on_login)) - else - quirk_holder.client.give_award(/datum/award/achievement/misc/debt_extinguished, quirk_holder) - podspawn(list( - "target" = get_turf(quirk_holder), - "style" = STYLE_BLUESPACE, - "spawn" = /obj/item/clothing/accessory/debt_payer_pin, - )) - -/datum/quirk/indebted/proc/award_on_login(mob/source) - SIGNAL_HANDLER - quirk_holder.client.give_award(/datum/award/achievement/misc/debt_extinguished, quirk_holder) - UnregisterSignal(source, COMSIG_MOB_LOGIN) - -/datum/quirk/numb - name = "Numb" - desc = "You can't feel pain at all." - icon = FA_ICON_STAR_OF_LIFE - value = -4 - gain_text = "You feel your body becoming numb." - lose_text = "The numbness subsides." - medical_record_text = "The patient exhibits congenital hypoesthesia, making them insensitive to pain stimuli." - hardcore_value = 4 - -/datum/quirk/numb/add(client/client_source) - quirk_holder.apply_status_effect(/datum/status_effect/grouped/screwy_hud/fake_healthy, type) - -/datum/quirk/numb/remove(client/client_source) - quirk_holder.remove_status_effect(/datum/status_effect/grouped/screwy_hud/fake_healthy, type) - diff --git a/code/datums/quirks/negative_quirks/non_violent.dm b/code/datums/quirks/negative_quirks/non_violent.dm new file mode 100644 index 00000000000000..e1dbb0e64802fe --- /dev/null +++ b/code/datums/quirks/negative_quirks/non_violent.dm @@ -0,0 +1,11 @@ +/datum/quirk/nonviolent + name = "Pacifist" + desc = "The thought of violence makes you sick. So much so, in fact, that you can't hurt anyone." + icon = FA_ICON_PEACE + value = -8 + mob_trait = TRAIT_PACIFISM + gain_text = span_danger("You feel repulsed by the thought of violence!") + lose_text = span_notice("You think you can defend yourself again.") + medical_record_text = "Patient is unusually pacifistic and cannot bring themselves to cause physical harm." + hardcore_value = 6 + mail_goodies = list(/obj/effect/spawner/random/decoration/flower, /obj/effect/spawner/random/contraband/cannabis) // flower power diff --git a/code/datums/quirks/negative_quirks/numb.dm b/code/datums/quirks/negative_quirks/numb.dm new file mode 100644 index 00000000000000..cd4f28cb302285 --- /dev/null +++ b/code/datums/quirks/negative_quirks/numb.dm @@ -0,0 +1,15 @@ +/datum/quirk/numb + name = "Numb" + desc = "You can't feel pain at all." + icon = FA_ICON_STAR_OF_LIFE + value = -4 + gain_text = "You feel your body becoming numb." + lose_text = "The numbness subsides." + medical_record_text = "The patient exhibits congenital hypoesthesia, making them insensitive to pain stimuli." + hardcore_value = 4 + +/datum/quirk/numb/add(client/client_source) + quirk_holder.apply_status_effect(/datum/status_effect/grouped/screwy_hud/fake_healthy, type) + +/datum/quirk/numb/remove(client/client_source) + quirk_holder.remove_status_effect(/datum/status_effect/grouped/screwy_hud/fake_healthy, type) diff --git a/code/datums/quirks/negative_quirks/nyctophobia.dm b/code/datums/quirks/negative_quirks/nyctophobia.dm new file mode 100644 index 00000000000000..af891a2058ad28 --- /dev/null +++ b/code/datums/quirks/negative_quirks/nyctophobia.dm @@ -0,0 +1,46 @@ +/datum/quirk/nyctophobia + name = "Nyctophobia" + desc = "As far as you can remember, you've always been afraid of the dark. While in the dark without a light source, you instinctively act careful, and constantly feel a sense of dread." + icon = FA_ICON_LIGHTBULB + value = -3 + medical_record_text = "Patient demonstrates a fear of the dark. (Seriously?)" + hardcore_value = 5 + mail_goodies = list(/obj/effect/spawner/random/engineering/flashlight) + +/datum/quirk/nyctophobia/add(client/client_source) + RegisterSignal(quirk_holder, COMSIG_MOVABLE_MOVED, PROC_REF(on_holder_moved)) + +/datum/quirk/nyctophobia/remove() + UnregisterSignal(quirk_holder, COMSIG_MOVABLE_MOVED) + quirk_holder.clear_mood_event("nyctophobia") + +/// Called when the quirk holder moves. Updates the quirk holder's mood. +/datum/quirk/nyctophobia/proc/on_holder_moved(mob/living/source, atom/old_loc, dir, forced) + SIGNAL_HANDLER + + if(quirk_holder.stat != CONSCIOUS || quirk_holder.IsSleeping() || quirk_holder.IsUnconscious()) + return + + if(HAS_TRAIT(quirk_holder, TRAIT_FEARLESS)) + return + + var/mob/living/carbon/human/human_holder = quirk_holder + + if(human_holder.dna?.species.id in list(SPECIES_SHADOW, SPECIES_NIGHTMARE)) + return + + if((human_holder.sight & SEE_TURFS) == SEE_TURFS) + return + + var/turf/holder_turf = get_turf(quirk_holder) + + var/lums = holder_turf.get_lumcount() + + if(lums > LIGHTING_TILE_IS_DARK) + quirk_holder.clear_mood_event("nyctophobia") + return + + if(quirk_holder.move_intent == MOVE_INTENT_RUN) + to_chat(quirk_holder, span_warning("Easy, easy, take it slow... you're in the dark...")) + quirk_holder.toggle_move_intent() + quirk_holder.add_mood_event("nyctophobia", /datum/mood_event/nyctophobia) diff --git a/code/datums/quirks/negative_quirks/paraplegic.dm b/code/datums/quirks/negative_quirks/paraplegic.dm new file mode 100644 index 00000000000000..58e1c4ba31e870 --- /dev/null +++ b/code/datums/quirks/negative_quirks/paraplegic.dm @@ -0,0 +1,41 @@ +/datum/quirk/paraplegic + name = "Paraplegic" + desc = "Your legs do not function. Nothing will ever fix this. But hey, free wheelchair!" + icon = FA_ICON_WHEELCHAIR + value = -12 + gain_text = null // Handled by trauma. + lose_text = null + medical_record_text = "Patient has an untreatable impairment in motor function in the lower extremities." + hardcore_value = 15 + mail_goodies = list(/obj/vehicle/ridden/wheelchair/motorized) //yes a fullsized unfolded motorized wheelchair does fit + +/datum/quirk/paraplegic/add_unique(client/client_source) + if(quirk_holder.buckled) // Handle late joins being buckled to arrival shuttle chairs. + quirk_holder.buckled.unbuckle_mob(quirk_holder) + + var/turf/holder_turf = get_turf(quirk_holder) + var/obj/structure/chair/spawn_chair = locate() in holder_turf + + var/obj/vehicle/ridden/wheelchair/wheels + if(client_source?.get_award_status(/datum/award/score/hardcore_random) >= 5000) //More than 5k score? you unlock the gamer wheelchair. + wheels = new /obj/vehicle/ridden/wheelchair/gold(holder_turf) + else + wheels = new(holder_turf) + if(spawn_chair) // Makes spawning on the arrivals shuttle more consistent looking + wheels.setDir(spawn_chair.dir) + + wheels.buckle_mob(quirk_holder) + + // During the spawning process, they may have dropped what they were holding, due to the paralysis + // So put the things back in their hands. + for(var/obj/item/dropped_item in holder_turf) + if(dropped_item.fingerprintslast == quirk_holder.ckey) + quirk_holder.put_in_hands(dropped_item) + +/datum/quirk/paraplegic/add(client/client_source) + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.gain_trauma(/datum/brain_trauma/severe/paralysis/paraplegic, TRAUMA_RESILIENCE_ABSOLUTE) + +/datum/quirk/paraplegic/remove() + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.cure_trauma_type(/datum/brain_trauma/severe/paralysis/paraplegic, TRAUMA_RESILIENCE_ABSOLUTE) diff --git a/code/datums/quirks/negative_quirks/photophobia.dm b/code/datums/quirks/negative_quirks/photophobia.dm new file mode 100644 index 00000000000000..b543aeda07631c --- /dev/null +++ b/code/datums/quirks/negative_quirks/photophobia.dm @@ -0,0 +1,75 @@ +#define MOOD_CATEGORY_PHOTOPHOBIA "photophobia" + +/datum/quirk/photophobia + name = "Photophobia" + desc = "Bright lights seem to bother you more than others. Maybe it's a medical condition." + icon = FA_ICON_ARROWS_TO_EYE + value = -4 + gain_text = span_danger("The safety of light feels off...") + lose_text = span_notice("Enlightening.") + medical_record_text = "Patient has acute phobia of light, and insists it is physically harmful." + hardcore_value = 4 + mail_goodies = list( + /obj/item/flashlight/flashdark, + /obj/item/food/grown/mushroom/glowshroom/shadowshroom, + /obj/item/skillchip/light_remover, + ) + +/datum/quirk/photophobia/add(client/client_source) + RegisterSignal(quirk_holder, COMSIG_CARBON_GAIN_ORGAN, PROC_REF(check_eyes)) + RegisterSignal(quirk_holder, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(restore_eyes)) + RegisterSignal(quirk_holder, COMSIG_MOVABLE_MOVED, PROC_REF(on_holder_moved)) + update_eyes(quirk_holder.get_organ_slot(ORGAN_SLOT_EYES)) + +/datum/quirk/photophobia/remove() + UnregisterSignal(quirk_holder, list( + COMSIG_CARBON_GAIN_ORGAN, + COMSIG_CARBON_LOSE_ORGAN, + COMSIG_MOVABLE_MOVED,)) + quirk_holder.clear_mood_event(MOOD_CATEGORY_PHOTOPHOBIA) + var/obj/item/organ/internal/eyes/normal_eyes = quirk_holder.get_organ_slot(ORGAN_SLOT_EYES) + if(istype(normal_eyes)) + normal_eyes.flash_protect = initial(normal_eyes.flash_protect) + +/datum/quirk/photophobia/proc/check_eyes(obj/item/organ/internal/eyes/sensitive_eyes) + SIGNAL_HANDLER + if(!istype(sensitive_eyes)) + return + update_eyes(sensitive_eyes) + +/datum/quirk/photophobia/proc/update_eyes(obj/item/organ/internal/eyes/target_eyes) + if(!istype(target_eyes)) + return + target_eyes.flash_protect = max(target_eyes.flash_protect - 1, FLASH_PROTECTION_HYPER_SENSITIVE) + +/datum/quirk/photophobia/proc/restore_eyes(obj/item/organ/internal/eyes/normal_eyes) + SIGNAL_HANDLER + if(!istype(normal_eyes)) + return + normal_eyes.flash_protect = initial(normal_eyes.flash_protect) + +/datum/quirk/photophobia/proc/on_holder_moved(mob/living/source, atom/old_loc, dir, forced) + SIGNAL_HANDLER + + if(quirk_holder.stat != CONSCIOUS || quirk_holder.IsSleeping() || quirk_holder.IsUnconscious()) + return + + if(HAS_TRAIT(quirk_holder, TRAIT_FEARLESS)) + return + + var/mob/living/carbon/human/human_holder = quirk_holder + + if(human_holder.sight & SEE_TURFS) + return + + var/turf/holder_turf = get_turf(quirk_holder) + + var/lums = holder_turf.get_lumcount() + + var/eye_protection = quirk_holder.get_eye_protection() + if(lums < LIGHTING_TILE_IS_DARK || eye_protection >= FLASH_PROTECTION_NONE) + quirk_holder.clear_mood_event(MOOD_CATEGORY_PHOTOPHOBIA) + return + quirk_holder.add_mood_event(MOOD_CATEGORY_PHOTOPHOBIA, /datum/mood_event/photophobia) + + #undef MOOD_CATEGORY_PHOTOPHOBIA diff --git a/code/datums/quirks/negative_quirks/poor_aim.dm b/code/datums/quirks/negative_quirks/poor_aim.dm new file mode 100644 index 00000000000000..d86feb809b0082 --- /dev/null +++ b/code/datums/quirks/negative_quirks/poor_aim.dm @@ -0,0 +1,19 @@ +/datum/quirk/poor_aim + name = "Stormtrooper Aim" + desc = "You've never hit anything you were aiming for in your life." + icon = FA_ICON_BULLSEYE + value = -4 + medical_record_text = "Patient possesses a strong tremor in both hands." + hardcore_value = 3 + mail_goodies = list(/obj/item/cardboard_cutout) // for target practice + +/datum/quirk/poor_aim/add(client/client_source) + RegisterSignal(quirk_holder, COMSIG_MOB_FIRED_GUN, PROC_REF(on_mob_fired_gun)) + +/datum/quirk/poor_aim/remove(client/client_source) + UnregisterSignal(quirk_holder, COMSIG_MOB_FIRED_GUN) + +/datum/quirk/poor_aim/proc/on_mob_fired_gun(mob/user, obj/item/gun/gun_fired, target, params, zone_override, list/bonus_spread_values) + SIGNAL_HANDLER + bonus_spread_values[MIN_BONUS_SPREAD_INDEX] += 10 + bonus_spread_values[MAX_BONUS_SPREAD_INDEX] += 35 diff --git a/code/datums/quirks/negative_quirks/prosopagnosia.dm b/code/datums/quirks/negative_quirks/prosopagnosia.dm new file mode 100644 index 00000000000000..8634e13bf638c1 --- /dev/null +++ b/code/datums/quirks/negative_quirks/prosopagnosia.dm @@ -0,0 +1,9 @@ +/datum/quirk/prosopagnosia + name = "Prosopagnosia" + desc = "You have a mental disorder that prevents you from being able to recognize faces at all." + icon = FA_ICON_USER_SECRET + value = -4 + mob_trait = TRAIT_PROSOPAGNOSIA + medical_record_text = "Patient suffers from prosopagnosia and cannot recognize faces." + hardcore_value = 5 + mail_goodies = list(/obj/item/skillchip/appraiser) // bad at recognizing faces but good at recognizing IDs diff --git a/code/datums/quirks/negative_quirks/prosthetic_limb.dm b/code/datums/quirks/negative_quirks/prosthetic_limb.dm new file mode 100644 index 00000000000000..f6f0e304a6dece --- /dev/null +++ b/code/datums/quirks/negative_quirks/prosthetic_limb.dm @@ -0,0 +1,42 @@ +/datum/quirk/prosthetic_limb + name = "Prosthetic Limb" + desc = "An accident caused you to lose one of your limbs. Because of this, you now have a surplus prosthetic!" + icon = "tg-prosthetic-leg" + value = -3 + medical_record_text = "During physical examination, patient was found to have a low-budget prosthetic limb." + hardcore_value = 3 + quirk_flags = QUIRK_HUMAN_ONLY // while this technically changes appearance, we don't want it to be shown on the dummy because it's randomized at roundstart + mail_goodies = list(/obj/item/weldingtool/mini, /obj/item/stack/cable_coil/five) + /// The slot to replace, in string form + var/slot_string = "limb" + /// the original limb from before the prosthetic was applied + var/obj/item/bodypart/old_limb + +/datum/quirk/prosthetic_limb/add_unique(client/client_source) + var/limb_slot = pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) + var/mob/living/carbon/human/human_holder = quirk_holder + var/obj/item/bodypart/prosthetic + switch(limb_slot) + if(BODY_ZONE_L_ARM) + prosthetic = new /obj/item/bodypart/arm/left/robot/surplus + slot_string = "left arm" + if(BODY_ZONE_R_ARM) + prosthetic = new /obj/item/bodypart/arm/right/robot/surplus + slot_string = "right arm" + if(BODY_ZONE_L_LEG) + prosthetic = new /obj/item/bodypart/leg/left/robot/surplus + slot_string = "left leg" + if(BODY_ZONE_R_LEG) + prosthetic = new /obj/item/bodypart/leg/right/robot/surplus + slot_string = "right leg" + medical_record_text = "During physical examination, patient was found to have a low-budget prosthetic [slot_string]." + old_limb = human_holder.return_and_replace_bodypart(prosthetic, special = TRUE) + +/datum/quirk/prosthetic_limb/post_add() + to_chat(quirk_holder, span_boldannounce("Your [slot_string] has been replaced with a surplus prosthetic. It is fragile and will easily come apart under duress. Additionally, \ + you need to use a welding tool and cables to repair it, instead of bruise packs and ointment.")) + +/datum/quirk/prosthetic_limb/remove() + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.del_and_replace_bodypart(old_limb, special = TRUE) + old_limb = null diff --git a/code/datums/quirks/negative_quirks/prosthetic_organ.dm b/code/datums/quirks/negative_quirks/prosthetic_organ.dm new file mode 100644 index 00000000000000..6330035b5a7219 --- /dev/null +++ b/code/datums/quirks/negative_quirks/prosthetic_organ.dm @@ -0,0 +1,63 @@ +/datum/quirk/prosthetic_organ + name = "Prosthetic Organ" + desc = "An accident caused you to lose one of your organs. Because of this, you now have a surplus prosthetic!" + icon = FA_ICON_LUNGS + value = -3 + medical_record_text = "During physical examination, patient was found to have a low-budget prosthetic organ. \ + Removal of these organs is known to be dangerous to the patient as well as the practitioner." + hardcore_value = 3 + mail_goodies = list(/obj/item/storage/organbox) + /// The slot to replace, in string form + var/slot_string = "organ" + /// The original organ from before the prosthetic was applied + var/obj/item/organ/old_organ + +/datum/quirk/prosthetic_organ/add_unique(client/client_source) + var/mob/living/carbon/human/human_holder = quirk_holder + var/static/list/organ_slots = list( + ORGAN_SLOT_HEART, + ORGAN_SLOT_LUNGS, + ORGAN_SLOT_LIVER, + ORGAN_SLOT_STOMACH, + ) + var/list/possible_organ_slots = organ_slots.Copy() + if(HAS_TRAIT(human_holder, TRAIT_NOBLOOD)) + possible_organ_slots -= ORGAN_SLOT_HEART + if(HAS_TRAIT(human_holder, TRAIT_NOBREATH)) + possible_organ_slots -= ORGAN_SLOT_LUNGS + if(HAS_TRAIT(human_holder, TRAIT_LIVERLESS_METABOLISM)) + possible_organ_slots -= ORGAN_SLOT_LIVER + if(HAS_TRAIT(human_holder, TRAIT_NOHUNGER)) + possible_organ_slots -= ORGAN_SLOT_STOMACH + if(!length(organ_slots)) //what the hell + return + var/organ_slot = pick(possible_organ_slots) + var/obj/item/organ/prosthetic + switch(organ_slot) + if(ORGAN_SLOT_HEART) + prosthetic = new /obj/item/organ/internal/heart/cybernetic/surplus + slot_string = "heart" + if(ORGAN_SLOT_LUNGS) + prosthetic = new /obj/item/organ/internal/lungs/cybernetic/surplus + slot_string = "lungs" + if(ORGAN_SLOT_LIVER) + prosthetic = new /obj/item/organ/internal/liver/cybernetic/surplus + slot_string = "liver" + if(ORGAN_SLOT_STOMACH) + prosthetic = new /obj/item/organ/internal/stomach/cybernetic/surplus + slot_string = "stomach" + medical_record_text = "During physical examination, patient was found to have a low-budget prosthetic [slot_string]. \ + Removal of these organs is known to be dangerous to the patient as well as the practitioner." + old_organ = human_holder.get_organ_slot(organ_slot) + if(prosthetic.Insert(human_holder, special = TRUE, drop_if_replaced = TRUE)) + old_organ.moveToNullspace() + STOP_PROCESSING(SSobj, old_organ) + +/datum/quirk/prosthetic_organ/post_add() + to_chat(quirk_holder, span_boldannounce("Your [slot_string] has been replaced with a surplus organ. It is fragile and will easily come apart under duress. \ + Additionally, any EMP will make it stop working entirely.")) + +/datum/quirk/prosthetic_organ/remove() + if(old_organ) + old_organ.Insert(quirk_holder, special = TRUE) + old_organ = null diff --git a/code/datums/quirks/negative_quirks/pushover.dm b/code/datums/quirks/negative_quirks/pushover.dm new file mode 100644 index 00000000000000..663d81737593bc --- /dev/null +++ b/code/datums/quirks/negative_quirks/pushover.dm @@ -0,0 +1,11 @@ +/datum/quirk/pushover + name = "Pushover" + desc = "Your first instinct is always to let people push you around. Resisting out of grabs will take conscious effort." + icon = FA_ICON_HANDSHAKE + value = -8 + mob_trait = TRAIT_GRABWEAKNESS + gain_text = span_danger("You feel like a pushover.") + lose_text = span_notice("You feel like standing up for yourself.") + medical_record_text = "Patient presents a notably unassertive personality and is easy to manipulate." + hardcore_value = 4 + mail_goodies = list(/obj/item/clothing/gloves/cargo_gauntlet) diff --git a/code/datums/quirks/negative_quirks/quadruple_amputee.dm b/code/datums/quirks/negative_quirks/quadruple_amputee.dm new file mode 100644 index 00000000000000..493cdf0b71cda6 --- /dev/null +++ b/code/datums/quirks/negative_quirks/quadruple_amputee.dm @@ -0,0 +1,20 @@ +/datum/quirk/quadruple_amputee + name = "Quadruple Amputee" + desc = "Oops! All Prosthetics! Due to some truly cruel cosmic punishment, all your limbs have been replaced with surplus prosthetics." + icon = "tg-prosthetic-full" + value = -6 + medical_record_text = "During physical examination, patient was found to have all low-budget prosthetic limbs." + hardcore_value = 6 + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE + mail_goodies = list(/obj/item/weldingtool/mini, /obj/item/stack/cable_coil/five) + +/datum/quirk/quadruple_amputee/add_unique(client/client_source) + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.del_and_replace_bodypart(new /obj/item/bodypart/arm/left/robot/surplus, special = TRUE) + human_holder.del_and_replace_bodypart(new /obj/item/bodypart/arm/right/robot/surplus, special = TRUE) + human_holder.del_and_replace_bodypart(new /obj/item/bodypart/leg/left/robot/surplus, special = TRUE) + human_holder.del_and_replace_bodypart(new /obj/item/bodypart/leg/right/robot/surplus, special = TRUE) + +/datum/quirk/quadruple_amputee/post_add() + to_chat(quirk_holder, span_boldannounce("All your limbs have been replaced with surplus prosthetics. They are fragile and will easily come apart under duress. \ + Additionally, you need to use a welding tool and cables to repair them, instead of bruise packs and ointment.")) diff --git a/code/datums/quirks/negative_quirks/social_anxiety.dm b/code/datums/quirks/negative_quirks/social_anxiety.dm new file mode 100644 index 00000000000000..3d140bd80a073a --- /dev/null +++ b/code/datums/quirks/negative_quirks/social_anxiety.dm @@ -0,0 +1,114 @@ +/datum/quirk/social_anxiety + name = "Social Anxiety" + desc = "Talking to people is very difficult for you, and you often stutter or even lock up." + icon = FA_ICON_COMMENT_SLASH + value = -3 + gain_text = span_danger("You start worrying about what you're saying.") + lose_text = span_notice("You feel easier about talking again.") //if only it were that easy! + medical_record_text = "Patient is usually anxious in social encounters and prefers to avoid them." + hardcore_value = 4 + mob_trait = TRAIT_ANXIOUS + mail_goodies = list(/obj/item/storage/pill_bottle/psicodine) + var/dumb_thing = TRUE + +/datum/quirk/social_anxiety/add(client/client_source) + RegisterSignal(quirk_holder, COMSIG_MOB_EYECONTACT, PROC_REF(eye_contact)) + RegisterSignal(quirk_holder, COMSIG_MOB_EXAMINATE, PROC_REF(looks_at_floor)) + RegisterSignal(quirk_holder, COMSIG_MOB_SAY, PROC_REF(handle_speech)) + +/datum/quirk/social_anxiety/remove() + UnregisterSignal(quirk_holder, list(COMSIG_MOB_EYECONTACT, COMSIG_MOB_EXAMINATE, COMSIG_MOB_SAY)) + +/datum/quirk/social_anxiety/proc/handle_speech(datum/source, list/speech_args) + SIGNAL_HANDLER + + if(HAS_TRAIT(quirk_holder, TRAIT_FEARLESS)) + return + + var/moodmod + if(quirk_holder.mob_mood) + moodmod = (1+0.02*(50-(max(50, quirk_holder.mob_mood.mood_level*(7-quirk_holder.mob_mood.sanity_level))))) //low sanity levels are better, they max at 6 + else + moodmod = (1+0.02*(50-(max(50, 0.1*quirk_holder.nutrition)))) + var/nearby_people = 0 + for(var/mob/living/carbon/human/H in oview(3, quirk_holder)) + if(H.client) + nearby_people++ + var/message = speech_args[SPEECH_MESSAGE] + if(message) + var/list/message_split = splittext(message, " ") + var/list/new_message = list() + var/mob/living/carbon/human/quirker = quirk_holder + for(var/word in message_split) + if(prob(max(5,(nearby_people*12.5*moodmod))) && word != message_split[1]) //Minimum 1/20 chance of filler + new_message += pick("uh,","erm,","um,") + if(prob(min(5,(0.05*(nearby_people*12.5)*moodmod)))) //Max 1 in 20 chance of cutoff after a successful filler roll, for 50% odds in a 15 word sentence + quirker.set_silence_if_lower(6 SECONDS) + to_chat(quirker, span_danger("You feel self-conscious and stop talking. You need a moment to recover!")) + break + if(prob(max(5,(nearby_people*12.5*moodmod)))) //Minimum 1/20 chance of stutter + // Add a short stutter, THEN treat our word + quirker.adjust_stutter(0.5 SECONDS) + var/list/message_data = quirker.treat_message(word, capitalize_message = FALSE) + new_message += message_data["message"] + else + new_message += word + + message = jointext(new_message, " ") + var/mob/living/carbon/human/quirker = quirk_holder + if(prob(min(50,(0.50*(nearby_people*12.5)*moodmod)))) //Max 50% chance of not talking + if(dumb_thing) + to_chat(quirker, span_userdanger("You think of a dumb thing you said a long time ago and scream internally.")) + dumb_thing = FALSE //only once per life + if(prob(1)) + new/obj/item/food/spaghetti/pastatomato(get_turf(quirker)) //now that's what I call spaghetti code + else + to_chat(quirk_holder, span_warning("You think that wouldn't add much to the conversation and decide not to say it.")) + if(prob(min(25,(0.25*(nearby_people*12.75)*moodmod)))) //Max 25% chance of silence stacks after successful not talking roll + to_chat(quirker, span_danger("You retreat into yourself. You really don't feel up to talking.")) + quirker.set_silence_if_lower(10 SECONDS) + + speech_args[SPEECH_MESSAGE] = pick("Uh.","Erm.","Um.") + else + speech_args[SPEECH_MESSAGE] = message + +// small chance to make eye contact with inanimate objects/mindless mobs because of nerves +/datum/quirk/social_anxiety/proc/looks_at_floor(datum/source, atom/A) + SIGNAL_HANDLER + + var/mob/living/mind_check = A + if(prob(85) || (istype(mind_check) && mind_check.mind)) + return + + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), quirk_holder, span_smallnotice("You make eye contact with [A].")), 3) + +/datum/quirk/social_anxiety/proc/eye_contact(datum/source, mob/living/other_mob, triggering_examiner) + SIGNAL_HANDLER + + if(prob(75)) + return + var/msg + if(triggering_examiner) + msg = "You make eye contact with [other_mob], " + else + msg = "[other_mob] makes eye contact with you, " + + switch(rand(1,3)) + if(1) + quirk_holder.set_jitter_if_lower(20 SECONDS) + msg += "causing you to start fidgeting!" + if(2) + quirk_holder.set_stutter_if_lower(6 SECONDS) + msg += "causing you to start stuttering!" + if(3) + quirk_holder.Stun(2 SECONDS) + msg += "causing you to freeze up!" + + quirk_holder.add_mood_event("anxiety_eyecontact", /datum/mood_event/anxiety_eyecontact) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), quirk_holder, span_userdanger("[msg]")), 3) // so the examine signal has time to fire and this will print after + return COMSIG_BLOCK_EYECONTACT + +/datum/mood_event/anxiety_eyecontact + description = "Sometimes eye contact makes me so nervous..." + mood_change = -5 + timeout = 3 MINUTES diff --git a/code/datums/quirks/negative_quirks/softspoken.dm b/code/datums/quirks/negative_quirks/softspoken.dm new file mode 100644 index 00000000000000..41be5f1aca0065 --- /dev/null +++ b/code/datums/quirks/negative_quirks/softspoken.dm @@ -0,0 +1,9 @@ +/datum/quirk/softspoken + name = "Soft-Spoken" + desc = "You are soft-spoken, and your voice is hard to hear." + icon = FA_ICON_COMMENT + value = -2 + mob_trait = TRAIT_SOFTSPOKEN + gain_text = span_danger("You feel like you're speaking more quietly.") + lose_text = span_notice("You feel like you're speaking louder.") + medical_record_text = "Patient is soft-spoken and difficult to hear." diff --git a/code/datums/quirks/negative_quirks/tin_man.dm b/code/datums/quirks/negative_quirks/tin_man.dm new file mode 100644 index 00000000000000..5a4ab4b1357f51 --- /dev/null +++ b/code/datums/quirks/negative_quirks/tin_man.dm @@ -0,0 +1,37 @@ +/datum/quirk/tin_man + name = "Tin Man" + desc = "Oops! All Prosthetics! Due to some truly cruel cosmic punishment, most of your internal organs have been replaced with surplus prosthetics." + icon = FA_ICON_ROBOT + value = -6 + medical_record_text = "During physical examination, patient was found to have numerous low-budget prosthetic internal organs. \ + Removal of these organs is known to be dangerous to the patient as well as the practitioner." + hardcore_value = 6 + mail_goodies = list(/obj/item/storage/organbox) + +/datum/quirk/tin_man/add_unique(client/client_source) + var/mob/living/carbon/human/human_holder = quirk_holder + var/static/list/organ_slots = list( + ORGAN_SLOT_HEART = /obj/item/organ/internal/heart/cybernetic/surplus, + ORGAN_SLOT_LUNGS = /obj/item/organ/internal/lungs/cybernetic/surplus, + ORGAN_SLOT_LIVER = /obj/item/organ/internal/liver/cybernetic/surplus, + ORGAN_SLOT_STOMACH = /obj/item/organ/internal/stomach/cybernetic/surplus, + ) + var/list/possible_organ_slots = organ_slots.Copy() + if(HAS_TRAIT(human_holder, TRAIT_NOBLOOD)) + possible_organ_slots -= ORGAN_SLOT_HEART + if(HAS_TRAIT(human_holder, TRAIT_NOBREATH)) + possible_organ_slots -= ORGAN_SLOT_LUNGS + if(HAS_TRAIT(human_holder, TRAIT_LIVERLESS_METABOLISM)) + possible_organ_slots -= ORGAN_SLOT_LIVER + if(HAS_TRAIT(human_holder, TRAIT_NOHUNGER)) + possible_organ_slots -= ORGAN_SLOT_STOMACH + if(!length(organ_slots)) //what the hell + return + for(var/organ_slot in possible_organ_slots) + var/organ_path = possible_organ_slots[organ_slot] + var/obj/item/organ/new_organ = new organ_path() + new_organ.Insert(human_holder, special = TRUE, drop_if_replaced = FALSE) + +/datum/quirk/tin_man/post_add() + to_chat(quirk_holder, span_boldannounce("Most of your internal organs have been replaced with surplus prosthetics. They are fragile and will easily come apart under duress. \ + Additionally, any EMP will make them stop working entirely.")) diff --git a/code/datums/quirks/negative_quirks/unstable.dm b/code/datums/quirks/negative_quirks/unstable.dm new file mode 100644 index 00000000000000..5d39776eeba204 --- /dev/null +++ b/code/datums/quirks/negative_quirks/unstable.dm @@ -0,0 +1,11 @@ +/datum/quirk/unstable + name = "Unstable" + desc = "Due to past troubles, you are unable to recover your sanity if you lose it. Be very careful managing your mood!" + icon = FA_ICON_ANGRY + value = -10 + mob_trait = TRAIT_UNSTABLE + gain_text = span_danger("There's a lot on your mind right now.") + lose_text = span_notice("Your mind finally feels calm.") + medical_record_text = "Patient's mind is in a vulnerable state, and cannot recover from traumatic events." + hardcore_value = 9 + mail_goodies = list(/obj/effect/spawner/random/entertainment/plushie) diff --git a/code/datums/quirks/neutral_quirks/bald.dm b/code/datums/quirks/neutral_quirks/bald.dm new file mode 100644 index 00000000000000..8a760f6ceefdb9 --- /dev/null +++ b/code/datums/quirks/neutral_quirks/bald.dm @@ -0,0 +1,53 @@ +/datum/quirk/item_quirk/bald + name = "Smooth-Headed" + desc = "You have no hair and are quite insecure about it! Keep your wig on, or at least your head covered up." + icon = FA_ICON_EGG + value = 0 + mob_trait = TRAIT_BALD + gain_text = span_notice("Your head is as smooth as can be, it's terrible.") + lose_text = span_notice("Your head itches, could it be... growing hair?!") + medical_record_text = "Patient starkly refused to take off headwear during examination." + mail_goodies = list(/obj/item/clothing/head/wig/random) + /// The user's starting hairstyle + var/old_hair + +/datum/quirk/item_quirk/bald/add(client/client_source) + var/mob/living/carbon/human/human_holder = quirk_holder + old_hair = human_holder.hairstyle + human_holder.set_hairstyle("Bald", update = TRUE) + RegisterSignal(human_holder, COMSIG_CARBON_EQUIP_HAT, PROC_REF(equip_hat)) + RegisterSignal(human_holder, COMSIG_CARBON_UNEQUIP_HAT, PROC_REF(unequip_hat)) + +/datum/quirk/item_quirk/bald/add_unique(client/client_source) + var/obj/item/clothing/head/wig/natural/baldie_wig = new(get_turf(quirk_holder)) + if(old_hair == "Bald") + baldie_wig.hairstyle = pick(GLOB.hairstyles_list - "Bald") + else + baldie_wig.hairstyle = old_hair + + baldie_wig.update_appearance() + + give_item_to_holder(baldie_wig, list(LOCATION_HEAD = ITEM_SLOT_HEAD, LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) + +/datum/quirk/item_quirk/bald/remove() + . = ..() + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.hairstyle = old_hair + human_holder.update_body_parts() + UnregisterSignal(human_holder, list(COMSIG_CARBON_EQUIP_HAT, COMSIG_CARBON_UNEQUIP_HAT)) + human_holder.clear_mood_event("bad_hair_day") + +///Checks if the headgear equipped is a wig and sets the mood event accordingly +/datum/quirk/item_quirk/bald/proc/equip_hat(mob/user, obj/item/hat) + SIGNAL_HANDLER + + if(istype(hat, /obj/item/clothing/head/wig)) + quirk_holder.add_mood_event("bad_hair_day", /datum/mood_event/confident_mane) //Our head is covered, but also by a wig so we're happy. + else + quirk_holder.clear_mood_event("bad_hair_day") //Our head is covered + +///Applies a bad moodlet for having an uncovered head +/datum/quirk/item_quirk/bald/proc/unequip_hat(mob/user, obj/item/clothing, force, newloc, no_move, invdrop, silent) + SIGNAL_HANDLER + + quirk_holder.add_mood_event("bad_hair_day", /datum/mood_event/bald) diff --git a/code/datums/quirks/neutral_quirks/colorist.dm b/code/datums/quirks/neutral_quirks/colorist.dm new file mode 100644 index 00000000000000..f82fd5bf6fe3e4 --- /dev/null +++ b/code/datums/quirks/neutral_quirks/colorist.dm @@ -0,0 +1,13 @@ +/* SKYRAT EDIT REMOVAL +/datum/quirk/item_quirk/colorist + name = "Colorist" + desc = "You like carrying around a hair dye spray to quickly apply color patterns to your hair." + icon = FA_ICON_FILL_DRIP + value = 0 + medical_record_text = "Patient enjoys dyeing their hair with pretty colors." + mail_goodies = list(/obj/item/dyespray) + +/datum/quirk/item_quirk/colorist/add_unique(client/client_source) + give_item_to_holder(/obj/item/dyespray, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) +*/ +//SKYRAT EDIT REMOVAL diff --git a/code/datums/quirks/neutral_quirks/deviant_tastes.dm b/code/datums/quirks/neutral_quirks/deviant_tastes.dm new file mode 100644 index 00000000000000..566b469c7a77d3 --- /dev/null +++ b/code/datums/quirks/neutral_quirks/deviant_tastes.dm @@ -0,0 +1,24 @@ +/datum/quirk/deviant_tastes + name = "Deviant Tastes" + desc = "You dislike food that most people enjoy, and find delicious what they don't." + icon = FA_ICON_GRIN_TONGUE_SQUINT + value = 0 + gain_text = span_notice("You start craving something that tastes strange.") + lose_text = span_notice("You feel like eating normal food again.") + medical_record_text = "Patient demonstrates irregular nutrition preferences." + mail_goodies = list(/obj/item/food/urinalcake, /obj/item/food/badrecipe) // Mhhhmmm yummy + +/datum/quirk/deviant_tastes/add(client/client_source) + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + var/liked_foodtypes = tongue.liked_foodtypes + tongue.liked_foodtypes = tongue.disliked_foodtypes + tongue.disliked_foodtypes = liked_foodtypes + +/datum/quirk/deviant_tastes/remove() + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + tongue.liked_foodtypes = initial(tongue.liked_foodtypes) + tongue.disliked_foodtypes = initial(tongue.disliked_foodtypes) diff --git a/code/datums/quirks/neutral_quirks/extrovert.dm b/code/datums/quirks/neutral_quirks/extrovert.dm new file mode 100644 index 00000000000000..5622956ba5b5b5 --- /dev/null +++ b/code/datums/quirks/neutral_quirks/extrovert.dm @@ -0,0 +1,10 @@ +/datum/quirk/extrovert + name = "Extrovert" + desc = "You are energized by talking to others, and enjoy spending your free time in the bar." + icon = FA_ICON_USERS + value = 0 + mob_trait = TRAIT_EXTROVERT + gain_text = span_notice("You feel like hanging out with other people.") + lose_text = span_danger("You feel like you're over the bar scene.") + medical_record_text = "Patient will not shut the hell up." + mail_goodies = list(/obj/item/reagent_containers/cup/glass/flask) diff --git a/code/datums/quirks/neutral_quirks/foreigner.dm b/code/datums/quirks/neutral_quirks/foreigner.dm new file mode 100644 index 00000000000000..da317a7e66a44f --- /dev/null +++ b/code/datums/quirks/neutral_quirks/foreigner.dm @@ -0,0 +1,21 @@ +/datum/quirk/foreigner + name = "Foreigner" + desc = "You're not from around here. You don't know Galactic Common!" + icon = FA_ICON_LANGUAGE + value = 0 + gain_text = span_notice("The words being spoken around you don't make any sense.") + lose_text = span_notice("You've developed fluency in Galactic Common.") + medical_record_text = "Patient does not speak Galactic Common and may require an interpreter." + mail_goodies = list(/obj/item/taperecorder) // for translation + +/datum/quirk/foreigner/add(client/client_source) + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.add_blocked_language(/datum/language/common) + if(ishumanbasic(human_holder)) + human_holder.grant_language(/datum/language/uncommon, source = LANGUAGE_QUIRK) + +/datum/quirk/foreigner/remove() + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.remove_blocked_language(/datum/language/common) + if(ishumanbasic(human_holder)) + human_holder.remove_language(/datum/language/uncommon) diff --git a/code/datums/quirks/neutral_quirks/gamer.dm b/code/datums/quirks/neutral_quirks/gamer.dm new file mode 100644 index 00000000000000..0ab2e780480ee9 --- /dev/null +++ b/code/datums/quirks/neutral_quirks/gamer.dm @@ -0,0 +1,90 @@ +#define GAMING_WITHDRAWAL_TIME (15 MINUTES) +/datum/quirk/gamer + name = "Gamer" + desc = "You are a hardcore gamer, and you have a need to game. You love winning and hate losing. You only like gamer food." + icon = FA_ICON_GAMEPAD + value = 0 + gain_text = span_notice("You feel the sudden urge to game.") + lose_text = span_notice("You've lost all interest in gaming.") + medical_record_text = "Patient has a severe video game addiction." + mob_trait = TRAIT_GAMER + mail_goodies = list(/obj/item/toy/intento, /obj/item/clothing/head/fedora) + /// Timer for gaming withdrawal to kick in + var/gaming_withdrawal_timer = TIMER_ID_NULL + +/datum/quirk/gamer/add(client/client_source) + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(tongue) + // Gamer diet + tongue.liked_foodtypes = JUNKFOOD + RegisterSignal(quirk_holder, COMSIG_MOB_WON_VIDEOGAME, PROC_REF(won_game)) + RegisterSignal(quirk_holder, COMSIG_MOB_LOST_VIDEOGAME, PROC_REF(lost_game)) + RegisterSignal(quirk_holder, COMSIG_MOB_PLAYED_VIDEOGAME, PROC_REF(gamed)) + +/datum/quirk/gamer/add_unique(client/client_source) + // The gamer starts off quelled + gaming_withdrawal_timer = addtimer(CALLBACK(src, PROC_REF(enter_withdrawal)), GAMING_WITHDRAWAL_TIME, TIMER_STOPPABLE) + +/datum/quirk/gamer/remove() + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(tongue) + tongue.liked_foodtypes = initial(tongue.liked_foodtypes) + UnregisterSignal(quirk_holder, COMSIG_MOB_WON_VIDEOGAME) + UnregisterSignal(quirk_holder, COMSIG_MOB_LOST_VIDEOGAME) + UnregisterSignal(quirk_holder, COMSIG_MOB_PLAYED_VIDEOGAME) + +/** + * Gamer won a game + * + * Executed on the COMSIG_MOB_WON_VIDEOGAME signal + * This signal should be called whenever a player has won a video game. + * (E.g. Orion Trail) + */ +/datum/quirk/gamer/proc/won_game() + SIGNAL_HANDLER + // Epic gamer victory + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.add_mood_event("gamer_won", /datum/mood_event/gamer_won) + +/** + * Gamer lost a game + * + * Executed on the COMSIG_MOB_LOST_VIDEOGAME signal + * This signal should be called whenever a player has lost a video game. + * (E.g. Orion Trail) + */ +/datum/quirk/gamer/proc/lost_game() + SIGNAL_HANDLER + // Executed when a gamer has lost + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.add_mood_event("gamer_lost", /datum/mood_event/gamer_lost) + // Executed asynchronously due to say() + INVOKE_ASYNC(src, PROC_REF(gamer_moment)) +/** + * Gamer is playing a game + * + * Executed on the COMSIG_MOB_PLAYED_VIDEOGAME signal + * This signal should be called whenever a player interacts with a video game. + */ +/datum/quirk/gamer/proc/gamed() + SIGNAL_HANDLER + + var/mob/living/carbon/human/human_holder = quirk_holder + // Remove withdrawal malus + human_holder.clear_mood_event("gamer_withdrawal") + // Reset withdrawal timer + if (gaming_withdrawal_timer) + deltimer(gaming_withdrawal_timer) + gaming_withdrawal_timer = addtimer(CALLBACK(src, PROC_REF(enter_withdrawal)), GAMING_WITHDRAWAL_TIME, TIMER_STOPPABLE) + + +/datum/quirk/gamer/proc/gamer_moment() + // It was a heated gamer moment... + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.say(";[pick("SHIT", "PISS", "FUCK", "CUNT", "COCKSUCKER", "MOTHERFUCKER")]!!", forced = name) + +/datum/quirk/gamer/proc/enter_withdrawal() + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.add_mood_event("gamer_withdrawal", /datum/mood_event/gamer_withdrawal) + +#undef GAMING_WITHDRAWAL_TIME diff --git a/code/datums/quirks/neutral_quirks/heretochromatic.dm b/code/datums/quirks/neutral_quirks/heretochromatic.dm new file mode 100644 index 00000000000000..1df079c0e45f59 --- /dev/null +++ b/code/datums/quirks/neutral_quirks/heretochromatic.dm @@ -0,0 +1,54 @@ +/datum/quirk/heterochromatic + name = "Heterochromatic" + desc = "One of your eyes is a different color than the other!" + icon = FA_ICON_EYE_LOW_VISION // Ignore the icon name, its actually a fairly good representation of different color eyes + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE + value = 0 + mail_goodies = list(/obj/item/clothing/glasses/eyepatch) + +// Only your first eyes are heterochromatic +// If someone comes and says "well mr coder you can have DNA bound heterochromia so it's not unrealistic +// to allow all inserted replacement eyes to become heterochromatic or for it to transfer between mobs" +// Then just change this to [proc/add] I really don't care +/datum/quirk/heterochromatic/add_unique(client/client_source) + var/color = client_source?.prefs.read_preference(/datum/preference/color/heterochromatic) + if(!color) + return + + apply_heterochromatic_eyes(color) + +/// Applies the passed color to this mob's eyes +/datum/quirk/heterochromatic/proc/apply_heterochromatic_eyes(color) + var/mob/living/carbon/human/human_holder = quirk_holder + var/was_not_hetero = !human_holder.eye_color_heterochromatic + human_holder.eye_color_heterochromatic = TRUE + human_holder.eye_color_right = color + + var/obj/item/organ/internal/eyes/eyes_of_the_holder = quirk_holder.get_organ_by_type(/obj/item/organ/internal/eyes) + if(!eyes_of_the_holder) + return + + eyes_of_the_holder.eye_color_right = color + eyes_of_the_holder.old_eye_color_right = color + eyes_of_the_holder.refresh() + + if(was_not_hetero) + RegisterSignal(human_holder, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(check_eye_removal)) + +/datum/quirk/heterochromatic/remove() + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.eye_color_heterochromatic = FALSE + human_holder.eye_color_right = human_holder.eye_color_left + UnregisterSignal(human_holder, COMSIG_CARBON_LOSE_ORGAN) + +/datum/quirk/heterochromatic/proc/check_eye_removal(datum/source, obj/item/organ/internal/eyes/removed) + SIGNAL_HANDLER + + if(!istype(removed)) + return + + // Eyes were removed, remove heterochromia from the human holder and bid them adieu + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.eye_color_heterochromatic = FALSE + human_holder.eye_color_right = human_holder.eye_color_left + UnregisterSignal(human_holder, COMSIG_CARBON_LOSE_ORGAN) diff --git a/code/datums/quirks/neutral_quirks/introvert.dm b/code/datums/quirks/neutral_quirks/introvert.dm new file mode 100644 index 00000000000000..51f6f3e785e43d --- /dev/null +++ b/code/datums/quirks/neutral_quirks/introvert.dm @@ -0,0 +1,10 @@ +/datum/quirk/introvert + name = "Introvert" + desc = "You are energized by having time to yourself, and enjoy spending your free time in the library." + icon = FA_ICON_BOOK_READER + value = 0 + mob_trait = TRAIT_INTROVERT + gain_text = span_notice("You feel like reading a good book quietly.") + lose_text = span_danger("You feel like libraries are boring.") + medical_record_text = "Patient doesn't seem to say much." + mail_goodies = list(/obj/item/book/random) diff --git a/code/datums/quirks/neutral_quirks/monochromatic.dm b/code/datums/quirks/neutral_quirks/monochromatic.dm new file mode 100644 index 00000000000000..dd66220cb56a90 --- /dev/null +++ b/code/datums/quirks/neutral_quirks/monochromatic.dm @@ -0,0 +1,23 @@ +/datum/quirk/monochromatic + name = "Monochromacy" + desc = "You suffer from full colorblindness, and perceive nearly the entire world in blacks and whites." + icon = FA_ICON_ADJUST + value = 0 + medical_record_text = "Patient is afflicted with almost complete color blindness." + mail_goodies = list( // Noir detective wannabe + /obj/item/clothing/suit/jacket/det_suit/noir, + /obj/item/clothing/suit/jacket/det_suit/dark, + /obj/item/clothing/head/fedora/beige, + /obj/item/clothing/head/fedora/white, + ) + +/datum/quirk/monochromatic/add(client/client_source) + quirk_holder.add_client_colour(/datum/client_colour/monochrome) + +/datum/quirk/monochromatic/post_add() + if(is_detective_job(quirk_holder.mind.assigned_role)) + to_chat(quirk_holder, span_boldannounce("Mmm. Nothing's ever clear on this station. It's all shades of gray...")) + quirk_holder.playsound_local(quirk_holder, 'sound/ambience/ambidet1.ogg', 50, FALSE) + +/datum/quirk/monochromatic/remove() + quirk_holder.remove_client_colour(/datum/client_colour/monochrome) diff --git a/code/datums/quirks/neutral_quirks/neutral_quirks.dm b/code/datums/quirks/neutral_quirks/neutral_quirks.dm deleted file mode 100644 index 8917b361df0e85..00000000000000 --- a/code/datums/quirks/neutral_quirks/neutral_quirks.dm +++ /dev/null @@ -1,485 +0,0 @@ -//traits with no real impact that can be taken freely -//MAKE SURE THESE DO NOT MAJORLY IMPACT GAMEPLAY. those should be positive or negative traits. - -/datum/quirk/extrovert - name = "Extrovert" - desc = "You are energized by talking to others, and enjoy spending your free time in the bar." - icon = FA_ICON_USERS - value = 0 - mob_trait = TRAIT_EXTROVERT - gain_text = span_notice("You feel like hanging out with other people.") - lose_text = span_danger("You feel like you're over the bar scene.") - medical_record_text = "Patient will not shut the hell up." - mail_goodies = list(/obj/item/reagent_containers/cup/glass/flask) - -/datum/quirk/introvert - name = "Introvert" - desc = "You are energized by having time to yourself, and enjoy spending your free time in the library." - icon = FA_ICON_BOOK_READER - value = 0 - mob_trait = TRAIT_INTROVERT - gain_text = span_notice("You feel like reading a good book quietly.") - lose_text = span_danger("You feel like libraries are boring.") - medical_record_text = "Patient doesn't seem to say much." - mail_goodies = list(/obj/item/book/random) - -/datum/quirk/no_taste - name = "Ageusia" - desc = "You can't taste anything! Toxic food will still poison you." - icon = FA_ICON_MEH_BLANK - value = 0 - mob_trait = TRAIT_AGEUSIA - gain_text = span_notice("You can't taste anything!") - lose_text = span_notice("You can taste again!") - medical_record_text = "Patient suffers from ageusia and is incapable of tasting food or reagents." - mail_goodies = list(/obj/effect/spawner/random/food_or_drink/condiment) // but can you taste the salt? CAN YOU?! - -/datum/quirk/foreigner - name = "Foreigner" - desc = "You're not from around here. You don't know Galactic Common!" - icon = FA_ICON_LANGUAGE - value = 0 - gain_text = span_notice("The words being spoken around you don't make any sense.") - lose_text = span_notice("You've developed fluency in Galactic Common.") - medical_record_text = "Patient does not speak Galactic Common and may require an interpreter." - mail_goodies = list(/obj/item/taperecorder) // for translation - -/datum/quirk/foreigner/add(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.add_blocked_language(/datum/language/common) - if(ishumanbasic(human_holder)) - human_holder.grant_language(/datum/language/uncommon, source = LANGUAGE_QUIRK) - -/datum/quirk/foreigner/remove() - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.remove_blocked_language(/datum/language/common) - if(ishumanbasic(human_holder)) - human_holder.remove_language(/datum/language/uncommon) - -/datum/quirk/vegetarian - name = "Vegetarian" - desc = "You find the idea of eating meat morally and physically repulsive." - icon = FA_ICON_CARROT - value = 0 - gain_text = span_notice("You feel repulsion at the idea of eating meat.") - lose_text = span_notice("You feel like eating meat isn't that bad.") - medical_record_text = "Patient reports a vegetarian diet." - mail_goodies = list(/obj/effect/spawner/random/food_or_drink/salad) - -/datum/quirk/vegetarian/add(client/client_source) - var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) - if(!tongue) - return - tongue.liked_foodtypes &= ~MEAT - tongue.disliked_foodtypes |= MEAT - -/datum/quirk/vegetarian/remove() - var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) - if(!tongue) - return - tongue.liked_foodtypes = initial(tongue.liked_foodtypes) - tongue.disliked_foodtypes = initial(tongue.disliked_foodtypes) - -/datum/quirk/snob - name = "Snob" - desc = "You care about the finer things, if a room doesn't look nice its just not really worth it, is it?" - icon = FA_ICON_USER_TIE - value = 0 - gain_text = span_notice("You feel like you understand what things should look like.") - lose_text = span_notice("Well who cares about deco anyways?") - medical_record_text = "Patient seems to be rather stuck up." - mob_trait = TRAIT_SNOB - mail_goodies = list(/obj/item/chisel, /obj/item/paint_palette) - -/datum/quirk/pineapple_liker - name = "Ananas Affinity" - desc = "You find yourself greatly enjoying fruits of the ananas genus. You can't seem to ever get enough of their sweet goodness!" - icon = FA_ICON_THUMBS_UP - value = 0 - gain_text = span_notice("You feel an intense craving for pineapple.") - lose_text = span_notice("Your feelings towards pineapples seem to return to a lukewarm state.") - medical_record_text = "Patient demonstrates a pathological love of pineapple." - mail_goodies = list(/obj/item/food/pizzaslice/pineapple) - -/datum/quirk/pineapple_liker/add(client/client_source) - var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) - if(!tongue) - return - tongue.liked_foodtypes |= PINEAPPLE - -/datum/quirk/pineapple_liker/remove() - var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) - if(!tongue) - return - tongue.liked_foodtypes = initial(tongue.liked_foodtypes) - -/datum/quirk/pineapple_hater - name = "Ananas Aversion" - desc = "You find yourself greatly detesting fruits of the ananas genus. Serious, how the hell can anyone say these things are good? And what kind of madman would even dare putting it on a pizza!?" - icon = FA_ICON_THUMBS_DOWN - value = 0 - gain_text = span_notice("You find yourself pondering what kind of idiot actually enjoys pineapples...") - lose_text = span_notice("Your feelings towards pineapples seem to return to a lukewarm state.") - medical_record_text = "Patient is correct to think that pineapple is disgusting." - mail_goodies = list( // basic pizza slices - /obj/item/food/pizzaslice/margherita, - /obj/item/food/pizzaslice/meat, - /obj/item/food/pizzaslice/mushroom, - /obj/item/food/pizzaslice/vegetable, - /obj/item/food/pizzaslice/sassysage, - ) - -/datum/quirk/pineapple_hater/add(client/client_source) - var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) - if(!tongue) - return - tongue.disliked_foodtypes |= PINEAPPLE - -/datum/quirk/pineapple_hater/remove() - var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) - if(!tongue) - return - tongue.disliked_foodtypes = initial(tongue.disliked_foodtypes) - -/datum/quirk/deviant_tastes - name = "Deviant Tastes" - desc = "You dislike food that most people enjoy, and find delicious what they don't." - icon = FA_ICON_GRIN_TONGUE_SQUINT - value = 0 - gain_text = span_notice("You start craving something that tastes strange.") - lose_text = span_notice("You feel like eating normal food again.") - medical_record_text = "Patient demonstrates irregular nutrition preferences." - mail_goodies = list(/obj/item/food/urinalcake, /obj/item/food/badrecipe) // Mhhhmmm yummy - -/datum/quirk/deviant_tastes/add(client/client_source) - var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) - if(!tongue) - return - var/liked_foodtypes = tongue.liked_foodtypes - tongue.liked_foodtypes = tongue.disliked_foodtypes - tongue.disliked_foodtypes = liked_foodtypes - -/datum/quirk/deviant_tastes/remove() - var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) - if(!tongue) - return - tongue.liked_foodtypes = initial(tongue.liked_foodtypes) - tongue.disliked_foodtypes = initial(tongue.disliked_foodtypes) - -/datum/quirk/heterochromatic - name = "Heterochromatic" - desc = "One of your eyes is a different color than the other!" - icon = FA_ICON_EYE_LOW_VISION // Ignore the icon name, its actually a fairly good representation of different color eyes - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE - value = 0 - mail_goodies = list(/obj/item/clothing/glasses/eyepatch) - -// Only your first eyes are heterochromatic -// If someone comes and says "well mr coder you can have DNA bound heterochromia so it's not unrealistic -// to allow all inserted replacement eyes to become heterochromatic or for it to transfer between mobs" -// Then just change this to [proc/add] I really don't care -/datum/quirk/heterochromatic/add_unique(client/client_source) - var/color = client_source?.prefs.read_preference(/datum/preference/color/heterochromatic) - if(!color) - return - - apply_heterochromatic_eyes(color) - -/// Applies the passed color to this mob's eyes -/datum/quirk/heterochromatic/proc/apply_heterochromatic_eyes(color) - var/mob/living/carbon/human/human_holder = quirk_holder - var/was_not_hetero = !human_holder.eye_color_heterochromatic - human_holder.eye_color_heterochromatic = TRUE - human_holder.eye_color_right = color - - var/obj/item/organ/internal/eyes/eyes_of_the_holder = quirk_holder.get_organ_by_type(/obj/item/organ/internal/eyes) - if(!eyes_of_the_holder) - return - - eyes_of_the_holder.eye_color_right = color - eyes_of_the_holder.old_eye_color_right = color - eyes_of_the_holder.refresh() - - if(was_not_hetero) - RegisterSignal(human_holder, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(check_eye_removal)) - -/datum/quirk/heterochromatic/remove() - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.eye_color_heterochromatic = FALSE - human_holder.eye_color_right = human_holder.eye_color_left - UnregisterSignal(human_holder, COMSIG_CARBON_LOSE_ORGAN) - -/datum/quirk/heterochromatic/proc/check_eye_removal(datum/source, obj/item/organ/internal/eyes/removed) - SIGNAL_HANDLER - - if(!istype(removed)) - return - - // Eyes were removed, remove heterochromia from the human holder and bid them adieu - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.eye_color_heterochromatic = FALSE - human_holder.eye_color_right = human_holder.eye_color_left - UnregisterSignal(human_holder, COMSIG_CARBON_LOSE_ORGAN) - -/datum/quirk/monochromatic - name = "Monochromacy" - desc = "You suffer from full colorblindness, and perceive nearly the entire world in blacks and whites." - icon = FA_ICON_ADJUST - value = 0 - medical_record_text = "Patient is afflicted with almost complete color blindness." - mail_goodies = list( // Noir detective wannabe - /obj/item/clothing/suit/jacket/det_suit/noir, - /obj/item/clothing/suit/jacket/det_suit/dark, - /obj/item/clothing/head/fedora/beige, - /obj/item/clothing/head/fedora/white, - ) - -/datum/quirk/monochromatic/add(client/client_source) - quirk_holder.add_client_colour(/datum/client_colour/monochrome) - -/datum/quirk/monochromatic/post_add() - if(is_detective_job(quirk_holder.mind.assigned_role)) - to_chat(quirk_holder, span_boldannounce("Mmm. Nothing's ever clear on this station. It's all shades of gray...")) - quirk_holder.playsound_local(quirk_holder, 'sound/ambience/ambidet1.ogg', 50, FALSE) - -/datum/quirk/monochromatic/remove() - quirk_holder.remove_client_colour(/datum/client_colour/monochrome) - -/datum/quirk/phobia - name = "Phobia" - desc = "You are irrationally afraid of something." - icon = FA_ICON_SPIDER - value = 0 - medical_record_text = "Patient has an irrational fear of something." - mail_goodies = list(/obj/item/clothing/glasses/blindfold, /obj/item/storage/pill_bottle/psicodine) - -// Phobia will follow you between transfers -/datum/quirk/phobia/add(client/client_source) - var/phobia = client_source?.prefs.read_preference(/datum/preference/choiced/phobia) - if(!phobia) - return - - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.gain_trauma(new /datum/brain_trauma/mild/phobia(phobia), TRAUMA_RESILIENCE_ABSOLUTE) - -/datum/quirk/phobia/remove() - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.cure_trauma_type(/datum/brain_trauma/mild/phobia, TRAUMA_RESILIENCE_ABSOLUTE) - -/datum/quirk/shifty_eyes - name = "Shifty Eyes" - desc = "Your eyes tend to wander all over the place, whether you mean to or not, causing people to sometimes think you're looking directly at them when you aren't." - icon = FA_ICON_EYE - value = 0 - medical_record_text = "Fucking creep kept staring at me the whole damn checkup. I'm only diagnosing this because it's less awkward than thinking it was on purpose." - mob_trait = TRAIT_SHIFTY_EYES - mail_goodies = list(/obj/item/clothing/head/costume/papersack, /obj/item/clothing/head/costume/papersack/smiley) - -/datum/quirk/item_quirk/bald - name = "Smooth-Headed" - desc = "You have no hair and are quite insecure about it! Keep your wig on, or at least your head covered up." - icon = FA_ICON_EGG - value = 0 - mob_trait = TRAIT_BALD - gain_text = span_notice("Your head is as smooth as can be, it's terrible.") - lose_text = span_notice("Your head itches, could it be... growing hair?!") - medical_record_text = "Patient starkly refused to take off headwear during examination." - mail_goodies = list(/obj/item/clothing/head/wig/random) - /// The user's starting hairstyle - var/old_hair - -/datum/quirk/item_quirk/bald/add(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - old_hair = human_holder.hairstyle - human_holder.set_hairstyle("Bald", update = TRUE) - RegisterSignal(human_holder, COMSIG_CARBON_EQUIP_HAT, PROC_REF(equip_hat)) - RegisterSignal(human_holder, COMSIG_CARBON_UNEQUIP_HAT, PROC_REF(unequip_hat)) - -/datum/quirk/item_quirk/bald/add_unique(client/client_source) - var/obj/item/clothing/head/wig/natural/baldie_wig = new(get_turf(quirk_holder)) - if(old_hair == "Bald") - baldie_wig.hairstyle = pick(GLOB.hairstyles_list - "Bald") - else - baldie_wig.hairstyle = old_hair - - baldie_wig.update_appearance() - - give_item_to_holder(baldie_wig, list(LOCATION_HEAD = ITEM_SLOT_HEAD, LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) - -/datum/quirk/item_quirk/bald/remove() - . = ..() - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.hairstyle = old_hair - human_holder.update_body_parts() - UnregisterSignal(human_holder, list(COMSIG_CARBON_EQUIP_HAT, COMSIG_CARBON_UNEQUIP_HAT)) - human_holder.clear_mood_event("bad_hair_day") - -///Checks if the headgear equipped is a wig and sets the mood event accordingly -/datum/quirk/item_quirk/bald/proc/equip_hat(mob/user, obj/item/hat) - SIGNAL_HANDLER - - if(istype(hat, /obj/item/clothing/head/wig)) - quirk_holder.add_mood_event("bad_hair_day", /datum/mood_event/confident_mane) //Our head is covered, but also by a wig so we're happy. - else - quirk_holder.clear_mood_event("bad_hair_day") //Our head is covered - -///Applies a bad moodlet for having an uncovered head -/datum/quirk/item_quirk/bald/proc/unequip_hat(mob/user, obj/item/clothing, force, newloc, no_move, invdrop, silent) - SIGNAL_HANDLER - - quirk_holder.add_mood_event("bad_hair_day", /datum/mood_event/bald) - -/datum/quirk/item_quirk/photographer - name = "Photographer" - desc = "You carry your camera and personal photo album everywhere you go, and your scrapbooks are legendary among your coworkers." - icon = FA_ICON_CAMERA - value = 0 - mob_trait = TRAIT_PHOTOGRAPHER - gain_text = span_notice("You know everything about photography.") - lose_text = span_danger("You forget how photo cameras work.") - medical_record_text = "Patient mentions photography as a stress-relieving hobby." - mail_goodies = list(/obj/item/camera_film) - -/datum/quirk/item_quirk/photographer/add_unique(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - var/obj/item/storage/photo_album/personal/photo_album = new(get_turf(human_holder)) - photo_album.persistence_id = "personal_[human_holder.last_mind?.key]" // this is a persistent album, the ID is tied to the account's key to avoid tampering - photo_album.persistence_load() - photo_album.name = "[human_holder.real_name]'s photo album" - - give_item_to_holder(photo_album, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) - give_item_to_holder( - /obj/item/camera, - list( - LOCATION_NECK = ITEM_SLOT_NECK, - LOCATION_LPOCKET = ITEM_SLOT_LPOCKET, - LOCATION_RPOCKET = ITEM_SLOT_RPOCKET, - LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, - LOCATION_HANDS = ITEM_SLOT_HANDS - ) - ) - -/* SKYRAT EDIT REMOVAL -/datum/quirk/item_quirk/colorist - name = "Colorist" - desc = "You like carrying around a hair dye spray to quickly apply color patterns to your hair." - icon = FA_ICON_FILL_DRIP - value = 0 - medical_record_text = "Patient enjoys dyeing their hair with pretty colors." - mail_goodies = list(/obj/item/dyespray) - -/datum/quirk/item_quirk/colorist/add_unique(client/client_source) - give_item_to_holder(/obj/item/dyespray, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) -*/ - -#define GAMING_WITHDRAWAL_TIME (15 MINUTES) -/datum/quirk/gamer - name = "Gamer" - desc = "You are a hardcore gamer, and you have a need to game. You love winning and hate losing. You only like gamer food." - icon = FA_ICON_GAMEPAD - value = 0 - gain_text = span_notice("You feel the sudden urge to game.") - lose_text = span_notice("You've lost all interest in gaming.") - medical_record_text = "Patient has a severe video game addiction." - mob_trait = TRAIT_GAMER - mail_goodies = list(/obj/item/toy/intento, /obj/item/clothing/head/fedora) - /// Timer for gaming withdrawal to kick in - var/gaming_withdrawal_timer = TIMER_ID_NULL - -/datum/quirk/gamer/add(client/client_source) - var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) - if(tongue) - // Gamer diet - tongue.liked_foodtypes = JUNKFOOD - RegisterSignal(quirk_holder, COMSIG_MOB_WON_VIDEOGAME, PROC_REF(won_game)) - RegisterSignal(quirk_holder, COMSIG_MOB_LOST_VIDEOGAME, PROC_REF(lost_game)) - RegisterSignal(quirk_holder, COMSIG_MOB_PLAYED_VIDEOGAME, PROC_REF(gamed)) - -/datum/quirk/gamer/add_unique(client/client_source) - // The gamer starts off quelled - gaming_withdrawal_timer = addtimer(CALLBACK(src, PROC_REF(enter_withdrawal)), GAMING_WITHDRAWAL_TIME, TIMER_STOPPABLE) - -/datum/quirk/gamer/remove() - var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) - if(tongue) - tongue.liked_foodtypes = initial(tongue.liked_foodtypes) - UnregisterSignal(quirk_holder, COMSIG_MOB_WON_VIDEOGAME) - UnregisterSignal(quirk_holder, COMSIG_MOB_LOST_VIDEOGAME) - UnregisterSignal(quirk_holder, COMSIG_MOB_PLAYED_VIDEOGAME) - -/** - * Gamer won a game - * - * Executed on the COMSIG_MOB_WON_VIDEOGAME signal - * This signal should be called whenever a player has won a video game. - * (E.g. Orion Trail) - */ -/datum/quirk/gamer/proc/won_game() - SIGNAL_HANDLER - // Epic gamer victory - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.add_mood_event("gamer_won", /datum/mood_event/gamer_won) - -/** - * Gamer lost a game - * - * Executed on the COMSIG_MOB_LOST_VIDEOGAME signal - * This signal should be called whenever a player has lost a video game. - * (E.g. Orion Trail) - */ -/datum/quirk/gamer/proc/lost_game() - SIGNAL_HANDLER - // Executed when a gamer has lost - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.add_mood_event("gamer_lost", /datum/mood_event/gamer_lost) - // Executed asynchronously due to say() - INVOKE_ASYNC(src, PROC_REF(gamer_moment)) -/** - * Gamer is playing a game - * - * Executed on the COMSIG_MOB_PLAYED_VIDEOGAME signal - * This signal should be called whenever a player interacts with a video game. - */ -/datum/quirk/gamer/proc/gamed() - SIGNAL_HANDLER - - var/mob/living/carbon/human/human_holder = quirk_holder - // Remove withdrawal malus - human_holder.clear_mood_event("gamer_withdrawal") - // Reset withdrawal timer - if (gaming_withdrawal_timer) - deltimer(gaming_withdrawal_timer) - gaming_withdrawal_timer = addtimer(CALLBACK(src, PROC_REF(enter_withdrawal)), GAMING_WITHDRAWAL_TIME, TIMER_STOPPABLE) - - -/datum/quirk/gamer/proc/gamer_moment() - // It was a heated gamer moment... - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.say(";[pick("SHIT", "PISS", "FUCK", "CUNT", "COCKSUCKER", "MOTHERFUCKER")]!!", forced = name) - -/datum/quirk/gamer/proc/enter_withdrawal() - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.add_mood_event("gamer_withdrawal", /datum/mood_event/gamer_withdrawal) - -#undef GAMING_WITHDRAWAL_TIME - - -/datum/quirk/item_quirk/pride_pin - name = "Pride Pin" - desc = "Show off your pride with this changing pride pin!" - icon = FA_ICON_RAINBOW - value = 0 - gain_text = span_notice("You feel fruity.") - lose_text = span_danger("You feel only slightly less fruity than before.") - medical_record_text = "Patient appears to be fruity." - -/datum/quirk/item_quirk/pride_pin/add_unique(client/client_source) - var/obj/item/clothing/accessory/pride/pin = new(get_turf(quirk_holder)) - - var/pride_choice = client_source?.prefs?.read_preference(/datum/preference/choiced/pride_pin) || assoc_to_keys(GLOB.pride_pin_reskins)[1] - var/pride_reskin = GLOB.pride_pin_reskins[pride_choice] - - pin.current_skin = pride_choice - pin.icon_state = pride_reskin - - give_item_to_holder(pin, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) diff --git a/code/datums/quirks/neutral_quirks/no_taste.dm b/code/datums/quirks/neutral_quirks/no_taste.dm new file mode 100644 index 00000000000000..664aaf1d9de236 --- /dev/null +++ b/code/datums/quirks/neutral_quirks/no_taste.dm @@ -0,0 +1,10 @@ +/datum/quirk/no_taste + name = "Ageusia" + desc = "You can't taste anything! Toxic food will still poison you." + icon = FA_ICON_MEH_BLANK + value = 0 + mob_trait = TRAIT_AGEUSIA + gain_text = span_notice("You can't taste anything!") + lose_text = span_notice("You can taste again!") + medical_record_text = "Patient suffers from ageusia and is incapable of tasting food or reagents." + mail_goodies = list(/obj/effect/spawner/random/food_or_drink/condiment) // but can you taste the salt? CAN YOU?! diff --git a/code/datums/quirks/neutral_quirks/phobia.dm b/code/datums/quirks/neutral_quirks/phobia.dm new file mode 100644 index 00000000000000..224401f0670c5c --- /dev/null +++ b/code/datums/quirks/neutral_quirks/phobia.dm @@ -0,0 +1,20 @@ +/datum/quirk/phobia + name = "Phobia" + desc = "You are irrationally afraid of something." + icon = FA_ICON_SPIDER + value = 0 + medical_record_text = "Patient has an irrational fear of something." + mail_goodies = list(/obj/item/clothing/glasses/blindfold, /obj/item/storage/pill_bottle/psicodine) + +// Phobia will follow you between transfers +/datum/quirk/phobia/add(client/client_source) + var/phobia = client_source?.prefs.read_preference(/datum/preference/choiced/phobia) + if(!phobia) + return + + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.gain_trauma(new /datum/brain_trauma/mild/phobia(phobia), TRAUMA_RESILIENCE_ABSOLUTE) + +/datum/quirk/phobia/remove() + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.cure_trauma_type(/datum/brain_trauma/mild/phobia, TRAUMA_RESILIENCE_ABSOLUTE) diff --git a/code/datums/quirks/neutral_quirks/photographer.dm b/code/datums/quirks/neutral_quirks/photographer.dm new file mode 100644 index 00000000000000..d2284df240ca72 --- /dev/null +++ b/code/datums/quirks/neutral_quirks/photographer.dm @@ -0,0 +1,29 @@ +/datum/quirk/item_quirk/photographer + name = "Photographer" + desc = "You carry your camera and personal photo album everywhere you go, and your scrapbooks are legendary among your coworkers." + icon = FA_ICON_CAMERA + value = 0 + mob_trait = TRAIT_PHOTOGRAPHER + gain_text = span_notice("You know everything about photography.") + lose_text = span_danger("You forget how photo cameras work.") + medical_record_text = "Patient mentions photography as a stress-relieving hobby." + mail_goodies = list(/obj/item/camera_film) + +/datum/quirk/item_quirk/photographer/add_unique(client/client_source) + var/mob/living/carbon/human/human_holder = quirk_holder + var/obj/item/storage/photo_album/personal/photo_album = new(get_turf(human_holder)) + photo_album.persistence_id = "personal_[human_holder.last_mind?.key]" // this is a persistent album, the ID is tied to the account's key to avoid tampering + photo_album.persistence_load() + photo_album.name = "[human_holder.real_name]'s photo album" + + give_item_to_holder(photo_album, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) + give_item_to_holder( + /obj/item/camera, + list( + LOCATION_NECK = ITEM_SLOT_NECK, + LOCATION_LPOCKET = ITEM_SLOT_LPOCKET, + LOCATION_RPOCKET = ITEM_SLOT_RPOCKET, + LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, + LOCATION_HANDS = ITEM_SLOT_HANDS + ) + ) diff --git a/code/datums/quirks/neutral_quirks/pineapple_hater.dm b/code/datums/quirks/neutral_quirks/pineapple_hater.dm new file mode 100644 index 00000000000000..f17eb4224ec4c5 --- /dev/null +++ b/code/datums/quirks/neutral_quirks/pineapple_hater.dm @@ -0,0 +1,27 @@ +/datum/quirk/pineapple_hater + name = "Ananas Aversion" + desc = "You find yourself greatly detesting fruits of the ananas genus. Serious, how the hell can anyone say these things are good? And what kind of madman would even dare putting it on a pizza!?" + icon = FA_ICON_THUMBS_DOWN + value = 0 + gain_text = span_notice("You find yourself pondering what kind of idiot actually enjoys pineapples...") + lose_text = span_notice("Your feelings towards pineapples seem to return to a lukewarm state.") + medical_record_text = "Patient is correct to think that pineapple is disgusting." + mail_goodies = list( // basic pizza slices + /obj/item/food/pizzaslice/margherita, + /obj/item/food/pizzaslice/meat, + /obj/item/food/pizzaslice/mushroom, + /obj/item/food/pizzaslice/vegetable, + /obj/item/food/pizzaslice/sassysage, + ) + +/datum/quirk/pineapple_hater/add(client/client_source) + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + tongue.disliked_foodtypes |= PINEAPPLE + +/datum/quirk/pineapple_hater/remove() + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + tongue.disliked_foodtypes = initial(tongue.disliked_foodtypes) diff --git a/code/datums/quirks/neutral_quirks/pineapple_liker.dm b/code/datums/quirks/neutral_quirks/pineapple_liker.dm new file mode 100644 index 00000000000000..c342e14769cf83 --- /dev/null +++ b/code/datums/quirks/neutral_quirks/pineapple_liker.dm @@ -0,0 +1,21 @@ +/datum/quirk/pineapple_liker + name = "Ananas Affinity" + desc = "You find yourself greatly enjoying fruits of the ananas genus. You can't seem to ever get enough of their sweet goodness!" + icon = FA_ICON_THUMBS_UP + value = 0 + gain_text = span_notice("You feel an intense craving for pineapple.") + lose_text = span_notice("Your feelings towards pineapples seem to return to a lukewarm state.") + medical_record_text = "Patient demonstrates a pathological love of pineapple." + mail_goodies = list(/obj/item/food/pizzaslice/pineapple) + +/datum/quirk/pineapple_liker/add(client/client_source) + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + tongue.liked_foodtypes |= PINEAPPLE + +/datum/quirk/pineapple_liker/remove() + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + tongue.liked_foodtypes = initial(tongue.liked_foodtypes) diff --git a/code/datums/quirks/neutral_quirks/pride_pin.dm b/code/datums/quirks/neutral_quirks/pride_pin.dm new file mode 100644 index 00000000000000..488c0a2bccb58b --- /dev/null +++ b/code/datums/quirks/neutral_quirks/pride_pin.dm @@ -0,0 +1,19 @@ +/datum/quirk/item_quirk/pride_pin + name = "Pride Pin" + desc = "Show off your pride with this changing pride pin!" + icon = FA_ICON_RAINBOW + value = 0 + gain_text = span_notice("You feel fruity.") + lose_text = span_danger("You feel only slightly less fruity than before.") + medical_record_text = "Patient appears to be fruity." + +/datum/quirk/item_quirk/pride_pin/add_unique(client/client_source) + var/obj/item/clothing/accessory/pride/pin = new(get_turf(quirk_holder)) + + var/pride_choice = client_source?.prefs?.read_preference(/datum/preference/choiced/pride_pin) || assoc_to_keys(GLOB.pride_pin_reskins)[1] + var/pride_reskin = GLOB.pride_pin_reskins[pride_choice] + + pin.current_skin = pride_choice + pin.icon_state = pride_reskin + + give_item_to_holder(pin, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) diff --git a/code/datums/quirks/neutral_quirks/shifty_eyes.dm b/code/datums/quirks/neutral_quirks/shifty_eyes.dm new file mode 100644 index 00000000000000..29f1def3761505 --- /dev/null +++ b/code/datums/quirks/neutral_quirks/shifty_eyes.dm @@ -0,0 +1,8 @@ +/datum/quirk/shifty_eyes + name = "Shifty Eyes" + desc = "Your eyes tend to wander all over the place, whether you mean to or not, causing people to sometimes think you're looking directly at them when you aren't." + icon = FA_ICON_EYE + value = 0 + medical_record_text = "Fucking creep kept staring at me the whole damn checkup. I'm only diagnosing this because it's less awkward than thinking it was on purpose." + mob_trait = TRAIT_SHIFTY_EYES + mail_goodies = list(/obj/item/clothing/head/costume/papersack, /obj/item/clothing/head/costume/papersack/smiley) diff --git a/code/datums/quirks/neutral_quirks/snob.dm b/code/datums/quirks/neutral_quirks/snob.dm new file mode 100644 index 00000000000000..ab273f1ae530ef --- /dev/null +++ b/code/datums/quirks/neutral_quirks/snob.dm @@ -0,0 +1,10 @@ +/datum/quirk/snob + name = "Snob" + desc = "You care about the finer things, if a room doesn't look nice its just not really worth it, is it?" + icon = FA_ICON_USER_TIE + value = 0 + gain_text = span_notice("You feel like you understand what things should look like.") + lose_text = span_notice("Well who cares about deco anyways?") + medical_record_text = "Patient seems to be rather stuck up." + mob_trait = TRAIT_SNOB + mail_goodies = list(/obj/item/chisel, /obj/item/paint_palette) diff --git a/code/datums/quirks/neutral_quirks/vegetarian.dm b/code/datums/quirks/neutral_quirks/vegetarian.dm new file mode 100644 index 00000000000000..0ade72acafe571 --- /dev/null +++ b/code/datums/quirks/neutral_quirks/vegetarian.dm @@ -0,0 +1,23 @@ +/datum/quirk/vegetarian + name = "Vegetarian" + desc = "You find the idea of eating meat morally and physically repulsive." + icon = FA_ICON_CARROT + value = 0 + gain_text = span_notice("You feel repulsion at the idea of eating meat.") + lose_text = span_notice("You feel like eating meat isn't that bad.") + medical_record_text = "Patient reports a vegetarian diet." + mail_goodies = list(/obj/effect/spawner/random/food_or_drink/salad) + +/datum/quirk/vegetarian/add(client/client_source) + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + tongue.liked_foodtypes &= ~MEAT + tongue.disliked_foodtypes |= MEAT + +/datum/quirk/vegetarian/remove() + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + tongue.liked_foodtypes = initial(tongue.liked_foodtypes) + tongue.disliked_foodtypes = initial(tongue.disliked_foodtypes) diff --git a/code/datums/quirks/positive_quirks/alcohol_tolerance.dm b/code/datums/quirks/positive_quirks/alcohol_tolerance.dm new file mode 100644 index 00000000000000..6458513007df2b --- /dev/null +++ b/code/datums/quirks/positive_quirks/alcohol_tolerance.dm @@ -0,0 +1,10 @@ +/datum/quirk/alcohol_tolerance + name = "Alcohol Tolerance" + desc = "You become drunk more slowly and suffer fewer drawbacks from alcohol." + icon = FA_ICON_BEER + value = 4 + mob_trait = TRAIT_ALCOHOL_TOLERANCE + gain_text = span_notice("You feel like you could drink a whole keg!") + lose_text = span_danger("You don't feel as resistant to alcohol anymore. Somehow.") + medical_record_text = "Patient demonstrates a high tolerance for alcohol." + mail_goodies = list(/obj/item/skillchip/wine_taster) diff --git a/code/datums/quirks/positive_quirks/apathetic.dm b/code/datums/quirks/positive_quirks/apathetic.dm new file mode 100644 index 00000000000000..170cb6f5d448e1 --- /dev/null +++ b/code/datums/quirks/positive_quirks/apathetic.dm @@ -0,0 +1,14 @@ +/datum/quirk/apathetic + name = "Apathetic" + desc = "You just don't care as much as other people. That's nice to have in a place like this, I guess." + icon = FA_ICON_MEH + value = 4 + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED + medical_record_text = "Patient was administered the Apathy Evaluation Scale but did not bother to complete it." + mail_goodies = list(/obj/item/hourglass) + +/datum/quirk/apathetic/add(client/client_source) + quirk_holder.mob_mood?.mood_modifier -= 0.2 + +/datum/quirk/apathetic/remove() + quirk_holder.mob_mood?.mood_modifier += 0.2 diff --git a/code/datums/quirks/positive_quirks/bilingual.dm b/code/datums/quirks/positive_quirks/bilingual.dm new file mode 100644 index 00000000000000..324054198b8d66 --- /dev/null +++ b/code/datums/quirks/positive_quirks/bilingual.dm @@ -0,0 +1,24 @@ +/datum/quirk/bilingual + name = "Bilingual" + desc = "Over the years you've picked up an extra language!" + icon = FA_ICON_GLOBE + value = 4 + gain_text = span_notice("Some of the words of the people around you certainly aren't common. Good thing you studied for this.") + lose_text = span_notice("You seem to have forgotten your second language.") + medical_record_text = "Patient speaks multiple languages." + mail_goodies = list(/obj/item/taperecorder, /obj/item/clothing/head/frenchberet, /obj/item/clothing/mask/fakemoustache/italian) + +/datum/quirk/bilingual/add_unique(client/client_source) + var/wanted_language = client_source?.prefs.read_preference(/datum/preference/choiced/language) + var/datum/language/language_type + if(wanted_language == "Random") + language_type = pick(GLOB.uncommon_roundstart_languages) + else + language_type = GLOB.language_types_by_name[wanted_language] + if(quirk_holder.has_language(language_type)) + language_type = /datum/language/uncommon + if(quirk_holder.has_language(language_type)) + to_chat(quirk_holder, span_boldnotice("You are already familiar with the quirk in your preferences, so you did not learn one.")) + return + to_chat(quirk_holder, span_boldnotice("You are already familiar with the quirk in your preferences, so you learned Galactic Uncommon instead.")) + quirk_holder.grant_language(language_type, source = LANGUAGE_QUIRK) diff --git a/code/datums/quirks/positive_quirks/clown_enjoyer.dm b/code/datums/quirks/positive_quirks/clown_enjoyer.dm new file mode 100644 index 00000000000000..984b0f7a6e4768 --- /dev/null +++ b/code/datums/quirks/positive_quirks/clown_enjoyer.dm @@ -0,0 +1,31 @@ +/datum/quirk/item_quirk/clown_enjoyer + name = "Clown Enjoyer" + desc = "You enjoy clown antics and get a mood boost from wearing your clown pin." + icon = FA_ICON_MAP_PIN + value = 2 + mob_trait = TRAIT_CLOWN_ENJOYER + gain_text = span_notice("You are a big enjoyer of clowns.") + lose_text = span_danger("The clown doesn't seem so great.") + medical_record_text = "Patient reports being a big enjoyer of clowns." + mail_goodies = list( + /obj/item/bikehorn, + /obj/item/stamp/clown, + /obj/item/megaphone/clown, + /obj/item/clothing/shoes/clown_shoes, + /obj/item/bedsheet/clown, + /obj/item/clothing/mask/gas/clown_hat, + /obj/item/storage/backpack/clown, + /obj/item/storage/backpack/duffelbag/clown, + /obj/item/toy/crayon/rainbow, + /obj/item/toy/figure/clown, + /obj/item/tank/internals/emergency_oxygen/engi/clown/n2o, + /obj/item/tank/internals/emergency_oxygen/engi/clown/bz, + /obj/item/tank/internals/emergency_oxygen/engi/clown/helium, + ) + +/datum/quirk/item_quirk/clown_enjoyer/add_unique(client/client_source) + give_item_to_holder(/obj/item/clothing/accessory/clown_enjoyer_pin, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) + +/datum/quirk/item_quirk/clown_enjoyer/add(client/client_source) + var/datum/atom_hud/fan = GLOB.huds[DATA_HUD_FAN] + fan.show_to(quirk_holder) diff --git a/code/datums/quirks/positive_quirks/drunk_healing.dm b/code/datums/quirks/positive_quirks/drunk_healing.dm new file mode 100644 index 00000000000000..fbab2503b4e9c4 --- /dev/null +++ b/code/datums/quirks/positive_quirks/drunk_healing.dm @@ -0,0 +1,22 @@ +/datum/quirk/drunkhealing + name = "Drunken Resilience" + desc = "Nothing like a good drink to make you feel on top of the world. Whenever you're drunk, you slowly recover from injuries." + icon = FA_ICON_WINE_BOTTLE + value = 8 + gain_text = span_notice("You feel like a drink would do you good.") + lose_text = span_danger("You no longer feel like drinking would ease your pain.") + medical_record_text = "Patient has unusually efficient liver metabolism and can slowly regenerate wounds by drinking alcoholic beverages." + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES + mail_goodies = list(/obj/effect/spawner/random/food_or_drink/booze) + +/datum/quirk/drunkhealing/process(seconds_per_tick) + switch(quirk_holder.get_drunk_amount()) + if (6 to 40) + quirk_holder.adjustBruteLoss(-0.1 * seconds_per_tick, FALSE, required_bodytype = BODYTYPE_ORGANIC) + quirk_holder.adjustFireLoss(-0.05 * seconds_per_tick, required_bodytype = BODYTYPE_ORGANIC) + if (41 to 60) + quirk_holder.adjustBruteLoss(-0.4 * seconds_per_tick, FALSE, required_bodytype = BODYTYPE_ORGANIC) + quirk_holder.adjustFireLoss(-0.2 * seconds_per_tick, required_bodytype = BODYTYPE_ORGANIC) + if (61 to INFINITY) + quirk_holder.adjustBruteLoss(-0.8 * seconds_per_tick, FALSE, required_bodytype = BODYTYPE_ORGANIC) + quirk_holder.adjustFireLoss(-0.4 * seconds_per_tick, required_bodytype = BODYTYPE_ORGANIC) diff --git a/code/datums/quirks/positive_quirks/empath.dm b/code/datums/quirks/positive_quirks/empath.dm new file mode 100644 index 00000000000000..3379f8a97c458e --- /dev/null +++ b/code/datums/quirks/positive_quirks/empath.dm @@ -0,0 +1,10 @@ +/datum/quirk/empath + name = "Empath" + desc = "Whether it's a sixth sense or careful study of body language, it only takes you a quick glance at someone to understand how they feel." + icon = FA_ICON_SMILE_BEAM + value = 6 // SKYRAT EDIT CHANGE - Quirk Rebalance - Original: value = 8 + mob_trait = TRAIT_EMPATH + gain_text = span_notice("You feel in tune with those around you.") + lose_text = span_danger("You feel isolated from others.") + medical_record_text = "Patient is highly perceptive of and sensitive to social cues, or may possibly have ESP. Further testing needed." + mail_goodies = list(/obj/item/toy/foamfinger) diff --git a/code/datums/quirks/positive_quirks/freerunning.dm b/code/datums/quirks/positive_quirks/freerunning.dm new file mode 100644 index 00000000000000..541d2b1cc441af --- /dev/null +++ b/code/datums/quirks/positive_quirks/freerunning.dm @@ -0,0 +1,10 @@ +/datum/quirk/freerunning + name = "Freerunning" + desc = "You're great at quick moves! You can climb tables more quickly and take no damage from short falls." + icon = FA_ICON_RUNNING + value = 8 + mob_trait = TRAIT_FREERUNNING + gain_text = span_notice("You feel lithe on your feet!") + lose_text = span_danger("You feel clumsy again.") + medical_record_text = "Patient scored highly on cardio tests." + mail_goodies = list(/obj/item/melee/skateboard, /obj/item/clothing/shoes/wheelys/rollerskates) diff --git a/code/datums/quirks/positive_quirks/friendly.dm b/code/datums/quirks/positive_quirks/friendly.dm new file mode 100644 index 00000000000000..8ab0003639bc39 --- /dev/null +++ b/code/datums/quirks/positive_quirks/friendly.dm @@ -0,0 +1,11 @@ +/datum/quirk/friendly + name = "Friendly" + desc = "You give the best hugs, especially when you're in the right mood." + icon = FA_ICON_HANDS_HELPING + value = 2 + mob_trait = TRAIT_FRIENDLY + gain_text = span_notice("You want to hug someone.") + lose_text = span_danger("You no longer feel compelled to hug others.") + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED + medical_record_text = "Patient demonstrates low-inhibitions for physical contact and well-developed arms. Requesting another doctor take over this case." + mail_goodies = list(/obj/item/storage/box/hug) diff --git a/code/datums/quirks/positive_quirks/jolly.dm b/code/datums/quirks/positive_quirks/jolly.dm new file mode 100644 index 00000000000000..7f6c334ba9dd7e --- /dev/null +++ b/code/datums/quirks/positive_quirks/jolly.dm @@ -0,0 +1,9 @@ +/datum/quirk/jolly + name = "Jolly" + desc = "You sometimes just feel happy, for no reason at all." + icon = FA_ICON_GRIN + value = 4 + mob_trait = TRAIT_JOLLY + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED + medical_record_text = "Patient demonstrates constant euthymia irregular for environment. It's a bit much, to be honest." + mail_goodies = list(/obj/item/clothing/mask/joy) diff --git a/code/datums/quirks/positive_quirks/light_step.dm b/code/datums/quirks/positive_quirks/light_step.dm new file mode 100644 index 00000000000000..80418b79b9da09 --- /dev/null +++ b/code/datums/quirks/positive_quirks/light_step.dm @@ -0,0 +1,10 @@ +/datum/quirk/light_step + name = "Light Step" + desc = "You walk with a gentle step; footsteps and stepping on sharp objects is quieter and less painful. Also, your hands and clothes will not get messed in case of stepping in blood." + icon = FA_ICON_SHOE_PRINTS + value = 4 + mob_trait = TRAIT_LIGHT_STEP + gain_text = span_notice("You walk with a little more litheness.") + lose_text = span_danger("You start tromping around like a barbarian.") + medical_record_text = "Patient's dexterity belies a strong capacity for stealth." + mail_goodies = list(/obj/item/clothing/shoes/sandal) diff --git a/code/datums/quirks/positive_quirks/mime_fan.dm b/code/datums/quirks/positive_quirks/mime_fan.dm new file mode 100644 index 00000000000000..5145b4a2240e62 --- /dev/null +++ b/code/datums/quirks/positive_quirks/mime_fan.dm @@ -0,0 +1,29 @@ +/datum/quirk/item_quirk/mime_fan + name = "Mime Fan" + desc = "You're a fan of mime antics and get a mood boost from wearing your mime pin." + icon = FA_ICON_THUMBTACK + value = 2 + mob_trait = TRAIT_MIME_FAN + gain_text = span_notice("You are a big fan of the Mime.") + lose_text = span_danger("The mime doesn't seem so great.") + medical_record_text = "Patient reports being a big fan of mimes." + mail_goodies = list( + /obj/item/toy/crayon/mime, + /obj/item/clothing/mask/gas/mime, + /obj/item/storage/backpack/mime, + /obj/item/clothing/under/rank/civilian/mime, + /obj/item/reagent_containers/cup/glass/bottle/bottleofnothing, + /obj/item/stamp/mime, + /obj/item/storage/box/survival/hug/black, + /obj/item/bedsheet/mime, + /obj/item/clothing/shoes/sneakers/mime, + /obj/item/toy/figure/mime, + /obj/item/toy/crayon/spraycan/mimecan, + ) + +/datum/quirk/item_quirk/mime_fan/add_unique(client/client_source) + give_item_to_holder(/obj/item/clothing/accessory/mime_fan_pin, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) + +/datum/quirk/item_quirk/mime_fan/add(client/client_source) + var/datum/atom_hud/fan = GLOB.huds[DATA_HUD_FAN] + fan.show_to(quirk_holder) diff --git a/code/datums/quirks/positive_quirks/musician.dm b/code/datums/quirks/positive_quirks/musician.dm new file mode 100644 index 00000000000000..9d5e10f5f827ef --- /dev/null +++ b/code/datums/quirks/positive_quirks/musician.dm @@ -0,0 +1,13 @@ +/datum/quirk/item_quirk/musician + name = "Musician" + desc = "You can tune handheld musical instruments to play melodies that clear certain negative effects and soothe the soul." + icon = FA_ICON_GUITAR + value = 2 + mob_trait = TRAIT_MUSICIAN + gain_text = span_notice("You know everything about musical instruments.") + lose_text = span_danger("You forget how musical instruments work.") + medical_record_text = "Patient brain scans show a highly-developed auditory pathway." + mail_goodies = list(/obj/effect/spawner/random/entertainment/musical_instrument, /obj/item/instrument/piano_synth/headphones) + +/datum/quirk/item_quirk/musician/add_unique(client/client_source) + give_item_to_holder(/obj/item/choice_beacon/music, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) diff --git a/code/datums/quirks/positive_quirks/night_vision.dm b/code/datums/quirks/positive_quirks/night_vision.dm new file mode 100644 index 00000000000000..808a213db514b1 --- /dev/null +++ b/code/datums/quirks/positive_quirks/night_vision.dm @@ -0,0 +1,28 @@ +/datum/quirk/night_vision + name = "Night Vision" + desc = "You can see slightly more clearly in full darkness than most people." + icon = FA_ICON_MOON + value = 4 + mob_trait = TRAIT_NIGHT_VISION + gain_text = span_notice("The shadows seem a little less dark.") + lose_text = span_danger("Everything seems a little darker.") + medical_record_text = "Patient's eyes show above-average acclimation to darkness." + mail_goodies = list( + /obj/item/flashlight/flashdark, + /obj/item/food/grown/mushroom/glowshroom/shadowshroom, + /obj/item/skillchip/light_remover, + ) + +/datum/quirk/night_vision/add(client/client_source) + refresh_quirk_holder_eyes() + +/datum/quirk/night_vision/remove() + refresh_quirk_holder_eyes() + +/datum/quirk/night_vision/proc/refresh_quirk_holder_eyes() + var/mob/living/carbon/human/human_quirk_holder = quirk_holder + var/obj/item/organ/internal/eyes/eyes = human_quirk_holder.get_organ_by_type(/obj/item/organ/internal/eyes) + if(!eyes || eyes.lighting_cutoff) + return + // We've either added or removed TRAIT_NIGHT_VISION before calling this proc. Just refresh the eyes. + eyes.refresh() diff --git a/code/datums/quirks/positive_quirks/positive_quirks.dm b/code/datums/quirks/positive_quirks/positive_quirks.dm deleted file mode 100644 index 23cfc9f2a44346..00000000000000 --- a/code/datums/quirks/positive_quirks/positive_quirks.dm +++ /dev/null @@ -1,400 +0,0 @@ -//predominantly positive traits -//this file is named weirdly so that positive traits are listed above negative ones - -/datum/quirk/alcohol_tolerance - name = "Alcohol Tolerance" - desc = "You become drunk more slowly and suffer fewer drawbacks from alcohol." - icon = FA_ICON_BEER - value = 4 - mob_trait = TRAIT_ALCOHOL_TOLERANCE - gain_text = span_notice("You feel like you could drink a whole keg!") - lose_text = span_danger("You don't feel as resistant to alcohol anymore. Somehow.") - medical_record_text = "Patient demonstrates a high tolerance for alcohol." - mail_goodies = list(/obj/item/skillchip/wine_taster) - -/datum/quirk/apathetic - name = "Apathetic" - desc = "You just don't care as much as other people. That's nice to have in a place like this, I guess." - icon = FA_ICON_MEH - value = 4 - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED - medical_record_text = "Patient was administered the Apathy Evaluation Scale but did not bother to complete it." - mail_goodies = list(/obj/item/hourglass) - -/datum/quirk/apathetic/add(client/client_source) - quirk_holder.mob_mood?.mood_modifier -= 0.2 - -/datum/quirk/apathetic/remove() - quirk_holder.mob_mood?.mood_modifier += 0.2 - -/datum/quirk/drunkhealing - name = "Drunken Resilience" - desc = "Nothing like a good drink to make you feel on top of the world. Whenever you're drunk, you slowly recover from injuries." - icon = FA_ICON_WINE_BOTTLE - value = 8 - gain_text = span_notice("You feel like a drink would do you good.") - lose_text = span_danger("You no longer feel like drinking would ease your pain.") - medical_record_text = "Patient has unusually efficient liver metabolism and can slowly regenerate wounds by drinking alcoholic beverages." - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES - mail_goodies = list(/obj/effect/spawner/random/food_or_drink/booze) - -/datum/quirk/drunkhealing/process(seconds_per_tick) - switch(quirk_holder.get_drunk_amount()) - if (6 to 40) - quirk_holder.adjustBruteLoss(-0.1 * seconds_per_tick, FALSE, required_bodytype = BODYTYPE_ORGANIC) - quirk_holder.adjustFireLoss(-0.05 * seconds_per_tick, required_bodytype = BODYTYPE_ORGANIC) - if (41 to 60) - quirk_holder.adjustBruteLoss(-0.4 * seconds_per_tick, FALSE, required_bodytype = BODYTYPE_ORGANIC) - quirk_holder.adjustFireLoss(-0.2 * seconds_per_tick, required_bodytype = BODYTYPE_ORGANIC) - if (61 to INFINITY) - quirk_holder.adjustBruteLoss(-0.8 * seconds_per_tick, FALSE, required_bodytype = BODYTYPE_ORGANIC) - quirk_holder.adjustFireLoss(-0.4 * seconds_per_tick, required_bodytype = BODYTYPE_ORGANIC) - -/datum/quirk/empath - name = "Empath" - desc = "Whether it's a sixth sense or careful study of body language, it only takes you a quick glance at someone to understand how they feel." - icon = FA_ICON_SMILE_BEAM - value = 6 /// SKYRAT EDIT - Quirk Rebalance - Original: value = 8 - mob_trait = TRAIT_EMPATH - gain_text = span_notice("You feel in tune with those around you.") - lose_text = span_danger("You feel isolated from others.") - medical_record_text = "Patient is highly perceptive of and sensitive to social cues, or may possibly have ESP. Further testing needed." - mail_goodies = list(/obj/item/toy/foamfinger) - -/datum/quirk/item_quirk/clown_enjoyer - name = "Clown Enjoyer" - desc = "You enjoy clown antics and get a mood boost from wearing your clown pin." - icon = FA_ICON_MAP_PIN - value = 2 - mob_trait = TRAIT_CLOWN_ENJOYER - gain_text = span_notice("You are a big enjoyer of clowns.") - lose_text = span_danger("The clown doesn't seem so great.") - medical_record_text = "Patient reports being a big enjoyer of clowns." - mail_goodies = list( - /obj/item/bikehorn, - /obj/item/stamp/clown, - /obj/item/megaphone/clown, - /obj/item/clothing/shoes/clown_shoes, - /obj/item/bedsheet/clown, - /obj/item/clothing/mask/gas/clown_hat, - /obj/item/storage/backpack/clown, - /obj/item/storage/backpack/duffelbag/clown, - /obj/item/toy/crayon/rainbow, - /obj/item/toy/figure/clown, - /obj/item/tank/internals/emergency_oxygen/engi/clown/n2o, - /obj/item/tank/internals/emergency_oxygen/engi/clown/bz, - /obj/item/tank/internals/emergency_oxygen/engi/clown/helium, - ) - -/datum/quirk/item_quirk/clown_enjoyer/add_unique(client/client_source) - give_item_to_holder(/obj/item/clothing/accessory/clown_enjoyer_pin, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) - -/datum/quirk/item_quirk/clown_enjoyer/add(client/client_source) - var/datum/atom_hud/fan = GLOB.huds[DATA_HUD_FAN] - fan.show_to(quirk_holder) - -/datum/quirk/item_quirk/mime_fan - name = "Mime Fan" - desc = "You're a fan of mime antics and get a mood boost from wearing your mime pin." - icon = FA_ICON_THUMBTACK - value = 2 - mob_trait = TRAIT_MIME_FAN - gain_text = span_notice("You are a big fan of the Mime.") - lose_text = span_danger("The mime doesn't seem so great.") - medical_record_text = "Patient reports being a big fan of mimes." - mail_goodies = list( - /obj/item/toy/crayon/mime, - /obj/item/clothing/mask/gas/mime, - /obj/item/storage/backpack/mime, - /obj/item/clothing/under/rank/civilian/mime, - /obj/item/reagent_containers/cup/glass/bottle/bottleofnothing, - /obj/item/stamp/mime, - /obj/item/storage/box/survival/hug/black, - /obj/item/bedsheet/mime, - /obj/item/clothing/shoes/sneakers/mime, - /obj/item/toy/figure/mime, - /obj/item/toy/crayon/spraycan/mimecan, - ) - -/datum/quirk/item_quirk/mime_fan/add_unique(client/client_source) - give_item_to_holder(/obj/item/clothing/accessory/mime_fan_pin, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) - -/datum/quirk/item_quirk/mime_fan/add(client/client_source) - var/datum/atom_hud/fan = GLOB.huds[DATA_HUD_FAN] - fan.show_to(quirk_holder) - -/datum/quirk/freerunning - name = "Freerunning" - desc = "You're great at quick moves! You can climb tables more quickly and take no damage from short falls." - icon = FA_ICON_RUNNING - value = 8 - mob_trait = TRAIT_FREERUNNING - gain_text = span_notice("You feel lithe on your feet!") - lose_text = span_danger("You feel clumsy again.") - medical_record_text = "Patient scored highly on cardio tests." - mail_goodies = list(/obj/item/melee/skateboard, /obj/item/clothing/shoes/wheelys/rollerskates) - -/datum/quirk/friendly - name = "Friendly" - desc = "You give the best hugs, especially when you're in the right mood." - icon = FA_ICON_HANDS_HELPING - value = 2 - mob_trait = TRAIT_FRIENDLY - gain_text = span_notice("You want to hug someone.") - lose_text = span_danger("You no longer feel compelled to hug others.") - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED - medical_record_text = "Patient demonstrates low-inhibitions for physical contact and well-developed arms. Requesting another doctor take over this case." - mail_goodies = list(/obj/item/storage/box/hug) - -/datum/quirk/jolly - name = "Jolly" - desc = "You sometimes just feel happy, for no reason at all." - icon = FA_ICON_GRIN - value = 4 - mob_trait = TRAIT_JOLLY - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED - medical_record_text = "Patient demonstrates constant euthymia irregular for environment. It's a bit much, to be honest." - mail_goodies = list(/obj/item/clothing/mask/joy) - -/datum/quirk/light_step - name = "Light Step" - desc = "You walk with a gentle step; footsteps and stepping on sharp objects is quieter and less painful. Also, your hands and clothes will not get messed in case of stepping in blood." - icon = FA_ICON_SHOE_PRINTS - value = 4 - mob_trait = TRAIT_LIGHT_STEP - gain_text = span_notice("You walk with a little more litheness.") - lose_text = span_danger("You start tromping around like a barbarian.") - medical_record_text = "Patient's dexterity belies a strong capacity for stealth." - mail_goodies = list(/obj/item/clothing/shoes/sandal) - -/datum/quirk/item_quirk/musician - name = "Musician" - desc = "You can tune handheld musical instruments to play melodies that clear certain negative effects and soothe the soul." - icon = FA_ICON_GUITAR - value = 2 - mob_trait = TRAIT_MUSICIAN - gain_text = span_notice("You know everything about musical instruments.") - lose_text = span_danger("You forget how musical instruments work.") - medical_record_text = "Patient brain scans show a highly-developed auditory pathway." - mail_goodies = list(/obj/effect/spawner/random/entertainment/musical_instrument, /obj/item/instrument/piano_synth/headphones) - -/datum/quirk/item_quirk/musician/add_unique(client/client_source) - give_item_to_holder(/obj/item/choice_beacon/music, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) - -/datum/quirk/night_vision - name = "Night Vision" - desc = "You can see slightly more clearly in full darkness than most people." - icon = FA_ICON_MOON - value = 4 - mob_trait = TRAIT_NIGHT_VISION - gain_text = span_notice("The shadows seem a little less dark.") - lose_text = span_danger("Everything seems a little darker.") - medical_record_text = "Patient's eyes show above-average acclimation to darkness." - mail_goodies = list( - /obj/item/flashlight/flashdark, - /obj/item/food/grown/mushroom/glowshroom/shadowshroom, - /obj/item/skillchip/light_remover, - ) - -/datum/quirk/night_vision/add(client/client_source) - refresh_quirk_holder_eyes() - -/datum/quirk/night_vision/remove() - refresh_quirk_holder_eyes() - -/datum/quirk/night_vision/proc/refresh_quirk_holder_eyes() - var/mob/living/carbon/human/human_quirk_holder = quirk_holder - var/obj/item/organ/internal/eyes/eyes = human_quirk_holder.get_organ_by_type(/obj/item/organ/internal/eyes) - if(!eyes || eyes.lighting_cutoff) - return - // We've either added or removed TRAIT_NIGHT_VISION before calling this proc. Just refresh the eyes. - eyes.refresh() - -/datum/quirk/bilingual - name = "Bilingual" - desc = "Over the years you've picked up an extra language!" - icon = FA_ICON_GLOBE - value = 4 - gain_text = span_notice("Some of the words of the people around you certainly aren't common. Good thing you studied for this.") - lose_text = span_notice("You seem to have forgotten your second language.") - medical_record_text = "Patient speaks multiple languages." - mail_goodies = list(/obj/item/taperecorder, /obj/item/clothing/head/frenchberet, /obj/item/clothing/mask/fakemoustache/italian) - -/datum/quirk/bilingual/add_unique(client/client_source) - var/wanted_language = client_source?.prefs.read_preference(/datum/preference/choiced/language) - var/datum/language/language_type - if(wanted_language == "Random") - language_type = pick(GLOB.uncommon_roundstart_languages) - else - language_type = GLOB.language_types_by_name[wanted_language] - if(quirk_holder.has_language(language_type)) - language_type = /datum/language/uncommon - if(quirk_holder.has_language(language_type)) - to_chat(quirk_holder, span_boldnotice("You are already familiar with the quirk in your preferences, so you did not learn one.")) - return - to_chat(quirk_holder, span_boldnotice("You are already familiar with the quirk in your preferences, so you learned Galactic Uncommon instead.")) - quirk_holder.grant_language(language_type, source = LANGUAGE_QUIRK) - -/datum/quirk/item_quirk/poster_boy - name = "Poster Boy" - desc = "You have some great posters! Hang them up and make everyone have a great time." - icon = FA_ICON_TAPE - value = 4 - mob_trait = TRAIT_POSTERBOY - medical_record_text = "Patient reports a desire to cover walls with homemade objects." - mail_goodies = list(/obj/item/poster/random_official) - -/datum/quirk/item_quirk/poster_boy/add_unique() - var/mob/living/carbon/human/posterboy = quirk_holder - var/obj/item/storage/box/posterbox/newbox = new() - newbox.add_quirk_posters(posterboy.mind) - give_item_to_holder(newbox, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) - -/obj/item/storage/box/posterbox - name = "Box of Posters" - desc = "You made them yourself!" - -/// fills box of posters based on job, one neutral poster and 2 department posters -/obj/item/storage/box/posterbox/proc/add_quirk_posters(datum/mind/posterboy) - new /obj/item/poster/quirk/crew/random(src) - var/department = posterboy.assigned_role.paycheck_department - if(department == ACCOUNT_CIV) //if you are not part of a department you instead get 3 neutral posters - for(var/i in 1 to 2) - new /obj/item/poster/quirk/crew/random(src) - return - for(var/obj/item/poster/quirk/potential_poster as anything in subtypesof(/obj/item/poster/quirk)) - if(initial(potential_poster.quirk_poster_department) != department) - continue - new potential_poster(src) - -/datum/quirk/selfaware - name = "Self-Aware" - desc = "You know your body well, and can accurately assess the extent of your wounds." - icon = FA_ICON_BONE - value = 8 - mob_trait = TRAIT_SELF_AWARE - medical_record_text = "Patient demonstrates an uncanny knack for self-diagnosis." - mail_goodies = list(/obj/item/clothing/neck/stethoscope, /obj/item/skillchip/entrails_reader) - -/datum/quirk/skittish - name = "Skittish" - desc = "You're easy to startle, and hide frequently. Run into a closed locker to jump into it, as long as you have access. You can walk to avoid this." - icon = FA_ICON_TRASH - value = 8 - mob_trait = TRAIT_SKITTISH - medical_record_text = "Patient demonstrates a high aversion to danger and has described hiding in containers out of fear." - mail_goodies = list(/obj/structure/closet/cardboard) - -/datum/quirk/item_quirk/spiritual - name = "Spiritual" - desc = "You hold a spiritual belief, whether in God, nature or the arcane rules of the universe. You gain comfort from the presence of holy people, and believe that your prayers are more special than others. Being in the chapel makes you happy." - icon = FA_ICON_BIBLE - value = 2 /// SKYRAT EDIT - Quirk Rebalance - Original: value = 4 - mob_trait = TRAIT_SPIRITUAL - gain_text = span_notice("You have faith in a higher power.") - lose_text = span_danger("You lose faith!") - medical_record_text = "Patient reports a belief in a higher power." - mail_goodies = list( - /obj/item/book/bible/booze, - /obj/item/reagent_containers/cup/glass/bottle/holywater, - /obj/item/bedsheet/chaplain, - /obj/item/toy/cards/deck/tarot, - /obj/item/storage/fancy/candle_box, - ) - -/datum/quirk/item_quirk/spiritual/add_unique(client/client_source) - give_item_to_holder(/obj/item/storage/fancy/candle_box, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) - give_item_to_holder(/obj/item/storage/box/matches, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) - -/datum/quirk/item_quirk/tagger - name = "Tagger" - desc = "You're an experienced artist. People will actually be impressed by your graffiti, and you can get twice as many uses out of drawing supplies." - icon = FA_ICON_SPRAY_CAN - value = 4 - mob_trait = TRAIT_TAGGER - gain_text = span_notice("You know how to tag walls efficiently.") - lose_text = span_danger("You forget how to tag walls properly.") - medical_record_text = "Patient was recently seen for possible paint huffing incident." - mail_goodies = list( - /obj/item/toy/crayon/spraycan, - /obj/item/canvas/nineteen_nineteen, - /obj/item/canvas/twentythree_nineteen, - /obj/item/canvas/twentythree_twentythree - ) - -/datum/quirk/item_quirk/tagger/add_unique(client/client_source) - var/obj/item/toy/crayon/spraycan/can = new - can.set_painting_tool_color(client_source?.prefs.read_preference(/datum/preference/color/paint_color)) - give_item_to_holder(can, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) - -/datum/quirk/throwingarm - name = "Throwing Arm" - desc = "Your arms have a lot of heft to them! Objects that you throw just always seem to fly further than everyone elses, and you never miss a toss." - icon = FA_ICON_BASEBALL - value = 7 - mob_trait = TRAIT_THROWINGARM - gain_text = span_notice("Your arms are full of energy!") - lose_text = span_danger("Your arms ache a bit.") - medical_record_text = "Patient displays mastery over throwing balls." - mail_goodies = list(/obj/item/toy/beach_ball/baseball, /obj/item/toy/basketball, /obj/item/toy/dodgeball) - -/datum/quirk/voracious - name = "Voracious" - desc = "Nothing gets between you and your food. You eat faster and can binge on junk food! Being fat suits you just fine." - icon = FA_ICON_DRUMSTICK_BITE - value = 4 - mob_trait = TRAIT_VORACIOUS - gain_text = span_notice("You feel HONGRY.") - lose_text = span_danger("You no longer feel HONGRY.") - mail_goodies = list(/obj/effect/spawner/random/food_or_drink/dinner) - -/datum/quirk/item_quirk/signer - name = "Signer" - desc = "You possess excellent communication skills in sign language." - icon = FA_ICON_HANDS - value = 4 - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE - mail_goodies = list(/obj/item/clothing/gloves/radio) - -/datum/quirk/item_quirk/signer/add_unique(client/client_source) - quirk_holder.AddComponent(/datum/component/sign_language) - var/obj/item/clothing/gloves/gloves_type = /obj/item/clothing/gloves/radio - if(isplasmaman(quirk_holder)) - gloves_type = /obj/item/clothing/gloves/color/plasmaman/radio - give_item_to_holder(gloves_type, list(LOCATION_GLOVES = ITEM_SLOT_GLOVES, LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) - -/datum/quirk/item_quirk/signer/remove() - qdel(quirk_holder.GetComponent(/datum/component/sign_language)) - -/datum/quirk/item_quirk/settler - name = "Settler" - desc = "You are from a lineage of the earliest space settlers! While your family's generational exposure to varying gravity \ - has resulted in a ... smaller height than is typical for your species, you make up for it by being much better at outdoorsmanship and \ - carrying heavy equipment. You also get along great with animals. However, you are a bit on the slow side due to your small legs." - gain_text = span_bold("You feel like the world is your oyster!") - lose_text = span_danger("You think you might stay home today.") - icon = FA_ICON_HOUSE - value = 4 - mob_trait = TRAIT_SETTLER - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE - medical_record_text = "Patient appears to be abnormally stout." - mail_goodies = list( - /obj/item/clothing/shoes/workboots/mining, - /obj/item/gps, - ) - -/datum/quirk/item_quirk/settler/add_unique(client/client_source) - give_item_to_holder(/obj/item/storage/box/papersack/wheat, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) - give_item_to_holder(/obj/item/storage/toolbox/fishing/small, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) - var/mob/living/carbon/human/human_quirkholder = quirk_holder - human_quirkholder.set_mob_height(HUMAN_HEIGHT_SHORTEST) - human_quirkholder.add_movespeed_modifier(/datum/movespeed_modifier/settler) - human_quirkholder.physiology.hunger_mod *= 0.5 //good for you, shortass, you don't get hungry nearly as often - -/datum/quirk/item_quirk/settler/remove() - if(QDELING(quirk_holder)) - return - var/mob/living/carbon/human/human_quirkholder = quirk_holder - human_quirkholder.set_mob_height(HUMAN_HEIGHT_MEDIUM) - human_quirkholder.remove_movespeed_modifier(/datum/movespeed_modifier/settler) - human_quirkholder.physiology.hunger_mod *= 2 diff --git a/code/datums/quirks/positive_quirks/poster_boy.dm b/code/datums/quirks/positive_quirks/poster_boy.dm new file mode 100644 index 00000000000000..4991ebc540b4c7 --- /dev/null +++ b/code/datums/quirks/positive_quirks/poster_boy.dm @@ -0,0 +1,31 @@ +/datum/quirk/item_quirk/poster_boy + name = "Poster Boy" + desc = "You have some great posters! Hang them up and make everyone have a great time." + icon = FA_ICON_TAPE + value = 4 + mob_trait = TRAIT_POSTERBOY + medical_record_text = "Patient reports a desire to cover walls with homemade objects." + mail_goodies = list(/obj/item/poster/random_official) + +/datum/quirk/item_quirk/poster_boy/add_unique() + var/mob/living/carbon/human/posterboy = quirk_holder + var/obj/item/storage/box/posterbox/newbox = new() + newbox.add_quirk_posters(posterboy.mind) + give_item_to_holder(newbox, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) + +/obj/item/storage/box/posterbox + name = "Box of Posters" + desc = "You made them yourself!" + +/// fills box of posters based on job, one neutral poster and 2 department posters +/obj/item/storage/box/posterbox/proc/add_quirk_posters(datum/mind/posterboy) + new /obj/item/poster/quirk/crew/random(src) + var/department = posterboy.assigned_role.paycheck_department + if(department == ACCOUNT_CIV) //if you are not part of a department you instead get 3 neutral posters + for(var/i in 1 to 2) + new /obj/item/poster/quirk/crew/random(src) + return + for(var/obj/item/poster/quirk/potential_poster as anything in subtypesof(/obj/item/poster/quirk)) + if(initial(potential_poster.quirk_poster_department) != department) + continue + new potential_poster(src) diff --git a/code/datums/quirks/positive_quirks/self_aware.dm b/code/datums/quirks/positive_quirks/self_aware.dm new file mode 100644 index 00000000000000..022d08659eff93 --- /dev/null +++ b/code/datums/quirks/positive_quirks/self_aware.dm @@ -0,0 +1,8 @@ +/datum/quirk/selfaware + name = "Self-Aware" + desc = "You know your body well, and can accurately assess the extent of your wounds." + icon = FA_ICON_BONE + value = 8 + mob_trait = TRAIT_SELF_AWARE + medical_record_text = "Patient demonstrates an uncanny knack for self-diagnosis." + mail_goodies = list(/obj/item/clothing/neck/stethoscope, /obj/item/skillchip/entrails_reader) diff --git a/code/datums/quirks/positive_quirks/settler.dm b/code/datums/quirks/positive_quirks/settler.dm new file mode 100644 index 00000000000000..81402c050cdd89 --- /dev/null +++ b/code/datums/quirks/positive_quirks/settler.dm @@ -0,0 +1,32 @@ +/datum/quirk/item_quirk/settler + name = "Settler" + desc = "You are from a lineage of the earliest space settlers! While your family's generational exposure to varying gravity \ + has resulted in a ... smaller height than is typical for your species, you make up for it by being much better at outdoorsmanship and \ + carrying heavy equipment. You also get along great with animals. However, you are a bit on the slow side due to your small legs." + gain_text = span_bold("You feel like the world is your oyster!") + lose_text = span_danger("You think you might stay home today.") + icon = FA_ICON_HOUSE + value = 4 + mob_trait = TRAIT_SETTLER + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE + medical_record_text = "Patient appears to be abnormally stout." + mail_goodies = list( + /obj/item/clothing/shoes/workboots/mining, + /obj/item/gps, + ) + +/datum/quirk/item_quirk/settler/add_unique(client/client_source) + give_item_to_holder(/obj/item/storage/box/papersack/wheat, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) + give_item_to_holder(/obj/item/storage/toolbox/fishing/small, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) + var/mob/living/carbon/human/human_quirkholder = quirk_holder + human_quirkholder.set_mob_height(HUMAN_HEIGHT_SHORTEST) + human_quirkholder.add_movespeed_modifier(/datum/movespeed_modifier/settler) + human_quirkholder.physiology.hunger_mod *= 0.5 //good for you, shortass, you don't get hungry nearly as often + +/datum/quirk/item_quirk/settler/remove() + if(QDELING(quirk_holder)) + return + var/mob/living/carbon/human/human_quirkholder = quirk_holder + human_quirkholder.set_mob_height(HUMAN_HEIGHT_MEDIUM) + human_quirkholder.remove_movespeed_modifier(/datum/movespeed_modifier/settler) + human_quirkholder.physiology.hunger_mod *= 2 diff --git a/code/datums/quirks/positive_quirks/signer.dm b/code/datums/quirks/positive_quirks/signer.dm new file mode 100644 index 00000000000000..df0a2f34c5dd43 --- /dev/null +++ b/code/datums/quirks/positive_quirks/signer.dm @@ -0,0 +1,17 @@ +/datum/quirk/item_quirk/signer + name = "Signer" + desc = "You possess excellent communication skills in sign language." + icon = FA_ICON_HANDS + value = 4 + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE + mail_goodies = list(/obj/item/clothing/gloves/radio) + +/datum/quirk/item_quirk/signer/add_unique(client/client_source) + quirk_holder.AddComponent(/datum/component/sign_language) + var/obj/item/clothing/gloves/gloves_type = /obj/item/clothing/gloves/radio + if(isplasmaman(quirk_holder)) + gloves_type = /obj/item/clothing/gloves/color/plasmaman/radio + give_item_to_holder(gloves_type, list(LOCATION_GLOVES = ITEM_SLOT_GLOVES, LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) + +/datum/quirk/item_quirk/signer/remove() + qdel(quirk_holder.GetComponent(/datum/component/sign_language)) diff --git a/code/datums/quirks/positive_quirks/skittish.dm b/code/datums/quirks/positive_quirks/skittish.dm new file mode 100644 index 00000000000000..24bbac8e556cfb --- /dev/null +++ b/code/datums/quirks/positive_quirks/skittish.dm @@ -0,0 +1,8 @@ +/datum/quirk/skittish + name = "Skittish" + desc = "You're easy to startle, and hide frequently. Run into a closed locker to jump into it, as long as you have access. You can walk to avoid this." + icon = FA_ICON_TRASH + value = 8 + mob_trait = TRAIT_SKITTISH + medical_record_text = "Patient demonstrates a high aversion to danger and has described hiding in containers out of fear." + mail_goodies = list(/obj/structure/closet/cardboard) diff --git a/code/datums/quirks/positive_quirks/spacer.dm b/code/datums/quirks/positive_quirks/spacer.dm index 4e0adcf73cd024..24dc91fa62703e 100644 --- a/code/datums/quirks/positive_quirks/spacer.dm +++ b/code/datums/quirks/positive_quirks/spacer.dm @@ -15,6 +15,8 @@ /obj/item/storage/pill_bottle/ondansetron, /obj/item/reagent_containers/pill/gravitum, ) + /// How high spacers get bumped up to + var/modded_height = HUMAN_HEIGHT_TALLER /// How long on a planet before we get averse effects var/planet_period = 3 MINUTES /// TimerID for time spend on a planet @@ -44,7 +46,7 @@ quirk_holder.inertia_move_delay *= 0.8 var/mob/living/carbon/human/human_quirker = quirk_holder - human_quirker.set_mob_height(HUMAN_HEIGHT_TALLEST) + human_quirker.set_mob_height(modded_height) human_quirker.physiology.pressure_mod *= 0.8 human_quirker.physiology.cold_mod *= 0.8 diff --git a/code/datums/quirks/positive_quirks/spiritual.dm b/code/datums/quirks/positive_quirks/spiritual.dm new file mode 100644 index 00000000000000..b08fe8b60c6fce --- /dev/null +++ b/code/datums/quirks/positive_quirks/spiritual.dm @@ -0,0 +1,20 @@ +/datum/quirk/item_quirk/spiritual + name = "Spiritual" + desc = "You hold a spiritual belief, whether in God, nature or the arcane rules of the universe. You gain comfort from the presence of holy people, and believe that your prayers are more special than others. Being in the chapel makes you happy." + icon = FA_ICON_BIBLE + value = 2 /// SKYRAT EDIT - Quirk Rebalance - Original: value = 4 + mob_trait = TRAIT_SPIRITUAL + gain_text = span_notice("You have faith in a higher power.") + lose_text = span_danger("You lose faith!") + medical_record_text = "Patient reports a belief in a higher power." + mail_goodies = list( + /obj/item/book/bible/booze, + /obj/item/reagent_containers/cup/glass/bottle/holywater, + /obj/item/bedsheet/chaplain, + /obj/item/toy/cards/deck/tarot, + /obj/item/storage/fancy/candle_box, + ) + +/datum/quirk/item_quirk/spiritual/add_unique(client/client_source) + give_item_to_holder(/obj/item/storage/fancy/candle_box, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) + give_item_to_holder(/obj/item/storage/box/matches, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) diff --git a/code/datums/quirks/positive_quirks/tagger.dm b/code/datums/quirks/positive_quirks/tagger.dm new file mode 100644 index 00000000000000..5aba24d850a458 --- /dev/null +++ b/code/datums/quirks/positive_quirks/tagger.dm @@ -0,0 +1,20 @@ +/datum/quirk/item_quirk/tagger + name = "Tagger" + desc = "You're an experienced artist. People will actually be impressed by your graffiti, and you can get twice as many uses out of drawing supplies." + icon = FA_ICON_SPRAY_CAN + value = 4 + mob_trait = TRAIT_TAGGER + gain_text = span_notice("You know how to tag walls efficiently.") + lose_text = span_danger("You forget how to tag walls properly.") + medical_record_text = "Patient was recently seen for possible paint huffing incident." + mail_goodies = list( + /obj/item/toy/crayon/spraycan, + /obj/item/canvas/nineteen_nineteen, + /obj/item/canvas/twentythree_nineteen, + /obj/item/canvas/twentythree_twentythree + ) + +/datum/quirk/item_quirk/tagger/add_unique(client/client_source) + var/obj/item/toy/crayon/spraycan/can = new + can.set_painting_tool_color(client_source?.prefs.read_preference(/datum/preference/color/paint_color)) + give_item_to_holder(can, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) diff --git a/code/datums/quirks/positive_quirks/throwing_arm.dm b/code/datums/quirks/positive_quirks/throwing_arm.dm new file mode 100644 index 00000000000000..5157b3990095be --- /dev/null +++ b/code/datums/quirks/positive_quirks/throwing_arm.dm @@ -0,0 +1,10 @@ +/datum/quirk/throwingarm + name = "Throwing Arm" + desc = "Your arms have a lot of heft to them! Objects that you throw just always seem to fly further than everyone elses, and you never miss a toss." + icon = FA_ICON_BASEBALL + value = 7 + mob_trait = TRAIT_THROWINGARM + gain_text = span_notice("Your arms are full of energy!") + lose_text = span_danger("Your arms ache a bit.") + medical_record_text = "Patient displays mastery over throwing balls." + mail_goodies = list(/obj/item/toy/beach_ball/baseball, /obj/item/toy/basketball, /obj/item/toy/dodgeball) diff --git a/code/datums/quirks/positive_quirks/voracious.dm b/code/datums/quirks/positive_quirks/voracious.dm new file mode 100644 index 00000000000000..68073304f0d82a --- /dev/null +++ b/code/datums/quirks/positive_quirks/voracious.dm @@ -0,0 +1,9 @@ +/datum/quirk/voracious + name = "Voracious" + desc = "Nothing gets between you and your food. You eat faster and can binge on junk food! Being fat suits you just fine." + icon = FA_ICON_DRUMSTICK_BITE + value = 4 + mob_trait = TRAIT_VORACIOUS + gain_text = span_notice("You feel HONGRY.") + lose_text = span_danger("You no longer feel HONGRY.") + mail_goodies = list(/obj/effect/spawner/random/food_or_drink/dinner) diff --git a/code/datums/ruins/lavaland.dm b/code/datums/ruins/lavaland.dm index 69e2d10a67fc1b..968e6df544e828 100644 --- a/code/datums/ruins/lavaland.dm +++ b/code/datums/ruins/lavaland.dm @@ -278,3 +278,11 @@ suffix = "lavaland_surface_phonebooth.dmm" allow_duplicates = FALSE cost = 5 + +/datum/map_template/ruin/lavaland/battle_site + name = "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" + allow_duplicates = TRUE + cost = 3 diff --git a/code/datums/ruins/space.dm b/code/datums/ruins/space.dm index a43470d46f5451..4862aa5e2742d2 100644 --- a/code/datums/ruins/space.dm +++ b/code/datums/ruins/space.dm @@ -126,6 +126,12 @@ name = "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" + 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" diff --git a/code/datums/shuttles/emergency.dm b/code/datums/shuttles/emergency.dm index af87dc641d8d2e..5e8553c69ee51d 100644 --- a/code/datums/shuttles/emergency.dm +++ b/code/datums/shuttles/emergency.dm @@ -3,12 +3,42 @@ /datum/map_template/shuttle/emergency // SKYRAT EDIT OVERRIDE - OVERRIDEN IN ADVANCED_SHUTTLES - shuttles.dm port_id = "emergency" name = "Base Shuttle Template (Emergency)" + ///assoc list of shuttle events to add to this shuttle on spawn (typepath = weight) + var/list/events + ///pick all events instead of random + var/use_all_events = FALSE + ///how many do we pick + var/event_amount = 1 + ///do we empty the event list before adding our events + var/events_override = FALSE /datum/map_template/shuttle/emergency/New() . = ..() if(!occupancy_limit && who_can_purchase) CRASH("The [name] needs an occupancy limit!") - + if(HAS_TRAIT(SSstation, STATION_TRAIT_SHUTTLE_SALE) && credit_cost > 0 && prob(15)) + var/discount_amount = round(rand(25, 80), 5) + name += " ([discount_amount]% Discount!)" + var/discount_multiplier = 100 - discount_amount + credit_cost = ((credit_cost * discount_multiplier) / 100) + +///on post_load use our variables to change shuttle events +/datum/map_template/shuttle/emergency/post_load(obj/docking_port/mobile/mobile) + . = ..() + if(!events) + return + if(events_override) + mobile.event_list.Cut() + if(use_all_events) + for(var/path in events) + mobile.event_list.Add(new path(mobile)) + events -= path + else + for(var/i in 1 to event_amount) + var/path = pick_weight(events) + events -= path + mobile.event_list.Add(new path(mobile)) + /datum/map_template/shuttle/emergency/backup prefix = "_maps/shuttles/" suffix = "backup" @@ -44,6 +74,19 @@ credit_cost = CARGO_CRATE_VALUE * 10 occupancy_limit = "45" +/datum/map_template/shuttle/emergency/humpback + suffix = "humpback" + name = "Humpback Emergency Shuttle" + description = "A repurposed cargo hauling and salvaging ship, for sightseeing and tourism. Has a bar. Complete with a 2 minute vacation plan to carp territory." + credit_cost = CARGO_CRATE_VALUE * 12 + occupancy_limit = "30" + events = list( + /datum/shuttle_event/simple_spawner/carp/friendly = 10, + /datum/shuttle_event/simple_spawner/carp/friendly_but_no_personal_space = 2, + /datum/shuttle_event/simple_spawner/carp = 2, + /datum/shuttle_event/simple_spawner/carp/magic = 1, + ) + /datum/map_template/shuttle/emergency/bar suffix = "bar" name = "The Emergency Escape Bar" diff --git a/code/datums/station_traits/_station_trait.dm b/code/datums/station_traits/_station_trait.dm index e42ce87f3e57f5..1205673c565f9b 100644 --- a/code/datums/station_traits/_station_trait.dm +++ b/code/datums/station_traits/_station_trait.dm @@ -52,7 +52,7 @@ ///type of info the centcom report has on this trait, if any. /datum/station_trait/proc/get_report() - return "[name] - [report_message]" + return "[name] - [report_message]" /// Will attempt to revert the station trait, used by admins. /datum/station_trait/proc/revert() diff --git a/code/datums/station_traits/positive_traits.dm b/code/datums/station_traits/positive_traits.dm index 0b5a2df246ce90..165cc4c2ad4834 100644 --- a/code/datums/station_traits/positive_traits.dm +++ b/code/datums/station_traits/positive_traits.dm @@ -355,5 +355,79 @@ trait_to_give = STATION_TRAIT_BIGGER_PODS blacklist = list(/datum/station_trait/cramped_escape_pods) +/datum/station_trait/medbot_mania + name = "Advanced Medbots" + trait_type = STATION_TRAIT_POSITIVE + weight = 5 + show_in_report = TRUE + report_message = "Your station's medibots have recieved a hardware upgrade, enabling expanded healing capabilities." + trait_to_give = STATION_TRAIT_MEDBOT_MANIA + +/datum/station_trait/random_event_weight_modifier/shuttle_loans + name = "Loaner Shuttle" + report_message = "Due to an uptick in pirate attacks around your sector, there are few supply vessels in nearby space willing to assist with special requests. Expect to recieve more shuttle loan opportunities, with slightly higher payouts." + trait_type = STATION_TRAIT_POSITIVE + weight = 4 + event_control_path = /datum/round_event_control/shuttle_loan + weight_multiplier = 2.5 + max_occurrences_modifier = 5 //All but one loan event will occur over the course of a round. + trait_to_give = STATION_TRAIT_LOANER_SHUTTLE + +/datum/station_trait/random_event_weight_modifier/wise_cows + name = "Wise Cow Invasion" + report_message = "Bluespace harmonic readings show unusual interpolative signals between your sector and agricultural sector MMF-D-02. Expect an increase in cow encounters. Encownters, if you will." + trait_type = STATION_TRAIT_POSITIVE + weight = 1 + event_control_path = /datum/round_event_control/wisdomcow + weight_multiplier = 3 + max_occurrences_modifier = 10 //lotta cows + +/datum/station_trait/shuttle_sale + name = "Shuttle Firesale" + report_message = "The Nanotrasen Emergency Dispatch team is celebrating a record number of shuttle calls in the recent quarter. Some of your emergency shuttle options have been discounted!" + trait_type = STATION_TRAIT_POSITIVE + weight = 4 + trait_to_give = STATION_TRAIT_SHUTTLE_SALE + show_in_report = TRUE + +/datum/station_trait/missing_wallet + name = "Misplaced Wallet" + report_message = "A repair technician left their wallet in a locker somewhere. They would greatly appreciate if you could locate and return it to them when the shift has ended." + trait_type = STATION_TRAIT_POSITIVE + weight = 5 + show_in_report = TRUE + +/datum/station_trait/missing_wallet/on_round_start() + . = ..() + + var/obj/structure/closet/locker_to_fill = pick(GLOB.roundstart_station_closets) + + var/obj/item/storage/wallet/new_wallet = new(locker_to_fill) + + new /obj/item/stack/spacecash/c500(new_wallet) + if(prob(25)) //Jackpot! + new /obj/item/stack/spacecash/c1000(new_wallet) + + new /obj/item/card/id/advanced/technician_id(new_wallet) + new_wallet.refreshID() + + if(prob(35)) + report_message += " The technician reports they last remember having their wallet around [get_area_name(new_wallet)]." + + message_admins("A missing wallet has been placed in the [locker_to_fill] locker, in the [get_area_name(locker_to_fill)] area.") + +/obj/item/card/id/advanced/technician_id + name = "Repair Technician ID" + desc = "Repair Technician? We don't have those in this sector, just a bunch of lazy engineers! This must have been from the between-shift crew..." + registered_name = "Pluoxium LXVII" + registered_age = 67 + trim = /datum/id_trim/technician_id + +/datum/id_trim/technician_id + access = list(ACCESS_EXTERNAL_AIRLOCKS, ACCESS_MAINT_TUNNELS) + assignment = "Repair Technician" + trim_state = "trim_stationengineer" + department_color = COLOR_ASSISTANT_GRAY + #undef PARTY_COOLDOWN_LENGTH_MIN #undef PARTY_COOLDOWN_LENGTH_MAX diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 637b731adbed94..b9747d54acc258 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -504,3 +504,16 @@ owner.RemoveElement(/datum/element/simple_flying) owner.remove_stun_absorption(id) remove_traits(list(TRAIT_IGNOREDAMAGESLOWDOWN, TRAIT_FREE_HYPERSPACE_MOVEMENT), MAD_WIZARD_TRAIT) + +/// Gives you a brief period of anti-gravity +/datum/status_effect/jump_jet + id = "jump_jet" + alert_type = null + duration = 5 SECONDS + +/datum/status_effect/jump_jet/on_apply() + owner.AddElement(/datum/element/forced_gravity, 0) + return TRUE + +/datum/status_effect/jump_jet/on_remove() + owner.RemoveElement(/datum/element/forced_gravity, 0) diff --git a/code/datums/status_effects/debuffs/choke.dm b/code/datums/status_effects/debuffs/choke.dm index f626cb52be5b6a..c16b946aa02bd4 100644 --- a/code/datums/status_effects/debuffs/choke.dm +++ b/code/datums/status_effects/debuffs/choke.dm @@ -110,7 +110,7 @@ if(choking_on && iscarbon(owner)) var/mob/living/carbon/carbon_owner = owner // This will yeet the thing we're choking on out of us - carbon_owner.vomit(lost_nutrition = 20, force = TRUE, distance = 2) + carbon_owner.vomit(vomit_flags = (VOMIT_CATEGORY_DEFAULT | MOB_VOMIT_FORCE), lost_nutrition = 20, distance = 2) /datum/status_effect/choke/proc/on_vomit(mob/source, distance, force) SIGNAL_HANDLER @@ -215,8 +215,8 @@ if(iscarbon(victim)) var/mob/living/carbon/carbon_victim = victim var/obj/item/bodypart/chest = carbon_victim.get_bodypart(BODY_ZONE_CHEST) - if(chest) - chest.force_wound_upwards(/datum/wound/blunt/bone/severe, wound_source = "human force to the chest") + carbon_victim.cause_wound_of_type_and_severity(WOUND_BLUNT, chest, WOUND_SEVERITY_SEVERE, wound_source = "human force to the chest") + playsound(owner, 'sound/creatures/crack_vomit.ogg', 120, extrarange = 5, falloff_exponent = 4) vomit_up() diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index 50fe9690b41b95..8c8f910fd572e6 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -411,7 +411,9 @@ var/still_bleeding = FALSE for(var/datum/wound/bleeding_thing as anything in throat.wounds) - if(bleeding_thing.wound_type == WOUND_SLASH && bleeding_thing.severity > WOUND_SEVERITY_MODERATE) + var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[bleeding_thing.type] + + if(pregen_data.wounding_types_valid(list(WOUND_SLASH)) && bleeding_thing.severity > WOUND_SEVERITY_MODERATE && bleeding_thing.blood_flow > 0) still_bleeding = TRUE break if(!still_bleeding) diff --git a/code/datums/status_effects/debuffs/drunk.dm b/code/datums/status_effects/debuffs/drunk.dm index 2e844a61b190a0..705fcc60eeb97b 100644 --- a/code/datums/status_effects/debuffs/drunk.dm +++ b/code/datums/status_effects/debuffs/drunk.dm @@ -170,7 +170,7 @@ owner.adjust_confusion(15 SECONDS) if(iscarbon(owner)) var/mob/living/carbon/carbon_owner = owner - carbon_owner.vomit() // Vomiting clears toxloss - consider this a blessing + carbon_owner.vomit(VOMIT_CATEGORY_DEFAULT) // Vomiting clears toxloss - consider this a blessing // Over 71, we will constantly have blurry eyes if(drunk_value >= 71) diff --git a/code/datums/status_effects/debuffs/screen_blur.dm b/code/datums/status_effects/debuffs/screen_blur.dm index f893a1d379f5ba..abdd07d3cd59b3 100644 --- a/code/datums/status_effects/debuffs/screen_blur.dm +++ b/code/datums/status_effects/debuffs/screen_blur.dm @@ -14,7 +14,7 @@ return ..() /datum/status_effect/eye_blur/on_apply() - if(owner.mob_biotypes & (MOB_ROBOTIC|MOB_SPIRIT|MOB_EPIC)) + if(owner.mob_biotypes & (MOB_ROBOTIC|MOB_SPIRIT|MOB_SPECIAL)) return FALSE // Refresh the blur when a client jumps into the mob, in case we get put on a clientless mob with no hud diff --git a/code/datums/status_effects/wound_effects.dm b/code/datums/status_effects/wound_effects.dm index 5da74ef7722e9c..6ec793c5672b28 100644 --- a/code/datums/status_effects/wound_effects.dm +++ b/code/datums/status_effects/wound_effects.dm @@ -54,11 +54,11 @@ right = C.get_bodypart(BODY_ZONE_R_LEG) update_limp() RegisterSignal(C, COMSIG_MOVABLE_MOVED, PROC_REF(check_step)) - RegisterSignals(C, list(COMSIG_CARBON_GAIN_WOUND, COMSIG_CARBON_LOSE_WOUND, COMSIG_CARBON_ATTACH_LIMB, COMSIG_CARBON_REMOVE_LIMB), PROC_REF(update_limp)) + RegisterSignals(C, list(COMSIG_CARBON_GAIN_WOUND, COMSIG_CARBON_POST_LOSE_WOUND, COMSIG_CARBON_ATTACH_LIMB, COMSIG_CARBON_REMOVE_LIMB), PROC_REF(update_limp)) return TRUE /datum/status_effect/limp/on_remove() - UnregisterSignal(owner, list(COMSIG_MOVABLE_MOVED, COMSIG_CARBON_GAIN_WOUND, COMSIG_CARBON_LOSE_WOUND, COMSIG_CARBON_ATTACH_LIMB, COMSIG_CARBON_REMOVE_LIMB)) + UnregisterSignal(owner, list(COMSIG_MOVABLE_MOVED, COMSIG_CARBON_GAIN_WOUND, COMSIG_CARBON_POST_LOSE_WOUND, COMSIG_CARBON_ATTACH_LIMB, COMSIG_CARBON_REMOVE_LIMB)) /atom/movable/screen/alert/status_effect/limp name = "Limping" @@ -165,37 +165,25 @@ if(W == linked_wound) qdel(src) +/datum/status_effect/wound/nextmove_modifier() + var/mob/living/carbon/C = owner -// bones -/datum/status_effect/wound/blunt/bone - -/datum/status_effect/wound/blunt/bone/on_apply() - . = ..() - RegisterSignal(owner, COMSIG_MOB_SWAP_HANDS, PROC_REF(on_swap_hands)) - on_swap_hands() - -/datum/status_effect/wound/blunt/bone/on_remove() - . = ..() - UnregisterSignal(owner, COMSIG_MOB_SWAP_HANDS) - var/mob/living/carbon/wound_owner = owner - wound_owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/blunt_wound) - -/datum/status_effect/wound/blunt/bone/proc/on_swap_hands() - SIGNAL_HANDLER + if(C.get_active_hand() == linked_limb) + return linked_wound.get_action_delay_mult() - var/mob/living/carbon/wound_owner = owner - if(wound_owner.get_active_hand() == linked_limb) - wound_owner.add_actionspeed_modifier(/datum/actionspeed_modifier/blunt_wound, (linked_wound.interaction_efficiency_penalty - 1)) - else - wound_owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/blunt_wound) + return ..() -/datum/status_effect/wound/blunt/bone/nextmove_modifier() +/datum/status_effect/wound/nextmove_adjust() var/mob/living/carbon/C = owner if(C.get_active_hand() == linked_limb) - return linked_wound.interaction_efficiency_penalty + return linked_wound.get_action_delay_increment() + + return ..() + - return 1 +// bones +/datum/status_effect/wound/blunt/bone // blunt /datum/status_effect/wound/blunt/bone/moderate diff --git a/code/datums/voice_of_god_command.dm b/code/datums/voice_of_god_command.dm index f1ce13f9fa53fd..1be31c33d2a8eb 100644 --- a/code/datums/voice_of_god_command.dm +++ b/code/datums/voice_of_god_command.dm @@ -144,7 +144,7 @@ GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands()) /datum/voice_of_god_command/vomit/execute(list/listeners, mob/living/user, power_multiplier = 1, message) for(var/mob/living/carbon/target in listeners) - target.vomit(10 * power_multiplier, distance = power_multiplier, stun = FALSE) + target.vomit(vomit_flags = (MOB_VOMIT_MESSAGE | MOB_VOMIT_HARM), lost_nutrition = (power_multiplier * 10), distance = power_multiplier) /// This command silences the listeners. Thrice as effective is the user is a mime or curator. /datum/voice_of_god_command/silence diff --git a/code/datums/wires/mass_driver.dm b/code/datums/wires/mass_driver.dm new file mode 100644 index 00000000000000..329da73c2dcb42 --- /dev/null +++ b/code/datums/wires/mass_driver.dm @@ -0,0 +1,25 @@ +/datum/wires/mass_driver + holder_type = /obj/machinery/mass_driver + proper_name = "Mass Driver" + +/datum/wires/mass_driver/New(atom/holder) + wires = list(WIRE_LAUNCH, WIRE_SAFETIES) + ..() + +/datum/wires/mass_driver/on_pulse(wire) + var/obj/machinery/mass_driver/the_mass_driver = holder + switch(wire) + if(WIRE_LAUNCH) + the_mass_driver.drive() + holder.visible_message(span_notice("The drive mechanism activates.")) + if(WIRE_SAFETIES) + the_mass_driver.power = 3 + holder.visible_message(span_notice("You hear a worrying whirring noise emitting from the mass driver.")) + +/datum/wires/mass_driver/on_cut(wire, mend, source) + var/obj/machinery/mass_driver/the_mass_driver = holder + switch(wire) + if(WIRE_SAFETIES) + if(the_mass_driver.power > 1) + the_mass_driver.power = 1 + holder.visible_message(span_notice("The whirring noise emitting from the mass driver stops.")) diff --git a/code/datums/wounds/_wound_static_data.dm b/code/datums/wounds/_wound_static_data.dm index 4d28e80a910b7a..7a59ea57413a24 100644 --- a/code/datums/wounds/_wound_static_data.dm +++ b/code/datums/wounds/_wound_static_data.dm @@ -2,28 +2,6 @@ // For example: You can make a pregen_data subtype for your wound that overrides can_be_applied_to to only apply to specifically slimeperson limbs. // Without this, youre stuck with very static initial variables. -GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate_wound_static_data()) - -/proc/generate_wound_static_data() - RETURN_TYPE(/list/datum/wound_pregen_data) - - var/list/datum/wound_pregen_data/data = list() - - for (var/datum/wound_pregen_data/path as anything in typecacheof(path = /datum/wound_pregen_data, ignore_root_path = TRUE)) - if (initial(path.abstract)) - continue - - if (!isnull(data[initial(path.wound_path_to_generate)])) - stack_trace("pre-existing pregen data for [initial(path.wound_path_to_generate)] when [path] was being considered: [data[initial(path.wound_path_to_generate)]]. \ - this is definitely a bug, and is probably because one of the two pregen data have the wrong wound typepath defined. [path] will not be instantiated") - - continue - - var/datum/wound_pregen_data/pregen_data = new path - data[pregen_data.wound_path_to_generate] = pregen_data - - return data - /// A singleton datum that holds pre-gen and static data about a wound. Each wound datum should have a corresponding wound_pregen_data. /datum/wound_pregen_data /// The typepath of the wound we will be handling and storing data of. NECESSARY IF THIS IS A NON-ABSTRACT TYPE! @@ -38,7 +16,7 @@ GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate /// A list of biostates a limb must have to receive our wound, in wounds.dm. var/required_limb_biostate /// If false, we will check if the limb has all of our required biostates instead of just any. - var/check_for_any = FALSE + var/require_any_biostate = FALSE /// If false, we will iterate through wounds on a given limb, and if any match our type, we wont add our wound. var/duplicates_allowed = FALSE @@ -48,6 +26,30 @@ GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate /// A list of bodyzones we are applicable to. var/list/viable_zones = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) + /// The types of attack that can generate this wound. E.g. WOUND_SLASH = A sharp attack can cause this, WOUND_BLUNT = an attack with no sharpness/an attack with sharpness against a limb with mangled exterior can cause this. + var/list/required_wounding_types + /// If true, this wound can only be generated by all [required_wounding_types] at once, not just any. + var/match_all_wounding_types = FALSE + + /// The weight that will be used if, by the end of wound selection, there are multiple valid wounds. This will be inserted into pick_weight, so use integers. + var/weight = WOUND_DEFAULT_WEIGHT + + /// The minimum injury roll a attack must get to generate us. Affected by our wound's threshold_penalty and series_threshold_penalty, as well as the attack's wound_bonus. See check_wounding_mods(). + var/threshold_minimum + + /// The series of wounds this is in. See wounds.dm (the defines file) for a more detailed explanation - but tldr is that no 2 wounds of the same series can be on a limb. + var/wound_series + + /// If true, we will attempt to, during a random wound roll, overpower and remove other wound typepaths from the possible wounds list using [competition_mode] and [overpower_wounds_of_even_severity]. + var/compete_for_wounding = TRUE + /// The competition mode with which we will remove other wounds from a possible wound roll assuming [compete_for_wounding] is TRUE. See wounds.dm, the defines file, for more information on what these do. + var/competition_mode = WOUND_COMPETITION_OVERPOWER_LESSERS + /// If this and [compete_for_wounding] is true, we will remove wounds of an even severity to us during a random wound roll. + var/overpower_wounds_of_even_severity = FALSE + + /// A list of BIO_ defines that will be iterated over in order to determine the scar file our wound will generate. + /// Use generate_scar_priorities to create a custom list. + var/list/scar_priorities /datum/wound_pregen_data/New() . = ..() @@ -58,21 +60,33 @@ GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate if (wound_path_to_generate == null) stack_trace("wound_path_to_generate null - please set it! occured on: [src.type]") + scar_priorities = generate_scar_priorities() + +/// Should return a list of BIO_ biostate priorities, in order. See [scar_priorities] for further documentation. +/datum/wound_pregen_data/proc/generate_scar_priorities() + RETURN_TYPE(/list) + + var/list/priorities = list( + "[BIO_FLESH]", + "[BIO_BONE]", + ) + + return priorities + // this proc is the primary reason this datum exists - a singleton instance so we can always run this proc even without the wound existing /** * Args: * * obj/item/bodypart/limb: The limb we are considering. - * * wound_type: The type of the "wound acquisition attempt". Example: A slashing attack cannot proc a blunt wound, so wound_type = WOUND_SLASH would - * fail if we expect WOUND_BLUNT. Defaults to the wound type we expect. + * * list/suggested_wounding_types: The wounding types to be checked against the wounding types we require. Defaults to required_wounding_types. * * datum/wound/old_wound: If we would replace a wound, this would be said wound. Nullable. * * random_roll = FALSE: If this is in the context of a random wound generation, and this wound wasn't specifically checked. * * Returns: - * FALSE if the limb cannot be wounded, if wound_type is not ours, if we have a higher severity wound already in our series, + * FALSE if the limb cannot be wounded, if the wounding types dont match ours (via wounding_types_valid()), if we have a higher severity wound already in our series, * if we have a biotype mismatch, if the limb isnt in a viable zone, or if theres any duplicate wound types. * TRUE otherwise. */ -/datum/wound_pregen_data/proc/can_be_applied_to(obj/item/bodypart/limb, wound_type = initial(wound_path_to_generate.wound_type), datum/wound/old_wound, random_roll = FALSE) +/datum/wound_pregen_data/proc/can_be_applied_to(obj/item/bodypart/limb, list/suggested_wounding_types = required_wounding_types, datum/wound/old_wound, random_roll = FALSE, duplicates_allowed = src.duplicates_allowed, care_about_existing_wounds = TRUE) SHOULD_BE_PURE(TRUE) if (!istype(limb) || !limb.owner) @@ -84,11 +98,13 @@ GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate if (HAS_TRAIT(limb.owner, TRAIT_NEVER_WOUNDED) || (limb.owner.status_flags & GODMODE)) return FALSE - if (wound_type != initial(wound_path_to_generate.wound_type)) - return - else + if (!wounding_types_valid(suggested_wounding_types)) + return FALSE + + if (care_about_existing_wounds) for (var/datum/wound/preexisting_wound as anything in limb.wounds) - if (preexisting_wound.wound_series == initial(wound_path_to_generate.wound_series)) + var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[preexisting_wound.type] + if (pregen_data.wound_series == wound_series) if (preexisting_wound.severity >= initial(wound_path_to_generate.severity)) return FALSE @@ -111,7 +127,7 @@ GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate /// Returns true if we have the given biostates, or any biostate in it if check_for_any is true. False otherwise. /datum/wound_pregen_data/proc/biostate_valid(biostate) - if (check_for_any) + if (require_any_biostate) if (!(biostate & required_limb_biostate)) return FALSE else if (!((biostate & required_limb_biostate) == required_limb_biostate)) // check for all @@ -119,6 +135,50 @@ GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate return TRUE +/** + * A simple getter for [weight], with arguments supplied to allow custom behavior. + * + * Args: + * * obj/item/bodypart/limb: The limb we are contemplating being added to. Nullable. + * * woundtype: The woundtype of the assumed attack that would generate us. Nullable. + * * damage: The raw damage that would cause us. Nullable. + * * attack_direction: The direction of the attack that'd cause us. Nullable. + * * damage_source: The entity that would cause us. Nullable. + * + * Returns: + * Our weight. + */ +/datum/wound_pregen_data/proc/get_weight(obj/item/bodypart/limb, woundtype, damage, attack_direction, damage_source) + return weight + +/// Returns TRUE if we use WOUND_ALL, or we require all types and have all/if we require any and have any, FALSE otherwise. +/datum/wound_pregen_data/proc/wounding_types_valid(list/suggested_wounding_types) + if (WOUND_ALL in required_wounding_types) + return TRUE + if (!length(suggested_wounding_types)) + return FALSE + + for (var/iter_wounding_type as anything in suggested_wounding_types) + if (!(iter_wounding_type in required_wounding_types)) + if (match_all_wounding_types) + return FALSE + else + if (!match_all_wounding_types) + return TRUE + + return match_all_wounding_types // if we get here, we've matched everything + +/** + * A simple getter for [threshold_minimum], with arguments supplied to allow custom behavior. + * + * Args: + * * obj/item/bodypart/part: The limb we are contemplating being added to. + * * attack_direction: The direction of the attack that'd generate us. Nullable. + * * damage_source: The source of the damage that'd cause us. Nullable. + */ +/datum/wound_pregen_data/proc/get_threshold_for(obj/item/bodypart/part, attack_direction, damage_source) + return threshold_minimum + /// Returns a new instance of our wound datum. /datum/wound_pregen_data/proc/generate_instance(obj/item/bodypart/limb, ...) RETURN_TYPE(/datum/wound) @@ -126,10 +186,13 @@ GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate return new wound_path_to_generate /datum/wound_pregen_data/Destroy(force, ...) - stack_trace("[src], a singleton wound pregen data instance, was destroyed! This should not happen!") + var/error_message = "[src], a singleton wound pregen data instance, was destroyed! This should not happen!" + if (force) + error_message += " NOTE: This Destroy() was called with force == TRUE. This instance will be deleted and replaced with a new one." + stack_trace(error_message) if (!force) - return + return QDEL_HINT_LETMELIVE . = ..() diff --git a/code/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm index 11f2dc6a63d1ab..faf1ef87057221 100644 --- a/code/datums/wounds/_wounds.dm +++ b/code/datums/wounds/_wounds.dm @@ -16,6 +16,11 @@ #define WOUND_CRITICAL_BLUNT_DISMEMBER_BONUS 15 +// Applied into wounds when they're scanned with the wound analyzer, halves time to treat them manually. +#define TRAIT_WOUND_SCANNED "wound_scanned" +// I dunno lol +#define ANALYZER_TRAIT "analyzer_trait" + /datum/wound /// What it's named var/name = "Wound" @@ -26,11 +31,19 @@ /// What the limb looks like on a cursory examine var/examine_desc = "is badly hurt" + /// Simple description, shortened for clarity if defined. Otherwise just takes the normal desc in the analyzer proc. + var/simple_desc + /// Simple analyzer's wound description, which focuses less on the clinical aspect of the wound and more on easily readable treatment instructions. + var/simple_treat_text = "Go to medbay idiot" + /// Improvised remedies indicated by the first aid analyzer only. + var/homemade_treat_text = "Remember to drink lots of water!" + + /// If this wound can generate a scar. var/can_scar = TRUE - /// The file we take our scar descriptions from. - var/scar_file + /// The default file we take our scar descriptions from, if we fail to get the ideal file. + var/default_scar_file /// needed for "your arm has a compound fracture" vs "your arm has some third degree burns" var/a_or_from = "a" @@ -43,10 +56,6 @@ /// Either WOUND_SEVERITY_TRIVIAL (meme wounds like stubbed toe), WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_SEVERE, or WOUND_SEVERITY_CRITICAL (or maybe WOUND_SEVERITY_LOSS) var/severity = WOUND_SEVERITY_MODERATE - /// The type of attack that can generate this wound. E.g. WOUND_SLASH = A sword can cause us, or WOUND_BLUNT = a hammer can cause us/a sword attacking mangled flesh. - var/wound_type - /// The series of wounds this is in. See wounds.dm (the defines file) for a more detailed explanation - but tldr is that no 2 wounds of the same series can be on a limb. - var/wound_series /// Who owns the body part that we're wounding var/mob/living/carbon/victim = null @@ -57,28 +66,26 @@ var/list/treatable_by /// Specific items such as bandages or sutures that can try directly treating this wound only if the user has the victim in an aggressive grab or higher var/list/treatable_by_grabbed - /// Tools with the specified tool flag will also be able to try directly treating this wound - var/treatable_tool + /// Any tools with any of the flags in this list will be usable to try directly treating this wound + var/list/treatable_tools /// How long it will take to treat this wound with a standard effective tool, assuming it doesn't need surgery var/base_treat_time = 5 SECONDS /// Using this limb in a do_after interaction will multiply the length by this duration (arms) var/interaction_efficiency_penalty = 1 /// Incoming damage on this limb will be multiplied by this, to simulate tenderness and vulnerability (mostly burns). - var/damage_mulitplier_penalty = 1 + var/damage_multiplier_penalty = 1 /// If set and this wound is applied to a leg, we take this many deciseconds extra per step on this leg var/limp_slowdown /// If this wound has a limp_slowdown and is applied to a leg, it has this chance to limp each step var/limp_chance /// How much we're contributing to this limb's bleed_rate var/blood_flow - /// Essentially, keeps track of whether or not this wound is capable of bleeding (in case the owner has the NOBLOOD species trait) - var/no_bleeding = FALSE - /// The minimum we need to roll on [/obj/item/bodypart/proc/check_wounding] to begin suffering this wound, see check_wounding_mods() for more - var/threshold_minimum /// How much having this wound will add to all future check_wounding() rolls on this limb, to allow progression to worse injuries with repeated damage var/threshold_penalty + /// How much having this wound will add to all future check_wounding() rolls on this limb, but only for wounds of its own series + var/series_threshold_penalty = 0 /// If we need to process each life tick var/processes = FALSE @@ -89,9 +96,12 @@ var/status_effect_type /// If we're operating on this wound and it gets healed, we'll nix the surgery too var/datum/surgery/attached_surgery - /// if you're a lazy git and just throw them in cryo, the wound will go away after accumulating severity * 25 power + /// if you're a lazy git and just throw them in cryo, the wound will go away after accumulating severity * [base_xadone_progress_to_qdel] power var/cryo_progress + /// The base amount of [cryo_progress] required to have ourselves fully healed by cryo. Multiplied against severity. + var/base_xadone_progress_to_qdel = 33 + /// What kind of scars this wound will create description wise once healed var/scar_keyword = "generic" /// If we've already tried scarring while removing (remove_wound can be called twice in a del chain, let's be nice to our code yeah?) TODO: make this cleaner @@ -102,17 +112,66 @@ /// What flags apply to this wound var/wound_flags = (ACCEPTS_GAUZE) + /// The unique ID of our wound for use with [actionspeed_mod]. Defaults to REF(src). + var/unique_id + /// The actionspeed modifier we will use in case we are on the arms and have a interaction penalty. Qdelled on destroy. + var/datum/actionspeed_modifier/wound_interaction_inefficiency/actionspeed_mod + +/datum/wound/New() + . = ..() + + unique_id = generate_unique_id() + update_actionspeed_modifier() + /datum/wound/Destroy() - if(attached_surgery) - QDEL_NULL(attached_surgery) + QDEL_NULL(attached_surgery) if (limb) remove_wound() + + QDEL_NULL(actionspeed_mod) + return ..() -// Applied into wounds when they're scanned with the wound analyzer, halves time to treat them manually. -#define TRAIT_WOUND_SCANNED "wound_scanned" -// I dunno lol -#define ANALYZER_TRAIT "analyzer_trait" +/// If we should have an actionspeed_mod, ensures we do and updates its slowdown. Otherwise, ensures we dont have one +/// by qdeleting any existing modifier. +/datum/wound/proc/update_actionspeed_modifier() + if (should_have_actionspeed_modifier()) + if (!actionspeed_mod) + generate_actionspeed_modifier() + actionspeed_mod.multiplicative_slowdown = get_effective_actionspeed_modifier() + victim?.update_actionspeed() + else + remove_actionspeed_modifier() + +/// Returns TRUE if we have an interaction_efficiency_penalty, and if we are on the arms, FALSE otherwise. +/datum/wound/proc/should_have_actionspeed_modifier() + return (limb && victim && (limb.body_zone == BODY_ZONE_L_ARM || limb.body_zone == BODY_ZONE_R_ARM) && interaction_efficiency_penalty != 0) + +/// If we have no actionspeed_mod, generates a new one with our unique ID, sets actionspeed_mod to it, then returns it. +/datum/wound/proc/generate_actionspeed_modifier() + RETURN_TYPE(/datum/actionspeed_modifier) + + if (actionspeed_mod) + return actionspeed_mod + + var/datum/actionspeed_modifier/wound_interaction_inefficiency/new_modifier = new /datum/actionspeed_modifier/wound_interaction_inefficiency(unique_id, src) + new_modifier.multiplicative_slowdown = get_effective_actionspeed_modifier() + victim?.add_actionspeed_modifier(new_modifier) + + actionspeed_mod = new_modifier + return actionspeed_mod + +/// If we have an actionspeed_mod, qdels it and sets our ref of it to null. +/datum/wound/proc/remove_actionspeed_modifier() + if (!actionspeed_mod) + return + + victim?.remove_actionspeed_modifier(actionspeed_mod) + QDEL_NULL(actionspeed_mod) + +/// Generates the ID we use for [unique_id], which is also set as our actionspeed mod's ID +/datum/wound/proc/generate_unique_id() + return REF(src) // unique, cannot change, a perfect id /** * apply_wound() is used once a wound type is instantiated to assign it to a bodypart, and actually come into play. @@ -142,7 +201,6 @@ set_limb(L) LAZYADD(victim.all_wounds, src) LAZYADD(limb.wounds, src) - no_bleeding = HAS_TRAIT(victim, TRAIT_NOBLOOD) update_descriptions() limb.update_wounds() if(status_effect_type) @@ -162,7 +220,7 @@ var/msg = span_danger("[victim]'s [limb.plaintext_zone] [occur_text]!") var/vis_dist = COMBAT_MESSAGE_RANGE - if(severity != WOUND_SEVERITY_MODERATE) + if(severity > WOUND_SEVERITY_MODERATE) msg = "[msg]" vis_dist = DEFAULT_MESSAGE_RANGE @@ -183,7 +241,7 @@ // We assume we aren't being randomly applied - we have no reason to believe we are // And, besides, if we were, you could just as easily check our pregen data rather than run this proc // Generally speaking this proc is called in apply_wound, which is called when the caller is already confidant in its ability to be applied - return pregen_data.can_be_applied_to(L, wound_type, old_wound) + return pregen_data.can_be_applied_to(L, old_wound = old_wound) /// Returns the zones we can be applied to. /datum/wound/proc/get_viable_zones() @@ -205,13 +263,66 @@ SIGNAL_HANDLER set_victim(null) +/// Setter for [victim]. Should completely transfer signals, attributes, etc. To the new victim - if there is any, as it can be null. /datum/wound/proc/set_victim(new_victim) if(victim) + UnregisterSignal(victim, list(COMSIG_QDELETING, COMSIG_MOB_SWAP_HANDS, COMSIG_CARBON_POST_REMOVE_LIMB, COMSIG_CARBON_POST_ATTACH_LIMB)) UnregisterSignal(victim, COMSIG_QDELETING) + UnregisterSignal(victim, COMSIG_MOB_SWAP_HANDS) + UnregisterSignal(victim, COMSIG_CARBON_POST_REMOVE_LIMB) + if (actionspeed_mod) + victim.remove_actionspeed_modifier(actionspeed_mod) // no need to qdelete it, just remove it from our victim + remove_wound_from_victim() victim = new_victim if(victim) RegisterSignal(victim, COMSIG_QDELETING, PROC_REF(null_victim)) + RegisterSignals(victim, list(COMSIG_MOB_SWAP_HANDS, COMSIG_CARBON_POST_REMOVE_LIMB, COMSIG_CARBON_POST_ATTACH_LIMB), PROC_REF(add_or_remove_actionspeed_mod)) + + if (limb) + start_limping_if_we_should() // the status effect already handles removing itself + add_or_remove_actionspeed_mod() + +/// Proc called to change the variable `limb` and react to the event. +/datum/wound/proc/set_limb(obj/item/bodypart/new_value, replaced = FALSE) + if(limb == new_value) + return FALSE //Limb can either be a reference to something or `null`. Returning the number variable makes it clear no change was made. + . = limb + if(limb) // if we're nulling limb, we're basically detaching from it, so we should remove ourselves in that case + UnregisterSignal(limb, COMSIG_QDELETING) + UnregisterSignal(limb, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED)) + LAZYREMOVE(limb.wounds, src) + limb.update_wounds(replaced) + if (disabling) + limb.remove_traits(list(TRAIT_PARALYSIS, TRAIT_DISABLED_BY_WOUND), REF(src)) + + limb = new_value + + // POST-CHANGE + + if (limb) + RegisterSignal(limb, COMSIG_QDELETING, PROC_REF(source_died)) + RegisterSignals(limb, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED), PROC_REF(gauze_state_changed)) + if (disabling) + limb.add_traits(list(TRAIT_PARALYSIS, TRAIT_DISABLED_BY_WOUND), REF(src)) + + if (victim) + start_limping_if_we_should() // the status effect already handles removing itself + add_or_remove_actionspeed_mod() + + update_inefficiencies(replaced) + +/datum/wound/proc/add_or_remove_actionspeed_mod() + update_actionspeed_modifier() + if (actionspeed_mod) + if(victim.get_active_hand() == limb) + victim.add_actionspeed_modifier(actionspeed_mod, TRUE) + else + victim.remove_actionspeed_modifier(actionspeed_mod) + +/datum/wound/proc/start_limping_if_we_should() + if ((limb.body_zone == BODY_ZONE_L_LEG || limb.body_zone == BODY_ZONE_R_LEG) && limp_slowdown > 0 && limp_chance > 0) + victim.apply_status_effect(/datum/status_effect/limp) /datum/wound/proc/source_died() SIGNAL_HANDLER @@ -220,18 +331,27 @@ /// Remove the wound from whatever it's afflicting, and cleans up whateverstatus effects it had or modifiers it had on interaction times. ignore_limb is used for detachments where we only want to forget the victim /datum/wound/proc/remove_wound(ignore_limb, replaced = FALSE) //TODO: have better way to tell if we're getting removed without replacement (full heal) scar stuff + var/old_victim = victim + var/old_limb = limb + set_disabling(FALSE) if(limb && can_scar && !already_scarred && !replaced) already_scarred = TRUE var/datum/scar/new_scar = new new_scar.generate(limb, src) + remove_actionspeed_modifier() + null_victim() // we use the proc here because some behaviors may depend on changing victim to some new value if(limb && !ignore_limb) set_limb(null, replaced) // since we're removing limb's ref to us, we should do the same // if you want to keep the ref, do it externally, theres no reason for us to remember it + if (ismob(old_victim)) + var/mob/mob_victim = old_victim + SEND_SIGNAL(mob_victim, COMSIG_CARBON_POST_LOSE_WOUND, src, old_limb, ignore_limb, replaced) + /datum/wound/proc/remove_wound_from_victim() if(!victim) return @@ -259,28 +379,6 @@ /datum/wound/proc/wound_injury(datum/wound/old_wound = null, attack_direction = null) return -/// Proc called to change the variable `limb` and react to the event. -/datum/wound/proc/set_limb(obj/item/bodypart/new_value, replaced = FALSE) - if(limb == new_value) - return FALSE //Limb can either be a reference to something or `null`. Returning the number variable makes it clear no change was made. - . = limb - if(limb) // if we're nulling limb, we're basically detaching from it, so we should remove ourselves in that case - UnregisterSignal(limb, COMSIG_QDELETING) - LAZYREMOVE(limb.wounds, src) - limb.update_wounds(replaced) - if (disabling) - limb.remove_traits(list(TRAIT_PARALYSIS, TRAIT_DISABLED_BY_WOUND), REF(src)) - - limb = new_value - - // POST-CHANGE - - if (limb) - RegisterSignal(limb, COMSIG_QDELETING, PROC_REF(source_died)) - if(limb) - if(disabling) - limb.add_traits(list(TRAIT_PARALYSIS, TRAIT_DISABLED_BY_WOUND), REF(src)) - /// Proc called to change the variable `disabling` and react to the event. /datum/wound/proc/set_disabling(new_value) if(disabling == new_value) @@ -295,6 +393,60 @@ if(limb?.can_be_disabled) limb.update_disabled() +/// Setter for [interaction_efficiency_penalty]. Updates the actionspeed of our actionspeed mod. +/datum/wound/proc/set_interaction_efficiency_penalty(new_value) + var/should_update = (new_value != interaction_efficiency_penalty) + + interaction_efficiency_penalty = new_value + + if (should_update) + update_actionspeed_modifier() + +/// Returns a "adjusted" interaction_efficiency_penalty that will be used for the actionspeed mod. +/datum/wound/proc/get_effective_actionspeed_modifier() + return interaction_efficiency_penalty - 1 + +/// Returns the decisecond multiplier of any click interactions, assuming our limb is being used. +/datum/wound/proc/get_action_delay_mult() + SHOULD_BE_PURE(TRUE) + + return interaction_efficiency_penalty + +/// Returns the decisecond increment of any click interactions, assuming our limb is being used. +/datum/wound/proc/get_action_delay_increment() + SHOULD_BE_PURE(TRUE) + + return 0 + +/// Signal proc for if gauze has been applied or removed from our limb. +/datum/wound/proc/gauze_state_changed() + SIGNAL_HANDLER + + if (wound_flags & ACCEPTS_GAUZE) + update_inefficiencies() + +/// Updates our limping and interaction penalties in accordance with our gauze. +/datum/wound/proc/update_inefficiencies(replaced_or_replacing = FALSE) + if (wound_flags & ACCEPTS_GAUZE) + if(limb.body_zone in list(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) + if(limb.current_gauze?.splint_factor) + limp_slowdown = initial(limp_slowdown) * limb.current_gauze.splint_factor + limp_chance = initial(limp_chance) * limb.current_gauze.splint_factor + else + limp_slowdown = initial(limp_slowdown) + limp_chance = initial(limp_chance) + else if(limb.body_zone in list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) + if(limb.current_gauze?.splint_factor) + set_interaction_efficiency_penalty(1 + ((get_effective_actionspeed_modifier()) * limb.current_gauze.splint_factor)) + else + set_interaction_efficiency_penalty(initial(interaction_efficiency_penalty)) + + if(initial(disabling)) + set_disabling(!limb.current_gauze) + + limb.update_wounds(replaced_or_replacing) + + start_limping_if_we_should() /// Additional beneficial effects when the wound is gained, in case you want to give a temporary boost to allow the victim to try an escape or last stand /datum/wound/proc/second_wind() @@ -349,9 +501,9 @@ /// Returns TRUE if the item can be used to treat our wounds. Hooks into treat() - only things that return TRUE here may be used there. /datum/wound/proc/item_can_treat(obj/item/potential_treater, mob/user) // check if we have a valid treatable tool - if(potential_treater.tool_behaviour == treatable_tool) + if(potential_treater.tool_behaviour in treatable_tools) return TRUE - if(treatable_tool == TOOL_CAUTERY && potential_treater.get_temperature() && user == victim) // allow improvised cauterization on yourself without an aggro grab + if(TOOL_CAUTERY in treatable_tools && potential_treater.get_temperature() && user == victim) // allow improvised cauterization on yourself without an aggro grab return TRUE // failing that, see if we're aggro grabbing them and if we have an item that works for aggro grabs only if(user.pulling == victim && user.grab_state >= GRAB_AGGRESSIVE && check_grab_treatments(potential_treater, user)) @@ -388,11 +540,22 @@ /// Called from cryoxadone and pyroxadone when they're proc'ing. Wounds will slowly be fixed separately from other methods when these are in effect. crappy name but eh /datum/wound/proc/on_xadone(power) cryo_progress += power - if(cryo_progress > 33 * severity) + + return handle_xadone_progress() + +/// Does various actions based on [cryo_progress]. By default, qdeletes the wound past a certain threshold. +/datum/wound/proc/handle_xadone_progress() + if(cryo_progress > get_xadone_progress_to_qdel()) qdel(src) +/// Returns the amount of [cryo_progress] we need to be qdeleted. +/datum/wound/proc/get_xadone_progress_to_qdel() + SHOULD_BE_PURE(TRUE) + + return base_xadone_progress_to_qdel * severity + /// When synthflesh is applied to the victim, we call this. No sense in setting up an entire chem reaction system for wounds when we only care for a few chems. Probably will change in the future -/datum/wound/proc/on_synthflesh(power) +/datum/wound/proc/on_synthflesh(reac_volume) return /// Called when the patient is undergoing stasis, so that having fully treated a wound doesn't make you sit there helplessly until you think to unbuckle them @@ -486,19 +649,21 @@ return "[desc]." /datum/wound/proc/get_scanner_description(mob/user) - return "Type: [name]\nSeverity: [severity_text()]\nDescription: [desc]\nRecommended Treatment: [treat_text]" + return "Type: [name]\nSeverity: [severity_text(simple = FALSE)]\nDescription: [desc]\nRecommended Treatment: [treat_text]" + +/datum/wound/proc/get_simple_scanner_description(mob/user) + return "[name] detected!\nRisk: [severity_text(simple = TRUE)]\nDescription: [simple_desc ? simple_desc : desc]\nTreatment Guide: [simple_treat_text]\nHomemade Remedies: [homemade_treat_text]" -/datum/wound/proc/severity_text() +/datum/wound/proc/severity_text(simple = FALSE) switch(severity) if(WOUND_SEVERITY_TRIVIAL) return "Trivial" if(WOUND_SEVERITY_MODERATE) - return "Moderate" + return "Moderate" + (simple ? "!" : "") if(WOUND_SEVERITY_SEVERE) - return "Severe" + return "Severe" + (simple ? "!!" : "") if(WOUND_SEVERITY_CRITICAL) - return "Critical" - + return "Critical" + (simple ? "!!!" : "") /// Returns TRUE if our limb is the head or chest, FALSE otherwise. /// Essential in the sense of "we cannot live without it". @@ -511,7 +676,17 @@ /// Getter proc for our scar_file, in case we might have some custom scar gen logic. /datum/wound/proc/get_scar_file(obj/item/bodypart/scarred_limb, add_to_scars) - return scar_file + var/datum/wound_pregen_data/pregen_data = get_pregen_data() + // basically we iterate over biotypes until we find the one we want + // fleshy burns will look for flesh then bone + // dislocations will look for flesh, then bone, then metal + var/file = default_scar_file + for (var/biotype as anything in pregen_data.scar_priorities) + if (scarred_limb.biological_state & text2num(biotype)) + file = GLOB.biotypes_to_scar_file[biotype] + break + + return file /// Returns what string is displayed when a limb that has sustained this wound is examined /// (This is examining the LIMB ITSELF, when it's not attached to someone.) @@ -522,7 +697,17 @@ /datum/wound/proc/get_dismember_chance_bonus(existing_chance) SHOULD_BE_PURE(TRUE) - if (wound_type == WOUND_BLUNT && severity >= WOUND_SEVERITY_CRITICAL) + var/datum/wound_pregen_data/pregen_data = get_pregen_data() + + if (WOUND_BLUNT in pregen_data.required_wounding_types && severity >= WOUND_SEVERITY_CRITICAL) return WOUND_CRITICAL_BLUNT_DISMEMBER_BONUS // we only require mangled bone (T2 blunt), but if there's a critical blunt, we'll add 15% more +/// Returns our pregen data, which is practically guaranteed to exist, so this proc can safely be used raw. +/// In fact, since it's RETURN_TYPEd to wound_pregen_data, you can even directly access the variables without having to store the value of this proc in a typed variable. +/// Ex. get_pregen_data().wound_series +/datum/wound/proc/get_pregen_data() + RETURN_TYPE(/datum/wound_pregen_data) + + return GLOB.all_wound_pregen_data[type] + #undef WOUND_CRITICAL_BLUNT_DISMEMBER_BONUS diff --git a/code/datums/wounds/blunt.dm b/code/datums/wounds/blunt.dm index 8a9c34e163d859..219b7dd8805c14 100644 --- a/code/datums/wounds/blunt.dm +++ b/code/datums/wounds/blunt.dm @@ -1,4 +1,3 @@ /datum/wound/blunt name = "Blunt Wound" sound_effect = 'sound/effects/wounds/crack1.ogg' - wound_type = WOUND_BLUNT diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm index eed0fb1d883efe..59e64db1ccf3d6 100644 --- a/code/datums/wounds/bones.dm +++ b/code/datums/wounds/bones.dm @@ -7,11 +7,15 @@ abstract = TRUE required_limb_biostate = BIO_BONE + required_wounding_types = list(WOUND_BLUNT) + + wound_series = WOUND_SERIES_BONE_BLUNT_BASIC + /datum/wound/blunt/bone name = "Blunt (Bone) Wound" wound_flags = (ACCEPTS_GAUZE | SPLINT_OVERLAY) // SKYRAT EDIT: MEDICAL -- Makes bone wounds have a splint overlay - scar_file = BONE_SCAR_FILE + default_scar_file = BONE_SCAR_FILE /// Have we been bone gel'd? var/gelled @@ -32,8 +36,6 @@ /// If this is a chest wound and this is set, we have this chance to cough up blood when hit in the chest var/internal_bleeding_chance = 0 - wound_series = WOUND_SERIES_BONE_BLUNT_BASIC - /* Overwriting of base procs */ @@ -64,14 +66,6 @@ return ..() -/datum/wound/blunt/bone/set_limb(obj/item/bodypart/new_value) - if (limb) - UnregisterSignal(limb, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED)) - if (new_value) - RegisterSignals(new_value, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED), PROC_REF(update_inefficiencies)) - - return ..() - /datum/wound/blunt/bone/remove_wound(ignore_limb, replaced) limp_slowdown = 0 limp_chance = 0 @@ -179,28 +173,6 @@ New common procs for /datum/wound/blunt/bone/ */ -/datum/wound/blunt/bone/proc/update_inefficiencies() - SIGNAL_HANDLER - - if(limb.body_zone in list(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) - if(limb.current_gauze?.splint_factor) - limp_slowdown = initial(limp_slowdown) * limb.current_gauze.splint_factor - limp_chance = initial(limp_chance) * limb.current_gauze.splint_factor - else - limp_slowdown = initial(limp_slowdown) - limp_chance = initial(limp_chance) - victim.apply_status_effect(/datum/status_effect/limp) - else if(limb.body_zone in list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) - if(limb.current_gauze?.splint_factor) - interaction_efficiency_penalty = 1 + ((interaction_efficiency_penalty - 1) * limb.current_gauze.splint_factor) - else - interaction_efficiency_penalty = initial(interaction_efficiency_penalty) - - if(initial(disabling)) - set_disabling(!limb.current_gauze) - - limb.update_wounds() - /datum/wound/blunt/bone/get_scar_file(obj/item/bodypart/scarred_limb, add_to_scars) if (scarred_limb.biological_state & BIO_BONE && (!(scarred_limb.biological_state & BIO_FLESH))) // only bone return BONE_SCAR_FILE @@ -220,11 +192,14 @@ interaction_efficiency_penalty = 1.3 limp_slowdown = 3 limp_chance = 50 - threshold_minimum = 35 threshold_penalty = 15 - treatable_tool = TOOL_BONESET + treatable_tools = list(TOOL_BONESET) status_effect_type = /datum/status_effect/wound/blunt/bone/moderate - scar_keyword = "bluntmoderate" + scar_keyword = "dislocate" + + simple_desc = "Patient's bone has been dislocated, causing limping or reduced dexterity." + simple_treat_text = "Bandaging the wound will reduce its impact until treated with a bonesetter. Most commonly, it is treated by aggressively grabbing someone and helpfully wrenching the limb in place, though there's room for malfeasance when doing this." + homemade_treat_text = "Besides bandaging and wrenching, bone setters can be printed in lathes and utilized on oneself at the cost of great pain. As a last resort, crushing the patient with a firelock has sometimes been noted to fix their dislocated limb." /datum/wound_pregen_data/bone/dislocate abstract = FALSE @@ -233,6 +208,8 @@ required_limb_biostate = BIO_JOINTED + threshold_minimum = 35 + /datum/wound/blunt/bone/moderate/Destroy() if(victim) UnregisterSignal(victim, COMSIG_LIVING_DOORCRUSHED) @@ -349,7 +326,6 @@ interaction_efficiency_penalty = 2 limp_slowdown = 6 limp_chance = 60 - threshold_minimum = 60 threshold_penalty = 30 treatable_by = list(/obj/item/stack/sticky_tape/surgical, /obj/item/stack/medical/bone_gel) status_effect_type = /datum/status_effect/wound/blunt/bone/severe @@ -357,14 +333,21 @@ brain_trauma_group = BRAIN_TRAUMA_MILD trauma_cycle_cooldown = 1.5 MINUTES internal_bleeding_chance = 40 - wound_flags = (ACCEPTS_GAUZE | MANGLES_BONE | SPLINT_OVERLAY) // SKYRAT EDIT - MEDICAL (SPLINT_OVERLAY) + wound_flags = (ACCEPTS_GAUZE | MANGLES_INTERIOR | SPLINT_OVERLAY) // SKYRAT EDIT - MEDICAL (SPLINT_OVERLAY) regen_ticks_needed = 120 // ticks every 2 seconds, 240 seconds, so roughly 4 minutes default + simple_desc = "Patient's bone has cracked in the middle, drastically reducing limb functionality." + simple_treat_text = "Bandaging the wound will reduce its impact until surgically treated with bone gel and surgical tape." + homemade_treat_text = "Bone gel and surgical tape may be applied directly to the wound, though this is quite difficult for most people to do so individually unless they've dosed themselves with one or more painkillers (Morphine and Miner's Salve have been known to help)" + + /datum/wound_pregen_data/bone/hairline abstract = FALSE wound_path_to_generate = /datum/wound/blunt/bone/severe + threshold_minimum = 60 + /// Compound Fracture (Critical Blunt) /datum/wound/blunt/bone/critical name = "Compound Fracture" @@ -378,7 +361,6 @@ limp_slowdown = 7 limp_chance = 70 sound_effect = 'sound/effects/wounds/crack2.ogg' - threshold_minimum = 115 threshold_penalty = 50 disabling = TRUE treatable_by = list(/obj/item/stack/sticky_tape/surgical, /obj/item/stack/medical/bone_gel) @@ -387,14 +369,20 @@ brain_trauma_group = BRAIN_TRAUMA_SEVERE trauma_cycle_cooldown = 2.5 MINUTES internal_bleeding_chance = 60 - wound_flags = (ACCEPTS_GAUZE | MANGLES_BONE | SPLINT_OVERLAY) // SKYRAT EDIT - MEDICAL (SPLINT_OVERLAY) + wound_flags = (ACCEPTS_GAUZE | MANGLES_INTERIOR | SPLINT_OVERLAY) // SKYRAT EDIT - MEDICAL (SPLINT_OVERLAY) regen_ticks_needed = 240 // ticks every 2 seconds, 480 seconds, so roughly 8 minutes default + simple_desc = "Patient's bones have effectively shattered completely, causing total immobilization of the limb." + simple_treat_text = "Bandaging the wound will slightly reduce its impact until surgically treated with bone gel and surgical tape." + homemade_treat_text = "Although this is extremely difficult and slow to function, Bone gel and surgical tape may be applied directly to the wound, though this is nigh-impossible for most people to do so individually unless they've dosed themselves with one or more painkillers (Morphine and Miner's Salve have been known to help)" + /datum/wound_pregen_data/bone/compound abstract = FALSE wound_path_to_generate = /datum/wound/blunt/bone/critical + threshold_minimum = 115 + // doesn't make much sense for "a" bone to stick out of your head /datum/wound/blunt/bone/critical/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE, attack_direction = null, wound_source = "Unknown") if(L.body_zone == BODY_ZONE_HEAD) diff --git a/code/datums/wounds/burns.dm b/code/datums/wounds/burns.dm index 7ef1cd68268c0c..a97706c8e16d8d 100644 --- a/code/datums/wounds/burns.dm +++ b/code/datums/wounds/burns.dm @@ -6,28 +6,24 @@ /datum/wound/burn name = "Burn Wound" a_or_from = "from" - wound_type = WOUND_BURN sound_effect = 'sound/effects/wounds/sizzle1.ogg' /datum/wound/burn/flesh name = "Burn (Flesh) Wound" a_or_from = "from" - wound_type = WOUND_BURN processes = TRUE - scar_file = FLESH_SCAR_FILE - - wound_series = WOUND_SERIES_FLESH_BURN_BASIC + default_scar_file = FLESH_SCAR_FILE treatable_by = list(/obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh) // sterilizer and alcohol will require reagent treatments, coming soon - // Flesh damage vars + // Flesh damage vars /// How much damage to our flesh we currently have. Once both this and infestation reach 0, the wound is considered healed var/flesh_damage = 5 /// Our current counter for how much flesh regeneration we have stacked from regenerative mesh/synthflesh/whatever, decrements each tick and lowers flesh_damage var/flesh_healing = 0 - // Infestation vars (only for severe and critical) + // Infestation vars (only for severe and critical) /// How quickly infection breeds on this burn if we don't have disinfectant var/infestation_rate = 0 /// Our current level of infection @@ -50,14 +46,12 @@ victim.visible_message(span_danger("The infection on the remnants of [victim]'s [limb.plaintext_zone] shift and bubble nauseatingly!"), span_warning("You can feel the infection on the remnants of your [limb.plaintext_zone] coursing through your veins!"), vision_distance = COMBAT_MESSAGE_RANGE) return - if(victim.reagents) - if(HAS_TRAIT(victim, TRAIT_VIRUS_RESISTANCE)) - sanitization += 0.9 - if(victim.reagents.has_reagent(/datum/reagent/space_cleaner/sterilizine/)) - sanitization += 0.9 - if(victim.reagents.has_reagent(/datum/reagent/medicine/mine_salve)) - sanitization += 0.3 - flesh_healing += 0.5 + for(var/datum/reagent/reagent as anything in victim.reagents.reagent_list) + if(reagent.chemical_flags & REAGENT_AFFECTS_WOUNDS) + reagent.on_burn_wound_processing() + + if(HAS_TRAIT(victim, TRAIT_VIRUS_RESISTANCE)) + sanitization += 0.9 if(limb.current_gauze) limb.seep_gauze(WOUND_BURN_SANITIZATION_RATE * seconds_per_tick) @@ -265,14 +259,17 @@ if(sanitization > 0) infestation = max(infestation - (0.1 * WOUND_BURN_SANITIZATION_RATE * seconds_per_tick), 0) -/datum/wound/burn/flesh/on_synthflesh(amount) - flesh_healing += amount * 0.5 // 20u patch will heal 10 flesh standard +/datum/wound/burn/flesh/on_synthflesh(reac_volume) + flesh_healing += reac_volume * 0.5 // 20u patch will heal 10 flesh standard /datum/wound_pregen_data/flesh_burn abstract = TRUE + required_wounding_types = list(WOUND_BURN) required_limb_biostate = BIO_FLESH + wound_series = WOUND_SERIES_FLESH_BURN_BASIC + /datum/wound/burn/get_limb_examine_description() return span_warning("The flesh on this limb appears badly cooked.") @@ -284,18 +281,23 @@ examine_desc = "is badly burned and breaking out in blisters" occur_text = "breaks out with violent red burns" severity = WOUND_SEVERITY_MODERATE - damage_mulitplier_penalty = 1.1 - threshold_minimum = 40 + damage_multiplier_penalty = 1.1 threshold_penalty = 30 // burns cause significant decrease in limb integrity compared to other wounds status_effect_type = /datum/status_effect/wound/burn/flesh/moderate flesh_damage = 5 scar_keyword = "burnmoderate" + simple_desc = "Patient's skin is burned, weakening the limb and multiplying percieved damage!" + simple_treat_text = "Ointment will speed up recovery, as will regenerative mesh. Risk of infection is negligible." + homemade_treat_text = "Healthy tea will speed up recovery. Salt, or preferably a salt-water mixture, will sanitize the wound, but the former will cause skin irritation, increasing the risk of infection." + /datum/wound_pregen_data/flesh_burn/second_degree abstract = FALSE wound_path_to_generate = /datum/wound/burn/flesh/moderate + threshold_minimum = 40 + /datum/wound/burn/flesh/severe name = "Third Degree Burns" desc = "Patient is suffering extreme burns with full skin penetration, creating serious risk of infection and greatly reduced limb integrity." @@ -303,8 +305,7 @@ examine_desc = "appears seriously charred, with aggressive red splotches" occur_text = "chars rapidly, exposing ruined tissue and spreading angry red burns" severity = WOUND_SEVERITY_SEVERE - damage_mulitplier_penalty = 1.2 - threshold_minimum = 80 + damage_multiplier_penalty = 1.2 threshold_penalty = 40 status_effect_type = /datum/status_effect/wound/burn/flesh/severe treatable_by = list(/obj/item/flashlight/pen/paramedic, /obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh) @@ -312,11 +313,17 @@ flesh_damage = 12.5 scar_keyword = "burnsevere" + simple_desc = "Patient's skin is badly burned, significantly weakening the limb and compounding further damage!!" + simple_treat_text = "Bandages will speed up recovery, as will ointment or regenerative mesh. Spaceacilin, sterilizine, and 'Miner's Salve' will help with infection." + homemade_treat_text = "Healthy tea will speed up recovery. Salt, or preferably a salt-water mixture, will sanitize the wound, but the former especially will cause skin irritation and dehydration, speeding up infection. Space Cleaner can be used as disinfectant in a pinch." + /datum/wound_pregen_data/flesh_burn/third_degree abstract = FALSE wound_path_to_generate = /datum/wound/burn/flesh/severe + threshold_minimum = 80 + /datum/wound/burn/flesh/critical name = "Catastrophic Burns" desc = "Patient is suffering near complete loss of tissue and significantly charred muscle and bone, creating life-threatening risk of infection and negligible limb integrity." @@ -324,9 +331,8 @@ examine_desc = "is a ruined mess of blanched bone, melted fat, and charred tissue" occur_text = "vaporizes as flesh, bone, and fat melt together in a horrifying mess" severity = WOUND_SEVERITY_CRITICAL - damage_mulitplier_penalty = 1.3 + damage_multiplier_penalty = 1.3 sound_effect = 'sound/effects/wounds/sizzle2.ogg' - threshold_minimum = 140 threshold_penalty = 80 status_effect_type = /datum/status_effect/wound/burn/flesh/critical treatable_by = list(/obj/item/flashlight/pen/paramedic, /obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh) @@ -334,25 +340,32 @@ flesh_damage = 20 scar_keyword = "burncritical" + simple_desc = "Patient's skin is destroyed and tissue charred, leaving the limb with almost no integrity and a drastic chance of infection!!!" + simple_treat_text = "Immediately bandage the wound and treat it with ointment or regenerative mesh. Spaceacilin, sterilizine, or 'Miner's Salve' will stave off infection. Seek professional care immediately, before sepsis sets in and the wound becomes untreatable." + homemade_treat_text = "Healthy tea will help with recovery. A salt-water mixture, topically applied, might help stave off infection in the short term, but pure table salt is NOT recommended. Space Cleaner can be used as disinfectant in a pinch." + /datum/wound_pregen_data/flesh_burn/fourth_degree abstract = FALSE wound_path_to_generate = /datum/wound/burn/flesh/critical + threshold_minimum = 140 + ///special severe wound caused by sparring interference or other god related punishments. /datum/wound/burn/flesh/severe/brand name = "Holy Brand" desc = "Patient is suffering extreme burns from a strange brand marking, creating serious risk of infection and greatly reduced limb integrity." examine_desc = "appears to have holy symbols painfully branded into their flesh, leaving severe burns." occur_text = "chars rapidly into a strange pattern of holy symbols, burned into the flesh." + simple_desc = "Patient's skin has had strange markings burned onto it, significantly weakening the limb and compounding further damage!!" -/datum/wound_pregen_data/flesh_burn/holy +/datum/wound_pregen_data/flesh_burn/third_degree/holy abstract = FALSE can_be_randomly_generated = FALSE wound_path_to_generate = /datum/wound/burn/flesh/severe/brand -/// special severe wound caused by the cursed slot machine. +/// special severe wound caused by the cursed slot machine. /datum/wound/burn/flesh/severe/cursed_brand name = "Ancient Brand" desc = "Patient is suffering extreme burns with oddly ornate brand markings, creating serious risk of infection and greatly reduced limb integrity." @@ -362,7 +375,7 @@ /datum/wound/burn/flesh/severe/cursed_brand/get_limb_examine_description() return span_warning("The flesh on this limb has several ornate symbols burned into it, with pitting throughout.") -/datum/wound_pregen_data/flesh_burn/cursed_brand +/datum/wound_pregen_data/flesh_burn/third_degree/cursed_brand abstract = FALSE can_be_randomly_generated = FALSE diff --git a/code/datums/wounds/loss.dm b/code/datums/wounds/loss.dm index d396b3a469f98f..4fb5cad387f122 100644 --- a/code/datums/wounds/loss.dm +++ b/code/datums/wounds/loss.dm @@ -3,7 +3,13 @@ wound_path_to_generate = /datum/wound/loss required_limb_biostate = NONE - check_for_any = TRUE + require_any_biostate = TRUE + + required_wounding_types = list(WOUND_ALL) + + wound_series = WOUND_SERIES_LOSS_BASIC + + threshold_minimum = WOUND_DISMEMBER_OUTRIGHT_THRESH // not actually used since dismembering is handled differently, but may as well assign it since we got it /datum/wound/loss name = "Dismemberment Wound" @@ -11,14 +17,13 @@ sound_effect = 'sound/effects/dismember.ogg' severity = WOUND_SEVERITY_LOSS - threshold_minimum = WOUND_DISMEMBER_OUTRIGHT_THRESH // not actually used since dismembering is handled differently, but may as well assign it since we got it status_effect_type = null scar_keyword = "dismember" wound_flags = null already_scarred = TRUE // We manually assign scars for dismembers through endround missing limbs and aheals - /// The wound_type of the attack that caused us. Used to generate the description of our scar. Currently unused, but primarily exists in case non-biological wounds are added. - var/loss_wound_type + /// The wounding_type of the attack that caused us. Used to generate the description of our scar. Currently unused, but primarily exists in case non-biological wounds are added. + var/loss_wounding_type /// Our special proc for our special dismembering, the wounding type only matters for what text we have /datum/wound/loss/proc/apply_dismember(obj/item/bodypart/dismembered_part, wounding_type = WOUND_SLASH, outright = FALSE, attack_direction) @@ -39,14 +44,14 @@ victim.visible_message(msg, span_userdanger("Your [dismembered_part.plaintext_zone] [self_msg ? self_msg : occur_text]")) - loss_wound_type = wounding_type + loss_wounding_type = wounding_type set_limb(dismembered_part) second_wind() log_wound(victim, src) if(dismembered_part.can_bleed() && wounding_type != WOUND_BURN && victim.blood_volume) victim.spray_blood(attack_direction, severity) - dismembered_part.dismember(wounding_type == WOUND_BURN ? BURN : BRUTE, wound_type = wounding_type) + dismembered_part.dismember(wounding_type == WOUND_BURN ? BURN : BRUTE, wounding_type = wounding_type) qdel(src) return TRUE @@ -64,17 +69,8 @@ if(WOUND_BURN) occur_text = "is outright incinerated, falling to dust!" else - var/bone_text - if (biological_state & BIO_BONE) - bone_text = "bone" - else if (biological_state & BIO_METAL) - bone_text = "metal" - - var/tissue_text - if (biological_state & BIO_FLESH) - tissue_text = "flesh" - else if (biological_state & BIO_WIRED) - tissue_text = "wire" + var/bone_text = get_internal_description() + var/tissue_text = get_external_description() switch(wounding_type) if(WOUND_BLUNT) @@ -87,11 +83,3 @@ occur_text = "is completely incinerated, falling to dust!" return occur_text - -/datum/wound/loss/get_scar_file(obj/item/bodypart/scarred_limb, add_to_scars) - if (scarred_limb.biological_state & BIO_FLESH) - return FLESH_SCAR_FILE - if (scarred_limb.biological_state & BIO_BONE) - return BONE_SCAR_FILE - - return ..() diff --git a/code/datums/wounds/pierce.dm b/code/datums/wounds/pierce.dm index 72b9b3f2846b85..ec166584632fb9 100644 --- a/code/datums/wounds/pierce.dm +++ b/code/datums/wounds/pierce.dm @@ -2,20 +2,17 @@ Piercing wounds */ /datum/wound/pierce - wound_type = WOUND_PIERCE /datum/wound/pierce/bleed name = "Piercing Wound" sound_effect = 'sound/weapons/slice.ogg' processes = TRUE treatable_by = list(/obj/item/stack/medical/suture) - treatable_tool = TOOL_CAUTERY + treatable_tools = list(TOOL_CAUTERY) base_treat_time = 3 SECONDS - wound_flags = (ACCEPTS_GAUZE) + wound_flags = (ACCEPTS_GAUZE | CAN_BE_GRASPED) - wound_series = WOUND_SERIES_FLESH_PUNCTURE_BLEED - - scar_file = FLESH_SCAR_FILE + default_scar_file = FLESH_SCAR_FILE /// How much blood we start losing when this wound is first applied var/initial_flow @@ -29,13 +26,13 @@ /datum/wound/pierce/bleed/wound_injury(datum/wound/old_wound = null, attack_direction = null) set_blood_flow(initial_flow) - if(!no_bleeding && attack_direction && victim.blood_volume > BLOOD_VOLUME_OKAY) + if(limb.can_bleed() && attack_direction && victim.blood_volume > BLOOD_VOLUME_OKAY) victim.spray_blood(attack_direction, severity) return ..() /datum/wound/pierce/bleed/receive_damage(wounding_type, wounding_dmg, wound_bonus) - if(victim.stat == DEAD || (wounding_dmg < 5) || no_bleeding || !victim.blood_volume || !prob(internal_bleeding_chance + wounding_dmg)) + if(victim.stat == DEAD || (wounding_dmg < 5) || !limb.can_bleed() || !victim.blood_volume || !prob(internal_bleeding_chance + wounding_dmg)) return if(limb.current_gauze?.splint_factor) wounding_dmg *= (1 - limb.current_gauze.splint_factor) @@ -58,7 +55,7 @@ /datum/wound/pierce/bleed/get_bleed_rate_of_change() //basically if a species doesn't bleed, the wound is stagnant and will not heal on it's own (nor get worse) - if(no_bleeding) + if(!limb.can_bleed()) return BLOOD_FLOW_STEADY if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS)) return BLOOD_FLOW_INCREASING @@ -72,7 +69,7 @@ set_blood_flow(min(blood_flow, WOUND_SLASH_MAX_BLOODFLOW)) - if(!no_bleeding) + if(limb.can_bleed()) if(victim.bodytemperature < (BODYTEMP_NORMAL - 10)) adjust_blood_flow(-0.1 * seconds_per_tick) if(SPT_PROB(2.5, seconds_per_tick)) @@ -109,9 +106,9 @@ if (limb) // parent can cause us to be removed, so its reasonable to check if we're still applied adjust_blood_flow(-0.03 * power) // i think it's like a minimum of 3 power, so .09 blood_flow reduction per tick is pretty good for 0 effort -/datum/wound/pierce/bleed/on_synthflesh(power) +/datum/wound/pierce/bleed/on_synthflesh(reac_volume) . = ..() - adjust_blood_flow(-0.025 * power) // 20u * 0.05 = -1 blood flow, less than with slashes but still good considering smaller bleed rates + adjust_blood_flow(-0.025 * reac_volume) // 20u * 0.05 = -1 blood flow, less than with slashes but still good considering smaller bleed rates /// If someone is using a suture to close this puncture /datum/wound/pierce/bleed/proc/suture(obj/item/stack/medical/suture/I, mob/user) @@ -126,7 +123,7 @@ if(!do_after(user, treatment_delay, target = victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)))) return TRUE - var/bleeding_wording = (no_bleeding ? "holes" : "bleeding") + var/bleeding_wording = (!limb.can_bleed() ? "holes" : "bleeding") user.visible_message(span_green("[user] stitches up some of the [bleeding_wording] on [victim]."), span_green("You stitch up some of the [bleeding_wording] on [user == victim ? "yourself" : "[victim]"].")) var/blood_sutured = I.stop_bleeding / self_penalty_mult adjust_blood_flow(-blood_sutured) @@ -156,7 +153,7 @@ if(!do_after(user, treatment_delay, target = victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)))) return TRUE - var/bleeding_wording = (no_bleeding ? "holes" : "bleeding") + var/bleeding_wording = (!limb.can_bleed() ? "holes" : "bleeding") user.visible_message(span_green("[user] cauterizes some of the [bleeding_wording] on [victim]."), span_green("You cauterize some of the [bleeding_wording] on [victim].")) limb.receive_damage(burn = 2 + severity, wound_bonus = CANT_WOUND) if(prob(30)) @@ -172,6 +169,9 @@ abstract = TRUE required_limb_biostate = (BIO_FLESH) + required_wounding_types = list(WOUND_PIERCE) + + wound_series = WOUND_SERIES_FLESH_PUNCTURE_BLEED /datum/wound/pierce/get_limb_examine_description() return span_warning("The flesh on this limb appears badly perforated.") @@ -188,18 +188,22 @@ gauzed_clot_rate = 0.8 internal_bleeding_chance = 30 internal_bleeding_coefficient = 1.25 - threshold_minimum = 30 threshold_penalty = 20 status_effect_type = /datum/status_effect/wound/pierce/moderate scar_keyword = "piercemoderate" + simple_treat_text = "Bandaging the wound will reduce blood loss, help the wound close by itself quicker, and speed up the blood recovery period. The wound itself can be slowly sutured shut." + homemade_treat_text = "Tea stimulates the body's natural healing systems, slightly fastening clotting. The wound itself can be rinsed off on a sink or shower as well. Other remedies are unnecessary." + /datum/wound_pregen_data/flesh_pierce/breakage abstract = FALSE wound_path_to_generate = /datum/wound/pierce/bleed/moderate + threshold_minimum = 30 + /datum/wound/pierce/bleed/moderate/update_descriptions() - if(no_bleeding) + if(!limb.can_bleed()) examine_desc = "has a small, circular hole" occur_text = "splits a small hole open" @@ -215,18 +219,22 @@ gauzed_clot_rate = 0.6 internal_bleeding_chance = 60 internal_bleeding_coefficient = 1.5 - threshold_minimum = 50 threshold_penalty = 35 status_effect_type = /datum/status_effect/wound/pierce/severe scar_keyword = "piercesevere" + simple_treat_text = "Bandaging the wound is essential, and will reduce blood loss. Afterwards, the wound can be sutured shut, preferably while the patient is resting and/or grasping their wound." + homemade_treat_text = "Bed sheets can be ripped up to make makeshift gauze. Flour, table salt, or salt mixed with water can be applied directly to stem the flow, though unmixed salt will irritate the skin and worsen natural healing. Resting and grabbing your wound will also reduce bleeding." + /datum/wound_pregen_data/flesh_pierce/open_puncture abstract = FALSE wound_path_to_generate = /datum/wound/pierce/bleed/severe + threshold_minimum = 50 + /datum/wound/pierce/bleed/severe/update_descriptions() - if(no_bleeding) + if(!limb.can_bleed()) occur_text = "tears a hole open" /datum/wound/pierce/bleed/critical @@ -241,13 +249,17 @@ gauzed_clot_rate = 0.4 internal_bleeding_chance = 80 internal_bleeding_coefficient = 1.75 - threshold_minimum = 100 threshold_penalty = 50 status_effect_type = /datum/status_effect/wound/pierce/critical scar_keyword = "piercecritical" - wound_flags = (ACCEPTS_GAUZE | MANGLES_FLESH) + wound_flags = (ACCEPTS_GAUZE | MANGLES_EXTERIOR | CAN_BE_GRASPED) + + simple_treat_text = "Bandaging the wound is of utmost importance, as is seeking direct medical attention - Death will ensue if treatment is delayed whatsoever, with lack of oxygen killing the patient, thus Food, Iron, and saline solution is always recommended after treatment. This wound will not naturally seal itself." + homemade_treat_text = "Bed sheets can be ripped up to make makeshift gauze. Flour, salt, and saltwater topically applied will help. Dropping to the ground and grabbing your wound will reduce blood flow." /datum/wound_pregen_data/flesh_pierce/cavity abstract = FALSE wound_path_to_generate = /datum/wound/pierce/bleed/critical + + threshold_minimum = 100 diff --git a/code/datums/wounds/scars/_scars.dm b/code/datums/wounds/scars/_scars.dm index bf33af3fefc285..774d8cc5265f0a 100644 --- a/code/datums/wounds/scars/_scars.dm +++ b/code/datums/wounds/scars/_scars.dm @@ -61,7 +61,7 @@ return required_limb_biostate = pregen_data.required_limb_biostate - check_any_biostates = pregen_data.check_for_any + check_any_biostates = pregen_data.require_any_biostate limb = BP RegisterSignal(limb, COMSIG_QDELETING, PROC_REF(limb_gone)) @@ -81,7 +81,10 @@ qdel(src) return - description = pick_list(W.get_scar_file(BP, add_to_scars), W.get_scar_keyword(BP, add_to_scars)) || "general disfigurement" + description = pick_list(scar_file, scar_keyword) + if (!description) + stack_trace("no valid description found for scar! file: [scar_file] keyword: [scar_keyword] wound: [W.type]") + description = "general disfigurement" precise_location = pick_list_replacements(SCAR_LOC_FILE, limb.body_zone) switch(W.severity) @@ -103,7 +106,7 @@ LAZYADD(victim.all_scars, src) /// Used to "load" a persistent scar -/datum/scar/proc/load(obj/item/bodypart/BP, version, description, specific_location, severity = WOUND_SEVERITY_SEVERE, required_limb_biostate = BIO_STANDARD, char_slot, check_any_biostates = FALSE) +/datum/scar/proc/load(obj/item/bodypart/BP, version, description, specific_location, severity = WOUND_SEVERITY_SEVERE, required_limb_biostate = BIO_STANDARD_UNJOINTED, char_slot, check_any_biostates = FALSE) if(!BP.scarrable) qdel(src) return diff --git a/code/datums/wounds/slash.dm b/code/datums/wounds/slash.dm index e8165368952a15..4475d95f508c4a 100644 --- a/code/datums/wounds/slash.dm +++ b/code/datums/wounds/slash.dm @@ -6,26 +6,25 @@ /datum/wound/slash name = "Slashing (Cut) Wound" sound_effect = 'sound/weapons/slice.ogg' - wound_type = WOUND_SLASH /datum/wound_pregen_data/flesh_slash abstract = TRUE + required_wounding_types = list(WOUND_SLASH) required_limb_biostate = BIO_FLESH + wound_series = WOUND_SERIES_FLESH_SLASH_BLEED + /datum/wound/slash/flesh name = "Slashing (Cut) Flesh Wound" processes = TRUE - wound_type = WOUND_SLASH treatable_by = list(/obj/item/stack/medical/suture) treatable_by_grabbed = list(/obj/item/gun/energy/laser) - treatable_tool = TOOL_CAUTERY + treatable_tools = list(TOOL_CAUTERY) base_treat_time = 3 SECONDS - wound_flags = (ACCEPTS_GAUZE) + wound_flags = (ACCEPTS_GAUZE|CAN_BE_GRASPED) - scar_file = FLESH_SCAR_FILE - - wound_series = WOUND_SERIES_FLESH_SLASH_BLEED + default_scar_file = FLESH_SCAR_FILE /// How much blood we start losing when this wound is first applied var/initial_flow @@ -43,6 +42,11 @@ /// A bad system I'm using to track the worst scar we earned (since we can demote, we want the biggest our wound has been, not what it was when it was cured (probably moderate)) var/datum/scar/highest_scar +/datum/wound/slash/flesh/Destroy() + highest_scar = null + + return ..() + /datum/wound/slash/flesh/wound_injury(datum/wound/slash/flesh/old_wound = null, attack_direction = null) if(old_wound) set_blood_flow(max(old_wound.blood_flow, initial_flow)) @@ -51,7 +55,7 @@ old_wound.clear_highest_scar() else set_blood_flow(initial_flow) - if(!no_bleeding && attack_direction && victim.blood_volume > BLOOD_VOLUME_OKAY) + if(limb.can_bleed() && attack_direction && victim.blood_volume > BLOOD_VOLUME_OKAY) victim.spray_blood(attack_direction, severity) if(!highest_scar) @@ -119,7 +123,7 @@ /datum/wound/slash/flesh/get_bleed_rate_of_change() //basically if a species doesn't bleed, the wound is stagnant and will not heal on it's own (nor get worse) - if(no_bleeding) + if(!limb.can_bleed()) return BLOOD_FLOW_STEADY if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS)) return BLOOD_FLOW_INCREASING @@ -134,7 +138,7 @@ return // in case the victim has the NOBLOOD trait, the wound will simply not clot on it's own - if(!no_bleeding) + if(limb.can_bleed()) set_blood_flow(min(blood_flow, WOUND_SLASH_MAX_BLOODFLOW)) if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS)) @@ -147,7 +151,7 @@ adjust_blood_flow(-limb.current_gauze.absorption_rate * seconds_per_tick) limb.seep_gauze(limb.current_gauze.absorption_rate * seconds_per_tick) //otherwise, only clot if it's a bleeder - else if(!no_bleeding) + else if(limb.can_bleed()) adjust_blood_flow(-clot_rate * seconds_per_tick) if(blood_flow > highest_flow) @@ -157,7 +161,7 @@ if(demotes_to) replace_wound(new demotes_to) else - to_chat(victim, span_green("The cut on your [limb.plaintext_zone] has [no_bleeding ? "healed up" : "stopped bleeding"]!")) + to_chat(victim, span_green("The cut on your [limb.plaintext_zone] has [!limb.can_bleed() ? "healed up" : "stopped bleeding"]!")) qdel(src) /datum/wound/slash/flesh/on_stasis(seconds_per_tick, times_fired) @@ -229,9 +233,9 @@ if (limb) // parent can cause us to be removed, so its reasonable to check if we're still applied adjust_blood_flow(-0.03 * power) // i think it's like a minimum of 3 power, so .09 blood_flow reduction per tick is pretty good for 0 effort -/datum/wound/slash/flesh/on_synthflesh(power) +/datum/wound/slash/flesh/on_synthflesh(reac_volume) . = ..() - adjust_blood_flow(-0.075 * power) // 20u * 0.075 = -1.5 blood flow, pretty good for how little effort it is + adjust_blood_flow(-0.075 * reac_volume) // 20u * 0.075 = -1.5 blood flow, pretty good for how little effort it is /// If someone's putting a laser gun up to our cut to cauterize it /datum/wound/slash/flesh/proc/las_cauterize(obj/item/gun/energy/laser/lasgun, mob/user) @@ -264,7 +268,7 @@ if(!do_after(user, treatment_delay, target = victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)))) return - var/bleeding_wording = (no_bleeding ? "cuts" : "bleeding") + var/bleeding_wording = (!limb.can_bleed() ? "cuts" : "bleeding") user.visible_message(span_green("[user] cauterizes some of the [bleeding_wording] on [victim]."), span_green("You cauterize some of the [bleeding_wording] on [victim].")) limb.receive_damage(burn = 2 + severity, wound_bonus = CANT_WOUND) if(prob(30)) @@ -292,7 +296,7 @@ if(!do_after(user, treatment_delay, target = victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)))) return TRUE - var/bleeding_wording = (no_bleeding ? "cuts" : "bleeding") + var/bleeding_wording = (!limb.can_bleed() ? "cuts" : "bleeding") user.visible_message(span_green("[user] stitches up some of the [bleeding_wording] on [victim]."), span_green("You stitch up some of the [bleeding_wording] on [user == victim ? "yourself" : "[victim]"].")) var/blood_sutured = I.stop_bleeding / self_penalty_mult adjust_blood_flow(-blood_sutured) @@ -320,13 +324,15 @@ initial_flow = 2 minimum_flow = 0.5 clot_rate = 0.05 - threshold_minimum = 20 threshold_penalty = 10 status_effect_type = /datum/status_effect/wound/slash/flesh/moderate scar_keyword = "slashmoderate" + simple_treat_text = "Bandaging the wound will reduce blood loss, help the wound close by itself quicker, and speed up the blood recovery period. The wound itself can be slowly sutured shut." + homemade_treat_text = "Tea stimulates the body's natural healing systems, slightly fastening clotting. The wound itself can be rinsed off on a sink or shower as well. Other remedies are unnecessary." + /datum/wound/slash/flesh/moderate/update_descriptions() - if(no_bleeding) + if(!limb.can_bleed()) occur_text = "is cut open" /datum/wound_pregen_data/flesh_slash/abrasion @@ -334,6 +340,8 @@ wound_path_to_generate = /datum/wound/slash/flesh/moderate + threshold_minimum = 20 + /datum/wound/slash/flesh/severe name = "Open Laceration" desc = "Patient's skin is ripped clean open, allowing significant blood loss." @@ -345,19 +353,23 @@ initial_flow = 3.25 minimum_flow = 2.75 clot_rate = 0.03 - threshold_minimum = 50 threshold_penalty = 25 demotes_to = /datum/wound/slash/flesh/moderate status_effect_type = /datum/status_effect/wound/slash/flesh/severe scar_keyword = "slashsevere" + simple_treat_text = "Bandaging the wound is essential, and will reduce blood loss. Afterwards, the wound can be sutured shut, preferably while the patient is resting and/or grasping their wound." + homemade_treat_text = "Bed sheets can be ripped up to make makeshift gauze. Flour, table salt, or salt mixed with water can be applied directly to stem the flow, though unmixed salt will irritate the skin and worsen natural healing. Resting and grabbing your wound will also reduce bleeding." + /datum/wound_pregen_data/flesh_slash/laceration abstract = FALSE wound_path_to_generate = /datum/wound/slash/flesh/severe + threshold_minimum = 50 + /datum/wound/slash/flesh/severe/update_descriptions() - if(no_bleeding) + if(!limb.can_bleed()) occur_text = "is ripped open" /datum/wound/slash/flesh/critical @@ -371,17 +383,23 @@ initial_flow = 4 minimum_flow = 3.85 clot_rate = -0.015 // critical cuts actively get worse instead of better - threshold_minimum = 80 threshold_penalty = 40 demotes_to = /datum/wound/slash/flesh/severe status_effect_type = /datum/status_effect/wound/slash/flesh/critical scar_keyword = "slashcritical" - wound_flags = (ACCEPTS_GAUZE | MANGLES_FLESH) + wound_flags = (ACCEPTS_GAUZE | MANGLES_EXTERIOR | CAN_BE_GRASPED) + simple_treat_text = "Bandaging the wound is of utmost importance, as is seeking direct medical attention - Death will ensue if treatment is delayed whatsoever, with lack of oxygen killing the patient, thus Food, Iron, and saline solution is always recommended after treatment. This wound will not naturally seal itself." + homemade_treat_text = "Bed sheets can be ripped up to make makeshift gauze. Flour, salt, and saltwater topically applied will help. Dropping to the ground and grabbing your wound will reduce blood flow." + +/datum/wound/slash/flesh/critical/update_descriptions() + if (!limb.can_bleed()) + occur_text = "is torn open" /datum/wound_pregen_data/flesh_slash/avulsion abstract = FALSE wound_path_to_generate = /datum/wound/slash/flesh/critical + threshold_minimum = 80 /datum/wound/slash/flesh/moderate/many_cuts name = "Numerous Small Slashes" @@ -389,7 +407,7 @@ examine_desc = "has a ton of small cuts" occur_text = "is cut numerous times, leaving many small slashes." -/datum/wound_pregen_data/flesh_slash/cuts +/datum/wound_pregen_data/flesh_slash/abrasion/cuts abstract = FALSE can_be_randomly_generated = FALSE @@ -402,10 +420,10 @@ clot_rate = 0.01 /datum/wound/slash/flesh/critical/cleave/update_descriptions() - if(no_bleeding) + if(!limb.can_bleed()) occur_text = "is ruptured" -/datum/wound_pregen_data/flesh_slash/cleave +/datum/wound_pregen_data/flesh_slash/avulsion/clear abstract = FALSE can_be_randomly_generated = FALSE diff --git a/code/game/area/areas/station/science.dm b/code/game/area/areas/station/science.dm index fc968699df0aa5..f63798aca62daf 100644 --- a/code/game/area/areas/station/science.dm +++ b/code/game/area/areas/station/science.dm @@ -73,7 +73,7 @@ icon_state = "ass_line" /area/station/science/robotics/augments - name = "improper Augmentation Theater" + name = "\improper Augmentation Theater" icon_state = "robotics" sound_environment = SOUND_AREA_TUNNEL_ENCLOSED diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index aeedad9bf56e1e..033deff435875d 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -394,15 +394,17 @@ GLOBAL_LIST_EMPTY(dynamic_station_traits) /// Generates the threat level using lorentz distribution and assigns peaceful_percentage. /datum/game_mode/dynamic/proc/generate_threat() - threat_level = lorentz_to_amount(threat_curve_centre, threat_curve_width, max_threat_level) + // At lower pop levels we run a Liner Interpolation against the max threat based proportionally on the number + // of players ready. This creates a balanced lorentz curve within a smaller range than 0 to max_threat_level. + var/calculated_max_threat = (SSticker.totalPlayersReady < low_pop_player_threshold) ? LERP(low_pop_maximum_threat, max_threat_level, SSticker.totalPlayersReady / low_pop_player_threshold) : max_threat_level + log_dynamic("Calculated maximum threat level based on player count of [SSticker.totalPlayersReady]: [calculated_max_threat]") + + threat_level = lorentz_to_amount(threat_curve_centre, threat_curve_width, calculated_max_threat) for(var/datum/station_trait/station_trait in GLOB.dynamic_station_traits) threat_level = max(threat_level - GLOB.dynamic_station_traits[station_trait], 0) log_dynamic("Threat reduced by [GLOB.dynamic_station_traits[station_trait]]. Source: [type].") - if (SSticker.totalPlayersReady < low_pop_player_threshold) - threat_level = min(threat_level, LERP(low_pop_maximum_threat, max_threat_level, SSticker.totalPlayersReady / low_pop_player_threshold)) - peaceful_percentage = (threat_level/max_threat_level)*100 /// Generates the midround and roundstart budgets @@ -858,7 +860,7 @@ GLOBAL_LIST_EMPTY(dynamic_station_traits) * rand() calls without arguments returns a value between 0 and 1, allowing for smaller intervals. */ /datum/game_mode/dynamic/proc/lorentz_to_amount(centre = 0, scale = 1.8, max_threat = 100, interval = 1) - var/location = rand(-MAXIMUM_DYN_DISTANCE, MAXIMUM_DYN_DISTANCE) * rand() + var/location = RANDOM_DECIMAL(-MAXIMUM_DYN_DISTANCE, MAXIMUM_DYN_DISTANCE) * rand() var/lorentz_result = LORENTZ_CUMULATIVE_DISTRIBUTION(centre, location, scale) var/std_threat = lorentz_result * max_threat ///Without these, the amount won't come close to hitting 0% or 100% of the max threat. diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index 975b5dc7e2be99..df078c462d94c2 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -226,6 +226,7 @@ GLOBAL_VAR_INIT(revolutionary_win, FALSE) scaling_cost = 9 requirements = list(101,101,60,30,30,25,20,15,10,10) antag_cap = list("denominator" = 24) + ruleset_lazy_templates = list(LAZY_TEMPLATE_KEY_HERETIC_SACRIFICE) /datum/dynamic_ruleset/roundstart/heretics/pre_execute(population) diff --git a/code/game/machinery/bank_machine.dm b/code/game/machinery/bank_machine.dm index c48671a6e1820e..4d276b6ebae0f5 100644 --- a/code/game/machinery/bank_machine.dm +++ b/code/game/machinery/bank_machine.dm @@ -116,7 +116,8 @@ /obj/machinery/computer/bank_machine/proc/end_siphon() siphoning = FALSE unauthorized = FALSE - new /obj/item/holochip(drop_location(), syphoning_credits) //get the loot + if(syphoning_credits > 0) + new /obj/item/holochip(drop_location(), syphoning_credits) //get the loot syphoning_credits = 0 /obj/machinery/computer/bank_machine/proc/start_siphon(mob/living/carbon/user) diff --git a/code/game/machinery/barsigns.dm b/code/game/machinery/barsigns.dm index 83188b1ad8baed..ab1abc95e10318 100644 --- a/code/game/machinery/barsigns.dm +++ b/code/game/machinery/barsigns.dm @@ -27,6 +27,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign, 32) /obj/machinery/barsign/Initialize(mapload) . = ..() set_sign(new /datum/barsign/hiddensigns/signoff) + find_and_hang_on_wall() /obj/machinery/barsign/proc/set_sign(datum/barsign/sign) if(!istype(sign)) diff --git a/code/game/machinery/botlaunchpad.dm b/code/game/machinery/botlaunchpad.dm index f1c85a293c7f12..f77e11151e03e8 100644 --- a/code/game/machinery/botlaunchpad.dm +++ b/code/game/machinery/botlaunchpad.dm @@ -27,7 +27,7 @@ return var/obj/item/multitool/multitool = tool multitool.set_buffer(src) - to_chat(user, span_notice("You save the data in the [multitool.name]'s buffer.")) + balloon_alert(user, "saved to multitool buffer") return TOOL_ACT_TOOLTYPE_SUCCESS diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index 21a718d87050a2..5824f93dcc736d 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -55,6 +55,7 @@ board.accesses = req_one_access setup_device() + find_and_hang_on_wall() /obj/machinery/button/Destroy() QDEL_NULL(device) @@ -233,6 +234,20 @@ device.pulsed(user) SEND_GLOBAL_SIGNAL(COMSIG_GLOB_BUTTON_PRESSED,src) +/** + * Called when the mounted button's wall is knocked down. + */ +/obj/machinery/button/proc/knock_down() + if(device) + device.forceMove(get_turf(src)) + device = null + if(board) + board.forceMove(get_turf(src)) + req_access = list() + req_one_access = list() + board = null + qdel(src) + /obj/machinery/button/door name = "door button" desc = "A door remote control switch." diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index a47115a9f60f98..42f28a8b3ee299 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -30,7 +30,6 @@ var/busy = FALSE var/emped = FALSE //Number of consecutive EMP's on this camera var/in_use_lights = 0 - // Upgrades bitflag var/upgrades = 0 @@ -104,6 +103,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) update_appearance() alarm_manager = new(src) + find_and_hang_on_wall(directional = TRUE, \ + custom_drop_callback = CALLBACK(src, PROC_REF(deconstruct), FALSE)) + + RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) /obj/machinery/camera/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock) for(var/i in network) @@ -155,7 +158,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) if(!status && powered()) . += span_info("It can reactivated with wirecutters.") -/obj/machinery/camera/emp_act(severity) +/obj/machinery/camera/emp_act(severity, reset_time = 90 SECONDS) . = ..() if(!status) return @@ -168,7 +171,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) set_light(0) emped = emped+1 //Increase the number of consecutive EMP's update_appearance() - addtimer(CALLBACK(src, PROC_REF(post_emp_reset), emped, network), 90 SECONDS) + addtimer(CALLBACK(src, PROC_REF(post_emp_reset), emped, network), reset_time) for(var/i in GLOB.player_list) var/mob/M = i if (M.client?.eye == src) @@ -176,6 +179,11 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) M.reset_perspective(null) to_chat(M, span_warning("The screen bursts into static!")) +/obj/machinery/camera/proc/on_saboteur(datum/source, disrupt_duration) + SIGNAL_HANDLER + emp_act(EMP_LIGHT, reset_time = disrupt_duration) + return COMSIG_SABOTEUR_SUCCESS + /obj/machinery/camera/proc/post_emp_reset(thisemp, previous_network) if(QDELETED(src)) return @@ -188,7 +196,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) if(can_use()) GLOB.cameranet.addCamera(src) emped = 0 //Resets the consecutive EMP count - addtimer(CALLBACK(src, PROC_REF(cancelCameraAlarm)), 100) + addtimer(CALLBACK(src, PROC_REF(cancelCameraAlarm)), 10 SECONDS) /obj/machinery/camera/ex_act(severity, target) if(invuln) diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm index 37907a5ba2988d..786a2c3a39a7eb 100644 --- a/code/game/machinery/camera/camera_assembly.dm +++ b/code/game/machinery/camera/camera_assembly.dm @@ -67,6 +67,7 @@ . = ..() if(building) setDir(ndir) + find_and_hang_on_wall() /obj/structure/camera_assembly/update_icon_state() icon_state = "[xray_module ? "xray" : null][initial(icon_state)]" diff --git a/code/game/machinery/computer/atmos_computers/_air_sensor.dm b/code/game/machinery/computer/atmos_computers/_air_sensor.dm index faef0370ad0e8f..8d56b8a2f9052e 100644 --- a/code/game/machinery/computer/atmos_computers/_air_sensor.dm +++ b/code/game/machinery/computer/atmos_computers/_air_sensor.dm @@ -91,28 +91,28 @@ if(istype(multi_tool.buffer, /obj/machinery/atmospherics/components/unary/outlet_injector)) var/obj/machinery/atmospherics/components/unary/outlet_injector/input = multi_tool.buffer inlet_id = input.id_tag - multi_tool.set_buffer(null) + multi_tool.set_buffer(src) balloon_alert(user, "connected to input") else if(istype(multi_tool.buffer, /obj/machinery/atmospherics/components/unary/vent_pump)) var/obj/machinery/atmospherics/components/unary/vent_pump/output = multi_tool.buffer //so its no longer controlled by air alarm output.disconnect_from_area() - //configuration copied from /obj/machinery/atmospherics/components/unary/vent_pump/siphon + //configuration copied from /obj/machinery/atmospherics/components/unary/vent_pump/siphon but with max pressure output.pump_direction = ATMOS_DIRECTION_SIPHONING output.pressure_checks = ATMOS_INTERNAL_BOUND - output.internal_pressure_bound = 4000 + output.internal_pressure_bound = MAX_OUTPUT_PRESSURE output.external_pressure_bound = 0 //finally assign it to this sensor outlet_id = output.id_tag - multi_tool.set_buffer(null) + multi_tool.set_buffer(src) balloon_alert(user, "connected to output") else multi_tool.set_buffer(src) - balloon_alert(user, "added to multitool buffer") + balloon_alert(user, "sensor added to buffer") - return TRUE + return TOOL_ACT_TOOLTYPE_SUCCESS /** * A portable version of the /obj/machinery/air_sensor diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 738a05043fdff4..f32eff91c4e524 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -684,6 +684,7 @@ GLOBAL_VAR_INIT(cops_arrived, FALSE) "description" = shuttle_template.description, "occupancy_limit" = shuttle_template.occupancy_limit, "creditCost" = shuttle_template.credit_cost, + "initial_cost" = initial(shuttle_template.credit_cost), "emagOnly" = shuttle_template.emag_only, "prerequisites" = shuttle_template.prerequisites, "ref" = REF(shuttle_template), diff --git a/code/game/machinery/computer/teleporter.dm b/code/game/machinery/computer/teleporter.dm index 7177da8f4eeca9..dd8a051cc8e946 100644 --- a/code/game/machinery/computer/teleporter.dm +++ b/code/game/machinery/computer/teleporter.dm @@ -28,6 +28,14 @@ power_station = null return ..() +/obj/machinery/computer/teleporter/proc/check_for_disabled_beacon(datum/target) + if (!target) + return + if (target.weak_reference != target_ref) + return + turn_off() + set_teleport_target(null) + /obj/machinery/computer/teleporter/proc/link_power_station() if(power_station) return @@ -65,6 +73,11 @@ return data +/obj/machinery/computer/teleporter/proc/turn_off() + power_station.engaged = FALSE + power_station.teleporter_hub.update_appearance() + power_station.teleporter_hub.calibrated = FALSE + /obj/machinery/computer/teleporter/ui_act(action, params) . = ..() if(.) @@ -79,15 +92,11 @@ switch(action) if("regimeset") - power_station.engaged = FALSE - power_station.teleporter_hub.update_appearance() - power_station.teleporter_hub.calibrated = FALSE + turn_off() reset_regime() . = TRUE if("settarget") - power_station.engaged = FALSE - power_station.teleporter_hub.update_appearance() - power_station.teleporter_hub.calibrated = FALSE + turn_off() set_target(usr) . = TRUE if("calibrate") @@ -105,11 +114,18 @@ return TRUE /obj/machinery/computer/teleporter/proc/set_teleport_target(new_target) + var/datum/old_target var/datum/weakref/new_target_ref = WEAKREF(new_target) if (target_ref == new_target_ref) return + if (target_ref) + old_target = target_ref.resolve() SEND_SIGNAL(src, COMSIG_TELEPORTER_NEW_TARGET, new_target) target_ref = new_target_ref + if (istype(old_target, /obj/item/beacon)) + UnregisterSignal(old_target, COMSIG_BEACON_DISABLED) + if (istype(new_target, /obj/item/beacon)) + RegisterSignal(new_target, COMSIG_BEACON_DISABLED, PROC_REF(check_for_disabled_beacon)) /obj/machinery/computer/teleporter/proc/finish_calibration() calibrating = FALSE diff --git a/code/game/machinery/computer/telescreen.dm b/code/game/machinery/computer/telescreen.dm index b03ed09226989f..ceb3c2e923e291 100644 --- a/code/game/machinery/computer/telescreen.dm +++ b/code/game/machinery/computer/telescreen.dm @@ -56,6 +56,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/security/telescreen/entertai /obj/machinery/computer/security/telescreen/entertainment/Initialize(mapload) . = ..() RegisterSignal(src, COMSIG_CLICK, PROC_REF(BigClick)) + find_and_hang_on_wall() // Bypass clickchain to allow humans to use the telescreen from a distance /obj/machinery/computer/security/telescreen/entertainment/proc/BigClick() diff --git a/code/game/machinery/defibrillator_mount.dm b/code/game/machinery/defibrillator_mount.dm index d212f2ba45d7be..cb12a39926021f 100644 --- a/code/game/machinery/defibrillator_mount.dm +++ b/code/game/machinery/defibrillator_mount.dm @@ -23,6 +23,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/defibrillator_mount, 28) /obj/machinery/defibrillator_mount/loaded/Initialize(mapload) //loaded subtype for mapping use . = ..() defib = new/obj/item/defibrillator/loaded(src) + find_and_hang_on_wall() MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/defibrillator_mount, 28) diff --git a/code/game/machinery/digital_clock.dm b/code/game/machinery/digital_clock.dm index 0bfb8aeba72462..d0b695428afeb5 100644 --- a/code/game/machinery/digital_clock.dm +++ b/code/game/machinery/digital_clock.dm @@ -83,6 +83,7 @@ /obj/machinery/digital_clock/Initialize(mapload) . = ..() START_PROCESSING(SSdigital_clock, src) + find_and_hang_on_wall() /obj/machinery/digital_clock/Destroy() STOP_PROCESSING(SSdigital_clock, src) diff --git a/code/game/machinery/dish_drive.dm b/code/game/machinery/dish_drive.dm index 814fe788f8c9cb..e84e21314b3e72 100644 --- a/code/game/machinery/dish_drive.dm +++ b/code/game/machinery/dish_drive.dm @@ -9,7 +9,9 @@ density = FALSE circuit = /obj/item/circuitboard/machine/dish_drive pass_flags = PASSTABLE + /// List of dishes the drive can hold var/list/collectable_items = list(/obj/item/trash/waffles, // SKYRAT EDIT CHANGE - non-static list + /obj/item/trash/waffles, /obj/item/broken_bottle, /obj/item/kitchen/fork, /obj/item/plate, @@ -19,19 +21,26 @@ /obj/item/shard, /obj/item/trash/tray, ) - var/list/disposable_items = list(/obj/item/trash/waffles, // SKYRAT EDIT CHANGE - non-static list + /// List of items the drive detects as trash + var/static/list/disposable_items = list(/obj/item/trash/waffles, + /obj/item/trash/waffles, /obj/item/broken_bottle, /obj/item/plate_shard, /obj/item/shard, /obj/item/trash/tray, ) - var/time_since_dishes = 0 + /// Can this suck up dishes? var/suction_enabled = TRUE + /// Does this automatically dispose of trash? var/transmit_enabled = TRUE + /// List of dishes currently inside var/list/dish_drive_contents - var/succrange = 4 //SKYRAT EDIT ADDITION - SEC_HAUL + /// Distance this is capable of sucking dishes up over. (2 + servo tier) + var/suck_distance = 0 var/binrange = 7 //SKYRAT EDIT ADDITION - SEC_HAUL + COOLDOWN_DECLARE(time_since_dishes) + /obj/machinery/dish_drive/Initialize(mapload) . = ..() RefreshParts() @@ -40,16 +49,34 @@ . = ..() if(user.Adjacent(src)) . += span_notice("Alt-click it to beam its contents to any nearby disposal bins.") + if(!LAZYLEN(dish_drive_contents)) + . += "[src] is empty!" + return + // Makes a list of all dishes in the drive, as well as what dish will be taken out next. + var/list/dish_list = list() + // All the types in our list + var/list/dish_types = list() + for(var/obj/dish in dish_drive_contents) + dish_types[dish.type] += 1 + for(var/dish_path in unique_list(dish_types)) + // Counts our dish + var/dish_amount = dish_types[dish_path] + // Handles plurals + var/obj/dish = dish_path + var/dish_name = dish_amount == 1 ? initial(dish.name) : "[initial(dish.name)][plural_s(initial(dish.name))]" + dish_list += list("[dish_amount] [dish_name]") + + . += span_info("It contains [english_list(dish_list)].\n[peek(dish_drive_contents)] is at the top of the pile.") /obj/machinery/dish_drive/attack_hand(mob/living/user, list/modifiers) . = ..() if(!LAZYLEN(dish_drive_contents)) - to_chat(user, span_warning("There's nothing in [src]!")) + balloon_alert(user, "drive empty") return - var/obj/item/I = LAZYACCESS(dish_drive_contents, LAZYLEN(dish_drive_contents)) //the most recently-added item - LAZYREMOVE(dish_drive_contents, I) - user.put_in_hands(I) - to_chat(user, span_notice("You take out [I] from [src].")) + var/obj/item/dish = LAZYACCESS(dish_drive_contents, LAZYLEN(dish_drive_contents)) //the most recently-added item + LAZYREMOVE(dish_drive_contents, dish) + user.put_in_hands(dish) + balloon_alert(user, "[dish] taken") playsound(src, 'sound/items/pshoom.ogg', 50, TRUE) flick("synthesizer_beam", src) @@ -58,23 +85,27 @@ default_unfasten_wrench(user, tool) return TOOL_ACT_TOOLTYPE_SUCCESS -/obj/machinery/dish_drive/attackby(obj/item/I, mob/living/user, params) - if(is_type_in_list(I, collectable_items) && !user.combat_mode) - if(!user.transferItemToLoc(I, src)) +/obj/machinery/dish_drive/attackby(obj/item/dish, mob/living/user, params) + if(is_type_in_list(dish, collectable_items) && !user.combat_mode) + if(!user.transferItemToLoc(dish, src)) return - LAZYADD(dish_drive_contents, I) - to_chat(user, span_notice("You put [I] in [src], and it's beamed into energy!")) + LAZYADD(dish_drive_contents, dish) + balloon_alert(user, "[dish] placed in drive") playsound(src, 'sound/items/pshoom.ogg', 50, TRUE) flick("synthesizer_beam", src) return - else if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", initial(icon_state), I)) + else if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", initial(icon_state), dish)) return - else if(default_deconstruction_crowbar(I, FALSE)) + else if(default_deconstruction_crowbar(dish, FALSE)) return ..() /obj/machinery/dish_drive/RefreshParts() . = ..() + suck_distance = 0 + for(var/datum/stock_part/servo/servo in component_parts) + suck_distance = servo.tier + // Lowers power use for total tier var/total_rating = 0 for(var/datum/stock_part/stock_part in component_parts) total_rating += stock_part.tier @@ -83,31 +114,33 @@ else update_mode_power_usage(IDLE_POWER_USE, max(0, initial(idle_power_usage) - total_rating)) update_mode_power_usage(ACTIVE_POWER_USE, max(0, initial(active_power_usage) - total_rating)) + // Board options var/obj/item/circuitboard/machine/dish_drive/board = locate() in component_parts if(board) suction_enabled = board.suction transmit_enabled = board.transmit /obj/machinery/dish_drive/process() - if(time_since_dishes <= world.time && transmit_enabled) + if(COOLDOWN_FINISHED(src, time_since_dishes) && transmit_enabled) do_the_dishes() if(!suction_enabled) return - for(var/obj/item/I in view(succrange, src)) //SKYRAT EDIT CHANGE - ORIGINAL: for(var/obj/item/I in view(4, src)) - if(is_type_in_list(I, collectable_items) && I.loc != src && (!I.reagents || !I.reagents.total_volume) && (I.contents.len < 1)) - if(I.Adjacent(src)) - LAZYADD(dish_drive_contents, I) - visible_message(span_notice("[src] beams up [I]!")) - I.forceMove(src) + + for(var/obj/item/dish in view(2 + suck_distance, src)) + if(is_type_in_list(dish, collectable_items) && dish.loc != src && (!dish.reagents || !dish.reagents.total_volume) && (dish.contents.len < 1)) + if(dish.Adjacent(src)) + LAZYADD(dish_drive_contents, dish) + visible_message(span_notice("[src] beams up [dish]!")) + dish.forceMove(src) playsound(src, 'sound/items/pshoom.ogg', 50, TRUE) flick("synthesizer_beam", src) else - step_towards(I, src) + step_towards(dish, src) /obj/machinery/dish_drive/attack_ai(mob/living/user) if(machine_stat) return - to_chat(user, span_notice("You send a disposal transmission signal to [src].")) + balloon_alert(user, "disposal signal sent") do_the_dishes(TRUE) /obj/machinery/dish_drive/AltClick(mob/living/user) @@ -126,10 +159,10 @@ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE) return var/disposed = 0 - for(var/obj/item/I in dish_drive_contents) - if(is_type_in_list(I, disposable_items)) - LAZYREMOVE(dish_drive_contents, I) - I.forceMove(bin) + for(var/obj/item/dish in dish_drive_contents) + if(is_type_in_list(dish, disposable_items)) + LAZYREMOVE(dish_drive_contents, dish) + dish.forceMove(bin) use_power(active_power_usage) disposed++ if (disposed) @@ -143,4 +176,4 @@ if(manual) visible_message(span_notice("There are no disposable items in [src]!")) return - time_since_dishes = world.time + 600 + COOLDOWN_START(src, time_since_dishes, 1 MINUTES) diff --git a/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm b/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm index 9d0c10e8666bd9..5d4568a535ca5e 100644 --- a/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm @@ -115,7 +115,7 @@ var/mob/living/carbon/body = owner ASSERT(istype(body)) // we do not lose any nutrition as a fly when vomiting out food - body.vomit(lost_nutrition = 0, stun = FALSE, distance = 2, force = TRUE, purge_ratio = 0.67) + body.vomit(vomit_flags = (MOB_VOMIT_MESSAGE | MOB_VOMIT_FORCE | MOB_VOMIT_HARM), lost_nutrition = 0, distance = 2, purge_ratio = 0.67) playsound(get_turf(owner), 'sound/effects/splat.ogg', 50, TRUE) body.visible_message( span_danger("[body] vomits on the floor!"), diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock_electronics.dm index 4c5e080c653b46..73ae0994eb5176 100644 --- a/code/game/machinery/doors/airlock_electronics.dm +++ b/code/game/machinery/doors/airlock_electronics.dm @@ -22,6 +22,25 @@ . = ..() . += span_notice("Has a neat selection menu for modifying airlock access levels.") +/** + * Create a copy of the electronics + * Arguments + * * [location][atom]- the location to create the new copy in + */ +/obj/item/electronics/airlock/proc/create_copy(atom/location) + //create a copy + var/obj/item/electronics/airlock/new_electronics = new(location) + //copy all params + new_electronics.accesses = accesses.Copy() + new_electronics.one_access = one_access + new_electronics.unres_sides = unres_sides + new_electronics.passed_name = passed_name + new_electronics.passed_cycle_id = passed_cycle_id + new_electronics.shell = shell + //return copy + return new_electronics + + /obj/item/electronics/airlock/ui_state(mob/user) return GLOB.hands_state diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index be630c0a19edcc..5292c3a950cbf4 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -80,7 +80,7 @@ ) ) AddElement(/datum/element/contextual_screentip_mob_typechecks, hovering_mob_typechecks) - + find_and_hang_on_wall() update_appearance() diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index 8d3c4febd70169..8075b51dcab001 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -28,6 +28,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/flasher, 26) . = ..() // ..() is EXTREMELY IMPORTANT, never forget to add it if(!built) bulb = new(src) + find_and_hang_on_wall() /obj/machinery/flasher/vv_edit_var(vname, vval) . = ..() diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 3144ff93c831af..4104d7b93f888b 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -580,7 +580,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ if(speaker == holocall_to_update.hologram && holocall_to_update.user.client?.prefs.read_preference(/datum/preference/toggle/enable_runechat)) holocall_to_update.user.create_chat_message(speaker, message_language, raw_message, spans) else - holocall_to_update.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mods, message_range) + holocall_to_update.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mods, message_range = INFINITY) if(outgoing_call?.hologram && speaker == outgoing_call.user) outgoing_call.hologram.say(raw_message, sanitize = FALSE) diff --git a/code/game/machinery/igniter.dm b/code/game/machinery/igniter.dm index 73f527ca7d562b..060b29c4d20d76 100644 --- a/code/game/machinery/igniter.dm +++ b/code/game/machinery/igniter.dm @@ -162,6 +162,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/sparker, 26) spark_system.set_up(2, 1, src) spark_system.attach(src) register_context() + find_and_hang_on_wall() /obj/machinery/sparker/Destroy() QDEL_NULL(spark_system) diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index 816814b1bcfca2..7c73d2b6f65676 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -243,12 +243,12 @@ if(!(get_dist(src, attached) <= 1 && isturf(attached.loc))) if(isliving(attached)) - var/mob/living/attached_mob = attached + var/mob/living/carbon/attached_mob = attached to_chat(attached, span_userdanger("The IV drip needle is ripped out of you, leaving an open bleeding wound!")) var/list/arm_zones = shuffle(list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM)) var/obj/item/bodypart/chosen_limb = attached_mob.get_bodypart(arm_zones[1]) || attached_mob.get_bodypart(arm_zones[2]) || attached_mob.get_bodypart(BODY_ZONE_CHEST) chosen_limb.receive_damage(3) - chosen_limb.force_wound_upwards(/datum/wound/pierce/bleed/moderate, wound_source = "IV needle") + attached_mob.cause_wound_of_type_and_severity(WOUND_PIERCE, chosen_limb, WOUND_SEVERITY_MODERATE, wound_source = "IV needle") else visible_message(span_warning("[attached] is detached from [src].")) detach_iv() diff --git a/code/game/machinery/launch_pad.dm b/code/game/machinery/launch_pad.dm index f3f463bcae7b7f..5400cccf2f2e9a 100644 --- a/code/game/machinery/launch_pad.dm +++ b/code/game/machinery/launch_pad.dm @@ -78,7 +78,7 @@ return var/obj/item/multitool/M = I M.set_buffer(src) - to_chat(user, span_notice("You save the data in the [I.name]'s buffer.")) + balloon_alert(user, "saved to multitool buffer") return 1 if(default_deconstruction_crowbar(I)) diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm index 5bc618162f0b93..c9b220bb0cdc2d 100644 --- a/code/game/machinery/lightswitch.dm +++ b/code/game/machinery/lightswitch.dm @@ -31,6 +31,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light_switch, 26) area = get_area(src) if(!name) name = "light switch ([area.name])" + find_and_hang_on_wall(custom_drop_callback = CALLBACK(src, PROC_REF(deconstruct), TRUE)) update_appearance() diff --git a/code/game/machinery/mass_driver.dm b/code/game/machinery/mass_driver.dm index f925dfdbdc3507..e3922415a66cf7 100644 --- a/code/game/machinery/mass_driver.dm +++ b/code/game/machinery/mass_driver.dm @@ -3,10 +3,20 @@ desc = "The finest in spring-loaded piston toy technology, now on a space station near you." icon = 'icons/obj/machines/floor.dmi' icon_state = "mass_driver" + circuit = /obj/item/circuitboard/machine/mass_driver var/power = 1 var/code = 1 var/id = 1 - var/drive_range = 50 //this is mostly irrelevant since current mass drivers throw into space, but you could make a lower-range mass driver for interstation transport or something I guess. + var/drive_range = 10 + var/power_per_obj = 1000 + +/obj/machinery/mass_driver/Initialize(mapload) + . = ..() + wires = new /datum/wires/mass_driver(src) + +/obj/machinery/mass_driver/Destroy() + QDEL_NULL(wires) + . = ..() /obj/machinery/mass_driver/chapelgun name = "holy driver" @@ -31,9 +41,9 @@ id = "[port.shuttle_id]_[id]" /obj/machinery/mass_driver/proc/drive(amount) - if(machine_stat & (BROKEN|NOPOWER)) + if(machine_stat & (BROKEN|NOPOWER) || panel_open) return - use_power(active_power_usage) + use_power(power_per_obj) var/O_limit var/atom/target = get_edge_target_turf(src, dir) for(var/atom/movable/O in loc) @@ -44,14 +54,33 @@ if(O_limit >= 20) audible_message(span_notice("[src] lets out a screech, it doesn't seem to be able to handle the load.")) break - use_power(active_power_usage) + use_power(power_per_obj) O.throw_at(target, drive_range * power, power) flick("mass_driver1", src) +/obj/machinery/mass_driver/attackby(obj/item/I, mob/living/user, params) + + if(is_wire_tool(I) && panel_open) + wires.interact(user) + return + if(default_deconstruction_screwdriver(user, "mass_driver_o", "mass_driver", I)) + return + if(default_change_direction_wrench(user, I)) + return + if(default_deconstruction_crowbar(I)) + return + + return ..() + +/obj/machinery/mass_driver/RefreshParts() + . = ..() + for(var/datum/stock_part/servo/new_servo in component_parts) + drive_range += new_servo.tier * 10 + /obj/machinery/mass_driver/emp_act(severity) . = ..() if (. & EMP_PROTECT_SELF) return - if(machine_stat & (BROKEN|NOPOWER)) + if(machine_stat & (BROKEN|NOPOWER) || panel_open) return drive() diff --git a/code/game/machinery/mechlaunchpad.dm b/code/game/machinery/mechlaunchpad.dm index 54cda76f98902f..254467fc2171ea 100644 --- a/code/game/machinery/mechlaunchpad.dm +++ b/code/game/machinery/mechlaunchpad.dm @@ -37,7 +37,7 @@ return var/obj/item/multitool/multitool = tool multitool.set_buffer(src) - to_chat(user, span_notice("You save the data in the [multitool.name]'s buffer.")) + balloon_alert(user, "saved to multitool buffer") return TRUE /obj/machinery/mechpad/wirecutter_act(mob/living/user, obj/item/tool) diff --git a/code/game/machinery/nebula_shielding.dm b/code/game/machinery/nebula_shielding.dm index 73192dac2b732d..cd10a23150c875 100644 --- a/code/game/machinery/nebula_shielding.dm +++ b/code/game/machinery/nebula_shielding.dm @@ -16,6 +16,8 @@ var/power_use_per_block = BASE_MACHINE_ACTIVE_CONSUMPTION * 2 ///State we use when actively blocking a nebula var/active_icon_state + /// State for when we're broken and wont work anymore. Make sure to also set integrity_failure for this to work + var/broken_icon_state /obj/machinery/nebula_shielding/Initialize(mapload) . = ..() @@ -24,21 +26,33 @@ ///Nebula is asking us how strong we are. Return our shield strength is all is well /obj/machinery/nebula_shielding/proc/get_nebula_shielding() - if(panel_open) + if(panel_open || (machine_stat & BROKEN)) return if(!powered()) - icon_state = initial(icon_state) + update_appearance(UPDATE_ICON_STATE) return use_power_from_net(power_use_per_block) generate_reward() - icon_state = active_icon_state + + update_appearance(UPDATE_ICON_STATE) + return shielding_strength ///Generate a resource for defending against the nebula /obj/machinery/nebula_shielding/proc/generate_reward() return +/obj/machinery/nebula_shielding/update_icon_state() + . = ..() + + if((machine_stat & BROKEN) && broken_icon_state) + icon_state = broken_icon_state + else if(!powered()) + icon_state = initial(icon_state) + else + icon_state = active_icon_state + ///Short-lived nebula shielding sent by centcom in-case there hasn't been shielding for a while /obj/machinery/nebula_shielding/emergency density = TRUE @@ -76,12 +90,15 @@ icon_state = "radioactive_shielding" active_icon_state = "radioactive_shielding_on" + broken_icon_state = "radioactive_shielding_broken" circuit = /obj/item/circuitboard/machine/radioactive_nebula_shielding nebula_type = /datum/station_trait/nebula/hostile/radiation shielding_strength = 4 + integrity_failure = 0.4 + /obj/machinery/nebula_shielding/radiation/examine(mob/user) . = ..() diff --git a/code/game/machinery/newscaster/newscaster_machine.dm b/code/game/machinery/newscaster/newscaster_machine.dm index 98cce3900106ef..1ae08c066f043e 100644 --- a/code/game/machinery/newscaster/newscaster_machine.dm +++ b/code/game/machinery/newscaster/newscaster_machine.dm @@ -73,6 +73,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/newscaster, 30) GLOB.allCasters += src GLOB.allbountyboards += src update_appearance() + find_and_hang_on_wall() /obj/machinery/newscaster/Destroy() GLOB.allCasters -= src diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm index 79b421fa8de68c..fc646a3483e24c 100644 --- a/code/game/machinery/pipe/construction.dm +++ b/code/game/machinery/pipe/construction.dm @@ -338,7 +338,7 @@ Buildable meters if(iscarbon(user)) var/mob/living/carbon/C = user for(var/i in 1 to 20) - C.vomit(0, TRUE, FALSE, 4, FALSE) + C.vomit(vomit_flags = (MOB_VOMIT_BLOOD | MOB_VOMIT_HARM), lost_nutrition = 0, distance = 4) if(prob(20)) C.spew_organ() sleep(0.5 SECONDS) diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index b19a8032e7d10a..701d62223695ac 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -351,7 +351,7 @@ DEFINE_BITFIELD(turret_flags, list( return var/obj/item/multitool/M = I M.set_buffer(src) - to_chat(user, span_notice("You add [src] to multitool buffer.")) + balloon_alert(user, "saved to multitool buffer") else return ..() @@ -919,6 +919,7 @@ DEFINE_BITFIELD(turret_flags, list( if(built) locked = FALSE power_change() //Checks power and initial settings + find_and_hang_on_wall() /obj/machinery/turretid/Destroy() turrets.Cut() diff --git a/code/game/machinery/porta_turret/portable_turret_cover.dm b/code/game/machinery/porta_turret/portable_turret_cover.dm index 89f41386691670..86b1df20e7fea8 100644 --- a/code/game/machinery/porta_turret/portable_turret_cover.dm +++ b/code/game/machinery/porta_turret/portable_turret_cover.dm @@ -66,7 +66,7 @@ return var/obj/item/multitool/M = I M.set_buffer(parent_turret) - to_chat(user, span_notice("You add [parent_turret] to multitool buffer.")) + balloon_alert(user, "saved to multitool buffer") return return ..() diff --git a/code/game/machinery/quantum_pad.dm b/code/game/machinery/quantum_pad.dm index a855c2d552346e..037b4692fc7401 100644 --- a/code/game/machinery/quantum_pad.dm +++ b/code/game/machinery/quantum_pad.dm @@ -63,6 +63,7 @@ return var/obj/item/multitool/M = I M.set_buffer(src) + balloon_alert(user, "saved to multitool buffer") to_chat(user, span_notice("You save the data in [I]'s buffer. It can now be saved to pads with closed panels.")) return TRUE else if(I.tool_behaviour == TOOL_MULTITOOL) @@ -71,14 +72,14 @@ var/obj/item/multitool/M = I if(istype(M.buffer, /obj/machinery/quantumpad)) if(M.buffer == src) - to_chat(user, span_warning("You cannot link a pad to itself!")) + balloon_alert(user, "cannot link to self!") return TRUE else linked_pad = M.buffer - to_chat(user, span_notice("You link [src] to the one in [I]'s buffer.")) + balloon_alert(user, "data uploaded from buffer") return TRUE else - to_chat(user, span_warning("There is no quantum pad data saved in [I]'s buffer!")) + balloon_alert(user, "no quantum pad data found!") return TRUE else if(istype(I, /obj/item/quantum_keycard)) diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index cc6ead40627e4c..99e7540a35220a 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -12,7 +12,6 @@ var/safety_mode = FALSE // Temporarily stops machine if it detects a mob var/icon_name = "grinder-o" var/bloody = FALSE - var/eat_dir = WEST var/amount_produced = 50 var/crush_damage = 1000 var/eat_victim_items = TRUE @@ -34,6 +33,7 @@ /datum/material/bluespace ) materials = AddComponent(/datum/component/material_container, allowed_materials, INFINITY, MATCONTAINER_NO_INSERT|BREAKDOWN_FLAGS_RECYCLER) + AddComponent(/datum/component/simple_rotation) AddComponent(/datum/component/butchering/recycler, \ speed = 0.1 SECONDS, \ effectiveness = amount_produced, \ @@ -110,7 +110,7 @@ . = ..() if(!anchored) return - if(border_dir == eat_dir) + if(border_dir == dir) return TRUE /obj/machinery/recycler/proc/on_entered(datum/source, atom/movable/enterer, old_loc) diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index 49a5b60ad70236..dbdf86dac373e0 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -127,6 +127,7 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) radio = new /obj/item/radio(src) radio.set_listening(FALSE) + find_and_hang_on_wall() /obj/machinery/requests_console/Destroy() QDEL_NULL(radio) diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 612928dbdec1c0..76c82dd39ddc04 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -232,7 +232,7 @@ set_messages("shutl","not in service") return PROCESS_KILL else if(shuttle.timer) - var/line1 = "<<< [shuttle.getModeStr()]" + var/line1 = shuttle.getModeStr() var/line2 = shuttle.getTimerStr() set_messages(line1, line2) @@ -319,6 +319,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/status_display/evac, 32) AddComponent(/datum/component/usb_port, list( /obj/item/circuit_component/status_display, )) + find_and_hang_on_wall() /obj/machinery/status_display/evac/Destroy() SSradio.remove_object(src,frequency) @@ -397,7 +398,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/status_display/evac, 32) line1 = "" line2 = "" else - line1 = "<<< [SSshuttle.supply.getModeStr()]" + line1 = SSshuttle.supply.getModeStr() line2 = SSshuttle.supply.getTimerStr() set_messages(line1, line2) diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 93fbafeb43d356..8b6601dd471f17 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -186,13 +186,13 @@ var/obj/item/multitool/M = W if(panel_open) M.set_buffer(src) - to_chat(user, span_notice("You download the data to the [W.name]'s buffer.")) + balloon_alert(user, "saved to multitool buffer") else if(M.buffer && istype(M.buffer, /obj/machinery/teleport/station) && M.buffer != src) if(linked_stations.len < efficiency) linked_stations.Add(M.buffer) M.set_buffer(null) - to_chat(user, span_notice("You upload the data from the [W.name]'s buffer.")) + balloon_alert(user, "data uploaded from buffer") else to_chat(user, span_alert("This station can't hold more information, try to use better parts.")) return diff --git a/code/game/objects/effects/decals/cleanable/aliens.dm b/code/game/objects/effects/decals/cleanable/aliens.dm index e113eec5a3639e..4f4b2543792c0d 100644 --- a/code/game/objects/effects/decals/cleanable/aliens.dm +++ b/code/game/objects/effects/decals/cleanable/aliens.dm @@ -40,8 +40,9 @@ return if(mapload) for (var/i in 1 to range) - if(!isgroundlessturf(loc) || GET_TURF_BELOW(loc)) - new /obj/effect/decal/cleanable/xenoblood/xsplatter(loc) + var/turf/my_turf = get_turf(src) + if(!isgroundlessturf(my_turf) || GET_TURF_BELOW(my_turf)) + new /obj/effect/decal/cleanable/xenoblood/xsplatter(my_turf) if (!step_to(src, get_step(src, direction), 0)) break return diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index fc07a229251ff6..d329de34a5f214 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -159,8 +159,9 @@ return if(mapload) for (var/i in 1 to range) - if(!isgroundlessturf(loc) || GET_TURF_BELOW(loc)) - new /obj/effect/decal/cleanable/blood/splatter(loc) + var/turf/my_turf = get_turf(src) + if(!isgroundlessturf(my_turf) || GET_TURF_BELOW(my_turf)) + new /obj/effect/decal/cleanable/blood/splatter(my_turf) if (!step_to(src, get_step(src, direction), 0)) break return diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm index 61306e4ecebfbb..6a519650d10948 100644 --- a/code/game/objects/effects/decals/cleanable/misc.dm +++ b/code/game/objects/effects/decals/cleanable/misc.dm @@ -174,6 +174,20 @@ reagents.trans_to(H, reagents.total_volume, transferred_by = user, methods = INGEST) qdel(src) +/obj/effect/decal/cleanable/vomit/toxic // this has a more toned-down color palette, which may be why it's used as the default in so many spots + icon_state = "vomittox_1" + random_icon_states = list("vomittox_1", "vomittox_2", "vomittox_3", "vomittox_4") + +/obj/effect/decal/cleanable/vomit/purple // ourple + icon_state = "vomitpurp_1" + random_icon_states = list("vomitpurp_1", "vomitpurp_2", "vomitpurp_3", "vomitpurp_4") + +/obj/effect/decal/cleanable/vomit/nanites + name = "nanite-infested vomit" + desc = "Gosh, you can see something moving in there." + icon_state = "vomitnanite_1" + random_icon_states = list("vomitnanite_1", "vomitnanite_2", "vomitnanite_3", "vomitnanite_4") + /obj/effect/decal/cleanable/vomit/nebula name = "nebula vomit" desc = "Gosh, how... beautiful." diff --git a/code/game/objects/effects/decals/cleanable/robots.dm b/code/game/objects/effects/decals/cleanable/robots.dm index 65e6cc3900c16b..d248b5e691d87f 100644 --- a/code/game/objects/effects/decals/cleanable/robots.dm +++ b/code/game/objects/effects/decals/cleanable/robots.dm @@ -25,8 +25,9 @@ return if(mapload) for (var/i in 1 to range) - if(prob(40) && (!isgroundlessturf(loc) || GET_TURF_BELOW(loc))) - new /obj/effect/decal/cleanable/oil/streak(loc) + var/turf/my_turf = get_turf(src) + if(prob(40) && (!isgroundlessturf(my_turf) || GET_TURF_BELOW(my_turf))) + new /obj/effect/decal/cleanable/oil/streak(my_turf) if (!step_to(src, get_step(src, direction), 0)) break return diff --git a/code/game/objects/effects/phased_mob.dm b/code/game/objects/effects/phased_mob.dm index 7a0317c4c77a26..273a4c772a57a1 100644 --- a/code/game/objects/effects/phased_mob.dm +++ b/code/game/objects/effects/phased_mob.dm @@ -83,7 +83,7 @@ return var/area/destination_area = newloc.loc movedelay = world.time + movespeed - if(newloc.flags_1 & NOJAUNT) + if(newloc.turf_flags & NOJAUNT) to_chat(user, span_warning("Some strange aura is blocking the way.")) return if(destination_area.area_flags & NOTELEPORT || SSmapping.level_trait(newloc.z, ZTRAIT_NOPHASE)) diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index 3098d8c7125151..e88753d25c1f86 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -654,3 +654,38 @@ /obj/effect/temp_visual/crit/Initialize(mapload) . = ..() animate(src, pixel_y = pixel_y + 16, alpha = 0, time = duration) + +/obj/effect/temp_visual/jet_plume + name = "jet plume" + icon_state = "jet_plume" + layer = BELOW_MOB_LAYER + plane = GAME_PLANE + duration = 0.4 SECONDS + +/// Plays a dispersing animation on hivelord and legion minions so they don't just vanish +/obj/effect/temp_visual/hive_spawn_wither + name = "withering spawn" + duration = 1 SECONDS + +/obj/effect/temp_visual/hive_spawn_wither/Initialize(mapload, atom/copy_from) + if (isnull(copy_from)) + . = ..() + return INITIALIZE_HINT_QDEL + icon = copy_from.icon + icon_state = copy_from.icon_state + pixel_x = copy_from.pixel_x + pixel_y = copy_from.pixel_y + duration = rand(0.5 SECONDS, 1 SECONDS) + var/matrix/transformation = matrix(transform) + transformation.Turn(rand(-70, 70)) + transformation.Scale(0.7, 0.7) + animate( + src, + pixel_x = rand(-5, 5), + pixel_y = -5, + transform = transformation, + color = "#44444400", + time = duration, + flags = ANIMATION_RELATIVE, + ) + return ..() diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 9eb0daadb73364..c10c04a9fa1be4 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -211,8 +211,6 @@ ///A reagent the nutriments are converted into when the item is juiced. var/datum/reagent/consumable/juice_typepath - var/canMouseDown = FALSE - /// Used in obj/item/examine to give additional notes on what the weapon does, separate from the predetermined output variables var/offensive_notes /// Used in obj/item/examine to determines whether or not to detail an item's statistics even if it does not meet the force requirements @@ -986,11 +984,10 @@ /obj/item/proc/grind(datum/reagents/target_holder, mob/user) if(on_grind() == -1) return FALSE - if(!reagents) - reagents = new() - target_holder.add_reagent_list(grind_results) - if(reagents && target_holder) - reagents.trans_to(target_holder, reagents.total_volume, transferred_by = user) + if(target_holder) + target_holder.add_reagent_list(grind_results) + if(reagents) + reagents.trans_to(target_holder, reagents.total_volume, transferred_by = user) return TRUE ///Called BEFORE the object is ground up - use this to change grind results based on conditions. Return "-1" to prevent the grinding from occurring @@ -1003,9 +1000,10 @@ /obj/item/proc/juice(datum/reagents/target_holder, mob/user) if(on_juice() == -1) return FALSE - reagents.convert_reagent(/datum/reagent/consumable, juice_typepath, include_source_subtypes = TRUE) - if(reagents && target_holder) - reagents.trans_to(target_holder, reagents.total_volume, transferred_by = user) + if(reagents) + reagents.convert_reagent(/datum/reagent/consumable, juice_typepath, include_source_subtypes = TRUE) + if(target_holder) + reagents.trans_to(target_holder, reagents.total_volume, transferred_by = user) return TRUE /obj/item/proc/set_force_string() @@ -1346,7 +1344,7 @@ // victim's chest (for cavity implanting the item) var/obj/item/bodypart/chest/victim_cavity = victim.get_bodypart(BODY_ZONE_CHEST) if(victim_cavity.cavity_item) - victim.vomit(5, FALSE, FALSE, distance = 0) + victim.vomit(vomit_flags = (MOB_VOMIT_MESSAGE | MOB_VOMIT_HARM), lost_nutrition = 5, distance = 0) forceMove(drop_location()) to_chat(victim, span_warning("You vomit up a [name]! [source_item? "Was that in \the [source_item]?" : ""]")) else diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index eafe24a392cf9c..aaef891ee4a97e 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -219,22 +219,27 @@ CIGARETTE PACKETS ARE IN FANCY.DM if(!lighting_text) return ..() - var/mob/living/carbon/carbuser = user - - if(!istype(carbuser)) - carbuser = null - - if(!reagents.has_reagent(/datum/reagent/oxygen)) //cigarettes need oxygen - var/datum/gas_mixture/air = return_air() - if(!air || !air.has_gas(/datum/gas/oxygen, 1) || !carbuser?.can_breathe_helmet()) //or oxygen on a tile to burn - to_chat(user, span_notice("Your [name] needs a source of oxygen to burn.")) - return ..() + if(!check_oxygen(user)) //cigarettes need oxygen + balloon_alert(user, "no air!") + return ..() if(smoketime > 0) light(lighting_text) else to_chat(user, span_warning("There is nothing to smoke!")) +/// Checks that we have enough air to smoke +/obj/item/clothing/mask/cigarette/proc/check_oxygen(mob/user) + if (reagents.has_reagent(/datum/reagent/oxygen)) + return TRUE + var/datum/gas_mixture/air = return_air() + if (!isnull(air) && air.has_gas(/datum/gas/oxygen, 1)) + return TRUE + if (!iscarbon(user)) + return FALSE + var/mob/living/carbon/the_smoker = user + return the_smoker.can_breathe_helmet() + /obj/item/clothing/mask/cigarette/afterattack(obj/item/reagent_containers/cup/glass, mob/user, proximity) . = ..() if(!proximity || lit) //can't dip if cigarette is lit (it will heat the reagents in the glass instead) @@ -366,18 +371,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM var/mob/living/user = isliving(loc) ? loc : null user?.ignite_mob() - var/mob/living/carbon/carbuser - if(user) - carbuser = user - - if(carbuser && !istype(carbuser)) - carbuser = null - - if(!reagents.has_reagent(/datum/reagent/oxygen)) //cigarettes need oxygen - var/datum/gas_mixture/air = return_air() - if(!air || !air.has_gas(/datum/gas/oxygen, 1) || !carbuser?.can_breathe_helmet()) //or oxygen on a tile to burn - extinguish() - return + if(!check_oxygen(user)) + extinguish() + return // SKYRAT EDIT ADDITION START - Pollution var/turf/location = get_turf(src) diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index b0807aff4663f5..e5b7144dc8c3ad 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -56,6 +56,13 @@ /datum/stock_part/capacitor = 1, /obj/item/electronics/airlock = 1) +/obj/item/circuitboard/machine/mass_driver + name = "Mass Driver" + greyscale_colors = CIRCUIT_COLOR_ENGINEERING + build_path = /obj/machinery/mass_driver + req_components = list( + /datum/stock_part/servo = 1,) + /obj/item/circuitboard/machine/autolathe name = "Autolathe" greyscale_colors = CIRCUIT_COLOR_ENGINEERING diff --git a/code/game/objects/items/climbingrope.dm b/code/game/objects/items/climbingrope.dm new file mode 100644 index 00000000000000..2c96d1844b13b1 --- /dev/null +++ b/code/game/objects/items/climbingrope.dm @@ -0,0 +1,86 @@ +/obj/item/climbing_hook + name = "climbing hook" + desc = "Standard hook with rope to scale up holes. The rope is of average quality, but due to your weight amongst other factors, may not withstand extreme use." + icon = 'icons/obj/mining.dmi' + icon_state = "climbingrope" + inhand_icon_state = "crowbar_brass" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + force = 5 + throwforce = 10 + reach = 2 + throw_range = 4 + w_class = WEIGHT_CLASS_NORMAL + attack_verb_continuous = list("whacks", "flails", "bludgeons") + attack_verb_simple = list("whack", "flail", "bludgeon") + resistance_flags = FLAMMABLE + ///how many times can we climb with this rope + var/uses = 5 + ///climb time + var/climb_time = 2.5 SECONDS + +/obj/item/climbing_hook/examine(mob/user) + . = ..() + var/list/look_binds = user.client.prefs.key_bindings["look up"] + . += span_notice("Firstly, look upwards by holding [english_list(look_binds, nothing_text = "(nothing bound)", and_text = " or ", comma_text = ", or ")]!") + . += span_notice("Then, click solid ground adjacent to the hole above you.") + . += span_notice("The rope looks like you could use it [uses] times before it falls apart.") + +/obj/item/climbing_hook/afterattack(turf/open/target, mob/user, proximity_flag, click_parameters) + . = ..() + if(target.z == user.z) + return + if(!istype(target) || isopenspaceturf(target)) + return + if(target.is_blocked_turf(exclude_mobs = TRUE)) + return + var/turf/user_turf = get_turf(user) + var/turf/above = GET_TURF_ABOVE(user_turf) + if(!isopenspaceturf(above) || !above.Adjacent(target)) //are we below a hole, is the target blocked, is the target adjacent to our hole + balloon_alert(user, "blocked!") + return + var/away_dir = get_dir(above, target) + user.visible_message(span_notice("[user] begins climbing upwards with [src]."), span_notice("You get to work on properly hooking [src] and going upwards.")) + playsound(target, 'sound/effects/picaxe1.ogg', 50) //plays twice so people above and below can hear + playsound(user_turf, 'sound/effects/picaxe1.ogg', 50) + var/list/effects = list(new /obj/effect/temp_visual/climbing_hook(target, away_dir), new /obj/effect/temp_visual/climbing_hook(user_turf, away_dir)) + if(do_after(user, climb_time, target)) + user.Move(target) + uses-- + + if(uses <= 0) + user.visible_message(span_warning("[src] snaps and tears apart!")) + qdel(src) + + QDEL_LIST(effects) + +/obj/item/climbing_hook/emergency + name = "emergency climbing hook" + desc = "An emergency climbing hook to scale up holes. The rope is EXTREMELY cheap and may not withstand extended use." + uses = 2 + climb_time = 4 SECONDS + w_class = WEIGHT_CLASS_SMALL + +/obj/item/climbing_hook/syndicate + name = "suspicious climbing hook" + desc = "REALLY suspicious climbing hook to scale up holes. The hook has a syndicate logo engraved on it, and the rope appears rather durable." + icon_state = "climbingrope_s" + uses = 10 + climb_time = 1.5 SECONDS + +/obj/item/climbing_hook/infinite //debug stuff + name = "infinite climbing hook" + desc = "A plasteel hook, with rope. Upon closer inspection, the rope appears to be made out of plasteel woven into regular rope, amongst many other reinforcements." + uses = INFINITY + climb_time = 1 SECONDS + +/obj/effect/temp_visual/climbing_hook + icon = 'icons/mob/silicon/aibots.dmi' + icon_state = "path_indicator" + layer = BELOW_MOB_LAYER + plane = GAME_PLANE + duration = 4 SECONDS + +/obj/effect/temp_visual/climbing_hook/Initialize(mapload, direction) + . = ..() + dir = direction diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm index 4b03fd8013a3ae..48f195ced71a6c 100644 --- a/code/game/objects/items/devices/aicard.dm +++ b/code/game/objects/items/devices/aicard.dm @@ -54,7 +54,8 @@ force = 7 /obj/item/aicard/syndie/loaded - var/being_or_was_used = FALSE + /// Set to true while we're waiting for ghosts to sign up + var/finding_candidate = FALSE /obj/item/aicard/syndie/loaded/examine(mob/user) . = ..() @@ -62,43 +63,55 @@ . += span_notice("This one has a little S.E.L.F. insignia on the back, and a label next to it that says 'Activate for one FREE aligned AI! Please attempt uplink reintegration or ask your employers for reimbursal if AI is unavailable or belligerent.") /obj/item/aicard/syndie/loaded/attack_self(mob/user, modifiers) - if(AI || being_or_was_used) + if(!isnull(AI)) return ..() - being_or_was_used = TRUE + if(finding_candidate) + balloon_alert(user, "loading...") + return TRUE + finding_candidate = TRUE to_chat(user, span_notice("Connecting to S.E.L.F. dispatch...")) - being_or_was_used = procure_ai(user) + procure_ai(user) + finding_candidate = FALSE + return TRUE /obj/item/aicard/syndie/loaded/proc/procure_ai(mob/user) - var/datum/antagonist/nukeop/creator_op = user.mind?.has_antag_datum(/datum/antagonist/nukeop,TRUE) - if(!creator_op) - return FALSE - var/list/nuke_candidates = poll_ghost_candidates("Do you want to play as a syndicate artifical intelligence inside an intelliCard?", ROLE_OPERATIVE, ROLE_OPERATIVE, 150, POLL_IGNORE_SYNDICATE) + var/datum/antagonist/nukeop/op_datum = user.mind?.has_antag_datum(/datum/antagonist/nukeop,TRUE) + if(isnull(op_datum)) + balloon_alert(user, "invalid access!") + return + var/list/nuke_candidates = poll_ghost_candidates( + question = "Do you want to play as a nuclear operative MODsuit AI?", + jobban_type = ROLE_OPERATIVE, + be_special_flag = ROLE_OPERATIVE_MIDROUND, + poll_time = 15 SECONDS, + ignore_category = POLL_IGNORE_SYNDICATE, + ) if(QDELETED(src)) - return FALSE + return if(!LAZYLEN(nuke_candidates)) to_chat(user, span_warning("Unable to connect to S.E.L.F. dispatch. Please wait and try again later or use the intelliCard on your uplink to get your points refunded.")) - return FALSE + return // pick ghost, create AI and transfer var/mob/dead/observer/ghos = pick(nuke_candidates) - var/mob/living/silicon/ai/weak_syndie/new_ai = new /mob/living/silicon/ai/weak_syndie(get_turf(src), null, ghos) // wow so cool i love how laws go before the mob to insert for no reason this definitely didnt delay this pr for weeks - new_ai.key = ghos.key + var/mob/living/silicon/ai/weak_syndie/new_ai = new /mob/living/silicon/ai/weak_syndie(get_turf(src), new /datum/ai_laws/syndicate_override, ghos) // create and apply syndie datum var/datum/antagonist/nukeop/nuke_datum = new() nuke_datum.send_to_spawnpoint = FALSE - new_ai.mind.add_antag_datum(nuke_datum, creator_op.nuke_team) + new_ai.mind.add_antag_datum(nuke_datum, op_datum.nuke_team) new_ai.mind.special_role = "Syndicate AI" new_ai.faction |= ROLE_SYNDICATE // Make it look evil!!! new_ai.hologram_appearance = mutable_appearance('icons/mob/silicon/ai.dmi',"xeno_queen") //good enough - new_ai.icon_state = resolve_ai_icon("hades") // evli - pre_attack(new_ai, user) // i love shitcode! - AI.control_disabled = FALSE // re-enable wireless activity - AI.radio_enabled = TRUE // ditto + new_ai.icon_state = resolve_ai_icon("hades") + // Transfer the AI from the core we created into the card, then delete the core + capture_ai(new_ai, user) var/obj/structure/ai_core/deactivated/detritus = locate() in get_turf(src) qdel(detritus) + AI.control_disabled = FALSE + AI.radio_enabled = TRUE do_sparks(4, TRUE, src) playsound(src, 'sound/machines/chime.ogg', 25, TRUE) - return TRUE + return /obj/item/aicard/Destroy(force) if(AI) @@ -141,7 +154,7 @@ if(isnull(AI)) return FALSE - log_silicon("[key_name(user)] carded [key_name(AI)]", src) + log_silicon("[key_name(user)] carded [key_name(AI)]", list(src)) update_appearance() AI.cancel_camera() RegisterSignal(AI, COMSIG_MOB_STATCHANGE, PROC_REF(on_ai_stat_change)) diff --git a/code/game/objects/items/devices/beacon.dm b/code/game/objects/items/devices/beacon.dm index 00517f78915e83..e2936c0f538db9 100644 --- a/code/game/objects/items/devices/beacon.dm +++ b/code/game/objects/items/devices/beacon.dm @@ -20,14 +20,18 @@ GLOB.teleportbeacons -= src return ..() +/obj/item/beacon/proc/turn_off() + icon_state = "beacon-off" + GLOB.teleportbeacons -= src + SEND_SIGNAL(src, COMSIG_BEACON_DISABLED) + /obj/item/beacon/attack_self(mob/user) enabled = !enabled if (enabled) icon_state = "beacon" GLOB.teleportbeacons += src else - icon_state = "beacon-off" - GLOB.teleportbeacons -= src + turn_off() to_chat(user, span_notice("You [enabled ? "enable" : "disable"] the beacon.")) return diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 14fc91ea7d0ec8..735510ae9d4169 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -23,6 +23,8 @@ light_range = 4 light_power = 1 light_on = FALSE + /// If we've been forcibly disabled for a temporary amount of time. + COOLDOWN_DECLARE(disabled_time) /// Can we toggle this light on and off (used for contexual screentips only) var/toggle_context = TRUE /// The sound the light makes when it's turned on @@ -32,16 +34,15 @@ /// Is the light turned on or off currently var/on = FALSE -// SKYRAT EDIT REMOVAL BEGIN - MOVED TO MODUALR FLASHLIGHT.DM -/* /obj/item/flashlight/Initialize(mapload) . = ..() if(icon_state == "[initial(icon_state)]-on") on = TRUE update_brightness() register_context() -*/ -// SKYRAT EDIT REMOVAL END + + if(toggle_context) + RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) /obj/item/flashlight/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) // single use lights can be toggled on once @@ -68,19 +69,21 @@ if(light_system == STATIC_LIGHT) update_light() -// SKYRAT EDIT REMOVAL BEGIN - MOVED TO MODUALR FLASHLIGHT.DM -/* -/obj/item/flashlight/proc/toggle_light() +/obj/item/flashlight/proc/toggle_light(mob/user) + var/disrupted = FALSE on = !on - playsound(src, on ? sound_on : sound_off, 40, TRUE) + //playsound(src, on ? sound_on : sound_off, 40, TRUE) SKYRAT EDIT REMOVAL - SOUND HANDLED IN MODULAR FLASHLIGHT.DM + if(!COOLDOWN_FINISHED(src, disabled_time)) + if(user) + balloon_alert(user, "disrupted!") + on = FALSE + disrupted = TRUE update_brightness() update_item_action_buttons() - return TRUE + return !disrupted /obj/item/flashlight/attack_self(mob/user) - toggle_light() -*/ -// SKYRAT EDIT REMOVAL END + toggle_light(user) /obj/item/flashlight/attack_hand_secondary(mob/user, list/modifiers) attack_self(user) @@ -262,6 +265,14 @@ if(istype(user) && dir != user.dir) setDir(user.dir) +/// when hit by a light disruptor - turns the light off, forces the light to be disabled for a few seconds +/obj/item/flashlight/proc/on_saboteur(datum/source, disrupt_duration) + SIGNAL_HANDLER + if(on) + toggle_light() + COOLDOWN_START(src, disabled_time, disrupt_duration) + return COMSIG_SABOTEUR_SUCCESS + /obj/item/flashlight/pen name = "penlight" desc = "A pen-sized light, used by medical staff. It can also be used to create a hologram to alert people of incoming medical assistance." @@ -420,16 +431,15 @@ damtype = BURN . = ..() -/obj/item/flashlight/flare/turn_off() //SKYRAT EDIT CHANGE - //on = FALSE SKYRAT EDIT REMOVAL +/obj/item/flashlight/flare/proc/turn_off() + on = FALSE name = initial(name) attack_verb_continuous = initial(attack_verb_continuous) attack_verb_simple = initial(attack_verb_simple) hitsound = initial(hitsound) force = initial(force) damtype = initial(damtype) - //update_brightness() - SKYRAT EDIT MOVED TO PARENT - . = ..() //SKYRAT EDIT - MODULAR PARENT PROC + update_brightness() /obj/item/flashlight/flare/extinguish() . = ..() @@ -749,11 +759,9 @@ turn_off() STOP_PROCESSING(SSobj, src) -/* SKYRAT EDIT REMOVAL /obj/item/flashlight/glowstick/proc/turn_off() on = FALSE update_appearance(UPDATE_ICON) -*/ /obj/item/flashlight/glowstick/update_appearance(updates=ALL) . = ..() diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index 025f5fa5e8895d..17f5e7d490296f 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -41,14 +41,25 @@ user.visible_message(span_suicide("[user] puts the [src] to [user.p_their()] chest. It looks like [user.p_theyre()] trying to pulse [user.p_their()] heart off!")) return OXYLOSS//theres a reason it wasn't recommended by doctors +/** + * Sets the multitool internal object buffer + * + * Arguments: + * * buffer - the new object to assign to the multitool's buffer + */ /obj/item/multitool/proc/set_buffer(datum/buffer) if(src.buffer) UnregisterSignal(src.buffer, COMSIG_QDELETING) - if(QDELETED(buffer)) - return src.buffer = buffer - RegisterSignal(buffer, COMSIG_QDELETING, PROC_REF(on_buffer_del)) + if(!QDELETED(buffer)) + RegisterSignal(buffer, COMSIG_QDELETING, PROC_REF(on_buffer_del)) +/** + * Called when the buffer's stored object is deleted + * + * This proc does not clear the buffer of the multitool, it is here to + * handle the deletion of the object the buffer references + */ /obj/item/multitool/proc/on_buffer_del(datum/source) SIGNAL_HANDLER buffer = null diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 4c2e611bd256dd..13a054ec8e4984 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -129,6 +129,7 @@ GLOBAL_LIST_INIT(channel_tokens, list( name = "syndicate headset" desc = "A syndicate headset that can be used to hear all radio frequencies. Protects ears from flashbangs." icon_state = "syndie_headset" + worn_icon_state = "syndie_headset" /obj/item/radio/headset/syndicate/alt/Initialize(mapload) . = ..() @@ -138,20 +139,6 @@ GLOBAL_LIST_INIT(channel_tokens, list( name = "team leader headset" command = TRUE -/obj/item/radio/headset/syndicate/alt/psyker - name = "psychic headset" - desc = "A headset designed to boost psychic waves. Protects ears from flashbangs." - icon_state = "psyker_headset" - -/obj/item/radio/headset/syndicate/alt/psyker/equipped(mob/living/user, slot) - . = ..() - if(slot_flags & slot) - ADD_CLOTHING_TRAIT(user, TRAIT_ECHOLOCATION_EXTRA_RANGE) - -/obj/item/radio/headset/syndicate/alt/psyker/dropped(mob/user, silent) - . = ..() - REMOVE_CLOTHING_TRAIT(user, TRAIT_ECHOLOCATION_EXTRA_RANGE) - /obj/item/radio/headset/binary keyslot = /obj/item/encryptionkey/binary @@ -159,12 +146,14 @@ GLOBAL_LIST_INIT(channel_tokens, list( name = "security radio headset" desc = "This is used by your elite security force." icon_state = "sec_headset" + worn_icon_state = "sec_headset" keyslot = /obj/item/encryptionkey/headset_sec /obj/item/radio/headset/headset_sec/alt name = "security bowman headset" desc = "This is used by your elite security force. Protects ears from flashbangs." icon_state = "sec_headset_alt" + worn_icon_state = "sec_headset_alt" /obj/item/radio/headset/headset_sec/alt/Initialize(mapload) . = ..() @@ -174,48 +163,56 @@ GLOBAL_LIST_INIT(channel_tokens, list( name = "engineering radio headset" desc = "When the engineers wish to chat like girls." icon_state = "eng_headset" + worn_icon_state = "eng_headset" keyslot = /obj/item/encryptionkey/headset_eng /obj/item/radio/headset/headset_rob name = "robotics radio headset" desc = "Made specifically for the roboticists, who cannot decide between departments." icon_state = "rob_headset" + worn_icon_state = "rob_headset" keyslot = /obj/item/encryptionkey/headset_rob /obj/item/radio/headset/headset_med name = "medical radio headset" desc = "A headset for the trained staff of the medbay." icon_state = "med_headset" + worn_icon_state = "med_headset" keyslot = /obj/item/encryptionkey/headset_med /obj/item/radio/headset/headset_sci name = "science radio headset" desc = "A sciency headset. Like usual." icon_state = "sci_headset" + worn_icon_state = "sci_headset" keyslot = /obj/item/encryptionkey/headset_sci /obj/item/radio/headset/headset_medsci name = "medical research radio headset" desc = "A headset that is a result of the mating between medical and science." icon_state = "medsci_headset" + worn_icon_state = "medsci_headset" keyslot = /obj/item/encryptionkey/headset_medsci /obj/item/radio/headset/headset_srvsec name = "law and order headset" desc = "In the criminal justice headset, the encryption key represents two separate but equally important groups. Sec, who investigate crime, and Service, who provide services. These are their comms." icon_state = "srvsec_headset" + worn_icon_state = "srvsec_headset" keyslot = /obj/item/encryptionkey/headset_srvsec /obj/item/radio/headset/headset_srvmed name = "service medical headset" desc = "A headset allowing the wearer to communicate with medbay and service." icon_state = "srv_headset" + worn_icon_state = "srv_headset" keyslot = /obj/item/encryptionkey/headset_srvmed /obj/item/radio/headset/headset_com name = "command radio headset" desc = "A headset with a commanding channel." icon_state = "com_headset" + worn_icon_state = "com_headset" keyslot = /obj/item/encryptionkey/headset_com /obj/item/radio/headset/heads @@ -225,12 +222,14 @@ GLOBAL_LIST_INIT(channel_tokens, list( name = "\proper the captain's headset" desc = "The headset of the king." icon_state = "com_headset" + worn_icon_state = "com_headset" keyslot = /obj/item/encryptionkey/heads/captain /obj/item/radio/headset/heads/captain/alt name = "\proper the captain's bowman headset" desc = "The headset of the boss. Protects ears from flashbangs." icon_state = "com_headset_alt" + worn_icon_state = "com_headset_alt" /obj/item/radio/headset/heads/captain/alt/Initialize(mapload) . = ..() @@ -240,18 +239,21 @@ GLOBAL_LIST_INIT(channel_tokens, list( name = "\proper the research director's headset" desc = "Headset of the fellow who keeps society marching towards technological singularity." icon_state = "com_headset" + worn_icon_state = "com_headset" keyslot = /obj/item/encryptionkey/heads/rd /obj/item/radio/headset/heads/hos name = "\proper the head of security's headset" desc = "The headset of the man in charge of keeping order and protecting the station." icon_state = "com_headset" + worn_icon_state = "com_headset" keyslot = /obj/item/encryptionkey/heads/hos /obj/item/radio/headset/heads/hos/alt name = "\proper the head of security's bowman headset" desc = "The headset of the man in charge of keeping order and protecting the station. Protects ears from flashbangs." icon_state = "com_headset_alt" + worn_icon_state = "com_headset_alt" /obj/item/radio/headset/heads/hos/alt/Initialize(mapload) . = ..() @@ -261,36 +263,42 @@ GLOBAL_LIST_INIT(channel_tokens, list( name = "\proper the chief engineer's headset" desc = "The headset of the guy in charge of keeping the station powered and undamaged." icon_state = "com_headset" + worn_icon_state = "com_headset" keyslot = /obj/item/encryptionkey/heads/ce /obj/item/radio/headset/heads/cmo name = "\proper the chief medical officer's headset" desc = "The headset of the highly trained medical chief." icon_state = "com_headset" + worn_icon_state = "com_headset" keyslot = /obj/item/encryptionkey/heads/cmo /obj/item/radio/headset/heads/hop name = "\proper the head of personnel's headset" desc = "The headset of the guy who will one day be captain." icon_state = "com_headset" + worn_icon_state = "com_headset" keyslot = /obj/item/encryptionkey/heads/hop /obj/item/radio/headset/heads/qm name = "\proper the quartermaster's headset" desc = "The headset of the guy who runs the cargo department." icon_state = "com_headset" + worn_icon_state = "com_headset" keyslot = /obj/item/encryptionkey/heads/qm /obj/item/radio/headset/headset_cargo name = "supply radio headset" desc = "A headset used by the QM's slaves." icon_state = "cargo_headset" + worn_icon_state = "cargo_headset" keyslot = /obj/item/encryptionkey/headset_cargo /obj/item/radio/headset/headset_cargo/mining name = "mining radio headset" desc = "Headset used by shaft miners." icon_state = "mine_headset" + worn_icon_state = "mine_headset" // "puts the antenna down" while the headset is off overlay_speaker_idle = "headset_up" overlay_mic_idle = "headset_up" @@ -300,12 +308,14 @@ GLOBAL_LIST_INIT(channel_tokens, list( name = "service radio headset" desc = "Headset used by the service staff, tasked with keeping the station full, happy and clean." icon_state = "srv_headset" + worn_icon_state = "srv_headset" keyslot = /obj/item/encryptionkey/headset_service /obj/item/radio/headset/headset_cent name = "\improper CentCom headset" desc = "A headset used by the upper echelons of Nanotrasen." icon_state = "cent_headset" + worn_icon_state = "cent_headset" keyslot = /obj/item/encryptionkey/headset_cent keyslot2 = /obj/item/encryptionkey/headset_com @@ -320,6 +330,7 @@ GLOBAL_LIST_INIT(channel_tokens, list( name = "\improper CentCom bowman headset" desc = "A headset especially for emergency response personnel. Protects ears from flashbangs." icon_state = "cent_headset_alt" + worn_icon_state = "cent_headset_alt" keyslot2 = null /obj/item/radio/headset/headset_cent/alt/Initialize(mapload) diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index 918f241d16da4c..dcb7ddc1936ca4 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -34,6 +34,9 @@ return RegisterSignal(current_area, COMSIG_AREA_POWER_CHANGE, PROC_REF(AreaPowerCheck)) GLOB.intercoms_list += src + if(!unscrewed) + find_and_hang_on_wall(directional = TRUE, \ + custom_drop_callback = CALLBACK(src, PROC_REF(knock_down))) /obj/item/radio/intercom/Destroy() . = ..() @@ -79,8 +82,7 @@ if(tool.use_tool(src, user, 80)) user.visible_message(span_notice("[user] unsecures [src]!"), span_notice("You detach [src] from the wall.")) playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) - new/obj/item/wallframe/intercom(get_turf(src)) - qdel(src) + knock_down() /** * Override attack_tk_grab instead of attack_tk because we actually want attack_tk's @@ -174,6 +176,13 @@ set_on(current_area.powered(AREA_USAGE_EQUIP)) // set "on" to the equipment power status of our area. update_appearance() +/** + * Called by the wall mount component and reused during the tool deconstruction proc. + */ +/obj/item/radio/intercom/proc/knock_down() + new/obj/item/wallframe/intercom(get_turf(src)) + qdel(src) + //Created through the autolathe or through deconstructing intercoms. Can be applied to wall to make a new intercom on it! /obj/item/wallframe/intercom name = "intercom frame" diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm index cfaaf01d3e2a7f..50c42c5f75318a 100644 --- a/code/game/objects/items/devices/scanners/health_analyzer.dm +++ b/code/game/objects/items/devices/scanners/health_analyzer.dm @@ -506,7 +506,7 @@ #define AID_EMOTION_SAD "sad" /// Displays wounds with extended information on their status vs medscanners -/proc/woundscan(mob/user, mob/living/carbon/patient, obj/item/healthanalyzer/scanner) +/proc/woundscan(mob/user, mob/living/carbon/patient, obj/item/healthanalyzer/scanner, simple_scan = FALSE) if(!istype(patient) || user.incapacitated()) return @@ -517,7 +517,7 @@ render_list += "Warning: Physical trauma[LAZYLEN(wounded_part.wounds) > 1? "s" : ""] detected in [wounded_part.name]" for(var/limb_wound in wounded_part.wounds) var/datum/wound/current_wound = limb_wound - render_list += "
[current_wound.get_scanner_description()]
\n" + render_list += "
[simple_scan ? current_wound.get_simple_scanner_description() : current_wound.get_scanner_description()]
\n" if (scanner.give_wound_treatment_bonus) ADD_TRAIT(current_wound, TRAIT_WOUND_SCANNED, ANALYZER_TRAIT) if(!advised) @@ -525,11 +525,9 @@ advised = TRUE render_list += "
" - var/obj/item/healthanalyzer/simple/simple_scanner - if(istype(scanner, /obj/item/healthanalyzer/simple)) - simple_scanner = scanner if(render_list == "") - if (simple_scanner) + if(simple_scan) + var/obj/item/healthanalyzer/simple/simple_scanner = scanner // Only emit the cheerful scanner message if this scan came from a scanner playsound(simple_scanner, 'sound/machines/ping.ogg', 50, FALSE) to_chat(user, span_notice("\The [simple_scanner] makes a happy ping and briefly displays a smiley face with several exclamation points! It's really excited to report that [patient] has no wounds!")) @@ -537,7 +535,8 @@ to_chat(user, "No wounds detected in subject.") else to_chat(user, examine_block(jointext(render_list, "")), type = MESSAGE_TYPE_INFO) - if (simple_scanner) + if(simple_scan) + var/obj/item/healthanalyzer/simple/simple_scanner = scanner simple_scanner.show_emotion(AID_EMOTION_WARN) playsound(simple_scanner, 'sound/machines/twobeep.ogg', 50, FALSE) @@ -597,7 +596,7 @@ show_emotion(AI_EMOTION_SAD) return - woundscan(user, patient, src) + woundscan(user, patient, src, simple_scan = TRUE) flick(icon_state + "_pinprick", src) /obj/item/healthanalyzer/simple/update_overlays() diff --git a/code/game/objects/items/eightball.dm b/code/game/objects/items/eightball.dm index 7b8354b0a777bd..737ba7e947c5ae 100644 --- a/code/game/objects/items/eightball.dm +++ b/code/game/objects/items/eightball.dm @@ -11,8 +11,8 @@ var/shaking = FALSE var/on_cooldown = FALSE - var/shake_time = 50 - var/cooldown_time = 100 + var/shake_time = 5 SECONDS + var/cooldown_time = 10 SECONDS var/static/list/possible_answers = list( "It is certain", @@ -42,11 +42,16 @@ return INITIALIZE_HINT_QDEL /obj/item/toy/eightball/proc/MakeHaunted() - . = prob(1) - if(.) + if(prob(1)) new /obj/item/toy/eightball/haunted(loc) + return TRUE + return FALSE /obj/item/toy/eightball/attack_self(mob/user) + if(..()) + return + + . = TRUE if(shaking) return @@ -60,23 +65,19 @@ start_shaking(user) if(do_after(user, shake_time)) - var/answer = get_answer() - say(answer) + say(get_answer()) on_cooldown = TRUE - addtimer(CALLBACK(src, PROC_REF(clear_cooldown)), cooldown_time) + addtimer(VARSET_CALLBACK(src, on_cooldown, FALSE), cooldown_time) shaking = FALSE -/obj/item/toy/eightball/proc/start_shaking(user) +/obj/item/toy/eightball/proc/start_shaking(mob/user) return /obj/item/toy/eightball/proc/get_answer() return pick(possible_answers) -/obj/item/toy/eightball/proc/clear_cooldown() - on_cooldown = FALSE - // A broken magic eightball, it only says "YOU SUCK" over and over again. /obj/item/toy/eightball/broken @@ -97,7 +98,7 @@ /obj/item/toy/eightball/haunted shake_time = 30 SECONDS cooldown_time = 3 MINUTES - var/last_message + var/last_message = "Nothing!" var/selected_message //these kind of store the same thing but one is easier to work with. var/list/votes = list() @@ -160,6 +161,7 @@ notify_ghosts("[user] is shaking [src], hoping to get an answer to \"[selected_message]\"", source=src, enter_link="(Click to help)", action=NOTIFY_ATTACK, header = "Magic eightball") /obj/item/toy/eightball/haunted/Topic(href, href_list) + . = ..() if(href_list["interact"]) if(isobserver(usr)) interact(usr) @@ -169,7 +171,7 @@ var/top_vote for(var/vote in votes) - var/amount_of_votes = length(votes[vote]) + var/amount_of_votes = votes[vote] if(amount_of_votes > top_amount) top_vote = vote top_amount = amount_of_votes @@ -186,12 +188,19 @@ voted.Cut() - return top_vote + var/list/top_options = haunted_answers[top_vote] + return pick(top_options) + +// Only ghosts can interact because only ghosts can open the ui +/obj/item/toy/eightball/haunted/can_interact(mob/living/user) + return isobserver(user) /obj/item/toy/eightball/haunted/ui_state(mob/user) return GLOB.observer_state /obj/item/toy/eightball/haunted/ui_interact(mob/user, datum/tgui/ui) + if(!isobserver(user)) + return ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "EightBallVote", name) @@ -224,9 +233,11 @@ var/selected_answer = params["answer"] if(!(selected_answer in haunted_answers)) return - if(user.ckey in voted) - return - else - votes[selected_answer] += 1 - voted[user.ckey] = selected_answer - . = TRUE + var/oldvote = voted[user.ckey] + if(oldvote) + // detract their old vote + votes[oldvote] -= 1 + + votes[selected_answer] += 1 + voted[user.ckey] = selected_answer + return TRUE diff --git a/code/game/objects/items/food/_food.dm b/code/game/objects/items/food/_food.dm index 2b7e4b4cf36869..69cfdde4668bc9 100644 --- a/code/game/objects/items/food/_food.dm +++ b/code/game/objects/items/food/_food.dm @@ -51,10 +51,7 @@ ///Buff given when a hand-crafted version of this item is consumed. Randomized according to crafting_complexity if not assigned. var/datum/status_effect/food/crafted_food_buff = null -/obj/item/food/Initialize(mapload, starting_reagent_purity, no_base_reagents = FALSE) - src.starting_reagent_purity = starting_reagent_purity - if(no_base_reagents) - food_reagents = null +/obj/item/food/Initialize(mapload) if(food_reagents) food_reagents = string_assoc_list(food_reagents) . = ..() diff --git a/code/game/objects/items/food/bread.dm b/code/game/objects/items/food/bread.dm index 08722f101c5e9c..ba1845bb40da4a 100644 --- a/code/game/objects/items/food/bread.dm +++ b/code/game/objects/items/food/bread.dm @@ -55,10 +55,6 @@ . = ..() AddComponent(/datum/component/customizable_reagent_holder, /obj/item/food/bread/empty, CUSTOM_INGREDIENT_ICON_FILL, max_ingredients = 8) -// special subtype we use for the "Bread" Admin Smite (or the breadify proc) -/obj/item/food/bread/plain/smite - desc = "If you hold it up to your ear, you can hear the screams of the damned." - /obj/item/food/breadslice/plain name = "bread slice" desc = "A slice of home." diff --git a/code/game/objects/items/food/burgers.dm b/code/game/objects/items/food/burgers.dm index 311d87b319228d..191cc0eaf25733 100644 --- a/code/game/objects/items/food/burgers.dm +++ b/code/game/objects/items/food/burgers.dm @@ -226,10 +226,15 @@ verb_yell = "wails" venue_value = FOOD_PRICE_EXOTIC crafting_complexity = FOOD_COMPLEXITY_3 + preserved_food = TRUE // It's made of ghosts -/obj/item/food/burger/ghost/Initialize(mapload) +/obj/item/food/burger/ghost/Initialize(mapload, starting_reagent_purity, no_base_reagents) . = ..() START_PROCESSING(SSobj, src) + AddComponent(/datum/component/ghost_edible, bite_consumption = bite_consumption) + +/obj/item/food/burger/ghost/make_germ_sensitive() + return // This burger moves itself so it shouldn't pick up germs from walking onto the floor /obj/item/food/burger/ghost/process() if(!isturf(loc)) //no floating out of bags @@ -256,8 +261,6 @@ new /obj/effect/decal/cleanable/greenglow/ecto(loc) playsound(loc, 'sound/effects/splat.ogg', 200, TRUE) - //If i was less lazy i would make the burger forcefeed itself to a nearby mob here. - /obj/item/food/burger/ghost/Destroy() STOP_PROCESSING(SSobj, src) . = ..() diff --git a/code/game/objects/items/food/pancakes.dm b/code/game/objects/items/food/pancakes.dm index 6e4d33fb35049b..52829ab4c3acd4 100644 --- a/code/game/objects/items/food/pancakes.dm +++ b/code/game/objects/items/food/pancakes.dm @@ -147,6 +147,7 @@ var/mutable_appearance/pancake_visual = mutable_appearance(icon, "[pancake.stack_name]_[rand(1, 3)]") pancake_visual.pixel_x = rand(-1, 1) pancake_visual.pixel_y = 3 * contents.len - 1 + pancake_visual.layer = layer + (contents.len * 0.01) add_overlay(pancake_visual) update_appearance() diff --git a/code/game/objects/items/food/pastries.dm b/code/game/objects/items/food/pastries.dm index 02782c3e3f1444..46da05dea14039 100644 --- a/code/game/objects/items/food/pastries.dm +++ b/code/game/objects/items/food/pastries.dm @@ -34,6 +34,10 @@ foodtypes = GRAIN | FRUIT | SUGAR | BREAKFAST crafting_complexity = FOOD_COMPLEXITY_4 +/obj/item/food/muffin/booberry/Initialize(mapload, starting_reagent_purity, no_base_reagents) + . = ..() + AddComponent(/datum/component/ghost_edible, bite_consumption = bite_consumption) + /obj/item/food/muffin/moffin name = "moffin" icon_state = "moffin_1" @@ -367,7 +371,10 @@ */ var/list/prefill_flavours -/obj/item/food/icecream/Initialize(mapload, starting_reagent_purity, no_base_reagents, list/prefill_flavours) +/obj/item/food/icecream/New(loc, list/prefill_flavours) + return ..() + +/obj/item/food/icecream/Initialize(mapload, list/prefill_flavours) if(prefill_flavours) src.prefill_flavours = prefill_flavours return ..() diff --git a/code/game/objects/items/hand_items.dm b/code/game/objects/items/hand_items.dm index b136fc68cda38a..5dfb27e77eaadb 100644 --- a/code/game/objects/items/hand_items.dm +++ b/code/game/objects/items/hand_items.dm @@ -128,7 +128,7 @@ return FALSE var/obj/item/bodypart/head/the_head = target.get_bodypart(BODY_ZONE_HEAD) - if(!(the_head.biological_state & BIO_FLESH) || !IS_ORGANIC_LIMB(the_head)) + if(!(the_head.biological_state & BIO_FLESH)) to_chat(user, span_warning("You can't noogie [target], [target.p_they()] [target.p_have()] no skin on [target.p_their()] head!")) return diff --git a/code/game/objects/items/kirby_plants/kirbyplants.dm b/code/game/objects/items/kirby_plants/kirbyplants.dm index 6e7f5a99d958bb..74a0c8637e8949 100644 --- a/code/game/objects/items/kirby_plants/kirbyplants.dm +++ b/code/game/objects/items/kirby_plants/kirbyplants.dm @@ -75,21 +75,6 @@ var/next = WRAP(current+1,1,length(random_plant_states)) icon_state = random_plant_states[next] -/obj/item/kirbyplants/random - icon = 'icons/obj/fluff/flora/_flora.dmi' - icon_state = "random_plant" - -/obj/item/kirbyplants/random/Initialize(mapload) - . = ..() - //icon = 'icons/obj/flora/plants.dmi' // ORIGINAL - icon = 'modular_skyrat/modules/aesthetics/plants/plants.dmi' //SKYRAT EDIT CHANGE - if(!random_plant_states) - generate_states() - var/current = random_plant_states.Find(icon_state) - var/next = WRAP(current+1,1,length(random_plant_states)) - base_icon_state = random_plant_states[next] - update_appearance(UPDATE_ICON) - /obj/item/kirbyplants/proc/generate_states() random_plant_states = list() for(var/i in 1 to random_state_cap) //SKYRAT EDIT CHANGE - ORIGINAL: for(var/i in 1 to 24) @@ -107,7 +92,8 @@ /obj/item/kirbyplants/random/Initialize(mapload) . = ..() - icon = 'icons/obj/fluff/flora/plants.dmi' + //icon = 'icons/obj/flora/plants.dmi' // ORIGINAL + icon = 'modular_skyrat/modules/aesthetics/plants/plants.dmi' //SKYRAT EDIT CHANGE randomize_base_icon_state() //Handles randomizing the icon during initialize() diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index f24efb7d26380e..cd196ed48cfa23 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -60,8 +60,8 @@ //very imprecise /obj/item/melee/sabre - name = "officer's sabre" - desc = "An elegant weapon, its monomolecular edge is capable of cutting through flesh and bone with ease." + name = "officer's sabre" //SKYRAT EDIT - Buffed in modular_skyrat/modules/modular_weapons/code/melee.dm + desc = "An elegant weapon, its monomolecular edge is capable of cutting through flesh and bone with ease." icon = 'icons/obj/weapons/sword.dmi' icon_state = "sabre" inhand_icon_state = "sabre" diff --git a/code/game/objects/items/robot/items/food.dm b/code/game/objects/items/robot/items/food.dm index 832dcfd2cd6caf..a747f813ace869 100644 --- a/code/game/objects/items/robot/items/food.dm +++ b/code/game/objects/items/robot/items/food.dm @@ -61,10 +61,8 @@ food_item = new /obj/item/food/lollipop/cyborg(turf_to_dispense_to) if(DISPENSE_ICECREAM_MODE) food_item = new /obj/item/food/icecream( - /* loc = */ turf_to_dispense_to, - /* starting_reagent_purity = */ null, - /* no_base_reagents = */ FALSE, - /* prefill_flavours = */ list(ICE_CREAM_VANILLA), + loc = turf_to_dispense_to, + prefill_flavours = list(ICE_CREAM_VANILLA), ) food_item.desc = "Eat the ice cream." diff --git a/code/game/objects/items/robot/items/storage.dm b/code/game/objects/items/robot/items/storage.dm index 25f85644a1c439..6570e159b6a094 100644 --- a/code/game/objects/items/robot/items/storage.dm +++ b/code/game/objects/items/robot/items/storage.dm @@ -190,6 +190,21 @@ handle_reflling(arrived) return ..() +///Used by the service borg drink apparatus upgrade, holds drink-related items +/obj/item/borg/apparatus/beaker/drink + name = "secondary beverage storage apparatus" + desc = "A special apparatus for carrying drinks and condiment packets without spilling their contents. Will NOT resynthesize drinks unlike your standard apparatus." + icon_state = "borg_beaker_apparatus" + storable = list( + /obj/item/reagent_containers/cup/glass, + /obj/item/reagent_containers/condiment, + /obj/item/reagent_containers/cup/coffeepot, + /obj/item/reagent_containers/cup/bottle/syrup_bottle, + ) + +/obj/item/borg/apparatus/beaker/service2/add_glass() + stored = new /obj/item/reagent_containers/cup/glass/drinkingglass(src) + /// allows medical cyborgs to manipulate organs without hands /obj/item/borg/apparatus/organ_storage name = "organ storage bag" diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 496e4b39a46e32..94432b35d3df0d 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -731,6 +731,33 @@ if (E) R.model.remove_module(E, TRUE) +/obj/item/borg/upgrade/drink_app + name = "glass storage apparatus" + desc = "A supplementary drinking glass storage apparatus for service cyborgs." + icon_state = "cyborg_upgrade3" + require_model = TRUE + model_type = list(/obj/item/robot_model/service) + model_flags = BORG_MODEL_SERVICE + +/obj/item/borg/upgrade/drink_app/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) + var/obj/item/borg/apparatus/beaker/drink/E = locate() in R.model.modules + if(E) + to_chat(user, span_warning("This unit has no room for additional drink storage!")) + return FALSE + + E = new(R.model) + R.model.basic_modules += E + R.model.add_module(E, FALSE, TRUE) + +/obj/item/borg/upgrade/drink_app/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + var/obj/item/borg/apparatus/beaker/drink/E = locate() in R.model.modules + if (E) + R.model.remove_module(E, TRUE) + /obj/item/borg/upgrade/broomer name = "experimental push broom" desc = "An experimental push broom used for efficiently pushing refuse." diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index d071e3465afde2..081ab5d78e015e 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -433,7 +433,7 @@ patient.emote("scream") for(var/i in patient.bodyparts) - var/obj/item/bodypart/bone = i + var/obj/item/bodypart/bone = i // fine to just, use these raw, its a meme anyway var/datum/wound/blunt/bone/severe/oof_ouch = new oof_ouch.apply_wound(bone, wound_source = "bone gel") var/datum/wound/blunt/bone/critical/oof_OUCH = new diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 9257035d8dee2b..289920c8889858 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -505,6 +505,9 @@ GLOBAL_LIST_INIT(durathread_recipes, list ( \ . = ..() . += GLOB.durathread_recipes +/obj/item/stack/sheet/durathread/on_item_crafted(mob/builder, atom/created) + created.set_armor_rating(CONSUME, max(50, created.get_armor_rating(CONSUME))) + /obj/item/stack/sheet/cotton name = "raw cotton bundle" desc = "A bundle of raw cotton ready to be spun on the loom." diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 54fb486683510e..7050309268cd0e 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -145,18 +145,49 @@ /obj/item/stack/set_custom_materials(list/materials, multiplier=1, is_update=FALSE) return is_update ? ..() : set_mats_per_unit(materials, multiplier/(amount || 1)) - -/obj/item/stack/on_grind() - . = ..() - for(var/i in 1 to length(grind_results)) //This should only call if it's ground, so no need to check if grind_results exists - grind_results[grind_results[i]] *= get_amount() //Gets the key at position i, then the reagent amount of that key, then multiplies it by stack size - /obj/item/stack/grind_requirements() if(is_cyborg) to_chat(usr, span_warning("[src] is too integrated into your chassis and can't be ground up!")) return return TRUE +/obj/item/stack/grind(datum/reagents/target_holder, mob/user) + var/current_amount = get_amount() + if(current_amount <= 0 || QDELETED(src)) //just to get rid of this 0 amount/deleted stack we return success + return TRUE + if(on_grind() == -1) + return FALSE + if(isnull(target_holder)) + return TRUE + + if(reagents) + reagents.trans_to(target_holder, reagents.total_volume, transferred_by = user) + var/available_volume = target_holder.maximum_volume - target_holder.total_volume + + //compute total volume of reagents that will be occupied by grind_results + var/total_volume = 0 + for(var/reagent in grind_results) + total_volume += grind_results[reagent] + + //compute number of pieces(or sheets) from available_volume + var/available_amount = min(current_amount, round(available_volume / total_volume)) + if(available_amount <= 0) + return FALSE + + //Now transfer the grind results scaled by available_amount + var/list/grind_reagents = grind_results.Copy() + for(var/reagent in grind_reagents) + grind_reagents[reagent] *= available_amount + target_holder.add_reagent_list(grind_reagents) + + /** + * use available_amount of sheets/pieces, return TRUE only if all sheets/pieces of this stack were used + * we don't delete this stack when it reaches 0 because we expect the all in one grinder, etc to delete + * this stack if grinding was successfull + */ + use(available_amount, check = FALSE) + return available_amount == current_amount + /obj/item/stack/proc/get_main_recipes() RETURN_TYPE(/list) SHOULD_CALL_PARENT(TRUE) @@ -401,6 +432,7 @@ if(created) created.setDir(builder.dir) + on_item_crafted(builder, created) // Use up the material use(recipe.req_amount * multiplier) @@ -431,6 +463,10 @@ return TRUE +/// Run special logic on created items after they've been successfully crafted. +/obj/item/stack/proc/on_item_crafted(mob/builder, atom/created) + return + /obj/item/stack/vv_edit_var(vname, vval) if(vname == NAMEOF(src, amount)) add(clamp(vval, 1-amount, max_amount - amount)) //there must always be one. diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index 484797ca29ce14..a67d85979f1040 100644 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -75,6 +75,7 @@ /obj/item/wirecutters, /obj/item/wrench, /obj/item/spess_knife, + /obj/item/melee/sickly_blade/knock, )) /obj/item/storage/belt/utility/chief diff --git a/code/game/objects/items/storage/boxes/job_boxes.dm b/code/game/objects/items/storage/boxes/job_boxes.dm index 658b07a3980a32..335ccbe7185e9c 100644 --- a/code/game/objects/items/storage/boxes/job_boxes.dm +++ b/code/game/objects/items/storage/boxes/job_boxes.dm @@ -48,6 +48,9 @@ if(HAS_TRAIT(SSstation, STATION_TRAIT_RADIOACTIVE_NEBULA)) new /obj/item/storage/pill_bottle/potassiodide(src) + + if(SSmapping.is_planetary() && LAZYLEN(SSmapping.multiz_levels)) + new /obj/item/climbing_hook/emergency(src) new /obj/item/oxygen_candle(src) //SKYRAT EDIT ADDITION diff --git a/code/game/objects/items/storage/secure.dm b/code/game/objects/items/storage/secure.dm index 46eb8356c79d45..ad4be8d6e4088a 100644 --- a/code/game/objects/items/storage/secure.dm +++ b/code/game/objects/items/storage/secure.dm @@ -181,6 +181,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/item/storage/secure/safe, 32) . = ..() atom_storage.set_holdable(cant_hold_list = list(/obj/item/storage/secure/briefcase)) atom_storage.max_specific_storage = WEIGHT_CLASS_GIGANTIC + find_and_hang_on_wall() /obj/item/storage/secure/safe/PopulateContents() new /obj/item/paper(src) diff --git a/code/game/objects/items/surgery_tray.dm b/code/game/objects/items/surgery_tray.dm index 5ef5bfdae7a584..df597abee2576f 100644 --- a/code/game/objects/items/surgery_tray.dm +++ b/code/game/objects/items/surgery_tray.dm @@ -1,8 +1,31 @@ +/datum/storage/surgery_tray + max_total_storage = 30 + max_specific_storage = WEIGHT_CLASS_NORMAL + max_slots = 14 + +/datum/storage/surgery_tray/New() + . = ..() + set_holdable(list( + /obj/item/blood_filter, + /obj/item/bonesetter, + /obj/item/cautery, + /obj/item/circular_saw, + /obj/item/clothing/mask/surgical, + /obj/item/hemostat, + /obj/item/razor, + /obj/item/reagent_containers/medigel, + /obj/item/retractor, + /obj/item/scalpel, + /obj/item/stack/medical/bone_gel, + /obj/item/stack/sticky_tape/surgical, + /obj/item/surgical_drapes, + /obj/item/surgicaldrill, + )) + /** * Surgery Trays * A storage object that displays tools in its contents based on tier, better tools are more visible. * Can be folded up and carried. Click it to draw a random tool. - * */ /obj/item/surgery_tray name = "surgery tray" @@ -15,25 +38,10 @@ /// If true we're currently portable var/is_portable = TRUE - /// List of things that we spawn containing - var/list/initial_contents = list( - /obj/item/blood_filter, - /obj/item/bonesetter, - /obj/item/cautery, - /obj/item/circular_saw, - /obj/item/clothing/mask/surgical, - /obj/item/hemostat, - /obj/item/razor/surgery, - /obj/item/retractor, - /obj/item/scalpel, - /obj/item/stack/medical/bone_gel, - /obj/item/stack/sticky_tape/surgical, - /obj/item/surgical_drapes, - /obj/item/surgicaldrill, - ) -/obj/item/surgery_tray/deployed - is_portable = FALSE +/// Fills the tray with items it should contain on creation +/obj/item/surgery_tray/proc/populate_contents() + return /obj/item/surgery_tray/Initialize(mapload) . = ..() @@ -66,6 +74,7 @@ . += is_portable \ ? span_notice("You can click and drag it to yourself to pick it up, then use it in your hand to make it a cart!") \ : span_notice("You can click and drag it to yourself to turn it into a tray!") + . += span_notice("The top is screwed on.") /obj/item/surgery_tray/update_overlays() . = ..() @@ -102,12 +111,6 @@ for(var/surgery_tool in surgery_overlays) . |= surgery_overlays[surgery_tool] -///Spawn the things we contain on initialisation -/obj/item/surgery_tray/proc/populate_contents() - for (var/thing_path in initial_contents) - new thing_path(src) - update_appearance(UPDATE_OVERLAYS) - ///Sets the surgery tray's deployment state. Silent if user is null. /obj/item/surgery_tray/proc/set_tray_mode(new_mode, mob/user) is_portable = new_mode @@ -154,54 +157,82 @@ user.put_in_hands(grabbies) return TRUE +/obj/item/surgery_tray/screwdriver_act_secondary(mob/living/user, obj/item/tool) + . = ..() + tool.play_tool_sound(src) + to_chat(user, span_notice("You begin taking apart [src].")) + if(!tool.use_tool(src, user, 1 SECONDS)) + return + deconstruct(TRUE) + to_chat(user, span_notice("[src] has been taken apart.")) + /obj/item/surgery_tray/dump_contents() var/atom/drop_point = drop_location() for(var/atom/movable/tool as anything in contents) tool.forceMove(drop_point) /obj/item/surgery_tray/deconstruct(disassembled = TRUE) - dump_contents() + if(!(flags_1 & NODECONSTRUCT_1)) + dump_contents() + new /obj/item/stack/rods(drop_location(), 2) + new /obj/item/stack/sheet/mineral/silver(drop_location()) return ..() -/obj/item/surgery_tray/morgue +/obj/item/surgery_tray/deployed + is_portable = FALSE + +/obj/item/surgery_tray/full + +/obj/item/surgery_tray/full/deployed + is_portable = FALSE + +/obj/item/surgery_tray/full/populate_contents() + new /obj/item/blood_filter(src) + new /obj/item/bonesetter(src) + new /obj/item/cautery(src) + new /obj/item/circular_saw(src) + new /obj/item/clothing/mask/surgical(src) + new /obj/item/hemostat(src) + new /obj/item/razor/surgery(src) + new /obj/item/retractor(src) + new /obj/item/scalpel(src) + new /obj/item/stack/medical/bone_gel(src) + new /obj/item/stack/sticky_tape/surgical(src) + new /obj/item/surgical_drapes(src) + new /obj/item/surgicaldrill(src) + update_appearance(UPDATE_OVERLAYS) + +/obj/item/surgery_tray/full/morgue name = "autopsy tray" desc = "A Deforest brand surgery tray, made for use in morgues. It is a folding model, \ meaning the wheels on the bottom can be extended outwards, making it a cart." - initial_contents = list( - /obj/item/blood_filter, - /obj/item/bonesetter, - /obj/item/cautery/cruel, - /obj/item/circular_saw, - /obj/item/clothing/mask/surgical, - /obj/item/hemostat/cruel, - /obj/item/razor/surgery, - /obj/item/retractor/cruel, - /obj/item/scalpel/cruel, - /obj/item/stack/medical/bone_gel, - /obj/item/stack/sticky_tape/surgical, - /obj/item/surgical_drapes, - /obj/item/surgicaldrill, - ) - -/datum/storage/surgery_tray - max_total_storage = 30 - max_specific_storage = WEIGHT_CLASS_NORMAL - max_slots = 14 - -/datum/storage/surgery_tray/New() - . = ..() - set_holdable(list( - /obj/item/blood_filter, - /obj/item/bonesetter, - /obj/item/cautery, - /obj/item/circular_saw, - /obj/item/clothing/mask/surgical, - /obj/item/hemostat, - /obj/item/razor, - /obj/item/retractor, - /obj/item/scalpel, - /obj/item/stack/medical/bone_gel, - /obj/item/stack/sticky_tape/surgical, - /obj/item/surgical_drapes, - /obj/item/surgicaldrill, - )) + +/obj/item/surgery_tray/full/morgue/populate_contents() + new /obj/item/blood_filter(src) + new /obj/item/bonesetter(src) + new /obj/item/cautery/cruel(src) + new /obj/item/circular_saw(src) + new /obj/item/clothing/mask/surgical(src) + new /obj/item/hemostat/cruel(src) + new /obj/item/razor/surgery(src) + new /obj/item/retractor/cruel(src) + new /obj/item/scalpel/cruel(src) + new /obj/item/stack/medical/bone_gel(src) + new /obj/item/stack/sticky_tape/surgical(src) + new /obj/item/surgical_drapes(src) + new /obj/item/surgicaldrill(src) + +/// Surgery tray with advanced tools for debug +/obj/item/surgery_tray/full/advanced + +/obj/item/surgery_tray/full/advanced/populate_contents() + new /obj/item/scalpel/advanced + new /obj/item/retractor/advanced + new /obj/item/cautery/advanced + new /obj/item/surgical_drapes + new /obj/item/reagent_containers/medigel/sterilizine + new /obj/item/bonesetter + new /obj/item/blood_filter + new /obj/item/stack/medical/bone_gel + new /obj/item/stack/sticky_tape/surgical + new /obj/item/clothing/mask/surgical diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 2eef8cc116e443..c7f93c6ea68bfe 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -285,7 +285,7 @@ var/obj/item/bodypart/chest/CH = user.get_bodypart(BODY_ZONE_CHEST) if(CH.cavity_item) // if he's (un)bright enough to have a round and full belly... user.visible_message(span_danger("[user] regurgitates [src]!")) // I swear i dont have a fetish - user.vomit(100, TRUE, distance = 0) + user.vomit(VOMIT_CATEGORY_BLOOD, lost_nutrition = 100, distance = 0) user.adjustOxyLoss(120) user.dropItemToGround(src) // incase the crit state doesn't drop the singulo to the floor user.set_suicide(FALSE) diff --git a/code/game/objects/items/wall_mounted.dm b/code/game/objects/items/wall_mounted.dm index 3cfafe74f9735d..48142778a925e9 100644 --- a/code/game/objects/items/wall_mounted.dm +++ b/code/game/objects/items/wall_mounted.dm @@ -40,20 +40,19 @@ span_hear("You hear clicking.")) var/floor_to_wall = get_dir(user, on_wall) - var/obj/O = new result_path(get_turf(user), floor_to_wall, TRUE) - O.setDir(floor_to_wall) - + var/obj/hanging_object = new result_path(get_turf(user), floor_to_wall, TRUE) + hanging_object.setDir(floor_to_wall) if(pixel_shift) switch(floor_to_wall) if(NORTH) - O.pixel_y = pixel_shift + hanging_object.pixel_y = pixel_shift if(SOUTH) - O.pixel_y = -pixel_shift + hanging_object.pixel_y = -pixel_shift if(EAST) - O.pixel_x = pixel_shift + hanging_object.pixel_x = pixel_shift if(WEST) - O.pixel_x = -pixel_shift - after_attach(O) + hanging_object.pixel_x = -pixel_shift + after_attach(hanging_object) qdel(src) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 1e05bae62989d1..f4758b9019f460 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -1,5 +1,9 @@ #define LOCKER_FULL -1 +///A comprehensive list of all closets (NOT CRATES) in the game world +GLOBAL_LIST_EMPTY(roundstart_station_closets) + + /obj/structure/closet name = "closet" desc = "It's a basic storage unit." @@ -15,7 +19,7 @@ contents_pressure_protection = 0 /// How insulated the thing is, for the purposes of calculating body temperature. Must be between 0 and 1! contents_thermal_insulation = 0 - pass_flags_self = LETPASSCLICKS + pass_flags_self = PASSSTRUCTURE | LETPASSCLICKS /// The overlay for the closet's door var/obj/effect/overlay/closet_door/door_obj @@ -120,6 +124,9 @@ if(access_choices) access_choices = card_reader_choices + if(is_station_level(z) && mapload) + add_to_roundstart_list() + // if closed, any item at the crate's loc is put in the contents if (mapload && !opened) . = INITIALIZE_HINT_LATELOAD @@ -155,6 +162,7 @@ /obj/structure/closet/Destroy() id_card = null QDEL_NULL(door_obj) + GLOB.roundstart_station_closets -= src return ..() /obj/structure/closet/update_appearance(updates=ALL) @@ -1142,4 +1150,8 @@ /obj/structure/closet/preopen opened = TRUE +///Adds the closet to a global list. Placed in its own proc so that crates may be excluded. +/obj/structure/closet/proc/add_to_roundstart_list() + GLOB.roundstart_station_closets += src + #undef LOCKER_FULL diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index 8f7f34164c0f48..9700a3e80fa98f 100755 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -183,6 +183,7 @@ new /obj/item/pinpointer/crew(src) new /obj/item/binoculars(src) new /obj/item/storage/box/rxglasses/spyglasskit(src) + new /obj/item/clothing/head/fedora/inspector_hat(src) /obj/structure/closet/secure_closet/injection name = "lethal injections" diff --git a/code/game/objects/structures/crates_lockers/closets/syndicate.dm b/code/game/objects/structures/crates_lockers/closets/syndicate.dm index fdba3e10adb6db..aab8e4b8582869 100644 --- a/code/game/objects/structures/crates_lockers/closets/syndicate.dm +++ b/code/game/objects/structures/crates_lockers/closets/syndicate.dm @@ -29,6 +29,7 @@ new /obj/item/clothing/under/syndicate/skirt(src) new /obj/item/clothing/shoes/sneakers/black(src) new /obj/item/mod/module/plasma_stabilizer(src) + new /obj/item/climbing_hook/syndicate(src) /obj/structure/closet/syndicate/nuclear desc = "It's a storage unit for a Syndicate boarding party." diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 4059839641cca3..1f8322ad5dc9f1 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -352,3 +352,6 @@ . = ..() for(var/i in 1 to 4) new /obj/effect/spawner/random/decoration/generic(src) + +/obj/structure/closet/crate/add_to_roundstart_list() + return diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index ce000e91e696ab..62638f44eeb778 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -293,7 +293,6 @@ door = new airlock_type( loc ) door.setDir(dir) door.unres_sides = electronics.unres_sides - //door.req_access = req_access door.electronics = electronics door.heat_proof = heat_proof_finished door.security_level = 0 @@ -321,9 +320,11 @@ door.unres_sensor = TRUE door.previous_airlock = previous_assembly electronics.forceMove(door) + door.autoclose = TRUE + door.close() door.update_appearance() + qdel(src) - return door /obj/structure/door_assembly/update_overlays() . = ..() diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm index 04e48e489ac914..56d9147867d53f 100644 --- a/code/game/objects/structures/extinguisher.dm +++ b/code/game/objects/structures/extinguisher.dm @@ -22,6 +22,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/extinguisher_cabinet, 29) stored_extinguisher = new /obj/item/extinguisher(src) update_appearance(UPDATE_ICON) register_context() + find_and_hang_on_wall() /obj/structure/extinguisher_cabinet/add_context(atom/source, list/context, obj/item/held_item, mob/user) . = ..() diff --git a/code/game/objects/structures/fireaxe.dm b/code/game/objects/structures/fireaxe.dm index 75294549ebe4c6..59a00618b0e915 100644 --- a/code/game/objects/structures/fireaxe.dm +++ b/code/game/objects/structures/fireaxe.dm @@ -36,6 +36,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/fireaxecabinet, 32) if(populate_contents) held_item = new item_path(src) update_appearance() + find_and_hang_on_wall() /obj/structure/fireaxecabinet/Destroy() if(held_item) diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 21767551886cf1..3c99aee7233d30 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -27,6 +27,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror, 28) +/obj/structure/mirror/Initialize(mapload) + . = ..() + find_and_hang_on_wall() + /obj/structure/mirror/broken icon_state = "mirror_broke" diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 19e43c8bc3793a..c8a97f0cb8a113 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -362,10 +362,8 @@ GLOBAL_LIST_EMPTY(crematoriums) var/list/icecreams = list() for(var/mob/living/i_scream as anything in get_all_contents_type(/mob/living)) var/obj/item/food/icecream/IC = new /obj/item/food/icecream( - /* loc = */ null, - /* starting_reagent_purity = */ null, - /* no_base_reagents = */ FALSE, - /* prefill_flavours = */ list(ICE_CREAM_MOB = list(null, i_scream.name)) + loc = null, + prefill_flavours = list(ICE_CREAM_MOB = list(null, i_scream.name)) ) icecreams += IC . = ..() diff --git a/code/game/objects/structures/noticeboard.dm b/code/game/objects/structures/noticeboard.dm index 9d09a7470185d4..534622619d122f 100644 --- a/code/game/objects/structures/noticeboard.dm +++ b/code/game/objects/structures/noticeboard.dm @@ -26,6 +26,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/noticeboard, 32) I.forceMove(src) notices++ update_appearance(UPDATE_ICON) + find_and_hang_on_wall() //attaching papers!! /obj/structure/noticeboard/attackby(obj/item/O, mob/user, params) diff --git a/code/game/objects/structures/signs/_signs.dm b/code/game/objects/structures/signs/_signs.dm index cdb7ba0811f2aa..b8709334c37f6c 100644 --- a/code/game/objects/structures/signs/_signs.dm +++ b/code/game/objects/structures/signs/_signs.dm @@ -14,6 +14,8 @@ var/is_editable = FALSE ///sign_change_name is used to make nice looking, alphebetized and categorized names when you use a pen on any sign item or structure which is_editable. var/sign_change_name + ///Callback to the knock down proc for wallmounting behavior. + var/knock_down_callback /datum/armor/structure_sign melee = 50 @@ -23,6 +25,12 @@ /obj/structure/sign/Initialize(mapload) . = ..() register_context() + knock_down_callback = CALLBACK(src, PROC_REF(knock_down)) + find_and_hang_on_wall(custom_drop_callback = knock_down_callback) + +/obj/structure/sign/Destroy() + . = ..() + knock_down_callback = null /obj/structure/sign/add_context(atom/source, list/context, obj/item/held_item, mob/user) . = ..() @@ -55,18 +63,7 @@ playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) user.visible_message(span_notice("[user] unfastens [src]."), \ span_notice("You unfasten [src].")) - var/obj/item/sign/unwrenched_sign = new (get_turf(user)) - if(type != /obj/structure/sign/blank) //If it's still just a basic sign backing, we can (and should) skip some of the below variable transfers. - unwrenched_sign.name = name //Copy over the sign structure variables to the sign item we're creating when we unwrench a sign. - unwrenched_sign.desc = "[desc] It can be placed on a wall." - unwrenched_sign.icon = icon - unwrenched_sign.icon_state = icon_state - unwrenched_sign.sign_path = type - unwrenched_sign.set_custom_materials(custom_materials) //This is here so picture frames and wooden things don't get messed up. - unwrenched_sign.is_editable = is_editable - unwrenched_sign.update_integrity(get_integrity()) //Transfer how damaged it is. - unwrenched_sign.setDir(dir) - qdel(src) //The sign structure on the wall goes poof and only the sign item from unwrenching remains. + knock_down(user) return TRUE /obj/structure/sign/welder_act(mob/living/user, obj/item/I) @@ -115,6 +112,29 @@ return return ..() +/** + * This is called when a sign is removed from a wall, either through deconstruction or being knocked down. + * @param mob/living/user The user who removed the sign, if it was knocked down by a mob. + */ +/obj/structure/sign/proc/knock_down(mob/living/user) + var/turf/drop_turf + if(user) + drop_turf = get_turf(user) + else + drop_turf = drop_location() + var/obj/item/sign/unwrenched_sign = new (drop_turf) + if(type != /obj/structure/sign/blank) //If it's still just a basic sign backing, we can (and should) skip some of the below variable transfers. + unwrenched_sign.name = name //Copy over the sign structure variables to the sign item we're creating when we unwrench a sign. + unwrenched_sign.desc = "[desc] It can be placed on a wall." + unwrenched_sign.icon = icon + unwrenched_sign.icon_state = icon_state + unwrenched_sign.sign_path = type + unwrenched_sign.set_custom_materials(custom_materials) //This is here so picture frames and wooden things don't get messed up. + unwrenched_sign.is_editable = is_editable + unwrenched_sign.update_integrity(get_integrity()) //Transfer how damaged it is. + unwrenched_sign.setDir(dir) + qdel(src) //The sign structure on the wall goes poof and only the sign item from unwrenching remains. + /obj/structure/sign/blank //This subtype is necessary for now because some other things (posters, picture frames, paintings) inheret from the parent type. icon_state = "backing" name = "sign backing" @@ -211,6 +231,7 @@ playsound(target_turf, 'sound/items/deconstruct.ogg', 50, TRUE) placed_sign.update_integrity(get_integrity()) placed_sign.setDir(dir) + placed_sign.find_and_hang_on_wall(TRUE, placed_sign.knock_down_callback) qdel(src) /obj/item/sign/welder_act(mob/living/user, obj/item/I) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 708291182341c6..a3ff544800f542 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -66,7 +66,7 @@ if(istype(held_item, /obj/item/toy/cards/deck)) var/obj/item/toy/cards/deck/dealer_deck = held_item - if(dealer_deck.wielded) + if(HAS_TRAIT(dealer_deck, TRAIT_WIELDED)) context[SCREENTIP_CONTEXT_LMB] = "Deal card" context[SCREENTIP_CONTEXT_RMB] = "Deal card faceup" . = CONTEXTUAL_SCREENTIP_SET @@ -238,7 +238,7 @@ if(istype(I, /obj/item/toy/cards/deck)) var/obj/item/toy/cards/deck/dealer_deck = I - if(dealer_deck.wielded) // deal a card facedown on the table + if(HAS_TRAIT(dealer_deck, TRAIT_WIELDED)) // deal a card facedown on the table var/obj/item/toy/singlecard/card = dealer_deck.draw(user) if(card) attackby(card, user, params) @@ -284,7 +284,7 @@ /obj/structure/table/attackby_secondary(obj/item/weapon, mob/user, params) if(istype(weapon, /obj/item/toy/cards/deck)) var/obj/item/toy/cards/deck/dealer_deck = weapon - if(dealer_deck.wielded) // deal a card faceup on the table + if(HAS_TRAIT(dealer_deck, TRAIT_WIELDED)) // deal a card faceup on the table var/obj/item/toy/singlecard/card = dealer_deck.draw(user) if(card) card.Flip() diff --git a/code/game/objects/structures/toiletbong.dm b/code/game/objects/structures/toiletbong.dm index cb8d98305126f1..45ce79f9c32e48 100644 --- a/code/game/objects/structures/toiletbong.dm +++ b/code/game/objects/structures/toiletbong.dm @@ -53,7 +53,7 @@ to_chat(user, span_userdanger("There was something disgusting in the pipes!")) user.visible_message(span_danger("[user] spits out a mouse.")) user.adjust_disgust(50) - user.vomit(10) + user.vomit(VOMIT_CATEGORY_DEFAULT) var/mob/living/spawned_mob = new /mob/living/basic/mouse(get_turf(user)) spawned_mob.faction |= "[REF(user)]" if(prob(50)) diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index ec0ae01fbf6cae..b991bc0c2746f7 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -168,6 +168,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/urinal, 32) /obj/structure/urinal/Initialize(mapload) . = ..() hidden_item = new /obj/item/food/urinalcake + find_and_hang_on_wall() /obj/structure/urinal/attack_hand(mob/living/user, list/modifiers) . = ..() diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index b4498699bf70c3..46eb13ee2b7c14 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -30,7 +30,7 @@ var/state = "01" //How far the door assembly has progressed can_atmos_pass = ATMOS_PASS_PROC -/obj/structure/windoor_assembly/Initialize(mapload, loc, set_dir) +/obj/structure/windoor_assembly/Initialize(mapload, set_dir) . = ..() if(set_dir) setDir(set_dir) @@ -267,55 +267,11 @@ span_notice("You start prying the windoor into the frame...")) if(W.use_tool(src, user, 40, volume=100) && electronics) - set_density(TRUE) //Shouldn't matter but just incase - to_chat(user, span_notice("You finish the windoor.")) - - if(secure) - var/obj/machinery/door/window/brigdoor/windoor = new /obj/machinery/door/window/brigdoor(loc) - if(facing == "l") - windoor.icon_state = "leftsecureopen" - windoor.base_state = "leftsecure" - else - windoor.icon_state = "rightsecureopen" - windoor.base_state = "rightsecure" - windoor.setDir(dir) - windoor.set_density(FALSE) - - if(electronics.one_access) - windoor.req_one_access = electronics.accesses - else - windoor.req_access = electronics.accesses - windoor.electronics = electronics - electronics.forceMove(windoor) - if(created_name) - windoor.name = created_name - qdel(src) - windoor.close() - - else - var/obj/machinery/door/window/windoor = new /obj/machinery/door/window(loc) - if(facing == "l") - windoor.icon_state = "leftopen" - windoor.base_state = "left" - else - windoor.icon_state = "rightopen" - windoor.base_state = "right" - windoor.setDir(dir) - windoor.set_density(FALSE) - - if(electronics.one_access) - windoor.req_one_access = electronics.accesses - else - windoor.req_access = electronics.accesses - windoor.electronics = electronics - electronics.forceMove(windoor) - if(created_name) - windoor.name = created_name - qdel(src) - windoor.close() + to_chat(user, span_notice("You finish the windoor.")) + finish_door() else return ..() @@ -323,6 +279,54 @@ //Update to reflect changes(if applicable) update_appearance() +/obj/structure/windoor_assembly/proc/finish_door() + var/obj/machinery/door/window/windoor + if(secure) + windoor = new /obj/machinery/door/window/brigdoor(loc) + if(facing == "l") + windoor.icon_state = "leftsecureopen" + windoor.base_state = "leftsecure" + else + windoor.icon_state = "rightsecureopen" + windoor.base_state = "rightsecure" + + else + windoor = new /obj/machinery/door/window(loc) + if(facing == "l") + windoor.icon_state = "leftopen" + windoor.base_state = "left" + else + windoor.icon_state = "rightopen" + windoor.base_state = "right" + + windoor.setDir(dir) + windoor.set_density(FALSE) + if(created_name) + windoor.name = created_name + else if(electronics.passed_name) + windoor.name = electronics.passed_name + if(electronics.one_access) + windoor.req_one_access = electronics.accesses + else + windoor.req_access = electronics.accesses + if(electronics.unres_sides) + windoor.unres_sides = electronics.unres_sides + switch(dir) + if(NORTH,SOUTH) + windoor.unres_sides &= ~EAST + windoor.unres_sides &= ~WEST + if(EAST,WEST) + windoor.unres_sides &= ~NORTH + windoor.unres_sides &= ~SOUTH + windoor.unres_sensor = TRUE + electronics.forceMove(windoor) + windoor.electronics = electronics + windoor.autoclose = TRUE + windoor.close() + windoor.update_appearance() + + qdel(src) + /obj/structure/windoor_assembly/AltClick(mob/user) return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation diff --git a/code/game/shuttle_engines.dm b/code/game/shuttle_engines.dm index 4d6a96ca12c75d..159dab78ceeb83 100644 --- a/code/game/shuttle_engines.dm +++ b/code/game/shuttle_engines.dm @@ -33,6 +33,10 @@ fire = 50 acid = 70 +/obj/machinery/power/shuttle_engine/Initialize(mapload) + . = ..() + register_context() + /obj/machinery/power/shuttle_engine/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock) . = ..() if(!port) @@ -49,6 +53,27 @@ unsync_ship() return ..() +/obj/machinery/power/shuttle_engine/examine(mob/user) + . = ..() + switch(engine_state) + if(ENGINE_UNWRENCHED) + . += span_notice("\The [src] is unbolted from the floor. It needs to be wrenched to the floor to be installed.") + if(ENGINE_WRENCHED) + . += span_notice("\The [src] is bolted to the floor and can be unbolted with a wrench. It needs to be welded to the floor to finish installation.") + if(ENGINE_WELDED) + . += span_notice("\The [src] is welded to the floor and can be unwelded. It is currently fully installed.") + +/obj/machinery/power/shuttle_engine/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) + if(held_item?.tool_behaviour == TOOL_WELDER && engine_state == ENGINE_WRENCHED) + context[SCREENTIP_CONTEXT_LMB] = "Weld to Floor" + if(held_item?.tool_behaviour == TOOL_WELDER && engine_state == ENGINE_WELDED) + context[SCREENTIP_CONTEXT_LMB] = "Unweld from Floor" + if(held_item?.tool_behaviour == TOOL_WRENCH && engine_state == ENGINE_UNWRENCHED) + context[SCREENTIP_CONTEXT_LMB] = "Wrench to Floor" + if(held_item?.tool_behaviour == TOOL_WRENCH && engine_state == ENGINE_WRENCHED) + context[SCREENTIP_CONTEXT_LMB] = "Unwrench from Floor" + return CONTEXTUAL_SCREENTIP_SET + /** * Called on destroy and when we need to unsync an engine from their ship. */ diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm index 6a7f533e4de8d9..f5b40238ed60c7 100644 --- a/code/game/turfs/change_turf.dm +++ b/code/game/turfs/change_turf.dm @@ -105,7 +105,9 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( //We do this here so anything that doesn't want to persist can clear itself var/list/old_listen_lookup = _listen_lookup?.Copy() var/list/old_signal_procs = _signal_procs?.Copy() + var/carryover_turf_flags = (RESERVATION_TURF | UNUSED_RESERVATION_TURF) & turf_flags var/turf/new_turf = new path(src) + new_turf.turf_flags |= carryover_turf_flags // WARNING WARNING // Turfs DO NOT lose their signals when they get replaced, REMEMBER THIS diff --git a/code/game/turfs/closed/_closed.dm b/code/game/turfs/closed/_closed.dm index 5d913f196012ba..8ccaabc46c0afa 100644 --- a/code/game/turfs/closed/_closed.dm +++ b/code/game/turfs/closed/_closed.dm @@ -15,361 +15,3 @@ /turf/closed/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) return FALSE - -/turf/closed/indestructible - name = "wall" - desc = "Effectively impervious to conventional methods of destruction." - icon = 'icons/turf/walls.dmi' - explosive_resistance = 50 - -/turf/closed/indestructible/rust_heretic_act() - return - -/turf/closed/indestructible/TerraformTurf(path, new_baseturf, flags, defer_change = FALSE, ignore_air = FALSE) - return - -/turf/closed/indestructible/acid_act(acidpwr, acid_volume, acid_id) - return FALSE - -/turf/closed/indestructible/Melt() - to_be_destroyed = FALSE - return src - -/turf/closed/indestructible/singularity_act() - return - -/turf/closed/indestructible/attackby(obj/item/attacking_item, mob/user, params) - if(istype(attacking_item, /obj/item/poster) && Adjacent(user)) - return place_poster(attacking_item, user) - - return ..() - -/turf/closed/indestructible/oldshuttle - name = "strange shuttle wall" - icon = 'icons/turf/shuttleold.dmi' - icon_state = "block" - -/turf/closed/indestructible/weeb - name = "paper wall" - desc = "Reinforced paper walling. Someone really doesn't want you to leave." - icon = 'icons/obj/smooth_structures/paperframes.dmi' - icon_state = "paperframes-0" - base_icon_state = "paperframes" - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_PAPERFRAME - canSmoothWith = SMOOTH_GROUP_PAPERFRAME - var/static/mutable_appearance/indestructible_paper = mutable_appearance('icons/obj/smooth_structures/paperframes.dmi',icon_state = "paper", layer = CLOSED_TURF_LAYER - 0.1) - -/turf/closed/indestructible/weeb/Initialize(mapload) - . = ..() - update_appearance() - -/turf/closed/indestructible/weeb/update_overlays() - . = ..() - . += indestructible_paper - -/turf/closed/indestructible/sandstone - name = "sandstone wall" - desc = "A wall with sandstone plating. Rough." - icon = 'icons/turf/walls/sandstone_wall.dmi' - icon_state = "sandstone_wall-0" - base_icon_state = "sandstone_wall" - baseturfs = /turf/closed/indestructible/sandstone - smoothing_flags = SMOOTH_BITMASK - -/turf/closed/indestructible/oldshuttle/corner - icon_state = "corner" - -/turf/closed/indestructible/splashscreen - name = "Space Station 13" - desc = null - icon = 'icons/blanks/blank_title.png' - icon_state = "" - pixel_x = 0 // SKYRAT EDIT - Re-centering the title screen - ORIGINAL: pixel_x = -64 - plane = SPLASHSCREEN_PLANE - bullet_bounce_sound = null - -INITIALIZE_IMMEDIATE(/turf/closed/indestructible/splashscreen) -/* SKYRAT EDIT REMOVAL -/turf/closed/indestructible/splashscreen/Initialize(mapload) - . = ..() - SStitle.splash_turf = src - if(SStitle.icon) - icon = SStitle.icon - handle_generic_titlescreen_sizes() - -///helper proc that will center the screen if the icon is changed to a generic width, to make admins have to fudge around with pixel_x less. returns null -/turf/closed/indestructible/splashscreen/proc/handle_generic_titlescreen_sizes() - var/icon/size_check = icon(SStitle.icon, icon_state) - var/width = size_check.Width() - if(width == 480) // 480x480 is nonwidescreen - pixel_x = 0 - else if(width == 608) // 608x480 is widescreen - pixel_x = -64 - // SKYRAT EDIT START - Wider widescreen - else if(width == 672) // Skyrat's widescreen is slightly wider than /tg/'s, so we need to accomodate that too. - pixel_x = -96 - // SKYRAT EDIT END - -/turf/closed/indestructible/splashscreen/vv_edit_var(var_name, var_value) - . = ..() - if(.) - switch(var_name) - if(NAMEOF(src, icon)) - SStitle.icon = icon - handle_generic_titlescreen_sizes() -*/ -/turf/closed/indestructible/start_area - name = null - desc = null - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - -/turf/closed/indestructible/reinforced - name = "reinforced wall" - desc = "A huge chunk of reinforced metal used to separate rooms. Effectively impervious to conventional methods of destruction." - icon = 'icons/turf/walls/reinforced_wall.dmi' - icon_state = "reinforced_wall-0" - base_icon_state = "reinforced_wall" - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_WALLS - -/turf/closed/indestructible/riveted - icon = 'icons/turf/walls/riveted.dmi' - icon_state = "riveted-0" - base_icon_state = "riveted" - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_CLOSED_TURFS - -/turf/closed/indestructible/syndicate - icon = 'icons/turf/walls/plastitanium_wall.dmi' - icon_state = "plastitanium_wall-0" - base_icon_state = "plastitanium_wall" - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + SMOOTH_GROUP_SYNDICATE_WALLS - canSmoothWith = SMOOTH_GROUP_SHUTTLE_PARTS + SMOOTH_GROUP_AIRLOCK + SMOOTH_GROUP_PLASTITANIUM_WALLS + SMOOTH_GROUP_SYNDICATE_WALLS - -/turf/closed/indestructible/riveted/uranium - icon = 'icons/turf/walls/uranium_wall.dmi' - icon_state = "uranium_wall-0" - base_icon_state = "uranium_wall" - smoothing_flags = SMOOTH_BITMASK - -/turf/closed/indestructible/riveted/plastinum - name = "plastinum wall" - desc = "A luxurious wall made out of a plasma-platinum alloy. Effectively impervious to conventional methods of destruction." - icon = 'icons/turf/walls/plastinum_wall.dmi' - icon_state = "plastinum_wall-0" - base_icon_state = "plastinum_wall" - smoothing_flags = SMOOTH_BITMASK | SMOOTH_DIAGONAL_CORNERS - smoothing_groups = SMOOTH_GROUP_WALLS + SMOOTH_GROUP_PLASTINUM_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_PLASTINUM_WALLS - -/turf/closed/indestructible/riveted/plastinum/nodiagonal - icon_state = "map-shuttle_nd" - smoothing_flags = SMOOTH_BITMASK - -/turf/closed/indestructible/wood - icon = 'icons/turf/walls/wood_wall.dmi' - icon_state = "wood_wall-0" - base_icon_state = "wood_wall" - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_WOOD_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_WOOD_WALLS - - -/turf/closed/indestructible/alien - name = "alien wall" - desc = "A wall with alien alloy plating." - icon = 'icons/turf/walls/abductor_wall.dmi' - icon_state = "abductor_wall-0" - base_icon_state = "abductor_wall" - smoothing_flags = SMOOTH_BITMASK | SMOOTH_DIAGONAL_CORNERS - smoothing_groups = SMOOTH_GROUP_ABDUCTOR_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_ABDUCTOR_WALLS - - -/turf/closed/indestructible/cult - name = "runed metal wall" - desc = "A cold metal wall engraved with indecipherable symbols. Studying them causes your head to pound. Effectively impervious to conventional methods of destruction." - icon = 'icons/turf/walls/cult_wall.dmi' - icon_state = "cult_wall-0" - base_icon_state = "cult_wall" - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_WALLS - - -/turf/closed/indestructible/abductor - icon_state = "alien1" - -/turf/closed/indestructible/opshuttle - icon_state = "wall3" - - -/turf/closed/indestructible/fakeglass - name = "window" - icon = 'icons/obj/smooth_structures/reinforced_window.dmi' - icon_state = "fake_window" - base_icon_state = "reinforced_window" - opacity = FALSE - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_WINDOW_FULLTILE - canSmoothWith = SMOOTH_GROUP_WINDOW_FULLTILE - -/turf/closed/indestructible/fakeglass/Initialize(mapload) - . = ..() - underlays += mutable_appearance('icons/obj/structures.dmi', "grille", layer - 0.01) //add a grille underlay - underlays += mutable_appearance('icons/turf/floors.dmi', "plating", layer - 0.02) //add the plating underlay, below the grille - -/turf/closed/indestructible/opsglass - name = "window" - icon = 'icons/obj/smooth_structures/plastitanium_window.dmi' - icon_state = "plastitanium_window-0" - base_icon_state = "plastitanium_window" - opacity = FALSE - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_SHUTTLE_PARTS + SMOOTH_GROUP_WINDOW_FULLTILE_PLASTITANIUM - canSmoothWith = SMOOTH_GROUP_WINDOW_FULLTILE_PLASTITANIUM - -/turf/closed/indestructible/opsglass/Initialize(mapload) - . = ..() - icon_state = null - underlays += mutable_appearance('icons/obj/structures.dmi', "grille", layer - 0.01) - underlays += mutable_appearance('icons/turf/floors.dmi', "plating", layer - 0.02) - -/turf/closed/indestructible/fakedoor - name = "airlock" - icon = 'icons/obj/doors/airlocks/centcom/centcom.dmi' - icon_state = "fake_door" - -/turf/closed/indestructible/fakedoor/maintenance - icon = 'icons/obj/doors/airlocks/hatch/maintenance.dmi' - -/turf/closed/indestructible/fakedoor/glass_airlock - icon = 'icons/obj/doors/airlocks/external/external.dmi' - opacity = FALSE - -/turf/closed/indestructible/fakedoor/engineering - icon = 'icons/obj/doors/airlocks/station/engineering.dmi' - -/turf/closed/indestructible/rock - name = "dense rock" - desc = "An extremely densely-packed rock, most mining tools or explosives would never get through this." - icon = 'icons/turf/mining.dmi' - icon_state = "rock" - -/turf/closed/indestructible/rock/snow - name = "mountainside" - desc = "An extremely densely-packed rock, sheeted over with centuries worth of ice and snow." - icon = 'icons/turf/walls.dmi' - icon_state = "snowrock" - bullet_sizzle = TRUE - bullet_bounce_sound = null - -/turf/closed/indestructible/rock/snow/ice - name = "iced rock" - desc = "Extremely densely-packed sheets of ice and rock, forged over the years of the harsh cold." - icon = 'icons/turf/walls.dmi' - icon_state = "icerock" - -/turf/closed/indestructible/rock/snow/ice/ore - icon = 'icons/turf/walls/icerock_wall.dmi' - icon_state = "icerock_wall-0" - base_icon_state = "icerock_wall" - smoothing_flags = SMOOTH_BITMASK | SMOOTH_BORDER - canSmoothWith = SMOOTH_GROUP_CLOSED_TURFS - pixel_x = -4 - pixel_y = -4 - -/turf/closed/indestructible/paper - name = "thick paper wall" - desc = "A wall layered with impenetrable sheets of paper." - icon = 'icons/turf/walls.dmi' - icon_state = "paperwall" - -/turf/closed/indestructible/necropolis - name = "necropolis wall" - desc = "A seemingly impenetrable wall." - icon = 'icons/turf/walls.dmi' - icon_state = "necro" - explosive_resistance = 50 - baseturfs = /turf/closed/indestructible/necropolis - -/turf/closed/indestructible/necropolis/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) - underlay_appearance.icon = 'icons/turf/floors.dmi' - underlay_appearance.icon_state = "necro1" - return TRUE - -/turf/closed/indestructible/iron - name = "impervious iron wall" - desc = "A wall with tough iron plating." - icon = 'icons/turf/walls/iron_wall.dmi' - icon_state = "iron_wall-0" - base_icon_state = "iron_wall" - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_IRON_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS - canSmoothWith = SMOOTH_GROUP_IRON_WALLS - opacity = FALSE - -/turf/closed/indestructible/riveted/boss - name = "necropolis wall" - desc = "A thick, seemingly indestructible stone wall." - icon = 'icons/turf/walls/boss_wall.dmi' - icon_state = "boss_wall-0" - base_icon_state = "boss_wall" - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_CLOSED_TURFS + SMOOTH_GROUP_BOSS_WALLS - canSmoothWith = SMOOTH_GROUP_BOSS_WALLS - explosive_resistance = 50 - baseturfs = /turf/closed/indestructible/riveted/boss - -/turf/closed/indestructible/riveted/boss/see_through - opacity = FALSE - -/turf/closed/indestructible/riveted/boss/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) - underlay_appearance.icon = 'icons/turf/floors.dmi' - underlay_appearance.icon_state = "basalt" - return TRUE - -/turf/closed/indestructible/riveted/hierophant - name = "wall" - desc = "A wall made out of a strange metal. The squares on it pulse in a predictable pattern." - icon = 'icons/turf/walls/hierophant_wall.dmi' - icon_state = "wall" - smoothing_flags = SMOOTH_CORNERS - smoothing_groups = SMOOTH_GROUP_HIERO_WALL - canSmoothWith = SMOOTH_GROUP_HIERO_WALL - -/turf/closed/indestructible/resin - name = "resin wall" - icon = 'icons/obj/smooth_structures/alien/resin_wall.dmi' - icon_state = "resin_wall-0" - base_icon_state = "resin_wall" - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = SMOOTH_GROUP_ALIEN_WALLS + SMOOTH_GROUP_ALIEN_RESIN - canSmoothWith = SMOOTH_GROUP_ALIEN_WALLS - -/turf/closed/indestructible/resin/membrane - name = "resin membrane" - icon = 'icons/obj/smooth_structures/alien/resin_membrane.dmi' - icon_state = "resin_membrane-0" - base_icon_state = "resin_membrane" - opacity = FALSE - smoothing_groups = SMOOTH_GROUP_ALIEN_WALLS + SMOOTH_GROUP_ALIEN_RESIN - canSmoothWith = SMOOTH_GROUP_ALIEN_WALLS - -/turf/closed/indestructible/resin/membrane/Initialize(mapload) - . = ..() - underlays += mutable_appearance('icons/turf/floors.dmi', "engine") // add the reinforced floor underneath - -/turf/closed/indestructible/grille - name = "grille" - icon = 'icons/obj/structures.dmi' - icon_state = "grille" - base_icon_state = "grille" - -/turf/closed/indestructible/grille/Initialize(mapload) - . = ..() - underlays += mutable_appearance('icons/turf/floors.dmi', "plating") diff --git a/code/game/turfs/closed/indestructible.dm b/code/game/turfs/closed/indestructible.dm new file mode 100644 index 00000000000000..b364ad428d0359 --- /dev/null +++ b/code/game/turfs/closed/indestructible.dm @@ -0,0 +1,363 @@ +/turf/closed/indestructible + name = "wall" + desc = "Effectively impervious to conventional methods of destruction." + icon = 'icons/turf/walls.dmi' + explosive_resistance = 50 + +/turf/closed/indestructible/rust_heretic_act() + return + +/turf/closed/indestructible/TerraformTurf(path, new_baseturf, flags, defer_change = FALSE, ignore_air = FALSE) + return + +/turf/closed/indestructible/acid_act(acidpwr, acid_volume, acid_id) + return FALSE + +/turf/closed/indestructible/Melt() + to_be_destroyed = FALSE + return src + +/turf/closed/indestructible/singularity_act() + return + +/turf/closed/indestructible/attackby(obj/item/attacking_item, mob/user, params) + if(istype(attacking_item, /obj/item/poster) && Adjacent(user)) + return place_poster(attacking_item, user) + + return ..() + +/turf/closed/indestructible/oldshuttle + name = "strange shuttle wall" + icon = 'icons/turf/shuttleold.dmi' + icon_state = "block" + +/turf/closed/indestructible/weeb + name = "paper wall" + desc = "Reinforced paper walling. Someone really doesn't want you to leave." + icon = 'icons/obj/smooth_structures/paperframes.dmi' + icon_state = "paperframes-0" + base_icon_state = "paperframes" + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_PAPERFRAME + canSmoothWith = SMOOTH_GROUP_PAPERFRAME + var/static/mutable_appearance/indestructible_paper = mutable_appearance('icons/obj/smooth_structures/paperframes.dmi',icon_state = "paper", layer = CLOSED_TURF_LAYER - 0.1) + +/turf/closed/indestructible/weeb/Initialize(mapload) + . = ..() + update_appearance() + +/turf/closed/indestructible/weeb/update_overlays() + . = ..() + . += indestructible_paper + +/turf/closed/indestructible/sandstone + name = "sandstone wall" + desc = "A wall with sandstone plating. Rough." + icon = 'icons/turf/walls/sandstone_wall.dmi' + icon_state = "sandstone_wall-0" + base_icon_state = "sandstone_wall" + baseturfs = /turf/closed/indestructible/sandstone + smoothing_flags = SMOOTH_BITMASK + +/turf/closed/indestructible/oldshuttle/corner + icon_state = "corner" + +/turf/closed/indestructible/splashscreen + name = "Space Station 13" + desc = null + icon = 'icons/blanks/blank_title.png' + icon_state = "" + pixel_x = 0 // SKYRAT EDIT - Re-centering the title screen - ORIGINAL: pixel_x = -64 + plane = SPLASHSCREEN_PLANE + bullet_bounce_sound = null + +INITIALIZE_IMMEDIATE(/turf/closed/indestructible/splashscreen) +/* SKYRAT EDIT REMOVAL +/turf/closed/indestructible/splashscreen/Initialize(mapload) + . = ..() + SStitle.splash_turf = src + if(SStitle.icon) + icon = SStitle.icon + handle_generic_titlescreen_sizes() + +///helper proc that will center the screen if the icon is changed to a generic width, to make admins have to fudge around with pixel_x less. returns null +/turf/closed/indestructible/splashscreen/proc/handle_generic_titlescreen_sizes() + var/icon/size_check = icon(SStitle.icon, icon_state) + var/width = size_check.Width() + if(width == 480) // 480x480 is nonwidescreen + pixel_x = 0 + else if(width == 608) // 608x480 is widescreen + pixel_x = -64 + // SKYRAT EDIT START - Wider widescreen + else if(width == 672) // Skyrat's widescreen is slightly wider than /tg/'s, so we need to accomodate that too. + pixel_x = -96 + // SKYRAT EDIT END + +/turf/closed/indestructible/splashscreen/vv_edit_var(var_name, var_value) + . = ..() + if(.) + switch(var_name) + if(NAMEOF(src, icon)) + SStitle.icon = icon + handle_generic_titlescreen_sizes() + +/turf/closed/indestructible/splashscreen/examine() + desc = pick(strings(SPLASH_FILE, "splashes")) + return ..() +SKYRAT EDIT REMOVAL END */ + +/turf/closed/indestructible/start_area + name = null + desc = null + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + +/turf/closed/indestructible/reinforced + name = "reinforced wall" + desc = "A huge chunk of reinforced metal used to separate rooms. Effectively impervious to conventional methods of destruction." + icon = 'icons/turf/walls/reinforced_wall.dmi' + icon_state = "reinforced_wall-0" + base_icon_state = "reinforced_wall" + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_WALLS + + +/turf/closed/indestructible/riveted + icon = 'icons/turf/walls/riveted.dmi' + icon_state = "riveted-0" + base_icon_state = "riveted" + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_CLOSED_TURFS + +/turf/closed/indestructible/syndicate + icon = 'icons/turf/walls/plastitanium_wall.dmi' + icon_state = "plastitanium_wall-0" + base_icon_state = "plastitanium_wall" + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + SMOOTH_GROUP_SYNDICATE_WALLS + canSmoothWith = SMOOTH_GROUP_SHUTTLE_PARTS + SMOOTH_GROUP_AIRLOCK + SMOOTH_GROUP_PLASTITANIUM_WALLS + SMOOTH_GROUP_SYNDICATE_WALLS + +/turf/closed/indestructible/riveted/uranium + icon = 'icons/turf/walls/uranium_wall.dmi' + icon_state = "uranium_wall-0" + base_icon_state = "uranium_wall" + smoothing_flags = SMOOTH_BITMASK + +/turf/closed/indestructible/riveted/plastinum + name = "plastinum wall" + desc = "A luxurious wall made out of a plasma-platinum alloy. Effectively impervious to conventional methods of destruction." + icon = 'icons/turf/walls/plastinum_wall.dmi' + icon_state = "plastinum_wall-0" + base_icon_state = "plastinum_wall" + smoothing_flags = SMOOTH_BITMASK | SMOOTH_DIAGONAL_CORNERS + smoothing_groups = SMOOTH_GROUP_WALLS + SMOOTH_GROUP_PLASTINUM_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_PLASTINUM_WALLS + +/turf/closed/indestructible/riveted/plastinum/nodiagonal + icon_state = "map-shuttle_nd" + smoothing_flags = SMOOTH_BITMASK + +/turf/closed/indestructible/wood + icon = 'icons/turf/walls/wood_wall.dmi' + icon_state = "wood_wall-0" + base_icon_state = "wood_wall" + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_WOOD_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_WOOD_WALLS + + +/turf/closed/indestructible/alien + name = "alien wall" + desc = "A wall with alien alloy plating." + icon = 'icons/turf/walls/abductor_wall.dmi' + icon_state = "abductor_wall-0" + base_icon_state = "abductor_wall" + smoothing_flags = SMOOTH_BITMASK | SMOOTH_DIAGONAL_CORNERS + smoothing_groups = SMOOTH_GROUP_ABDUCTOR_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_ABDUCTOR_WALLS + + +/turf/closed/indestructible/cult + name = "runed metal wall" + desc = "A cold metal wall engraved with indecipherable symbols. Studying them causes your head to pound. Effectively impervious to conventional methods of destruction." + icon = 'icons/turf/walls/cult_wall.dmi' + icon_state = "cult_wall-0" + base_icon_state = "cult_wall" + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_WALLS + + +/turf/closed/indestructible/abductor + icon_state = "alien1" + +/turf/closed/indestructible/opshuttle + icon_state = "wall3" + + +/turf/closed/indestructible/fakeglass + name = "window" + icon = 'icons/obj/smooth_structures/reinforced_window.dmi' + icon_state = "fake_window" + base_icon_state = "reinforced_window" + opacity = FALSE + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_WINDOW_FULLTILE + canSmoothWith = SMOOTH_GROUP_WINDOW_FULLTILE + +/turf/closed/indestructible/fakeglass/Initialize(mapload) + . = ..() + underlays += mutable_appearance('icons/obj/structures.dmi', "grille", layer - 0.01) //add a grille underlay + underlays += mutable_appearance('icons/turf/floors.dmi', "plating", layer - 0.02) //add the plating underlay, below the grille + +/turf/closed/indestructible/opsglass + name = "window" + icon = 'icons/obj/smooth_structures/plastitanium_window.dmi' + icon_state = "plastitanium_window-0" + base_icon_state = "plastitanium_window" + opacity = FALSE + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_SHUTTLE_PARTS + SMOOTH_GROUP_WINDOW_FULLTILE_PLASTITANIUM + canSmoothWith = SMOOTH_GROUP_WINDOW_FULLTILE_PLASTITANIUM + +/turf/closed/indestructible/opsglass/Initialize(mapload) + . = ..() + icon_state = null + underlays += mutable_appearance('icons/obj/structures.dmi', "grille", layer - 0.01) + underlays += mutable_appearance('icons/turf/floors.dmi', "plating", layer - 0.02) + +/turf/closed/indestructible/fakedoor + name = "airlock" + icon = 'icons/obj/doors/airlocks/centcom/centcom.dmi' + icon_state = "fake_door" + +/turf/closed/indestructible/fakedoor/maintenance + icon = 'icons/obj/doors/airlocks/hatch/maintenance.dmi' + +/turf/closed/indestructible/fakedoor/glass_airlock + icon = 'icons/obj/doors/airlocks/external/external.dmi' + opacity = FALSE + +/turf/closed/indestructible/fakedoor/engineering + icon = 'icons/obj/doors/airlocks/station/engineering.dmi' + +/turf/closed/indestructible/rock + name = "dense rock" + desc = "An extremely densely-packed rock, most mining tools or explosives would never get through this." + icon = 'icons/turf/mining.dmi' + icon_state = "rock" + +/turf/closed/indestructible/rock/snow + name = "mountainside" + desc = "An extremely densely-packed rock, sheeted over with centuries worth of ice and snow." + icon = 'icons/turf/walls.dmi' + icon_state = "snowrock" + bullet_sizzle = TRUE + bullet_bounce_sound = null + +/turf/closed/indestructible/rock/snow/ice + name = "iced rock" + desc = "Extremely densely-packed sheets of ice and rock, forged over the years of the harsh cold." + icon = 'icons/turf/walls.dmi' + icon_state = "icerock" + +/turf/closed/indestructible/rock/snow/ice/ore + icon = 'icons/turf/walls/icerock_wall.dmi' + icon_state = "icerock_wall-0" + base_icon_state = "icerock_wall" + smoothing_flags = SMOOTH_BITMASK | SMOOTH_BORDER + canSmoothWith = SMOOTH_GROUP_CLOSED_TURFS + pixel_x = -4 + pixel_y = -4 + +/turf/closed/indestructible/paper + name = "thick paper wall" + desc = "A wall layered with impenetrable sheets of paper." + icon = 'icons/turf/walls.dmi' + icon_state = "paperwall" + +/turf/closed/indestructible/necropolis + name = "necropolis wall" + desc = "A seemingly impenetrable wall." + icon = 'icons/turf/walls.dmi' + icon_state = "necro" + explosive_resistance = 50 + baseturfs = /turf/closed/indestructible/necropolis + +/turf/closed/indestructible/necropolis/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) + underlay_appearance.icon = 'icons/turf/floors.dmi' + underlay_appearance.icon_state = "necro1" + return TRUE + +/turf/closed/indestructible/iron + name = "impervious iron wall" + desc = "A wall with tough iron plating." + icon = 'icons/turf/walls/iron_wall.dmi' + icon_state = "iron_wall-0" + base_icon_state = "iron_wall" + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_IRON_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_IRON_WALLS + opacity = FALSE + +/turf/closed/indestructible/riveted/boss + name = "necropolis wall" + desc = "A thick, seemingly indestructible stone wall." + icon = 'icons/turf/walls/boss_wall.dmi' + icon_state = "boss_wall-0" + base_icon_state = "boss_wall" + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_CLOSED_TURFS + SMOOTH_GROUP_BOSS_WALLS + canSmoothWith = SMOOTH_GROUP_BOSS_WALLS + explosive_resistance = 50 + baseturfs = /turf/closed/indestructible/riveted/boss + +/turf/closed/indestructible/riveted/boss/see_through + opacity = FALSE + +/turf/closed/indestructible/riveted/boss/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) + underlay_appearance.icon = 'icons/turf/floors.dmi' + underlay_appearance.icon_state = "basalt" + return TRUE + +/turf/closed/indestructible/riveted/hierophant + name = "wall" + desc = "A wall made out of a strange metal. The squares on it pulse in a predictable pattern." + icon = 'icons/turf/walls/hierophant_wall.dmi' + icon_state = "wall" + smoothing_flags = SMOOTH_CORNERS + smoothing_groups = SMOOTH_GROUP_HIERO_WALL + canSmoothWith = SMOOTH_GROUP_HIERO_WALL + +/turf/closed/indestructible/resin + name = "resin wall" + icon = 'icons/obj/smooth_structures/alien/resin_wall.dmi' + icon_state = "resin_wall-0" + base_icon_state = "resin_wall" + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_ALIEN_WALLS + SMOOTH_GROUP_ALIEN_RESIN + canSmoothWith = SMOOTH_GROUP_ALIEN_WALLS + +/turf/closed/indestructible/resin/membrane + name = "resin membrane" + icon = 'icons/obj/smooth_structures/alien/resin_membrane.dmi' + icon_state = "resin_membrane-0" + base_icon_state = "resin_membrane" + opacity = FALSE + smoothing_groups = SMOOTH_GROUP_ALIEN_WALLS + SMOOTH_GROUP_ALIEN_RESIN + canSmoothWith = SMOOTH_GROUP_ALIEN_WALLS + +/turf/closed/indestructible/resin/membrane/Initialize(mapload) + . = ..() + underlays += mutable_appearance('icons/turf/floors.dmi', "engine") // add the reinforced floor underneath + +/turf/closed/indestructible/grille + name = "grille" + icon = 'icons/obj/structures.dmi' + icon_state = "grille" + base_icon_state = "grille" + +/turf/closed/indestructible/grille/Initialize(mapload) + . = ..() + underlays += mutable_appearance('icons/turf/floors.dmi', "plating") diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm index 72e056288f3386..24c4c4914ec218 100644 --- a/code/game/turfs/open/_open.dm +++ b/code/game/turfs/open/_open.dm @@ -124,6 +124,9 @@ /turf/open/indestructible/light icon_state = "light_on-1" +/turf/open/indestructible/plating + icon_state = "plating" + /turf/open/indestructible/permalube icon_state = "darkfull" diff --git a/code/game/turfs/open/asteroid.dm b/code/game/turfs/open/asteroid.dm index cf7e07e75f359d..c15261a988059d 100644 --- a/code/game/turfs/open/asteroid.dm +++ b/code/game/turfs/open/asteroid.dm @@ -235,7 +235,8 @@ GLOBAL_LIST_EMPTY(dug_up_basalt) turf_flags = CAN_BE_DIRTY_1 | IS_SOLID | NO_RUST | NO_RUINS /turf/open/misc/asteroid/snow/icemoon/do_not_scrape - turf_flags = CAN_BE_DIRTY_1 | IS_SOLID | NO_RUST | NO_CLEARING + flags_1 = CAN_BE_DIRTY_1 + turf_flags = IS_SOLID | NO_RUST | NO_CLEARING /turf/open/lava/plasma/ice_moon initial_gas_mix = ICEMOON_DEFAULT_ATMOS diff --git a/code/game/turfs/open/floor.dm b/code/game/turfs/open/floor.dm index 6e8acf576cbcb6..a0d1a191bc6294 100644 --- a/code/game/turfs/open/floor.dm +++ b/code/game/turfs/open/floor.dm @@ -295,15 +295,11 @@ continue balloon_alert(user, "there's already a door!") return FALSE - var/obj/machinery/door/window/new_window = new the_rcd.airlock_type(src, user.dir, the_rcd.airlock_electronics?.unres_sides) - if(the_rcd.airlock_electronics) - new_window.name = the_rcd.airlock_electronics.passed_name || initial(new_window.name) - if(the_rcd.airlock_electronics.one_access) - new_window.req_one_access = the_rcd.airlock_electronics.accesses.Copy() - else - new_window.req_access = the_rcd.airlock_electronics.accesses.Copy() - new_window.autoclose = TRUE - new_window.update_appearance() + //create the assembly and let it finish itself + var/obj/structure/windoor_assembly/assembly = new /obj/structure/windoor_assembly(src, user.dir) + assembly.secure = ispath(the_rcd.airlock_type, /obj/machinery/door/window/brigdoor) + assembly.electronics = the_rcd.airlock_electronics.create_copy(assembly) + assembly.finish_door() return TRUE for(var/obj/machinery/door/door in src) @@ -311,29 +307,15 @@ continue balloon_alert(user, "there's already a door!") return FALSE - var/obj/machinery/door/airlock/new_airlock = new the_rcd.airlock_type(src) - new_airlock.electronics = new /obj/item/electronics/airlock(new_airlock) - if(the_rcd.airlock_electronics) - new_airlock.electronics.accesses = the_rcd.airlock_electronics.accesses.Copy() - new_airlock.electronics.one_access = the_rcd.airlock_electronics.one_access - new_airlock.electronics.unres_sides = the_rcd.airlock_electronics.unres_sides - new_airlock.electronics.passed_name = the_rcd.airlock_electronics.passed_name - new_airlock.electronics.passed_cycle_id = the_rcd.airlock_electronics.passed_cycle_id - new_airlock.electronics.shell = the_rcd.airlock_electronics.shell - if(new_airlock.electronics.one_access) - new_airlock.req_one_access = new_airlock.electronics.accesses + //create the assembly and let it finish itself + var/obj/structure/door_assembly/assembly = new (src) + if(ispath(the_rcd.airlock_type, /obj/machinery/door/airlock/glass)) + assembly.glass = TRUE + assembly.glass_type = the_rcd.airlock_type else - new_airlock.req_access = new_airlock.electronics.accesses - if(new_airlock.electronics.unres_sides) - new_airlock.unres_sides = new_airlock.electronics.unres_sides - new_airlock.unres_sensor = TRUE - if(new_airlock.electronics.passed_name) - new_airlock.name = sanitize(new_airlock.electronics.passed_name) - if(new_airlock.electronics.passed_cycle_id) - new_airlock.closeOtherId = new_airlock.electronics.passed_cycle_id - new_airlock.update_other_id() - new_airlock.autoclose = TRUE - new_airlock.update_appearance() + assembly.airlock_type = the_rcd.airlock_type + assembly.electronics = the_rcd.airlock_electronics.create_copy(assembly) + assembly.finish_door() return TRUE if(RCD_DECONSTRUCT) if(rcd_proof) diff --git a/code/game/turfs/open/openspace.dm b/code/game/turfs/open/openspace.dm index 12c7ade160c41d..91437e727a79b7 100644 --- a/code/game/turfs/open/openspace.dm +++ b/code/game/turfs/open/openspace.dm @@ -179,7 +179,7 @@ /turf/open/openspace/icemoon/Initialize(mapload) . = ..() - var/turf/T = below() + var/turf/T = GET_TURF_BELOW(src) //I wonder if I should error here if(!T) return diff --git a/code/game/turfs/open/space/transit.dm b/code/game/turfs/open/space/transit.dm index 3e3f7b0c55ef88..02d56a3be1e17f 100644 --- a/code/game/turfs/open/space/transit.dm +++ b/code/game/turfs/open/space/transit.dm @@ -4,7 +4,7 @@ icon_state = "black" dir = SOUTH baseturfs = /turf/open/space/transit - flags_1 = NOJAUNT //This line goes out to every wizard that ever managed to escape the den. I'm sorry. + turf_flags = NOJAUNT //This line goes out to every wizard that ever managed to escape the den. I'm sorry. explosive_resistance = INFINITY /turf/open/space/transit/Initialize(mapload) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 6010df76cd3cc8..3e2f43517aa31f 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -639,32 +639,19 @@ GLOBAL_LIST_EMPTY(station_turfs) /turf/AllowDrop() return TRUE -/turf/proc/add_vomit_floor(mob/living/M, vomit_type = VOMIT_TOXIC, purge_ratio = 0.1) +/turf/proc/add_vomit_floor(mob/living/vomiter, vomit_type = /obj/effect/decal/cleanable/vomit, vomit_flags, purge_ratio = 0.1) + var/obj/effect/decal/cleanable/vomit/throw_up = new vomit_type (src, vomiter.get_static_viruses()) - var/obj/effect/decal/cleanable/vomit/vomit - if (vomit_type == VOMIT_NEBULA) - vomit = new /obj/effect/decal/cleanable/vomit/nebula(src, M.get_static_viruses()) - else - vomit = new /obj/effect/decal/cleanable/vomit(src, M.get_static_viruses()) + // if the vomit combined, apply toxicity and reagents to the old vomit + if (QDELETED(throw_up)) + throw_up = locate() in src + if(isnull(throw_up)) + return - //if the vomit combined, apply toxicity and reagents to the old vomit - if (QDELETED(vomit)) - vomit = locate() in src - if(!vomit) + if(!iscarbon(vomiter) || (purge_ratio == 0)) return - // Apply the proper icon set based on vomit type - if(vomit_type == VOMIT_PURPLE) - vomit.icon_state = "vomitpurp_[pick(1,4)]" - else if (vomit_type == VOMIT_TOXIC) - vomit.icon_state = "vomittox_[pick(1,4)]" - //SKYRAT EDIT START - Nanite Slurry - else if (vomit_type == VOMIT_NANITE) - vomit.name = "metallic slurry" - vomit.desc = "A puddle of metallic slurry that looks vaguely like very fine sand. It almost seems like it's moving..." - vomit.icon_state = "vomitnanite_[pick(1,4)]" - // SKYRAT EDIT END - if (purge_ratio && iscarbon(M)) - clear_reagents_to_vomit_pool(M, vomit, purge_ratio) + + clear_reagents_to_vomit_pool(vomiter, throw_up, purge_ratio) /proc/clear_reagents_to_vomit_pool(mob/living/carbon/M, obj/effect/decal/cleanable/vomit/V, purge_ratio = 0.1) var/obj/item/organ/internal/stomach/belly = M.get_organ_slot(ORGAN_SLOT_STOMACH) diff --git a/code/game/world.dm b/code/game/world.dm index 380448d9fcfe77..e851bb992d4e32 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -399,31 +399,35 @@ GLOBAL_VAR(restart_counter) else hub_password = "SORRYNOPASSWORD" -// If this is called as a part of maploading you cannot call it on the newly loaded map zs, because those get handled later on in the pipeline -/world/proc/increaseMaxX(new_maxx, max_zs_to_load = maxz) +/** + * Handles incresing the world's maxx var and intializing the new turfs and assigning them to the global area. + * If map_load_z_cutoff is passed in, it will only load turfs up to that z level, inclusive. + * This is because maploading will handle the turfs it loads itself. + */ +/world/proc/increase_max_x(new_maxx, map_load_z_cutoff = maxz) if(new_maxx <= maxx) return var/old_max = world.maxx maxx = new_maxx - if(!max_zs_to_load) + if(!map_load_z_cutoff) return var/area/global_area = GLOB.areas_by_type[world.area] // We're guaranteed to be touching the global area, so we'll just do this var/list/to_add = block( locate(old_max + 1, 1, 1), - locate(maxx, maxy, max_zs_to_load)) + locate(maxx, maxy, map_load_z_cutoff)) global_area.contained_turfs += to_add -/world/proc/increaseMaxY(new_maxy, max_zs_to_load = maxz) +/world/proc/increase_max_y(new_maxy, map_load_z_cutoff = maxz) if(new_maxy <= maxy) return var/old_maxy = maxy maxy = new_maxy - if(!max_zs_to_load) + if(!map_load_z_cutoff) return var/area/global_area = GLOB.areas_by_type[world.area] // We're guarenteed to be touching the global area, so we'll just do this var/list/to_add = block( locate(1, old_maxy + 1, 1), - locate(maxx, maxy, max_zs_to_load)) + locate(maxx, maxy, map_load_z_cutoff)) global_area.contained_turfs += to_add /world/proc/incrementMaxZ() diff --git a/code/modules/actionspeed/_actionspeed_modifier.dm b/code/modules/actionspeed/_actionspeed_modifier.dm index 71bc966acf4dbf..761bfc3ff74a42 100644 --- a/code/modules/actionspeed/_actionspeed_modifier.dm +++ b/code/modules/actionspeed/_actionspeed_modifier.dm @@ -37,8 +37,11 @@ can next move /// Other modification datums this conflicts with. var/conflicts_with -/datum/actionspeed_modifier/New() +/datum/actionspeed_modifier/New(init_id) . = ..() + + id = init_id + if(!id) id = "[type]" //We turn the path into a string. diff --git a/code/modules/actionspeed/modifiers/wound.dm b/code/modules/actionspeed/modifiers/wound.dm new file mode 100644 index 00000000000000..845399e07616b6 --- /dev/null +++ b/code/modules/actionspeed/modifiers/wound.dm @@ -0,0 +1,10 @@ +/datum/actionspeed_modifier/wound_interaction_inefficiency + variable = TRUE + + var/datum/wound/parent + +/datum/actionspeed_modifier/wound_interaction_inefficiency/New(new_id, datum/wound/parent) + + src.parent = parent + + return ..() diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 913a0c55e53943..34e855230cb559 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -1059,7 +1059,7 @@ GLOBAL_PROTECT(admin_verbs_poll) if(!isobserver(usr)) admin_ghost() - usr.forceMove(coords2turf(reservation.bottom_left_coords)) + usr.forceMove(reservation.bottom_left_turfs[1]) message_admins("[key_name_admin(usr)] has loaded lazy template '[choice]'") to_chat(usr, span_boldnicegreen("Template loaded, you have been moved to the bottom left of the reservation.")) diff --git a/code/modules/admin/permissionedit.dm b/code/modules/admin/permissionedit.dm index 5544f90fb74816..cf816fef8a7a1f 100644 --- a/code/modules/admin/permissionedit.dm +++ b/code/modules/admin/permissionedit.dm @@ -192,6 +192,10 @@ admin_ckey = add_admin(admin_ckey, admin_key, use_db) if(!admin_ckey) return + + if(!admin_key) // Prevents failures in logging admin rank changes. + admin_key = admin_ckey + change_admin_rank(admin_ckey, admin_key, use_db, null, legacy_only) if("remove") remove_admin(admin_ckey, admin_key, use_db, D) diff --git a/code/modules/admin/smites/become_object.dm b/code/modules/admin/smites/become_object.dm new file mode 100644 index 00000000000000..5f1af4bee280ff --- /dev/null +++ b/code/modules/admin/smites/become_object.dm @@ -0,0 +1,42 @@ +#define OBJECTIFY_TIME (5 SECONDS) + +/// Turns the target into an object (for instance bread) +/datum/smite/objectify + name = "Become Object" + /// What are we going to turn them into? + var/atom/transform_path = /obj/item/food/bread/plain + +/datum/smite/objectify/configure(client/user) + var/attempted_target_path = input( + user, + "Enter typepath of an atom you'd like to turn your victim into.", + "Typepath", + "[/obj/item/food/bread/plain]", + ) as null|text + + if (isnull(attempted_target_path)) + return FALSE //The user pressed "Cancel" + + var/desired_object = text2path(attempted_target_path) + if(!ispath(desired_object)) + desired_object = pick_closest_path(attempted_target_path, get_fancy_list_of_atom_types()) + if(isnull(desired_object) || !ispath(desired_object)) + return FALSE //The user pressed "Cancel" + if(!ispath(desired_object, /atom)) + tgui_alert(user, "ERROR: Incorrect / improper path given.") + return FALSE + transform_path = desired_object + +/datum/smite/objectify/effect(client/user, mob/living/target) + if (!isliving(target)) + return // This doesn't work on ghosts + . = ..() + var/mutable_appearance/objectified_player = mutable_appearance(initial(transform_path.icon), initial(transform_path.icon_state)) + objectified_player.pixel_x = initial(transform_path.pixel_x) + objectified_player.pixel_y = initial(transform_path.pixel_y) + var/mutable_appearance/transform_scanline = mutable_appearance('icons/effects/effects.dmi', "transform_effect") + target.transformation_animation(objectified_player, OBJECTIFY_TIME, transform_scanline.appearance) + target.Immobilize(OBJECTIFY_TIME, ignore_canstun = TRUE) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(objectify), target, transform_path), OBJECTIFY_TIME) + +#undef OBJECTIFY_TIME diff --git a/code/modules/admin/smites/bloodless.dm b/code/modules/admin/smites/bloodless.dm index db68a1cd3a2788..c970e920f2253d 100644 --- a/code/modules/admin/smites/bloodless.dm +++ b/code/modules/admin/smites/bloodless.dm @@ -9,7 +9,7 @@ return var/mob/living/carbon/carbon_target = target for(var/_limb in carbon_target.bodyparts) - var/obj/item/bodypart/limb = _limb + var/obj/item/bodypart/limb = _limb // fine to use this raw, its a meme smite var/type_wound = pick(list(/datum/wound/slash/flesh/severe, /datum/wound/slash/flesh/moderate)) limb.force_wound_upwards(type_wound, smited = TRUE) type_wound = pick(list(/datum/wound/slash/flesh/critical, /datum/wound/slash/flesh/severe, /datum/wound/slash/flesh/moderate)) diff --git a/code/modules/admin/smites/boneless.dm b/code/modules/admin/smites/boneless.dm index 5d859669a6874c..bf402abdfdb629 100644 --- a/code/modules/admin/smites/boneless.dm +++ b/code/modules/admin/smites/boneless.dm @@ -11,11 +11,11 @@ var/mob/living/carbon/carbon_target = target for(var/obj/item/bodypart/limb as anything in carbon_target.bodyparts) - var/type_wound = pick(list( - /datum/wound/blunt/bone/critical, - /datum/wound/blunt/bone/severe, - /datum/wound/blunt/bone/critical, - /datum/wound/blunt/bone/severe, - /datum/wound/blunt/bone/moderate, + var/severity = pick(list( + "[WOUND_SEVERITY_MODERATE]", + "[WOUND_SEVERITY_SEVERE]", + "[WOUND_SEVERITY_SEVERE]", + "[WOUND_SEVERITY_CRITICAL]", + "[WOUND_SEVERITY_CRITICAL]", )) - limb.force_wound_upwards(type_wound, smited = TRUE) + carbon_target.cause_wound_of_type_and_severity(WOUND_BLUNT, limb, severity) diff --git a/code/modules/admin/smites/bread.dm b/code/modules/admin/smites/bread.dm deleted file mode 100644 index 22ed8836df3b22..00000000000000 --- a/code/modules/admin/smites/bread.dm +++ /dev/null @@ -1,14 +0,0 @@ -#define BREADIFY_TIME (5 SECONDS) - -/// Turns the target into bread -/datum/smite/bread - name = "Bread" - -/datum/smite/bread/effect(client/user, mob/living/target) - . = ..() - var/mutable_appearance/bread_appearance = mutable_appearance('icons/obj/food/burgerbread.dmi', "bread") - var/mutable_appearance/transform_scanline = mutable_appearance('icons/effects/effects.dmi', "transform_effect") - target.transformation_animation(bread_appearance, BREADIFY_TIME, transform_scanline.appearance) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(breadify), target), BREADIFY_TIME) - -#undef BREADIFY_TIME diff --git a/code/modules/admin/verbs/adminfun.dm b/code/modules/admin/verbs/adminfun.dm index 32734a21d94d46..b1e0327510a5f1 100644 --- a/code/modules/admin/verbs/adminfun.dm +++ b/code/modules/admin/verbs/adminfun.dm @@ -219,9 +219,9 @@ return smite.effect(src, target) -///"Turns" people into bread. Really, we just add them to the contents of the bread food item. -/proc/breadify(atom/movable/target) - var/obj/item/food/bread/plain/smite/tomb = new(get_turf(target)) +/// "Turns" people into objects. Really, we just add them to the contents of the item. +/proc/objectify(atom/movable/target, path) + var/atom/tomb = new path(get_turf(target)) target.forceMove(tomb) target.AddComponent(/datum/component/itembound, tomb) diff --git a/code/modules/admin/verbs/admingame.dm b/code/modules/admin/verbs/admingame.dm index 13178d32a5d68f..8bc58a7876c29b 100644 --- a/code/modules/admin/verbs/admingame.dm +++ b/code/modules/admin/verbs/admingame.dm @@ -32,6 +32,20 @@ if(M.client) body += "
\[First Seen: [M.client.player_join_date]\]\[Byond account registered on: [M.client.account_join_date]\]" + // SKYRAT EDIT ADDITION START - Player Ranks + var/list/player_ranks = list() + + if(SSplayer_ranks.is_donator(M.client, admin_bypass = FALSE)) + player_ranks += "Donator" + + if(SSplayer_ranks.is_mentor(M.client, admin_bypass = FALSE)) + player_ranks += "Mentor" + + if(SSplayer_ranks.is_veteran(M.client, admin_bypass = FALSE)) + player_ranks += "Veteran" + + body += "

Player Ranks: [length(player_ranks) ? player_ranks.Join(", ") : "None"]" + // SKYRAT EDIT END body += "

CentCom Galactic Ban DB: " if(CONFIG_GET(string/centcom_ban_db)) body += "Search" diff --git a/code/modules/admin/verbs/commandreport.dm b/code/modules/admin/verbs/commandreport.dm index 635cb28cbb28d5..badf3babb6698d 100644 --- a/code/modules/admin/verbs/commandreport.dm +++ b/code/modules/admin/verbs/commandreport.dm @@ -46,6 +46,8 @@ var/command_report_content /// Whether the report's contents are announced. var/announce_contents = TRUE + /// Whether a copy of the report is printed at every console. + var/print_report = TRUE /// The sound that's going to accompany our message. var/played_sound = DEFAULT_ANNOUNCEMENT_SOUND /// A static list of preset names that can be chosen. @@ -75,6 +77,7 @@ data["custom_name"] = custom_name data["command_report_content"] = command_report_content data["announce_contents"] = announce_contents + data["print_report"] = print_report data["played_sound"] = played_sound return data @@ -103,6 +106,8 @@ played_sound = params["picked_sound"] if("toggle_announce") announce_contents = !announce_contents + if("toggle_printing") + print_report = !print_report if("submit_report") if(!command_name) to_chat(ui_user, span_danger("You can't send a report with no command name.")) @@ -132,7 +137,9 @@ if(announce_contents) priority_announce(command_report_content, null, report_sound, has_important_message = TRUE) - print_command_report(command_report_content, "[announce_contents ? "" : "Classified "][command_name] Update", !announce_contents) + + if(!announce_contents || print_report) + print_command_report(command_report_content, "[announce_contents ? "" : "Classified "][command_name] Update", !announce_contents) change_command_name(original_command_name) diff --git a/code/modules/admin/view_variables/debug_variables.dm b/code/modules/admin/view_variables/debug_variables.dm index 24ee0032a33f5c..230a0e462844b0 100644 --- a/code/modules/admin/view_variables/debug_variables.dm +++ b/code/modules/admin/view_variables/debug_variables.dm @@ -90,7 +90,10 @@ for (var/i in GLOB.bitfields[name]) if (value & GLOB.bitfields[name][i]) flags += i + if(length(flags)) item = "[name_part] = [VV_HTML_ENCODE(jointext(flags, ", "))]" + else + item = "[name_part] = NONE" else item = "[name_part] = [VV_HTML_ENCODE(value)]" diff --git a/code/modules/admin/view_variables/reference_tracking.dm b/code/modules/admin/view_variables/reference_tracking.dm index 067179e1ecc3b6..a5b2af68c772e2 100644 --- a/code/modules/admin/view_variables/reference_tracking.dm +++ b/code/modules/admin/view_variables/reference_tracking.dm @@ -22,10 +22,6 @@ if(usr?.client) usr.client.running_find_references = type -#ifdef UNIT_TESTS - log_reftracker("Currently sleeping procs [byond_status()]") -#endif - log_reftracker("Beginning search for references to a [type].") var/starting_time = world.time diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index f97ecaeb42b2cf..5bbbfaa40b8898 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -59,6 +59,8 @@ GLOBAL_LIST_EMPTY(antagonists) var/can_assign_self_objectives = FALSE /// Default to fill in when entering a custom objective. var/default_custom_objective = "Cause chaos on the space station." + /// Whether we give a hardcore random bonus for greentexting as this antagonist while playing hardcore random + var/hardcore_random_bonus = FALSE //ANTAG UI diff --git a/code/modules/antagonists/abductor/equipment/glands/heal.dm b/code/modules/antagonists/abductor/equipment/glands/heal.dm index a8e01a45eeecdf..2fa677cba0ef00 100644 --- a/code/modules/antagonists/abductor/equipment/glands/heal.dm +++ b/code/modules/antagonists/abductor/equipment/glands/heal.dm @@ -1,3 +1,5 @@ +#define REJECTION_VOMIT_FLAGS (MOB_VOMIT_BLOOD | MOB_VOMIT_STUN | MOB_VOMIT_KNOCKDOWN | MOB_VOMIT_FORCE) + /obj/item/organ/internal/heart/gland/heal abductor_hint = "organic replicator. Forcibly ejects damaged and robotic organs from the abductee and regenerates them. Additionally, forcibly removes reagents (via vomit) from the abductee if they have moderate toxin damage or poison within the bloodstream, and regenerates blood to a healthy threshold if too low. The abductee will also reject implants such as mindshields." cooldown_low = 200 @@ -78,19 +80,19 @@ /obj/item/organ/internal/heart/gland/heal/proc/reject_implant(obj/item/implant/implant) owner.visible_message(span_warning("[owner] vomits up a tiny mangled implant!"), span_userdanger("You suddenly vomit up a tiny mangled implant!")) - owner.vomit(0, TRUE, TRUE, 1, FALSE, FALSE, FALSE, TRUE) + owner.vomit(REJECTION_VOMIT_FLAGS, lost_nutrition = 0) implant.removed(owner) qdel(implant) /obj/item/organ/internal/heart/gland/heal/proc/reject_cyberimp(obj/item/organ/internal/cyberimp/implant) owner.visible_message(span_warning("[owner] vomits up his [implant.name]!"), span_userdanger("You suddenly vomit up your [implant.name]!")) - owner.vomit(0, TRUE, TRUE, 1, FALSE, FALSE, FALSE, TRUE) + owner.vomit(REJECTION_VOMIT_FLAGS, lost_nutrition = 0) implant.Remove(owner) implant.forceMove(owner.drop_location()) /obj/item/organ/internal/heart/gland/heal/proc/replace_appendix(obj/item/organ/internal/appendix/appendix) if(appendix) - owner.vomit(0, TRUE, TRUE, 1, FALSE, FALSE, FALSE, TRUE) + owner.vomit(REJECTION_VOMIT_FLAGS, lost_nutrition = 0) appendix.Remove(owner) appendix.forceMove(owner.drop_location()) owner.visible_message(span_warning("[owner] vomits up his [appendix.name]!"), span_userdanger("You suddenly vomit up your [appendix.name]!")) @@ -106,7 +108,7 @@ /obj/item/organ/internal/heart/gland/heal/proc/replace_liver(obj/item/organ/internal/liver/liver) if(liver) owner.visible_message(span_warning("[owner] vomits up his [liver.name]!"), span_userdanger("You suddenly vomit up your [liver.name]!")) - owner.vomit(0, TRUE, TRUE, 1, FALSE, FALSE, FALSE, TRUE) + owner.vomit(REJECTION_VOMIT_FLAGS, lost_nutrition = 0) liver.Remove(owner) liver.forceMove(owner.drop_location()) else @@ -121,7 +123,7 @@ /obj/item/organ/internal/heart/gland/heal/proc/replace_lungs(obj/item/organ/internal/lungs/lungs) if(lungs) owner.visible_message(span_warning("[owner] vomits up his [lungs.name]!"), span_userdanger("You suddenly vomit up your [lungs.name]!")) - owner.vomit(0, TRUE, TRUE, 1, FALSE, FALSE, FALSE, TRUE) + owner.vomit(REJECTION_VOMIT_FLAGS, lost_nutrition = 0) lungs.Remove(owner) lungs.forceMove(owner.drop_location()) else @@ -136,7 +138,7 @@ /obj/item/organ/internal/heart/gland/heal/proc/replace_stomach(obj/item/organ/internal/stomach/stomach) if(stomach) owner.visible_message(span_warning("[owner] vomits up his [stomach.name]!"), span_userdanger("You suddenly vomit up your [stomach.name]!")) - owner.vomit(0, TRUE, TRUE, 1, FALSE, FALSE, FALSE, TRUE) + owner.vomit(REJECTION_VOMIT_FLAGS, lost_nutrition = 0) stomach.Remove(owner) stomach.forceMove(owner.drop_location()) else @@ -190,7 +192,7 @@ /obj/item/organ/internal/heart/gland/heal/proc/keep_replacing_blood() var/keep_going = FALSE - owner.vomit(0, TRUE, FALSE, 3, FALSE, FALSE, FALSE, TRUE) + owner.vomit(vomit_flags = (MOB_VOMIT_BLOOD | MOB_VOMIT_FORCE), lost_nutrition = 0, distance = 3) owner.Stun(15) owner.adjustToxLoss(-15, TRUE, TRUE) @@ -226,3 +228,5 @@ var/obj/item/bodypart/chest/new_chest = new(null) new_chest.replace_limb(owner, TRUE) qdel(chest) + +#undef REJECTION_VOMIT_FLAGS diff --git a/code/modules/antagonists/abductor/equipment/glands/plasma.dm b/code/modules/antagonists/abductor/equipment/glands/plasma.dm index c167dd8a3291e1..0d709579cc8c5d 100644 --- a/code/modules/antagonists/abductor/equipment/glands/plasma.dm +++ b/code/modules/antagonists/abductor/equipment/glands/plasma.dm @@ -19,4 +19,4 @@ var/turf/open/T = get_turf(owner) if(istype(T)) T.atmos_spawn_air("[GAS_PLASMA]=50;[TURF_TEMPERATURE(T20C)]") - owner.vomit() + owner.vomit(VOMIT_CATEGORY_DEFAULT) diff --git a/code/modules/antagonists/abductor/equipment/glands/slime.dm b/code/modules/antagonists/abductor/equipment/glands/slime.dm index e3c966e3b6c61b..faebce9fc874f6 100644 --- a/code/modules/antagonists/abductor/equipment/glands/slime.dm +++ b/code/modules/antagonists/abductor/equipment/glands/slime.dm @@ -19,7 +19,7 @@ /obj/item/organ/internal/heart/gland/slime/activate() to_chat(owner, span_warning("You feel nauseated!")) - owner.vomit(20) + owner.vomit(VOMIT_CATEGORY_DEFAULT, lost_nutrition = 20) var/mob/living/simple_animal/slime/Slime = new(get_turf(owner), "grey") Slime.set_friends(list(owner)) diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm index deef0a390cbd88..7a797273785d10 100644 --- a/code/modules/antagonists/brother/brother.dm +++ b/code/modules/antagonists/brother/brother.dm @@ -9,6 +9,7 @@ suicide_cry = "FOR MY BROTHER!!" var/datum/team/brother_team/team antag_moodlet = /datum/mood_event/focused + hardcore_random_bonus = TRUE /datum/antagonist/brother/create_team(datum/team/brother_team/new_team) if(!new_team) diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index b46b05000d9e51..82c83ecf0ba899 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -13,6 +13,7 @@ suicide_cry = "FOR THE HIVE!!" can_assign_self_objectives = TRUE default_custom_objective = "Consume the station's most valuable genomes." + hardcore_random_bonus = TRUE /// Whether to give this changeling objectives or not var/give_objectives = TRUE /// Weather we assign objectives which compete with other lings @@ -282,13 +283,15 @@ /datum/antagonist/changeling/proc/on_life(datum/source, seconds_per_tick, times_fired) SIGNAL_HANDLER + var/delta_time = DELTA_WORLD_TIME(SSmobs) + // If dead, we only regenerate up to half chem storage. if(owner.current.stat == DEAD) - adjust_chemicals((chem_recharge_rate - chem_recharge_slowdown) * seconds_per_tick, total_chem_storage * 0.5) + adjust_chemicals((chem_recharge_rate - chem_recharge_slowdown) * delta_time, total_chem_storage * 0.5) // If we're not dead - we go up to the full chem cap. else - adjust_chemicals((chem_recharge_rate - chem_recharge_slowdown) * seconds_per_tick) + adjust_chemicals((chem_recharge_rate - chem_recharge_slowdown) * delta_time) /** * Signal proc for [COMSIG_LIVING_POST_FULLY_HEAL], getting admin-healed restores our chemicals. diff --git a/code/modules/antagonists/changeling/powers/lesserform.dm b/code/modules/antagonists/changeling/powers/lesserform.dm index 854234af965f2d..87bd7c7c8b669e 100644 --- a/code/modules/antagonists/changeling/powers/lesserform.dm +++ b/code/modules/antagonists/changeling/powers/lesserform.dm @@ -40,7 +40,6 @@ user.humanize(species = chosen_species, instant = transform_instantly) changeling.transform(user, chosen_form) - user.regenerate_icons() return TRUE /// Returns the form to transform back into, automatically selects your only profile if you only have one diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index 309cffc0a75141..bf4f8c2b3da3e4 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -278,6 +278,7 @@ flags_1 = NONE w_class = WEIGHT_CLASS_HUGE slot_flags = NONE + antimagic_flags = NONE pinless = TRUE ammo_type = /obj/item/ammo_casing/magic/tentacle fire_sound = 'sound/effects/splat.ogg' diff --git a/code/modules/antagonists/changeling/powers/panacea.dm b/code/modules/antagonists/changeling/powers/panacea.dm index 683fe7e16b6fc1..25a267e03dfa9b 100644 --- a/code/modules/antagonists/changeling/powers/panacea.dm +++ b/code/modules/antagonists/changeling/powers/panacea.dm @@ -27,7 +27,7 @@ O.Remove(user) if(iscarbon(user)) var/mob/living/carbon/C = user - C.vomit(0) + C.vomit(VOMIT_CATEGORY_DEFAULT, lost_nutrition = 0) O.forceMove(get_turf(user)) //Skyrat Edit Start: Cortical Borer var/mob/living/basic/cortical_borer/cb_inside = user.has_borer() diff --git a/code/modules/antagonists/fugitive/hunters/hunter_gear.dm b/code/modules/antagonists/fugitive/hunters/hunter_gear.dm index 71082f199e0753..013359e9a68fca 100644 --- a/code/modules/antagonists/fugitive/hunters/hunter_gear.dm +++ b/code/modules/antagonists/fugitive/hunters/hunter_gear.dm @@ -198,3 +198,22 @@ continue return found_fugitive + +/obj/item/radio/headset/psyker + name = "psychic headset" + desc = "A headset designed to boost psychic waves. Protects ears from flashbangs." + icon_state = "psyker_headset" + worn_icon_state = "syndie_headset" + +/obj/item/radio/headset/psyker/Initialize(mapload) + . = ..() + AddComponent(/datum/component/wearertargeting/earprotection, list(ITEM_SLOT_EARS)) + +/obj/item/radio/headset/psyker/equipped(mob/living/user, slot) + . = ..() + if(slot_flags & slot) + ADD_CLOTHING_TRAIT(user, TRAIT_ECHOLOCATION_EXTRA_RANGE) + +/obj/item/radio/headset/psyker/dropped(mob/user, silent) + . = ..() + REMOVE_CLOTHING_TRAIT(user, TRAIT_ECHOLOCATION_EXTRA_RANGE) diff --git a/code/modules/antagonists/fugitive/hunters/hunter_outfits.dm b/code/modules/antagonists/fugitive/hunters/hunter_outfits.dm index 5865f76e9999ed..7df6818cdc44a4 100644 --- a/code/modules/antagonists/fugitive/hunters/hunter_outfits.dm +++ b/code/modules/antagonists/fugitive/hunters/hunter_outfits.dm @@ -187,7 +187,7 @@ name = "Psyker-Shikari Hunter" glasses = null head = null - ears = /obj/item/radio/headset/syndicate/alt/psyker + ears = /obj/item/radio/headset/psyker uniform = /obj/item/clothing/under/pants/track gloves = /obj/item/clothing/gloves/fingerless shoes = /obj/item/clothing/shoes/jackboots diff --git a/code/modules/antagonists/greentext/greentext.dm b/code/modules/antagonists/greentext/greentext.dm index d06977d2a63669..7133066f85694d 100644 --- a/code/modules/antagonists/greentext/greentext.dm +++ b/code/modules/antagonists/greentext/greentext.dm @@ -4,6 +4,7 @@ show_name_in_check_antagonists = TRUE //Not that it will be there for long suicide_cry = "FOR THE GREENTEXT!!" // This can never actually show up, but not including it is a missed opportunity count_against_dynamic_roll_chance = FALSE + hardcore_random_bonus = TRUE /datum/antagonist/greentext/forge_objectives() var/datum/objective/succeed_objective = new /datum/objective("Succeed") diff --git a/code/modules/antagonists/heretic/heretic_antag.dm b/code/modules/antagonists/heretic/heretic_antag.dm index 48c8dad7fa6bd4..0120c3b7ee3a86 100644 --- a/code/modules/antagonists/heretic/heretic_antag.dm +++ b/code/modules/antagonists/heretic/heretic_antag.dm @@ -25,6 +25,7 @@ preview_outfit = /datum/outfit/heretic can_assign_self_objectives = TRUE default_custom_objective = "Turn a department into a testament for your dark knowledge." + hardcore_random_bonus = TRUE /// Whether we give this antagonist objectives on gain. var/give_objectives = TRUE /// Whether we've ascended! (Completed one of the final rituals) @@ -63,6 +64,7 @@ PATH_VOID = "blue", PATH_BLADE = "label", // my favorite color is label PATH_COSMIC = "purple", + PATH_KNOCK = "yellow", ) var/static/list/path_to_rune_color = list( PATH_START = COLOR_LIME, @@ -72,6 +74,7 @@ PATH_VOID = COLOR_CYAN, PATH_BLADE = COLOR_SILVER, PATH_COSMIC = COLOR_PURPLE, + PATH_KNOCK = COLOR_YELLOW, ) /datum/antagonist/heretic/Destroy() @@ -508,6 +511,7 @@ .["Remove Heart Target"] = CALLBACK(src, PROC_REF(remove_target)) .["Adjust Knowledge Points"] = CALLBACK(src, PROC_REF(admin_change_points)) + .["Give Focus"] = CALLBACK(src, PROC_REF(admin_give_focus)) /** * Admin proc for giving a heretic a Living Heart easily. @@ -583,6 +587,18 @@ knowledge_points += change_num +/** + * Admin proc for giving a heretic a focus. + */ +/datum/antagonist/heretic/proc/admin_give_focus(mob/admin) + if(!admin.client?.holder) + to_chat(admin, span_warning("You shouldn't be using this!")) + return + + var/mob/living/pawn = owner.current + pawn.equip_to_slot_if_possible(new /obj/item/clothing/neck/heretic_focus(get_turf(pawn)), ITEM_SLOT_NECK, TRUE, TRUE) + to_chat(pawn, span_hypnophrase("The Mansus has manifested you a focus.")) + /datum/antagonist/heretic/antag_panel_data() var/list/string_of_knowledge = list() diff --git a/code/modules/antagonists/heretic/items/heretic_blades.dm b/code/modules/antagonists/heretic/items/heretic_blades.dm index c074e13c8d39b2..63493a5dc4bdbb 100644 --- a/code/modules/antagonists/heretic/items/heretic_blades.dm +++ b/code/modules/antagonists/heretic/items/heretic_blades.dm @@ -115,3 +115,14 @@ icon_state = "cosmic_blade" inhand_icon_state = "cosmic_blade" after_use_message = "The Stargazer hears your call..." + +// Path of Knock's blade +/obj/item/melee/sickly_blade/knock + name = "\improper key blade" + desc = "A blade and a key, a key to what? \ + What grand gates does it open?" + icon_state = "key_blade" + inhand_icon_state = "key_blade" + after_use_message = "The Mother of Ants hears your call..." + tool_behaviour = TOOL_CROWBAR + toolspeed = 1.3 diff --git a/code/modules/antagonists/heretic/items/keyring.dm b/code/modules/antagonists/heretic/items/keyring.dm new file mode 100644 index 00000000000000..0498ba9e8a2aad --- /dev/null +++ b/code/modules/antagonists/heretic/items/keyring.dm @@ -0,0 +1,186 @@ +/obj/effect/knock_portal + name = "crack in reality" + desc = "A crack in space, impossibly deep and painful to the eyes. Definitely not safe." + icon = 'icons/effects/eldritch.dmi' + icon_state = "realitycrack" + light_system = STATIC_LIGHT + light_power = 1 + light_on = TRUE + light_color = COLOR_GREEN + light_range = 3 + opacity = TRUE + density = FALSE //so we dont block doors closing + layer = OBJ_LAYER //under doors + ///The knock portal we teleport to + var/obj/effect/knock_portal/destination + ///The airlock we are linked to, we delete if it is destroyed + var/obj/machinery/door/our_airlock + +/obj/effect/knock_portal/Initialize(mapload, target) + . = ..() + if(target) + our_airlock = target + RegisterSignal(target, COMSIG_QDELETING, PROC_REF(delete_on_door_delete)) + + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + +///Deletes us and our destination portal if our_airlock is destroyed +/obj/effect/knock_portal/proc/delete_on_door_delete(datum/source) + SIGNAL_HANDLER + qdel(src) + +///Signal handler for when our location is entered, calls teleport on the victim, if their old_loc didnt contain a portal already (to prevent loops) +/obj/effect/knock_portal/proc/on_entered(datum/source, mob/living/loser, atom/old_loc) + SIGNAL_HANDLER + if(istype(loser) && !(locate(type) in old_loc)) + teleport(loser) + +/obj/effect/knock_portal/Destroy() + QDEL_NULL(destination) + our_airlock = null + return ..() + +///Teleports the teleportee, to a random airlock if the teleportee isnt a heretic, or the other portal if they are one +/obj/effect/knock_portal/proc/teleport(mob/living/teleportee) + if(isnull(destination)) //dumbass + qdel(src) + return + + //get it? + var/obj/machinery/door/doorstination = IS_HERETIC_OR_MONSTER(teleportee) ? destination.our_airlock : find_random_airlock() + if(!do_teleport(teleportee, get_turf(doorstination), channel = TELEPORT_CHANNEL_MAGIC)) + return + + if(!IS_HERETIC_OR_MONSTER(teleportee)) + teleportee.apply_damage(20, BRUTE) //so they dont roll it like a jackpot machine to see if they can land in the armory + to_chat(teleportee, span_userdanger("You stumble through [src], battered by forces beyond your comprehension, landing anywhere but where you thought you were going.")) + + INVOKE_ASYNC(src, PROC_REF(async_opendoor), doorstination) + +///Returns a random airlock on the same Z level as our portal, that isnt our airlock +/obj/effect/knock_portal/proc/find_random_airlock() + var/list/turf/possible_destinations = list() + for(var/obj/airlock as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/door/airlock)) + if(airlock.z != z) + continue + if(airlock.loc == loc) + continue + possible_destinations += airlock + return pick(possible_destinations) + +///Asynchronous proc to unbolt, then open the passed door +/obj/effect/knock_portal/proc/async_opendoor(obj/machinery/door/door) + if(istype(door, /obj/machinery/door/airlock)) //they can create portals on ANY door, but we should unlock airlocks so they can actually open + var/obj/machinery/door/airlock/as_airlock = door + as_airlock.unbolt() + door.open() + +///An ID card capable of shapeshifting to other IDs given by the Key Keepers Burden knowledge +/obj/item/card/id/advanced/heretic + ///List of IDs this card consumed + var/list/obj/item/card/id/fused_ids = list() + ///The first portal in the portal pair, so we can clear it later + var/obj/effect/knock_portal/portal_one + ///The second portal in the portal pair, so we can clear it later + var/obj/effect/knock_portal/portal_two + ///The first door we are linking in the pair, so we can create a portal pair + var/datum/weakref/link + +/obj/item/card/id/advanced/heretic/examine(mob/user) + . = ..() + if(!IS_HERETIC_OR_MONSTER(user)) + return + . += span_hypnophrase("Enchanted by the Mansus!") + . += span_hypnophrase("Using an ID on this will consume it and allow you to copy its accesses.") + . += span_hypnophrase("Using this in-hand allows you to change its appearance.") + . += span_hypnophrase("Using this on a pair of doors, allows you to link them together. Entering one door will transport you to the other, while heathens are instead teleported to a random airlock.") + +/obj/item/card/id/advanced/heretic/attack_self(mob/user) + . = ..() + if(!IS_HERETIC(user)) + return + var/cardname = tgui_input_list(user, "Shapeshift into?", "Shapeshift", fused_ids) + if(!cardname) + balloon_alert(user, "no options!") + return ..() + var/obj/item/card/id/card = fused_ids[cardname] + shapeshift(card) + +///Changes our appearance to the passed ID card +/obj/item/card/id/advanced/heretic/proc/shapeshift(obj/item/card/id/advanced/card) + trim = card.trim + assignment = card.assignment + registered_age = card.registered_age + registered_name = card.registered_name + icon_state = card.icon_state + inhand_icon_state = card.inhand_icon_state + assigned_icon_state = card.assigned_icon_state + name = card.name //not update_label because of the captains spare moment + update_icon() + +///Deletes and nulls our portal pair +/obj/item/card/id/advanced/heretic/proc/clear_portals() + QDEL_NULL(portal_one) + QDEL_NULL(portal_two) + +///Clears portal references +/obj/item/card/id/advanced/heretic/proc/clear_portal_refs() + SIGNAL_HANDLER + portal_one = null + portal_two = null + +///Creates a portal pair at door1 and door2, displays a balloon alert to user +/obj/item/card/id/advanced/heretic/proc/make_portal(mob/user, obj/machinery/door/door1, obj/machinery/door/door2) + var/message = "linked" + if(portal_one || portal_two) + clear_portals() + message += ", previous cleared" + + portal_one = new(get_turf(door2), door2) + portal_two = new(get_turf(door1), door1) + portal_one.destination = portal_two + RegisterSignal(portal_one, COMSIG_QDELETING, PROC_REF(clear_portal_refs)) //we only really need to register one because they already qdel both portals if one is destroyed + portal_two.destination = portal_one + balloon_alert(user, "[message]") + +/obj/item/card/id/advanced/heretic/attackby(obj/item/thing, mob/user, params) + if(!istype(thing, /obj/item/card/id/advanced) || !IS_HERETIC(user)) + return ..() + var/obj/item/card/id/card = thing + fused_ids[card.name] = card + card.moveToNullspace() + playsound(drop_location(),'sound/items/eatfood.ogg', rand(10,50), TRUE) + access += card.access + +/obj/item/card/id/advanced/heretic/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + . = ..() + if(!proximity_flag || !IS_HERETIC(user)) + return + if(istype(target, /obj/effect/knock_portal)) + clear_portals() + return + + if(!istype(target, /obj/machinery/door)) + return + + var/reference_resolved = link?.resolve() + if(reference_resolved == target) + return + + if(reference_resolved) + make_portal(user, reference_resolved, target) + to_chat(user, span_notice("You use [src], to link [link] and [target] together.")) + link = null + balloon_alert(user, "link 2/2") + else + link = WEAKREF(target) + balloon_alert(user, "link 1/2") + +/obj/item/card/id/advanced/heretic/Destroy() + QDEL_LIST_ASSOC(fused_ids) + link = null + clear_portals() + return ..() diff --git a/code/modules/antagonists/heretic/items/lintel.dm b/code/modules/antagonists/heretic/items/lintel.dm new file mode 100644 index 00000000000000..140453842c090c --- /dev/null +++ b/code/modules/antagonists/heretic/items/lintel.dm @@ -0,0 +1,64 @@ +/obj/effect/forcefield/wizard/heretic + name = "consecrated lintel" + desc = "A field of papers flying in the air, repulsing heathens with impossible force." + icon_state = "lintel" + initial_duration = 8 SECONDS + +/obj/effect/forcefield/wizard/heretic/Bumped(mob/living/bumpee) + . = ..() + if(!istype(bumpee) || IS_HERETIC_OR_MONSTER(bumpee)) + return + var/throwtarget = get_edge_target_turf(loc, get_dir(loc, get_step_away(bumpee, loc))) + bumpee.safe_throw_at(throwtarget, 10, 1, force = MOVE_FORCE_EXTREMELY_STRONG) + visible_message(span_danger("[src] repulses [bumpee] in a storm of paper!")) + +///A heretic item that spawns a barrier at the clicked turf, 3 uses +/obj/item/heretic_lintel + name = "consecrated book" + desc = "Some kind of book, its contents make your head hurt. The material is not known to you and it seems to shift and twist unnaturally." + icon = 'icons/obj/service/library.dmi' + icon_state = "hereticlintel" + force = 10 + damtype = BURN + worn_icon_state = "book" + throw_speed = 1 + throw_range = 5 + w_class = WEIGHT_CLASS_NORMAL + attack_verb_continuous = list("bashes", "curses") + attack_verb_simple = list("bash", "curse") + resistance_flags = FLAMMABLE + drop_sound = 'sound/items/handling/book_drop.ogg' + pickup_sound = 'sound/items/handling/book_pickup.ogg' + ///what type of barrier do we spawn when used + var/barrier_type = /obj/effect/forcefield/wizard/heretic + ///how many uses do we have left + var/uses = 3 + +/obj/item/heretic_lintel/examine(mob/user) + . = ..() + if(!IS_HERETIC_OR_MONSTER(user)) + return + . += span_hypnophrase("Materializes a barrier upon any tile in sight, which only you can pass through. Lasts 8 seconds.") + . += span_hypnophrase("It has [uses] uses left.") + +/obj/item/heretic_lintel/afterattack(atom/target, mob/user, proximity_flag) + . = ..() + if(IS_HERETIC(user)) + var/turf/turf_target = get_turf(target) + if(locate(barrier_type) in turf_target) + user.balloon_alert(user, "already occupied!") + return + turf_target.visible_message(span_warning("A storm of paper materializes!")) + new /obj/effect/temp_visual/paper_scatter(turf_target) + playsound(turf_target, 'sound/magic/smoke.ogg', 30) + new barrier_type(turf_target, user) + uses-- + if(uses <= 0) + to_chat(user, span_warning("[src] falls apart, turning into ash and dust!")) + qdel(src) + return + var/mob/living/carbon/human/human_user = user + to_chat(human_user, span_userdanger("Your mind burns as you stare deep into the book, a headache setting in like your brain is on fire!")) + human_user.adjustOrganLoss(ORGAN_SLOT_BRAIN, 30, 190) + human_user.add_mood_event("gates_of_mansus", /datum/mood_event/gates_of_mansus) + human_user.dropItemToGround(src) diff --git a/code/modules/antagonists/heretic/knowledge/flesh_lore.dm b/code/modules/antagonists/heretic/knowledge/flesh_lore.dm index 26395396c06800..07fa27181859a2 100644 --- a/code/modules/antagonists/heretic/knowledge/flesh_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/flesh_lore.dm @@ -262,6 +262,8 @@ I finally began to understand. And then, blood rained from the heavens." next_knowledge = list(/datum/heretic_knowledge/summon/stalker) route = PATH_FLESH + ///What type of wound do we apply on hit + var/wound_type = /datum/wound/slash/flesh/severe /datum/heretic_knowledge/blade_upgrade/flesh/do_melee_effects(mob/living/source, mob/living/target, obj/item/melee/sickly_blade/blade) if(!iscarbon(target) || source == target) @@ -269,7 +271,7 @@ var/mob/living/carbon/carbon_target = target var/obj/item/bodypart/bodypart = pick(carbon_target.bodyparts) - var/datum/wound/slash/flesh/severe/crit_wound = new() + var/datum/wound/crit_wound = new wound_type() crit_wound.apply_wound(bodypart, attack_direction = get_dir(source, target)) /datum/heretic_knowledge/summon/stalker diff --git a/code/modules/antagonists/heretic/knowledge/knock_lore.dm b/code/modules/antagonists/heretic/knowledge/knock_lore.dm new file mode 100644 index 00000000000000..fcb2c6ceb4c989 --- /dev/null +++ b/code/modules/antagonists/heretic/knowledge/knock_lore.dm @@ -0,0 +1,227 @@ +/** + * # The path of Knock. + * + * Goes as follows: + * + * A Locksmith’s Secret + * Grasp of Knock + * > Sidepaths: + * Ashen Eyes + * Codex Cicatrix + * Key Keeper’s Burden + * + * Rite Of Passage + * Mark Of Knock + * Ritual of Knowledge + * Burglar's Finesse + * > Sidepaths: + * Apetra Vulnera + * Opening Blast + * + * Opening Blade + * Caretaker’s Last Refuge + * + * Many secrets behind the Spider Door + */ +/datum/heretic_knowledge/limited_amount/starting/base_knock + name = "A Locksmith’s Secret" + desc = "Opens up the Path of Knock to you. \ + Allows you to transmute a knife and a crowbar into a Key Blade. \ + You can only create two at a time and they function as fast crowbars. \ + In addition, they can fit into utility belts." + gain_text = "The Knock permits no seal and no isolation. It thrusts us gleefully out of the safety of ignorance." + next_knowledge = list(/datum/heretic_knowledge/knock_grasp) + required_atoms = list( + /obj/item/knife = 1, + /obj/item/crowbar = 1, + ) + result_atoms = list(/obj/item/melee/sickly_blade/knock) + limit = 2 + route = PATH_KNOCK + +/datum/heretic_knowledge/knock_grasp + name = "Grasp of Knock" + desc = "Your mansus grasp allows you to access anything! Right click on an airlock or a locker to force it open. \ + DNA locks on mechs will be removed, and any pilot will be ejected. Works on consoles. \ + Makes a distinctive knocking sound on use." + gain_text = "Nothing may remain closed from my touch." + next_knowledge = list( + /datum/heretic_knowledge/key_ring, + /datum/heretic_knowledge/medallion, + /datum/heretic_knowledge/codex_cicatrix, + ) + cost = 1 + route = PATH_KNOCK + +/datum/heretic_knowledge/knock_grasp/on_gain(mob/user, datum/antagonist/heretic/our_heretic) + RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK_SECONDARY, PROC_REF(on_secondary_mansus_grasp)) + RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK, PROC_REF(on_mansus_grasp)) + +/datum/heretic_knowledge/knock_grasp/on_lose(mob/user, datum/antagonist/heretic/our_heretic) + UnregisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK_SECONDARY) + UnregisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK) + +/datum/heretic_knowledge/knock_grasp/proc/on_mansus_grasp(mob/living/source, mob/living/target) + SIGNAL_HANDLER + var/obj/item/clothing/under/suit = target.get_item_by_slot(ITEM_SLOT_ICLOTHING) + if(istype(suit) && suit.adjusted == NORMAL_STYLE) + suit.toggle_jumpsuit_adjust() + suit.update_appearance() + +/datum/heretic_knowledge/knock_grasp/proc/on_secondary_mansus_grasp(mob/living/source, atom/target) + SIGNAL_HANDLER + + if(ismecha(target)) + var/obj/vehicle/sealed/mecha/mecha = target + mecha.dna_lock = null + for(var/mob/living/occupant as anything in mecha.occupants) + if(isAI(occupant)) + continue + mecha.mob_exit(occupant, randomstep = TRUE) + else if(istype(target,/obj/machinery/door/airlock)) + var/obj/machinery/door/airlock/door = target + door.unbolt() + else if(istype(target, /obj/machinery/computer)) + var/obj/machinery/computer/computer = target + computer.authenticated = TRUE + computer.balloon_alert(source, "unlocked") + + var/turf/target_turf = get_turf(target) + SEND_SIGNAL(target_turf, COMSIG_ATOM_MAGICALLY_UNLOCKED, src, source) + playsound(target, 'sound/magic/hereticknock.ogg', 100, TRUE, -1) + + return COMPONENT_USE_HAND + +/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." + gain_text = "Gateways shall open before me, my very will ensnaring reality." + required_atoms = list( + /obj/item/storage/wallet = 1, + /obj/item/stack/rods = 1, + /obj/item/card/id = 1, + ) + result_atoms = list(/obj/item/card/id/advanced/heretic) + next_knowledge = list(/datum/heretic_knowledge/limited_amount/rite_of_passage) + cost = 1 + route = PATH_KNOCK + +/datum/heretic_knowledge/limited_amount/rite_of_passage // item that creates 3 max at a time heretic only barriers, probably should limit to 1 only, holy people can also pass + name = "Rite Of Passage" + desc = "Allows you to transmute a white crayon, a wooden plank, and a multitool to create a Consecrated Book. \ + It can materialize a barricade at range that only you and people resistant to magic can pass. 3 uses." + gain_text = "With this I can repel those that intend me harm." + required_atoms = list( + /obj/item/toy/crayon/white = 1, + /obj/item/stack/sheet/mineral/wood = 1, + /obj/item/multitool = 1, + ) + result_atoms = list(/obj/item/heretic_lintel) + next_knowledge = list(/datum/heretic_knowledge/mark/knock_mark) + cost = 1 + route = PATH_KNOCK + +/datum/heretic_knowledge/mark/knock_mark + name = "Mark of Knock" + desc = "Your Mansus Grasp now applies the Mark of Knock. \ + Attack a marked person to bar them from all passages for the duration of the mark. \ + This will make it so that they have no access whatsoever, even public access doors will reject them." + gain_text = "Their requests for passage will remain unheeded." + next_knowledge = list(/datum/heretic_knowledge/knowledge_ritual/knock) + route = PATH_KNOCK + mark_type = /datum/status_effect/eldritch/knock + +/datum/heretic_knowledge/knowledge_ritual/knock + next_knowledge = list(/datum/heretic_knowledge/spell/burglar_finesse) + route = PATH_KNOCK + +/datum/heretic_knowledge/spell/burglar_finesse + name = "Burglar's Finesse" + desc = "Grants you Burglar's Finesse, a single-target spell \ + that puts a random item from the victims backpack into your hand." + gain_text = "Their trinkets will be mine, as will their lives in due time." + next_knowledge = list( + /datum/heretic_knowledge/spell/apetra_vulnera, + /datum/heretic_knowledge/spell/opening_blast, + /datum/heretic_knowledge/blade_upgrade/flesh/knock, + ) + spell_to_add = /datum/action/cooldown/spell/pointed/burglar_finesse + cost = 2 + route = PATH_KNOCK + +/datum/heretic_knowledge/blade_upgrade/flesh/knock //basically a chance-based weeping avulsion version of the former + name = "Opening Blade" + desc = "Your blade has a chance to cause a weeping avulsion on attack." + gain_text = "The power of my patron courses through my blade, willing their very flesh to part." + next_knowledge = list(/datum/heretic_knowledge/spell/caretaker_refuge) + route = PATH_KNOCK + wound_type = /datum/wound/slash/flesh/critical + var/chance = 35 + +/datum/heretic_knowledge/blade_upgrade/flesh/knock/do_melee_effects(mob/living/source, mob/living/target, obj/item/melee/sickly_blade/blade) + if(prob(chance)) + return ..() + +/datum/heretic_knowledge/spell/caretaker_refuge + name = "Caretaker’s Last Refuge" + desc = "Gives you a spell that makes you transparent and not dense. Cannot be used near living sentient beings. \ + While in refuge, you cannot use your hands or spells, and you are immune to slowdown. \ + You are invincible but unable to harm anything. Cancelled by being hit with an anti-magic item." + gain_text = "Then I saw my my own reflection cascaded mind-numbingly enough times that I was but a haze." + next_knowledge = list(/datum/heretic_knowledge/ultimate/knock_final) + route = PATH_KNOCK + spell_to_add = /datum/action/cooldown/spell/caretaker + cost = 1 + +/datum/heretic_knowledge/ultimate/knock_final + name = "Many secrets behind the Spider Door" + 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 Spider Door; \ + 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." + gain_text = "With her knowledge, and what I had seen, I knew what to do. \ + I had to open the gates, with the holes in my foes as Ways! \ + Reality will soon be torn, the Spider Gate opened! WITNESS ME!" + required_atoms = list(/mob/living/carbon/human = 3) + route = PATH_KNOCK + +/datum/heretic_knowledge/ultimate/knock_final/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc) + . = ..() + if(!.) + return FALSE + + for(var/mob/living/carbon/human/body in atoms) + if(body.stat != DEAD) + continue + var/obj/item/bodypart/chest = body.get_bodypart(BODY_ZONE_CHEST) + if(LAZYLEN(chest.get_organs())) + to_chat(user, span_hierophant_warning("[body] has organs in their chest.")) + continue + + selected_atoms += body + + if(!LAZYLEN(selected_atoms)) + loc.balloon_alert(user, "ritual failed, not enough valid bodies!") + return FALSE + return TRUE + +/datum/heretic_knowledge/ultimate/knock_final/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc) + . = ..() + priority_announce("Delta-class dimensional anomaly detec[generate_heretic_text()] Reality rended, torn. Gates open, doors open, [user.real_name] has ascended! Fear the tide! [generate_heretic_text()]", "Centra[generate_heretic_text()]", ANNOUNCER_SPANOMALIES) + user.client?.give_award(/datum/award/achievement/misc/knock_ascension, user) + + // buffs + var/datum/action/cooldown/spell/shapeshift/eldritch/ascension/transform_spell = new(user.mind) + transform_spell.Grant(user) + + user.client?.give_award(/datum/award/achievement/misc/knock_ascension, user) + var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(user) + var/datum/heretic_knowledge/blade_upgrade/flesh/knock/blade_upgrade = heretic_datum.get_knowledge(/datum/heretic_knowledge/blade_upgrade/flesh/knock) + blade_upgrade.chance += 30 + new /obj/structure/knock_tear(loc, user.mind) diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm index 375a1b785905bf..3e37c17392361f 100644 --- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm +++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm @@ -40,18 +40,17 @@ #ifndef UNIT_TESTS // This is a decently hefty thing to generate while unit testing, so we should skip it. if(!heretic_level_generated) heretic_level_generated = TRUE - log_game("Generating z-level for heretic sacrifices...") + log_game("Loading heretic lazytemplate for heretic sacrifices...") INVOKE_ASYNC(src, PROC_REF(generate_heretic_z_level)) #endif /// Generate the sacrifice z-level. /datum/heretic_knowledge/hunt_and_sacrifice/proc/generate_heretic_z_level() - var/datum/map_template/heretic_sacrifice_level/new_level = new() - if(!new_level.load_new_z()) - log_game("The heretic sacrifice z-level failed to load.") - message_admins("The heretic sacrifice z-level failed to load. Heretic sacrifices won't be teleported to the shadow realm. \ + if(!SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_HERETIC_SACRIFICE)) + log_game("The heretic sacrifice template failed to load.") + message_admins("The heretic sacrifice lazy template failed to load. Heretic sacrifices won't be teleported to the shadow realm. \ If you want, you can spawn an /obj/effect/landmark/heretic somewhere to stop that from happening.") - CRASH("Failed to initialize heretic sacrifice z-level!") + CRASH("Failed to lazy load heretic sacrifice template!") /datum/heretic_knowledge/hunt_and_sacrifice/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc) var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(user) diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm index a31f0a7cc97ff9..983bbee32c600f 100644 --- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm +++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm @@ -3,14 +3,6 @@ /// A global assoc list of all landmarks that denote a heretic sacrifice location. [string heretic path] = [landmark]. GLOBAL_LIST_EMPTY(heretic_sacrifice_landmarks) -/** - * A map template loaded in when heretics are created. - * Hereteic sacrifices are sent here when completed. - */ -/datum/map_template/heretic_sacrifice_level - name = "Heretic Sacrifice Level" - mappath = "_maps/templates/heretic_sacrifice_template.dmm" - /// Lardmarks meant to designate where heretic sacrifices are sent. /obj/effect/landmark/heretic name = "default heretic sacrifice landmark" @@ -42,6 +34,10 @@ GLOBAL_LIST_EMPTY(heretic_sacrifice_landmarks) name = "rust heretic sacrifice landmark" for_heretic_path = PATH_RUST +/obj/effect/landmark/heretic/knock + name = "knock heretic sacrifice landmark" + for_heretic_path = PATH_KNOCK + // A fluff signpost object that doesn't teleport you somewhere when you touch it. /obj/structure/no_effect_signpost name = "signpost" @@ -114,3 +110,8 @@ GLOBAL_LIST_EMPTY(heretic_sacrifice_landmarks) name = "Mansus Rust Gate" ambience_index = AMBIENCE_REEBE sound_environment = SOUND_ENVIRONMENT_SEWER_PIPE + +/area/centcom/heretic_sacrifice/knock + name = "Mansus Knock Gate" + ambience_index = AMBIENCE_DANGER + sound_environment = SOUND_ENVIRONMENT_PSYCHOTIC diff --git a/code/modules/antagonists/heretic/knowledge/side_flesh_void.dm b/code/modules/antagonists/heretic/knowledge/side_flesh_void.dm index 4a315575d61b71..6439840fed5d5c 100644 --- a/code/modules/antagonists/heretic/knowledge/side_flesh_void.dm +++ b/code/modules/antagonists/heretic/knowledge/side_flesh_void.dm @@ -26,6 +26,7 @@ Also has a chance to transfer wounds from you to the victim." gain_text = "\"No matter the man, we bleed all the same.\" That's what the Marshal told me." next_knowledge = list( + /datum/heretic_knowledge/spell/apetra_vulnera, /datum/heretic_knowledge/spell/void_phase, /datum/heretic_knowledge/summon/raw_prophet, ) diff --git a/code/modules/antagonists/heretic/knowledge/side_knock_flesh.dm b/code/modules/antagonists/heretic/knowledge/side_knock_flesh.dm new file mode 100644 index 00000000000000..97218ce5e94105 --- /dev/null +++ b/code/modules/antagonists/heretic/knowledge/side_knock_flesh.dm @@ -0,0 +1,28 @@ +// Sidepaths for knowledge between Knock and Flesh. + +/datum/heretic_knowledge/spell/apetra_vulnera + name = "Apetra Vulnera" + desc = "Grants you Apetra Vulnera, a spell \ + which causes heavy bleeding on all bodyparts of the victim that have more than 15 brute damage. \ + Wounds a random limb if no limb is sufficiently damaged." + gain_text = "Flesh opens, and blood spills. My master seeks sacrifice, and I shall appease." + next_knowledge = list( + /datum/heretic_knowledge/spell/blood_siphon, + /datum/heretic_knowledge/void_cloak, + ) + spell_to_add = /datum/action/cooldown/spell/pointed/apetra_vulnera + cost = 1 + route = PATH_SIDE + +/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." + gain_text = "My shackles undone in dark fury, their feeble bindings crumble before my power." + next_knowledge = list( + /datum/heretic_knowledge/summon/ashy, + /datum/heretic_knowledge/void_cloak, + ) + spell_to_add = /datum/action/cooldown/spell/aoe/wave_of_desperation + cost = 1 + route = PATH_SIDE diff --git a/code/modules/antagonists/heretic/magic/apetravulnera.dm b/code/modules/antagonists/heretic/magic/apetravulnera.dm new file mode 100644 index 00000000000000..801104dddf9fc2 --- /dev/null +++ b/code/modules/antagonists/heretic/magic/apetravulnera.dm @@ -0,0 +1,59 @@ +/datum/action/cooldown/spell/pointed/apetra_vulnera + name = "Apetra Vulnera" + desc = "Causes severe bleeding on every limb of a target which has more than 15 brute damage. \ + Wounds a random limb if no limb is sufficiently damaged." + background_icon_state = "bg_heretic" + overlay_icon_state = "bg_heretic_border" + button_icon = 'icons/mob/actions/actions_ecult.dmi' + button_icon_state = "cleave" + + school = SCHOOL_FORBIDDEN + cooldown_time = 45 SECONDS + + invocation = "AP'TRA VULN'RA!" + invocation_type = INVOCATION_WHISPER + spell_requirements = NONE + + cast_range = 4 + /// What type of wound we apply + var/wound_type = /datum/wound/slash/flesh/critical/cleave + +/datum/action/cooldown/spell/pointed/apetra_vulnera/is_valid_target(atom/cast_on) + return ..() && ishuman(cast_on) + +/datum/action/cooldown/spell/pointed/apetra_vulnera/cast(mob/living/carbon/human/cast_on) + . = ..() + + if(IS_HERETIC_OR_MONSTER(cast_on)) + return FALSE + + if(!cast_on.blood_volume) + return FALSE + + if(cast_on.can_block_magic(antimagic_flags)) + cast_on.visible_message( + span_danger("[cast_on]'s bruises briefly glow, but repels the effect!"), + span_danger("Your bruises sting a little, but you are protected!") + ) + return FALSE + + var/a_limb_got_damaged = FALSE + for(var/obj/item/bodypart/bodypart in cast_on.bodyparts) + if(bodypart.brute_dam < 15) + continue + 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)) + + cast_on.visible_message( + 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 new file mode 100644 index 00000000000000..4395b4a54b340c --- /dev/null +++ b/code/modules/antagonists/heretic/magic/ascended_shapeshift.dm @@ -0,0 +1,32 @@ +// Given to ascended knock heretics, is a form of shapeshift that can turn into all 4 common heretic summons, and is not limited to 1 selection. +/datum/action/cooldown/spell/shapeshift/eldritch/ascension + name = "Ascended Shapechange" + desc = "A spell that allows you to take on the form of another eldritch creature, gaining their abilities. \ + You can change your choice at any time, and if your form dies, you dont die." + cooldown_time = 20 SECONDS + die_with_shapeshifted_form = FALSE + possible_shapes = list( + /mob/living/simple_animal/hostile/heretic_summon/raw_prophet, + /mob/living/simple_animal/hostile/heretic_summon/rust_spirit, + /mob/living/simple_animal/hostile/heretic_summon/ash_spirit, + /mob/living/simple_animal/hostile/heretic_summon/stalker, + ) + +/datum/action/cooldown/spell/shapeshift/eldritch/ascension/do_shapeshift(mob/living/caster) + . = ..() + if(!.) + return + //buff our forms so this ascension ability isnt shit + playsound(caster, 'sound/magic/demon_consume.ogg', 50, TRUE) + var/mob/living/monster = . + monster.AddComponent(/datum/component/seethrough_mob) + monster.maxHealth *= 1.5 + monster.health = monster.maxHealth + monster.melee_damage_lower = max((monster.melee_damage_lower * 2), 40) + monster.melee_damage_upper = monster.melee_damage_upper / 2 + monster.transform *= 1.5 + monster.AddElement(/datum/element/wall_smasher, strength_flag = ENVIRONMENT_SMASH_RWALLS) + +/datum/action/cooldown/spell/shapeshift/eldritch/ascension/do_unshapeshift(mob/living/caster) + . = ..() + shapeshift_type = null //pick another loser diff --git a/code/modules/antagonists/heretic/magic/burglar_finesse.dm b/code/modules/antagonists/heretic/magic/burglar_finesse.dm new file mode 100644 index 00000000000000..7bb6960354ec79 --- /dev/null +++ b/code/modules/antagonists/heretic/magic/burglar_finesse.dm @@ -0,0 +1,39 @@ +/datum/action/cooldown/spell/pointed/burglar_finesse + name = "Burglar's Finesse" + desc = "Steal a random item from the victim's backpack." + background_icon_state = "bg_heretic" + overlay_icon_state = "bg_heretic_border" + button_icon = 'icons/mob/actions/actions_ecult.dmi' + button_icon_state = "burglarsfinesse" + + school = SCHOOL_FORBIDDEN + cooldown_time = 40 SECONDS + + invocation = "Y'O'K!" + invocation_type = INVOCATION_WHISPER + spell_requirements = NONE + + cast_range = 4 + +/datum/action/cooldown/spell/pointed/burglar_finesse/is_valid_target(atom/cast_on) + return ..() && ishuman(cast_on) && (locate(/obj/item/storage/backpack) in cast_on.contents) + +/datum/action/cooldown/spell/pointed/burglar_finesse/cast(mob/living/carbon/human/cast_on) + . = ..() + if(cast_on.can_block_magic(antimagic_flags)) + to_chat(cast_on, span_danger("You feel a light tug, but are otherwise fine, you were protected by holiness!")) + to_chat(owner, span_danger("[cast_on] is protected by holy forces!")) + return FALSE + + var/obj/storage_item = locate(/obj/item/storage/backpack) in cast_on.contents + + if(isnull(storage_item)) + return FALSE + + var/item = pick(storage_item.contents) + if(isnull(item)) + return FALSE + + to_chat(cast_on, span_warning("Your [storage_item] feels lighter...")) + to_chat(owner, span_notice("With a blink, you pull [item] out of [cast_on][p_s()] [storage_item].")) + owner.put_in_active_hand(item) diff --git a/code/modules/antagonists/heretic/magic/caretaker.dm b/code/modules/antagonists/heretic/magic/caretaker.dm new file mode 100644 index 00000000000000..87f3a69dad1dc0 --- /dev/null +++ b/code/modules/antagonists/heretic/magic/caretaker.dm @@ -0,0 +1,39 @@ +/datum/action/cooldown/spell/caretaker + name = "Caretaker’s Last Refuge" + desc = "Shifts you into the Caretaker's Refuge, rendering you translucent and intangible. \ + While in the Refuge your movement is unrestricted, but you cannot use your hands or cast any spells. \ + You cannot enter the Refuge while near other sentient beings, \ + 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" + sound = 'sound/effects/curse2.ogg' + + school = SCHOOL_FORBIDDEN + cooldown_time = 1 MINUTES + + invocation_type = INVOCATION_NONE + spell_requirements = NONE + +/datum/action/cooldown/spell/caretaker/Remove(mob/living/remove_from) + if(remove_from.has_status_effect(/datum/status_effect/caretaker_refuge)) + remove_from.remove_status_effect(/datum/status_effect/caretaker_refuge) + return ..() + +/datum/action/cooldown/spell/caretaker/is_valid_target(atom/cast_on) + return isliving(cast_on) + +/datum/action/cooldown/spell/caretaker/cast(atom/cast_on) + . = ..() + for(var/mob/living/alive in orange(5, owner)) + if(alive.stat != DEAD && alive.client) + owner.balloon_alert(owner, "other minds nearby!") + return FALSE + + var/mob/living/carbon/carbon_user = owner + if(carbon_user.has_status_effect(/datum/status_effect/caretaker_refuge)) + carbon_user.remove_status_effect(/datum/status_effect/caretaker_refuge) + else + carbon_user.apply_status_effect(/datum/status_effect/caretaker_refuge) + return TRUE diff --git a/code/modules/antagonists/heretic/magic/wave_of_desperation.dm b/code/modules/antagonists/heretic/magic/wave_of_desperation.dm new file mode 100644 index 00000000000000..3b78b56ddc0ba1 --- /dev/null +++ b/code/modules/antagonists/heretic/magic/wave_of_desperation.dm @@ -0,0 +1,79 @@ +/datum/action/cooldown/spell/aoe/wave_of_desperation + name = "Wave Of Desperation" + desc = "Removes your restraints, repels and knocks down adjacent people, and applies certain effects of the Mansus Grasp upon everything nearby. \ + Cannot be cast unless you are restrained, and the stress renders you unconscious 12 seconds later!" + background_icon_state = "bg_heretic" + overlay_icon_state = "bg_heretic_border" + button_icon = 'icons/mob/actions/actions_ecult.dmi' + button_icon_state = "uncuff" + sound = 'sound/magic/swap.ogg' + + school = SCHOOL_FORBIDDEN + cooldown_time = 5 MINUTES + + invocation = "F'K 'FF." + invocation_type = INVOCATION_WHISPER + spell_requirements = NONE + + aoe_radius = 3 + +/datum/action/cooldown/spell/aoe/wave_of_desperation/is_valid_target(mob/living/carbon/cast_on) + return ..() && istype(cast_on) && (cast_on.handcuffed || cast_on.legcuffed) + +// Before the cast, we do some small AOE damage around the caster +/datum/action/cooldown/spell/aoe/wave_of_desperation/before_cast(mob/living/carbon/cast_on) + . = ..() + if(. & SPELL_CANCEL_CAST) + return + + if(cast_on.handcuffed) + cast_on.visible_message(span_danger("[cast_on.handcuffed] on [cast_on] shatter!")) + QDEL_NULL(cast_on.handcuffed) + if(cast_on.legcuffed) + cast_on.visible_message(span_danger("[cast_on.legcuffed] on [cast_on] shatters!")) + QDEL_NULL(cast_on.legcuffed) + + cast_on.apply_status_effect(/datum/status_effect/heretic_lastresort) + new /obj/effect/temp_visual/knockblast(get_turf(cast_on)) + + for(var/mob/living/victim in get_things_to_cast_on(cast_on, radius_override = 1)) + victim.AdjustKnockdown(3 SECONDS) + victim.AdjustParalyzed(0.5 SECONDS) + +/datum/action/cooldown/spell/aoe/wave_of_desperation/get_things_to_cast_on(atom/center, radius_override) + . = list() + for(var/atom/nearby in orange(center, radius_override ? radius_override : aoe_radius)) + if(nearby == owner || nearby == center || isarea(nearby)) + continue + if(!ismob(nearby)) + . += nearby + continue + var/mob/living/nearby_mob = nearby + if(!isturf(nearby_mob.loc)) + continue + if(IS_HERETIC_OR_MONSTER(nearby_mob)) + continue + if(nearby_mob.can_block_magic(antimagic_flags)) + continue + + . += nearby_mob + +/datum/action/cooldown/spell/aoe/wave_of_desperation/cast_on_thing_in_aoe(atom/victim, atom/caster) + if(!ismob(victim)) + SEND_SIGNAL(owner, COMSIG_HERETIC_MANSUS_GRASP_ATTACK_SECONDARY, victim) + + var/atom/movable/mover = victim + if(!istype(mover)) + return + + if(mover.anchored) + return + var/our_turf = get_turf(caster) + var/throwtarget = get_edge_target_turf(our_turf, get_dir(our_turf, get_step_away(mover, our_turf))) + mover.safe_throw_at(throwtarget, 3, 1, force = MOVE_FORCE_STRONG) + +/obj/effect/temp_visual/knockblast + icon = 'icons/effects/effects.dmi' + icon_state = "shield-flash" + alpha = 180 + duration = 1 SECONDS diff --git a/code/modules/antagonists/heretic/status_effects/buffs.dm b/code/modules/antagonists/heretic/status_effects/buffs.dm index 743aa2c5a0144e..f1c96c51ad464c 100644 --- a/code/modules/antagonists/heretic/status_effects/buffs.dm +++ b/code/modules/antagonists/heretic/status_effects/buffs.dm @@ -74,7 +74,8 @@ heal_amt = 3 if(WOUND_SEVERITY_CRITICAL) heal_amt = 6 - if(wound.wound_type == WOUND_BURN) + var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[wound.type] + if (pregen_data.wounding_types_valid(list(WOUND_BURN))) carbie.adjustFireLoss(-heal_amt) else carbie.adjustBruteLoss(-heal_amt) @@ -235,3 +236,53 @@ return addtimer(CALLBACK(src, PROC_REF(create_blade)), blade_recharge_time) + +/datum/status_effect/caretaker_refuge + id = "Caretaker’s Last Refuge" + status_type = STATUS_EFFECT_REFRESH + duration = -1 + alert_type = null + var/static/list/caretaking_traits = list(TRAIT_HANDS_BLOCKED, TRAIT_IGNORESLOWDOWN) + +/datum/status_effect/caretaker_refuge/on_apply() + owner.add_traits(caretaking_traits, TRAIT_STATUS_EFFECT(id)) + owner.status_flags |= GODMODE + animate(owner, alpha = 45,time = 0.5 SECONDS) + owner.density = FALSE + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_ALLOW_HERETIC_CASTING), PROC_REF(on_focus_lost)) + RegisterSignal(owner, COMSIG_MOB_BEFORE_SPELL_CAST, PROC_REF(prevent_spell_usage)) + RegisterSignal(owner, COMSIG_ATOM_HOLYATTACK, PROC_REF(nullrod_handler)) + return TRUE + +/datum/status_effect/caretaker_refuge/on_remove() + owner.remove_traits(caretaking_traits, TRAIT_STATUS_EFFECT(id)) + owner.status_flags &= ~GODMODE + owner.alpha = initial(owner.alpha) + owner.density = initial(owner.density) + UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_ALLOW_HERETIC_CASTING)) + UnregisterSignal(owner, COMSIG_MOB_BEFORE_SPELL_CAST) + UnregisterSignal(owner, COMSIG_ATOM_HOLYATTACK) + owner.visible_message( + span_warning("The haze around [owner] disappears, leaving them materialized!"), + span_notice("You exit the refuge."), + ) + +/datum/status_effect/caretaker_refuge/get_examine_text() + return span_warning("[owner.p_Theyre()] enveloped in an unholy haze!") + +/datum/status_effect/caretaker_refuge/proc/nullrod_handler(datum/source, obj/item/weapon) + SIGNAL_HANDLER + playsound(get_turf(owner), 'sound/effects/curse1.ogg', 80, TRUE) + owner.visible_message(span_warning("[weapon] repels the haze around [owner]!")) + owner.remove_status_effect(type) + +/datum/status_effect/caretaker_refuge/proc/on_focus_lost() + SIGNAL_HANDLER + to_chat(owner, span_danger("Without a focus, your refuge weakens and dissipates!")) + owner.remove_status_effect(type) + +/datum/status_effect/caretaker_refuge/proc/prevent_spell_usage(datum/source, datum/spell) + SIGNAL_HANDLER + if(!istype(spell, /datum/action/cooldown/spell/caretaker)) + owner.balloon_alert(owner, "may not cast spells in refuge!") + return SPELL_CANCEL_CAST diff --git a/code/modules/antagonists/heretic/status_effects/debuffs.dm b/code/modules/antagonists/heretic/status_effects/debuffs.dm index 3c7715111be2e5..c286c7b5092e6c 100644 --- a/code/modules/antagonists/heretic/status_effects/debuffs.dm +++ b/code/modules/antagonists/heretic/status_effects/debuffs.dm @@ -110,7 +110,7 @@ var/chance = rand(0, 100) switch(chance) if(0 to 10) - human_owner.vomit() + human_owner.vomit(VOMIT_CATEGORY_DEFAULT) if(20 to 30) human_owner.set_timed_status_effect(100 SECONDS, /datum/status_effect/dizziness, only_if_higher = TRUE) human_owner.set_timed_status_effect(100 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE) @@ -192,3 +192,25 @@ /datum/status_effect/star_mark/extended duration = 3 MINUTES + +// Last Resort +/datum/status_effect/heretic_lastresort + id = "heretic_lastresort" + alert_type = /atom/movable/screen/alert/status_effect/heretic_lastresort + duration = 12 SECONDS + status_type = STATUS_EFFECT_REPLACE + tick_interval = -1 + +/atom/movable/screen/alert/status_effect/heretic_lastresort + name = "Last Resort" + desc = "Your head spins, heart pumping as fast as it can, losing the fight with the ground. Run to safety!" + icon_state = "lastresort" + +/datum/status_effect/heretic_lastresort/on_apply() + ADD_TRAIT(owner, TRAIT_IGNORESLOWDOWN, TRAIT_STATUS_EFFECT(id)) + to_chat(owner, span_userdanger("You are on the brink of losing consciousness, run!")) + return TRUE + +/datum/status_effect/heretic_lastresort/on_remove() + REMOVE_TRAIT(owner, TRAIT_IGNORESLOWDOWN, TRAIT_STATUS_EFFECT(id)) + owner.AdjustUnconscious(20 SECONDS, ignore_canstun = TRUE) diff --git a/code/modules/antagonists/heretic/status_effects/mark_effects.dm b/code/modules/antagonists/heretic/status_effects/mark_effects.dm index c454ebdc46289a..068570f76c7b17 100644 --- a/code/modules/antagonists/heretic/status_effects/mark_effects.dm +++ b/code/modules/antagonists/heretic/status_effects/mark_effects.dm @@ -61,8 +61,7 @@ if(ishuman(owner)) var/mob/living/carbon/human/human_owner = owner var/obj/item/bodypart/bodypart = pick(human_owner.bodyparts) - var/datum/wound/slash/flesh/severe/crit_wound = new() - crit_wound.apply_wound(bodypart) + human_owner.cause_wound_of_type_and_severity(WOUND_SLASH, bodypart, WOUND_SEVERITY_SEVERE) return ..() @@ -247,3 +246,17 @@ new teleport_effect(get_turf(owner)) owner.Paralyze(2 SECONDS) return ..() + +// MARK OF KNOCK + +/datum/status_effect/eldritch/knock + effect_icon_state = "emark7" + duration = 10 SECONDS + +/datum/status_effect/eldritch/knock/on_apply() + . = ..() + ADD_TRAIT(owner, TRAIT_ALWAYS_NO_ACCESS, STATUS_EFFECT_TRAIT) + +/datum/status_effect/eldritch/knock/on_remove() + REMOVE_TRAIT(owner, TRAIT_ALWAYS_NO_ACCESS, STATUS_EFFECT_TRAIT) + return ..() diff --git a/code/modules/antagonists/heretic/structures/knock_final.dm b/code/modules/antagonists/heretic/structures/knock_final.dm new file mode 100644 index 00000000000000..85face85609586 --- /dev/null +++ b/code/modules/antagonists/heretic/structures/knock_final.dm @@ -0,0 +1,67 @@ +/obj/structure/knock_tear + name = "???" + desc = "It stares back. Theres no reason to remain. Run." + max_integrity = INFINITE + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + icon = 'icons/obj/anomaly.dmi' + icon_state = "bhole3" + color = "#53277E" + light_color = "#53277E" //cooler purple + light_range = 20 + anchored = TRUE + density = FALSE + layer = HIGH_PIPE_LAYER //0.01 above sigil layer used by heretic runes + move_resist = INFINITY + var/datum/mind/ascendee + ///a static list of heretic summons, this shouldnt even matter enough to be static but whatever + var/static/list/monster_types + +/obj/structure/knock_tear/Initialize(mapload, ascendant) + . = ..() + transform *= 3 + if(!monster_types) + monster_types = subtypesof(/mob/living/simple_animal/hostile/heretic_summon) - /mob/living/simple_animal/hostile/heretic_summon/armsy/prime + if(ascendant) + ascendee = ascendant + SSpoints_of_interest.make_point_of_interest(src) + INVOKE_ASYNC(src, PROC_REF(poll_ghosts)) + +/obj/structure/knock_tear/proc/poll_ghosts() + var/list/candidates = poll_ghost_candidates("Would you like to be a random eldritch monster attacking the crew?", ROLE_SENTIENCE, ROLE_SENTIENCE, 10 SECONDS, POLL_IGNORE_HERETIC_MONSTER) + while(LAZYLEN(candidates)) + var/mob/dead/observer/candidate = pick_n_take(candidates) + ghost_to_monster(candidate, should_ask = FALSE) + +/obj/structure/knock_tear/attack_ghost(mob/user) + . = ..() + if(.) + return + ghost_to_monster(user) + +/obj/structure/knock_tear/proc/ghost_to_monster(mob/dead/observer/user, should_ask = TRUE) + if(should_ask) + var/ask = tgui_alert(user, "Become a monster?", "Ascended Rift", list("Yes", "No")) + if(ask != "Yes" || QDELETED(src) || QDELETED(user)) + return FALSE + var/monster_type = pick(monster_types) + var/mob/living/monster = new monster_type(loc) + monster.key = user.key + monster.set_name() + var/datum/antagonist/heretic_monster/woohoo_free_antag = new(src) + monster.mind.add_antag_datum(woohoo_free_antag) + if(ascendee) + monster.faction = ascendee.current.faction + woohoo_free_antag.set_owner(ascendee) + var/datum/objective/kill_all_your_friends = new() + kill_all_your_friends.owner = monster.mind + kill_all_your_friends.explanation_text = "The station's crew must be culled." + kill_all_your_friends.completed = TRUE + woohoo_free_antag.objectives += kill_all_your_friends + +/obj/structure/knock_tear/move_crushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction) + return FALSE + +/obj/structure/knock_tear/Destroy(force) //this shouldnt happen but hey + if(ascendee) + ascendee = null + return ..() diff --git a/code/modules/antagonists/nightmare/nightmare_species.dm b/code/modules/antagonists/nightmare/nightmare_species.dm index 73f2f02f847d83..88331353657a3d 100644 --- a/code/modules/antagonists/nightmare/nightmare_species.dm +++ b/code/modules/antagonists/nightmare/nightmare_species.dm @@ -21,6 +21,8 @@ TRAIT_NOBLOOD, TRAIT_NO_DNA_COPY, TRAIT_NO_TRANSFORMATION_STING, + TRAIT_NODISMEMBER, + TRAIT_NEVER_WOUNDED, ) mutantheart = /obj/item/organ/internal/heart/nightmare diff --git a/code/modules/antagonists/ninja/ninja_explosive.dm b/code/modules/antagonists/ninja/ninja_explosive.dm index b371f12c2e7661..4c014da1863204 100644 --- a/code/modules/antagonists/ninja/ninja_explosive.dm +++ b/code/modules/antagonists/ninja/ninja_explosive.dm @@ -66,12 +66,12 @@ qdel(src) return //Since we already did the checks in afterattack, the denonator must be a ninja with the bomb objective. - if(!detonator) + if(isnull(detonator)) return + var/mob/ninja = detonator.resolve() . = ..() if(!.) return - var/mob/ninja = detonator.resolve() if (isnull(ninja)) return var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja) diff --git a/code/modules/antagonists/obsessed/obsessed.dm b/code/modules/antagonists/obsessed/obsessed.dm index 63adacca1e82db..7c921fdd228564 100644 --- a/code/modules/antagonists/obsessed/obsessed.dm +++ b/code/modules/antagonists/obsessed/obsessed.dm @@ -10,6 +10,7 @@ silent = TRUE //not actually silent, because greet will be called by the trauma anyway. suicide_cry = "FOR MY LOVE!!" preview_outfit = /datum/outfit/obsessed + hardcore_random_bonus = TRUE var/datum/brain_trauma/special/obsessed/trauma /datum/antagonist/obsessed/admin_add(datum/mind/new_owner,mob/admin) diff --git a/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm b/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm index ff9678ad519eae..57eb95a978c521 100644 --- a/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm +++ b/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm @@ -183,8 +183,8 @@ /obj/machinery/piratepad/multitool_act(mob/living/user, obj/item/multitool/I) . = ..() if (istype(I)) - to_chat(user, span_notice("You register [src] in [I]s buffer.")) I.set_buffer(src) + balloon_alert(user, "saved to multitool buffer") return TRUE /obj/machinery/piratepad/screwdriver_act_secondary(mob/living/user, obj/item/screwdriver/screw) diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm index 1857223df6b6cb..e88730f70267e9 100644 --- a/code/modules/antagonists/revolution/revolution.dm +++ b/code/modules/antagonists/revolution/revolution.dm @@ -176,6 +176,7 @@ job_rank = ROLE_REV_HEAD preview_outfit = /datum/outfit/revolutionary + hardcore_random_bonus = TRUE var/remove_clumsy = FALSE var/give_flash = FALSE diff --git a/code/modules/antagonists/survivalist/survivalist.dm b/code/modules/antagonists/survivalist/survivalist.dm index 7cb9df6ed25ee6..2480b186600a6a 100644 --- a/code/modules/antagonists/survivalist/survivalist.dm +++ b/code/modules/antagonists/survivalist/survivalist.dm @@ -22,6 +22,7 @@ /datum/antagonist/survivalist/guns greet_message = "Your own safety matters above all else, and the only way to ensure your safety is to stockpile weapons! Grab as many guns as possible, by any means necessary. Kill anyone who gets in your way." + hardcore_random_bonus = TRUE /datum/antagonist/survivalist/guns/forge_objectives() var/datum/objective/steal_n_of_type/summon_guns/guns = new @@ -32,6 +33,7 @@ /datum/antagonist/survivalist/magic name = "Amateur Magician" greet_message = "Grow your newfound talent! Grab as many magical artefacts as possible, by any means necessary. Kill anyone who gets in your way." + hardcore_random_bonus = TRUE /datum/antagonist/survivalist/magic/greet() . = ..() diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 3813009be42fb3..aaf162c15f8530 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -16,6 +16,7 @@ preview_outfit = /datum/outfit/traitor can_assign_self_objectives = TRUE default_custom_objective = "Perform an overcomplicated heist on valuable Nanotrasen assets." + hardcore_random_bonus = TRUE var/give_objectives = TRUE var/should_give_codewords = TRUE ///give this traitor an uplink? diff --git a/code/modules/antagonists/traitor/objectives/eyesnatching.dm b/code/modules/antagonists/traitor/objectives/eyesnatching.dm index d912be2384aad2..0540d83601ccfa 100644 --- a/code/modules/antagonists/traitor/objectives/eyesnatching.dm +++ b/code/modules/antagonists/traitor/objectives/eyesnatching.dm @@ -179,9 +179,10 @@ if(!do_after(user, eye_snatch_enthusiasm, target = target, extra_checks = CALLBACK(src, PROC_REF(eyeballs_exist), eyeballies, head, target))) return - var/datum/wound/blunt/bone/severe/severe_wound_type = /datum/wound/blunt/bone/severe - var/datum/wound/blunt/bone/critical/critical_wound_type = /datum/wound/blunt/bone/critical - target.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = rand(initial(severe_wound_type.threshold_minimum), initial(critical_wound_type.threshold_minimum) + 10), attacking_item = src) + var/min_wound = head.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_SEVERE, return_value_if_no_wound = 30, wound_source = src) + var/max_wound = head.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_CRITICAL, return_value_if_no_wound = 50, wound_source = src) + + target.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = rand(min_wound, max_wound + 10), attacking_item = src) target.visible_message( span_danger("[src] pierces through [target]'s skull, horribly mutilating their eyes!"), span_userdanger("Something penetrates your skull, horribly mutilating your eyes! Holy fuck!"), diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm index fc15d0b014b094..39d9605c3ef047 100644 --- a/code/modules/antagonists/wizard/equipment/artefact.dm +++ b/code/modules/antagonists/wizard/equipment/artefact.dm @@ -150,7 +150,7 @@ /obj/tear_in_reality/proc/deranged(mob/living/carbon/C) if(!C || C.stat == DEAD) return - C.vomit(0, TRUE, TRUE, 3, TRUE) + C.vomit(VOMIT_CATEGORY_BLOOD, lost_nutrition = 0, distance = 3) C.spew_organ(3, 2) C.investigate_log("has died from using telekinesis on a tear in reality.", INVESTIGATE_DEATHS) C.death() diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm index 45f7b671f12cbb..1e8df43cfbe766 100644 --- a/code/modules/antagonists/wizard/wizard.dm +++ b/code/modules/antagonists/wizard/wizard.dm @@ -14,6 +14,7 @@ GLOBAL_LIST_EMPTY(wizard_spellbook_purchases_by_key) preview_outfit = /datum/outfit/wizard can_assign_self_objectives = TRUE default_custom_objective = "Demonstrate your incredible and destructive magical powers." + hardcore_random_bonus = TRUE var/give_objectives = TRUE var/strip = TRUE //strip before equipping var/allow_rename = TRUE diff --git a/code/modules/asset_cache/assets/fish.dm b/code/modules/asset_cache/assets/fish.dm index 14258663d9b9aa..2fcf2b803e38c8 100644 --- a/code/modules/asset_cache/assets/fish.dm +++ b/code/modules/asset_cache/assets/fish.dm @@ -12,10 +12,3 @@ continue id_list += id Insert(id, fish_icon, fish_icon_state) - - -/datum/asset/simple/fishing_minigame - assets = list( - "fishing_background_default" = 'icons/ui_icons/fishing/default.png', - "fishing_background_lavaland" = 'icons/ui_icons/fishing/lavaland.png' - ) diff --git a/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm b/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm index 3ef5c9a4d33315..a11f439ec314bd 100644 --- a/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm +++ b/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm @@ -124,6 +124,7 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) GLOB.air_alarms += src update_appearance() + find_and_hang_on_wall() /obj/machinery/airalarm/process() if(!COOLDOWN_FINISHED(src, warning_cooldown)) diff --git a/code/modules/atmospherics/machinery/bluespace_vendor.dm b/code/modules/atmospherics/machinery/bluespace_vendor.dm index 7ea5b827d4a4c5..847533540180d5 100644 --- a/code/modules/atmospherics/machinery/bluespace_vendor.dm +++ b/code/modules/atmospherics/machinery/bluespace_vendor.dm @@ -69,6 +69,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/bluespace_vendor, 30) /obj/machinery/bluespace_vendor/Initialize(mapload) . = ..() AddComponent(/datum/component/payment, tank_cost, SSeconomy.get_dep_account(ACCOUNT_ENG), PAYMENT_ANGRY) + find_and_hang_on_wall( FALSE) /obj/machinery/bluespace_vendor/LateInitialize() . = ..() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/bluespace_sender.dm b/code/modules/atmospherics/machinery/components/unary_devices/bluespace_sender.dm index d4977eb6454f91..1685a027a5f285 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/bluespace_sender.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/bluespace_sender.dm @@ -123,7 +123,7 @@ GLOBAL_LIST_EMPTY_TYPED(bluespace_senders, /obj/machinery/atmospherics/component /obj/machinery/atmospherics/components/unary/bluespace_sender/multitool_act(mob/living/user, obj/item/item) var/obj/item/multitool/multitool = item multitool.set_buffer(src) - to_chat(user, span_notice("You store linkage information in [item]'s buffer.")) + balloon_alert(user, "saved to multitool buffer") return TRUE /obj/machinery/atmospherics/components/unary/bluespace_sender/wrench_act(mob/living/user, obj/item/tool) 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 269091d4bdfd1a..452d5d7b243585 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm @@ -43,16 +43,13 @@ . += span_notice("You can link it with an air sensor using a multitool.") /obj/machinery/atmospherics/components/unary/outlet_injector/multitool_act(mob/living/user, obj/item/multitool/multi_tool) - . = ..() - if(istype(multi_tool.buffer, /obj/machinery/air_sensor)) var/obj/machinery/air_sensor/sensor = multi_tool.buffer - sensor.inlet_id = id_tag - multi_tool.set_buffer(null) - balloon_alert(user, "input linked to sensor") + multi_tool.set_buffer(src) + sensor.multitool_act(user, multi_tool) return TOOL_ACT_TOOLTYPE_SUCCESS - balloon_alert(user, "saved in buffer") + balloon_alert(user, "injector saved in buffer") multi_tool.set_buffer(src) return TOOL_ACT_TOOLTYPE_SUCCESS 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 6449dc49357adf..3422f3e3adfa53 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm @@ -53,16 +53,13 @@ . += span_notice("You can link it with an air sensor using a multitool.") /obj/machinery/atmospherics/components/unary/vent_pump/multitool_act(mob/living/user, obj/item/multitool/multi_tool) - . = ..() - if(istype(multi_tool.buffer, /obj/machinery/air_sensor)) var/obj/machinery/air_sensor/sensor = multi_tool.buffer - sensor.outlet_id = id_tag - multi_tool.set_buffer(null) - balloon_alert(user, "output linked to sensor") + multi_tool.set_buffer(src) + sensor.multitool_act(user, multi_tool) return TOOL_ACT_TOOLTYPE_SUCCESS - balloon_alert(user, "saved in buffer") + balloon_alert(user, "vent saved in buffer") multi_tool.set_buffer(src) return TOOL_ACT_TOOLTYPE_SUCCESS diff --git a/code/modules/cards/cardhand.dm b/code/modules/cards/cardhand.dm index b03a29a43f4827..9dab4e65b584b1 100644 --- a/code/modules/cards/cardhand.dm +++ b/code/modules/cards/cardhand.dm @@ -29,7 +29,7 @@ /obj/item/toy/cards/cardhand/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) if(istype(held_item, /obj/item/toy/cards/deck)) var/obj/item/toy/cards/deck/dealer_deck = held_item - if(dealer_deck.wielded) + if(HAS_TRAIT(dealer_deck, TRAIT_WIELDED)) context[SCREENTIP_CONTEXT_LMB] = "Deal card" context[SCREENTIP_CONTEXT_RMB] = "Deal card faceup" return CONTEXTUAL_SCREENTIP_SET @@ -77,7 +77,7 @@ if(istype(weapon, /obj/item/toy/cards/deck)) var/obj/item/toy/cards/deck/dealer_deck = weapon - if(!dealer_deck.wielded) // recycle cardhand into deck (if unwielded) + if(!HAS_TRAIT(dealer_deck, TRAIT_WIELDED)) // recycle cardhand into deck (if unwielded) dealer_deck.insert(src) user.balloon_alert_to_viewers("puts card in deck") return diff --git a/code/modules/cards/deck/deck.dm b/code/modules/cards/deck/deck.dm index 189d88822ecfb5..632b01d509d74d 100644 --- a/code/modules/cards/deck/deck.dm +++ b/code/modules/cards/deck/deck.dm @@ -21,8 +21,6 @@ var/decksize = INFINITY /// The description of the cardgame that is played with this deck (used for memories) var/cardgame_desc = "card game" - /// Wielding status for holding with two hands - var/wielded = FALSE /// The holodeck computer used to spawn a holographic deck (see /obj/item/toy/cards/deck/syndicate/holographic) var/obj/machinery/computer/holodeck/holodeck /// If the cards in the deck have different card faces icons (blank and CAS decks do not) @@ -33,8 +31,6 @@ /obj/item/toy/cards/deck/Initialize(mapload) . = ..() AddElement(/datum/element/drag_pickup) - RegisterSignal(src, COMSIG_TWOHANDED_WIELD, PROC_REF(on_wield)) - RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, PROC_REF(on_unwield)) AddComponent(/datum/component/two_handed, attacksound='sound/items/cardflip.ogg') register_context() @@ -51,18 +47,6 @@ for(var/person in list("Jack", "Queen", "King")) initial_cards += "[person] of [suit]" -/// triggered on wield of two handed item -/obj/item/toy/cards/deck/proc/on_wield(obj/item/source, mob/user) - SIGNAL_HANDLER - - wielded = TRUE - -/// triggered on unwield of two handed item -/obj/item/toy/cards/deck/proc/on_unwield(obj/item/source, mob/user) - SIGNAL_HANDLER - - wielded = FALSE - /obj/item/toy/cards/deck/suicide_act(mob/living/carbon/user) user.visible_message(span_suicide("[user] is slitting [user.p_their()] wrists with \the [src]! It looks like their luck ran out!")) playsound(src, 'sound/items/cardshuffle.ogg', 50, TRUE) @@ -87,7 +71,7 @@ /obj/item/toy/cards/deck/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) if(src == held_item) var/obj/item/toy/cards/deck/dealer_deck = held_item - context[SCREENTIP_CONTEXT_LMB] = dealer_deck.wielded ? "Recycle mode" : "Dealer mode" + context[SCREENTIP_CONTEXT_LMB] = HAS_TRAIT(dealer_deck, TRAIT_WIELDED) ? "Recycle mode" : "Dealer mode" context[SCREENTIP_CONTEXT_ALT_LMB] = "Shuffle" return CONTEXTUAL_SCREENTIP_SET @@ -161,7 +145,7 @@ /obj/item/toy/cards/deck/AltClick(mob/living/user) if(user.can_perform_action(src, NEED_DEXTERITY|FORBID_TELEKINESIS_REACH)) - if(wielded) + if(HAS_TRAIT(src, TRAIT_WIELDED)) shuffle_cards(user) else to_chat(user, span_notice("You must hold the [src] with both hands to shuffle.")) diff --git a/code/modules/cards/deck/tarot.dm b/code/modules/cards/deck/tarot.dm index ced067c0c3979b..3dcdc8608c640c 100644 --- a/code/modules/cards/deck/tarot.dm +++ b/code/modules/cards/deck/tarot.dm @@ -36,8 +36,16 @@ /// ghost notification cooldown COOLDOWN_DECLARE(ghost_alert_cooldown) -/obj/item/toy/cards/deck/tarot/haunted/on_wield(obj/item/source, mob/living/carbon/user) +/obj/item/toy/cards/deck/tarot/haunted/Initialize(mapload) . = ..() + AddComponent( \ + /datum/component/two_handed, \ + attacksound = 'sound/items/cardflip.ogg', \ + wield_callback = CALLBACK(src, PROC_REF(on_wield)), \ + unwield_callback = CALLBACK(src, PROC_REF(on_unwield)), \ + ) + +/obj/item/toy/cards/deck/tarot/haunted/proc/on_wield(obj/item/source, mob/living/carbon/user) ADD_TRAIT(user, TRAIT_SIXTHSENSE, MAGIC_TRAIT) to_chat(user, span_notice("The veil to the underworld is opened. You can sense the dead souls calling out...")) @@ -54,15 +62,8 @@ action = NOTIFY_ORBIT, ) -/obj/item/toy/cards/deck/tarot/haunted/on_unwield(obj/item/source, mob/living/carbon/user) - . = ..() +/obj/item/toy/cards/deck/tarot/haunted/proc/on_unwield(obj/item/source, mob/living/carbon/user) REMOVE_TRAIT(user, TRAIT_SIXTHSENSE, MAGIC_TRAIT) to_chat(user, span_notice("The veil to the underworld closes shut. You feel your senses returning to normal.")) -/obj/item/toy/cards/deck/tarot/haunted/dropped(mob/living/carbon/user, silent) - . = ..() - if(wielded) - REMOVE_TRAIT(user, TRAIT_SIXTHSENSE, MAGIC_TRAIT) - to_chat(user, span_notice("The veil to the underworld closes shut. You feel your senses returning to normal.")) - #undef TAROT_GHOST_TIMER diff --git a/code/modules/cards/singlecard.dm b/code/modules/cards/singlecard.dm index b918d7708ca898..169715c51d9093 100644 --- a/code/modules/cards/singlecard.dm +++ b/code/modules/cards/singlecard.dm @@ -78,7 +78,7 @@ if(istype(held_item, /obj/item/toy/cards/deck)) var/obj/item/toy/cards/deck/dealer_deck = held_item - if(dealer_deck.wielded) + if(HAS_TRAIT(dealer_deck, TRAIT_WIELDED)) context[SCREENTIP_CONTEXT_LMB] = "Deal card" context[SCREENTIP_CONTEXT_RMB] = "Deal card faceup" return CONTEXTUAL_SCREENTIP_SET @@ -151,7 +151,7 @@ if(istype(item, /obj/item/toy/cards/deck)) var/obj/item/toy/cards/deck/dealer_deck = item - if(!dealer_deck.wielded) // recycle card into deck (if unwielded) + if(!HAS_TRAIT(dealer_deck, TRAIT_WIELDED)) // recycle card into deck (if unwielded) dealer_deck.insert(src) user.balloon_alert_to_viewers("puts card in deck") return diff --git a/code/modules/cargo/goodies.dm b/code/modules/cargo/goodies.dm index f309f725774644..69677e87df56ad 100644 --- a/code/modules/cargo/goodies.dm +++ b/code/modules/cargo/goodies.dm @@ -271,3 +271,9 @@ desc = "A standard-sized coffeepot, for use with a coffeemaker." cost = PAYCHECK_CREW contains = list(/obj/item/reagent_containers/cup/coffeepot) + +/datum/supply_pack/goody/climbing_hook + name = "Climbing hook" + desc = "A less cheap imported climbing hook. Absolutely no use outside of planetary stations." + cost = PAYCHECK_CREW * 5 + contains = list(/obj/item/climbing_hook) diff --git a/code/modules/cargo/markets/market_items/weapons.dm b/code/modules/cargo/markets/market_items/weapons.dm index f40e4fa1447ca7..6115b1e1557970 100644 --- a/code/modules/cargo/markets/market_items/weapons.dm +++ b/code/modules/cargo/markets/market_items/weapons.dm @@ -63,3 +63,13 @@ price_max = CARGO_CRATE_VALUE * 2 stock_max = 2 availability_prob = 50 + +/datum/market_item/weapon/fisher + name = "SC/FISHER Saboteur Handgun" + desc = "A self-recharging, compact pistol that disrupts flashlights and security cameras, if only temporarily. Also usable in melee." + item = /obj/item/gun/energy/recharge/fisher + + price_min = CARGO_CRATE_VALUE * 2 + price_max = CARGO_CRATE_VALUE * 4 + stock_max = 1 + availability_prob = 50 diff --git a/code/modules/cargo/packs/emergency.dm b/code/modules/cargo/packs/emergency.dm index 9c50372b6a8333..fca1a201ac103b 100644 --- a/code/modules/cargo/packs/emergency.dm +++ b/code/modules/cargo/packs/emergency.dm @@ -117,8 +117,6 @@ contains = list(/obj/item/clothing/head/utility/radiation = 2, /obj/item/clothing/suit/utility/radiation = 2, /obj/item/geiger_counter = 2, - /obj/item/clothing/suit/utility/radiation, - /obj/item/geiger_counter, /obj/item/reagent_containers/cup/glass/bottle/vodka, /obj/item/reagent_containers/cup/glass/drinkingglass/shotglass = 2, ) diff --git a/code/modules/cargo/supplypod_beacon.dm b/code/modules/cargo/supplypod_beacon.dm index 436a0ca6b93022..89c474635fa182 100644 --- a/code/modules/cargo/supplypod_beacon.dm +++ b/code/modules/cargo/supplypod_beacon.dm @@ -7,11 +7,17 @@ lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' w_class = WEIGHT_CLASS_SMALL + armor_type = /datum/armor/supplypod_beacon + resistance_flags = FIRE_PROOF var/obj/machinery/computer/cargo/express/express_console var/linked = FALSE var/ready = FALSE var/launched = FALSE +/datum/armor/supplypod_beacon + bomb = 100 + fire = 100 + /obj/item/supplypod_beacon/proc/update_status(consoleStatus) switch(consoleStatus) if (SP_LINKED) @@ -49,6 +55,7 @@ /obj/item/supplypod_beacon/examine(user) . = ..() + . += span_notice("It looks like it has a few anchoring bolts.") if(!express_console) . += span_notice("[src] is not currently linked to an Express Supply console.") else @@ -59,6 +66,11 @@ express_console.beacon = null return ..() +/obj/item/supplypod_beacon/wrench_act(mob/living/user, obj/item/tool) + . = ..() + default_unfasten_wrench(user, tool) + return TOOL_ACT_TOOLTYPE_SUCCESS + /obj/item/supplypod_beacon/proc/unlink_console() if(express_console) express_console.beacon = null diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index c3c6bd244254a8..2e655e91651eee 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -160,8 +160,6 @@ ///Autoclick list of two elements, first being the clicked thing, second being the parameters. var/list/atom/selected_target[2] - ///Autoclick variable referencing the associated item. - var/obj/item/active_mousedown_item = null ///Used in MouseDrag to preserve the original mouse click parameters var/mouseParams = "" ///Used in MouseDrag to preserve the last mouse-entered location. Weakref diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index cbebcff555073e..9c7b5e3e9436a6 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -598,7 +598,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( send2adminchat("Server", "[cheesy_message] (No admins online)") QDEL_LIST_ASSOC_VAL(char_render_holders) - active_mousedown_item = null SSambience.remove_ambience_client(src) SSmouse_entered.hovers -= src SSping.currentrun -= src diff --git a/code/modules/clothing/belts/polymorph_belt.dm b/code/modules/clothing/belts/polymorph_belt.dm index f6ccccae971dfe..e63e2c3bee36d0 100644 --- a/code/modules/clothing/belts/polymorph_belt.dm +++ b/code/modules/clothing/belts/polymorph_belt.dm @@ -60,8 +60,8 @@ if (!isanimal_or_basicmob(target_mob)) balloon_alert(user, "target too complex!") return TRUE - if (!(target_mob.mob_biotypes & MOB_ORGANIC)) - balloon_alert(user, "organic life only!") + 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)) diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm index 688b63bddbb26e..fc665e57c8ffcb 100644 --- a/code/modules/clothing/glasses/_glasses.dm +++ b/code/modules/clothing/glasses/_glasses.dm @@ -195,6 +195,7 @@ base_icon_state = "eyepatch" inhand_icon_state = null actions_types = list(/datum/action/item_action/flip) + dog_fashion = /datum/dog_fashion/head/eyepatch /obj/item/clothing/glasses/eyepatch/attack_self(mob/user, modifiers) . = ..() diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm index fd30bdd742f37e..4022e2595055ef 100644 --- a/code/modules/clothing/head/jobs.dm +++ b/code/modules/clothing/head/jobs.dm @@ -206,6 +206,116 @@ /obj/item/clothing/head/fedora/det_hat/minor flask_path = /obj/item/reagent_containers/cup/glass/flask/det/minor +///Detectives Fedora, but like Inspector Gadget. Not a subtype to not inherit candy corn stuff +/obj/item/clothing/head/fedora/inspector_hat + name = "inspector's fedora" + desc = "There's only one man can try to stop an evil villian." + armor_type = /datum/armor/fedora_det_hat + icon_state = "detective" + inhand_icon_state = "det_hat" + dog_fashion = /datum/dog_fashion/head/detective + ///prefix our phrases must begin with + var/prefix = "go go gadget" + ///an assoc list of phrase = item (like gun = revolver) + var/list/items_by_phrase = list() + ///how many gadgets can we hold + var/max_items = 4 + ///items above this weight cannot be put in the hat + var/max_weight = WEIGHT_CLASS_NORMAL + +/obj/item/clothing/head/fedora/inspector_hat/Initialize(mapload) + . = ..() + become_hearing_sensitive(ROUNDSTART_TRAIT) + QDEL_NULL(atom_storage) + +/obj/item/clothing/head/fedora/inspector_hat/examine(mob/user) + . = ..() + . += span_notice("You can put items inside, and get them out by saying a phrase, or using it in-hand!") + . += span_notice("The prefix is [prefix], and you can change it with alt-click!\n") + for(var/phrase in items_by_phrase) + var/obj/item/item = items_by_phrase[phrase] + . += span_notice("[icon2html(item, user)] You can remove [item] by saying \"[prefix] [phrase]\"!") + +/obj/item/clothing/head/fedora/inspector_hat/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list(), message_range) + . = ..() + var/mob/living/carbon/wearer = loc + if(!istype(wearer) || speaker != wearer) //if we are worn + return FALSE + + raw_message = htmlrendertext(raw_message) + var/prefix_index = findtext(raw_message, prefix) + if(prefix_index != 1) + return FALSE + + var/the_phrase = trim_left(replacetext(raw_message, prefix, "")) + var/obj/item/result = items_by_phrase[the_phrase] + if(!result) + return FALSE + + if(wearer.put_in_active_hand(result)) + wearer.visible_message(span_warning("[src] drops [result] into the hands of [wearer]!")) + else + balloon_alert(wearer, "cant put in hands!") + + return TRUE + +/obj/item/clothing/head/fedora/inspector_hat/attackby(obj/item/item, mob/user, params) + . = ..() + + if(LAZYLEN(contents) >= max_items) + balloon_alert(user, "full!") + return + if(item.w_class > max_weight) + balloon_alert(user, "too big!") + return + + var/input = tgui_input_text(user, "What is the activation phrase?", "Activation phrase", "gadget", max_length = 26) + if(!input) + return + if(input in items_by_phrase) + balloon_alert(user, "already used!") + return + + if(item.loc != user || !user.transferItemToLoc(item, src)) + return + + to_chat(user, span_notice("You install [item] into the [thtotext(contents.len)] slot in [src].")) + playsound(src, 'sound/machines/click.ogg', 30, TRUE) + items_by_phrase[input] = item + +/obj/item/clothing/head/fedora/inspector_hat/attack_self(mob/user) + . = ..() + var/phrase = tgui_input_list(user, "What item do you want to remove by phrase?", "Item Removal", items_by_phrase) + if(!phrase) + return + user.put_in_inactive_hand(items_by_phrase[phrase]) + +/obj/item/clothing/head/fedora/inspector_hat/AltClick(mob/user) + . = ..() + var/new_prefix = tgui_input_text(user, "What should be the new prefix?", "Activation prefix", prefix, max_length = 24) + if(!new_prefix) + return + prefix = new_prefix + +/obj/item/clothing/head/fedora/inspector_hat/Exited(atom/movable/gone, direction) + . = ..() + for(var/phrase in items_by_phrase) + var/obj/item/result = items_by_phrase[phrase] + if(gone == result) + items_by_phrase -= phrase + return + +/obj/item/clothing/head/fedora/inspector_hat/atom_destruction(damage_flag) + for(var/phrase in items_by_phrase) + var/obj/item/result = items_by_phrase[phrase] + result.forceMove(drop_location()) + items_by_phrase = null + return ..() + +/obj/item/clothing/head/fedora/inspector_hat/Destroy() + QDEL_LIST_ASSOC(items_by_phrase) + return ..() + //Mime /obj/item/clothing/head/beret name = "beret" diff --git a/code/modules/clothing/suits/ablativecoat.dm b/code/modules/clothing/suits/ablativecoat.dm index 0a6967753e161c..8bc37aaba22b76 100644 --- a/code/modules/clothing/suits/ablativecoat.dm +++ b/code/modules/clothing/suits/ablativecoat.dm @@ -4,6 +4,7 @@ worn_icon = 'icons/mob/clothing/head/helmet.dmi' desc = "Hood hopefully belonging to an ablative trenchcoat. Includes a visor for cool-o-vision." icon_state = "ablativehood" + flags_inv = HIDEHAIR|HIDEEARS armor_type = /datum/armor/hooded_ablative strip_delay = 30 var/hit_reflect_chance = 50 diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm index 61f293a97fe60e..3ed9be8cb1da32 100644 --- a/code/modules/clothing/suits/jobs.dm +++ b/code/modules/clothing/suits/jobs.dm @@ -219,19 +219,21 @@ allowed = list( /obj/item/stamp, /obj/item/storage/bag/mail, + /obj/item/universal_scanner, ) // Quartermaster /obj/item/clothing/suit/jacket/quartermaster - name = "quatermaster's overcoat" - desc = "A luxury, brown double-breasted overcoat, made from kangaroo skin. It's gold cuffs linked are styled on the credits symbol. It makes you feel more important then you probably are." + name = "quartermaster's overcoat" + desc = "A luxury, brown double-breasted overcoat made from kangaroo skin. It's gold cuffs are linked and styled on the credits symbol. It makes you feel more important than you probably are." icon_state = "qm_coat" blood_overlay_type = "coat" body_parts_covered = CHEST|GROIN|LEGS|ARMS allowed = list( /obj/item/stamp, /obj/item/storage/bag/mail, + /obj/item/universal_scanner, ) /obj/item/clothing/suit/toggle/lawyer/greyscale diff --git a/code/modules/clothing/suits/wintercoats.dm b/code/modules/clothing/suits/wintercoats.dm index a0f6e6d1047b2e..60cbcae1473351 100644 --- a/code/modules/clothing/suits/wintercoats.dm +++ b/code/modules/clothing/suits/wintercoats.dm @@ -590,6 +590,7 @@ allowed = list( /obj/item/storage/bag/mail, /obj/item/stamp, + /obj/item/universal_scanner, ) /obj/item/clothing/head/hooded/winterhood/cargo diff --git a/code/modules/events/brain_trauma.dm b/code/modules/events/brain_trauma.dm index 1e5c09aff48e99..e063c89e152e32 100644 --- a/code/modules/events/brain_trauma.dm +++ b/code/modules/events/brain_trauma.dm @@ -2,6 +2,7 @@ name = "Spontaneous Brain Trauma" typepath = /datum/round_event/brain_trauma weight = 25 + min_players = 13 category = EVENT_CATEGORY_HEALTH description = "A crewmember gains a random trauma." min_wizard_trigger_potency = 2 @@ -20,6 +21,10 @@ continue if(!(H.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) //please stop giving my centcom admin gimmicks full body paralysis continue + // SKYRAT EDIT ADD START - Station/area event candidate filtering + if(engaged_role_play_check(H, station = TRUE, dorms = TRUE)) + continue + // SKYRAT EDIT ADD END traumatize(H) announce_to_ghosts(H) break diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm index a323c7d83f00a5..4f251e871c7e83 100644 --- a/code/modules/events/disease_outbreak.dm +++ b/code/modules/events/disease_outbreak.dm @@ -61,6 +61,10 @@ continue if(length(candidate.diseases)) //Is our candidate already sick? continue + // SKYRAT EDIT ADD START - Station/area event candidate filtering + if(engaged_role_play_check(candidate, station = TRUE, dorms = TRUE)) + continue + // SKYRAT EDIT ADD END disease_candidates += candidate ///Handles checking and alerting admins about the number of valid candidates diff --git a/code/modules/events/fake_virus.dm b/code/modules/events/fake_virus.dm index fb6bfd5be97572..f690b1c4a8d5ee 100644 --- a/code/modules/events/fake_virus.dm +++ b/code/modules/events/fake_virus.dm @@ -10,6 +10,10 @@ for(var/mob/living/carbon/human/victim in shuffle(GLOB.player_list)) if(victim.stat == DEAD || HAS_TRAIT(victim, TRAIT_CRITICAL_CONDITION) || !(victim.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) continue + // SKYRAT EDIT ADD START - Station/area event candidate filtering + if(engaged_role_play_check(fake_virus_victims, station = TRUE, dorms = TRUE)) + continue + // SKYRAT EDIT ADD END fake_virus_victims += victim //first we do hard status effect victims diff --git a/code/modules/events/heart_attack.dm b/code/modules/events/heart_attack.dm index 8a8902d5724c3d..f073676c5b415a 100644 --- a/code/modules/events/heart_attack.dm +++ b/code/modules/events/heart_attack.dm @@ -34,6 +34,10 @@ continue if(!(candidate.mind.assigned_role.job_flags & JOB_CREW_MEMBER))//only crewmembers can get one, a bit unfair for some ghost roles and it wastes the event continue + // SKYRAT EDIT ADD START - Station/area event candidate filtering + if(engaged_role_play_check(candidate, station = TRUE, dorms = TRUE)) + continue + // SKYRAT EDIT ADD END if(candidate.satiety <= -60 && !candidate.has_status_effect(/datum/status_effect/exercised)) //Multiple junk food items recently //No foodmaxxing for the achievement heart_attack_candidates[candidate] = 3 else diff --git a/code/modules/events/shuttle_loan/shuttle_loan_datum.dm b/code/modules/events/shuttle_loan/shuttle_loan_datum.dm index 3cc5a15a5077d3..424eb157efec08 100644 --- a/code/modules/events/shuttle_loan/shuttle_loan_datum.dm +++ b/code/modules/events/shuttle_loan/shuttle_loan_datum.dm @@ -17,6 +17,8 @@ . = ..() if(!logging_desc) stack_trace("No logging blurb set for [src.type]!") + if(HAS_TRAIT(SSstation, STATION_TRAIT_LOANER_SHUTTLE)) + bonus_points *= 1.15 /// Spawns paths added to `spawn_list`, and passes empty shuttle turfs so you can spawn more complicated things like dead bodies. /datum/shuttle_loan_situation/proc/spawn_items(list/spawn_list, list/empty_shuttle_turfs) diff --git a/code/modules/events/supermatter_surge.dm b/code/modules/events/supermatter_surge.dm new file mode 100644 index 00000000000000..f8e1f2698f74a7 --- /dev/null +++ b/code/modules/events/supermatter_surge.dm @@ -0,0 +1,110 @@ +#define SURGE_DURATION_MIN 240 EVENT_SECONDS +#define SURGE_DURATION_MAX 270 EVENT_SECONDS +#define SURGE_SEVERITY_MIN 1 +#define SURGE_SEVERITY_MAX 4 +/// The amount of bullet energy we add for the duration of the SM surge +#define SURGE_BULLET_ENERGY_ADDITION 5 +/// The amount of powerloss inhibition (energy retention) we add for the duration of the SM surge +#define SURGE_BASE_POWERLOSS_INHIBITION 0.55 +/// The powerloss inhibition scaling based on surge severity +#define SURGE_POWERLOSS_INHIBITION_MODIFIER 0.175 +/// The power generation scaling based on surge severity +#define SURGE_POWER_GENERATION_MODIFIER 0.075 +/// The heat modifier scaling based on surge severity +#define SURGE_HEAT_MODIFIER 0.25 + +/** + * Supermatter Surge + * + * An engineering challenge event where the properties of the SM changes to be in a 'surge' of power. + * For the duration of the event a powerloss inhibition is added to nitrogen, causing the crystal to retain more of its internal energy. + * Heat modifier is lowered to generate some heat but not a high temp burn. + * Bullet energy from emitters is raised slightly to raise meV while turned on. + */ + +/datum/round_event_control/supermatter_surge + name = "Supermatter Surge" + typepath = /datum/round_event/supermatter_surge + category = EVENT_CATEGORY_ENGINEERING + weight = 15 + max_occurrences = 1 + earliest_start = 20 MINUTES + description = "The supermatter will increase in power and heat by a random amount, and announce it." + min_wizard_trigger_potency = 4 + max_wizard_trigger_potency = 7 + admin_setup = list( + /datum/event_admin_setup/input_number/surge_spiciness, + ) + +/datum/round_event_control/supermatter_surge/can_spawn_event(players_amt, allow_magic = FALSE) + . = ..() + + if(!SSjob.has_minimum_jobs(crew_threshold = 3, jobs = JOB_GROUP_ENGINEERS, head_jobs = list(JOB_CHIEF_ENGINEER))) + return FALSE + +/datum/round_event/supermatter_surge + announce_when = 4 + end_when = SURGE_DURATION_MIN + /// How powerful is the supermatter surge going to be? + var/surge_class = SURGE_SEVERITY_MIN + /// Typecasted reference to the supermatter chosen at event start + var/obj/machinery/power/supermatter_crystal/engine + /// Typecasted reference to the nitrogen properies in the SM chamber + var/datum/sm_gas/nitrogen/sm_gas + +/datum/event_admin_setup/input_number/surge_spiciness + input_text = "Set surge intensity. (Higher is more severe.)" + min_value = 1 + max_value = 4 + +/datum/event_admin_setup/input_number/surge_spiciness/prompt_admins() + default_value = rand(1, 4) + return ..() + +/datum/event_admin_setup/input_number/surge_spiciness/apply_to_event(datum/round_event/supermatter_surge/event) + event.surge_class = chosen_value + +/datum/round_event/supermatter_surge/setup() + engine = GLOB.main_supermatter_engine + if(isnull(engine)) + stack_trace("SM surge event failed to find a supermatter engine!") + return + + sm_gas = LAZYACCESS(engine.current_gas_behavior, /datum/gas/nitrogen) + if(isnull(sm_gas)) + stack_trace("SM surge event failed to find gas properties for [engine].") + return + + if(isnull(surge_class)) + surge_class = rand(SURGE_SEVERITY_MIN, SURGE_SEVERITY_MAX) + + end_when = rand(SURGE_DURATION_MIN, SURGE_DURATION_MAX) + +/datum/round_event/supermatter_surge/announce() + priority_announce("The Crystal Integrity Monitoring System has detected unusual atmospheric properties in the supermatter chamber and energy output from the supermatter crystal has increased significantly. Engineering intervention is required to stabilize the engine.", "Class [surge_class] Supermatter Surge Alert", 'sound/machines/engine_alert3.ogg') + +/datum/round_event/supermatter_surge/start() + engine.bullet_energy = surge_class + SURGE_BULLET_ENERGY_ADDITION + sm_gas.powerloss_inhibition = (surge_class * SURGE_POWERLOSS_INHIBITION_MODIFIER) + SURGE_BASE_POWERLOSS_INHIBITION + sm_gas.heat_power_generation = (surge_class * SURGE_POWER_GENERATION_MODIFIER) - 1 + sm_gas.heat_modifier = (surge_class * SURGE_HEAT_MODIFIER) - 1 + + +/datum/round_event/supermatter_surge/end() + engine.bullet_energy = initial(engine.bullet_energy) + sm_gas.powerloss_inhibition = initial(sm_gas.powerloss_inhibition) + sm_gas.heat_power_generation = initial(sm_gas.heat_power_generation) + sm_gas.heat_modifier = initial(sm_gas.heat_modifier) + priority_announce("The supermatter surge has dissipated, crystal output readings have normalized.", "Anomaly Cleared") + engine = null + sm_gas = null + +#undef SURGE_DURATION_MIN +#undef SURGE_DURATION_MAX +#undef SURGE_SEVERITY_MIN +#undef SURGE_SEVERITY_MAX +#undef SURGE_BULLET_ENERGY_ADDITION +#undef SURGE_BASE_POWERLOSS_INHIBITION +#undef SURGE_POWERLOSS_INHIBITION_MODIFIER +#undef SURGE_POWER_GENERATION_MODIFIER +#undef SURGE_HEAT_MODIFIER diff --git a/code/modules/fishing/fish/chasm_detritus.dm b/code/modules/fishing/fish/chasm_detritus.dm index b3964eb401563e..8d6653781595f3 100644 --- a/code/modules/fishing/fish/chasm_detritus.dm +++ b/code/modules/fishing/fish/chasm_detritus.dm @@ -40,22 +40,21 @@ GLOBAL_LIST_INIT_TYPED(chasm_detritus_types, /datum/chasm_detritus, init_chasm_d ), ) -/datum/chasm_detritus/proc/dispense_reward(turf/fishing_spot, turf/fisher_turf) - if (prob(default_contents_chance)) +/datum/chasm_detritus/proc/dispense_detritus(mob/fisherman, turf/fishing_spot) + if(prob(default_contents_chance)) var/default_spawn = pick(default_contents[default_contents_key]) - return new default_spawn(fisher_turf) - return find_chasm_contents(fishing_spot, fisher_turf) + return new default_spawn(get_turf(fisherman)) + return find_chasm_contents(fishing_spot, get_turf(fisherman)) /// Returns the chosen detritus from the given list of things to choose from /datum/chasm_detritus/proc/determine_detritus(list/chasm_stuff) return pick(chasm_stuff) -/// Returns an objected which is currently inside of a nearby chasm. -/datum/chasm_detritus/proc/find_chasm_contents(datum/source, turf/fishing_spot, turf/fisher_turf) - SIGNAL_HANDLER +/// Returns an object which is currently inside of a nearby chasm. +/datum/chasm_detritus/proc/find_chasm_contents(turf/fishing_spot, turf/fisher_turf) var/list/chasm_contents = get_chasm_contents(fishing_spot) - if (!length(chasm_contents)) + if(!length(chasm_contents)) var/default_spawn = pick(default_contents[default_contents_key]) return new default_spawn(fisher_turf) @@ -63,7 +62,7 @@ GLOBAL_LIST_INIT_TYPED(chasm_detritus_types, /datum/chasm_detritus, init_chasm_d /datum/chasm_detritus/proc/get_chasm_contents(turf/fishing_spot) . = list() - for (var/obj/effect/abstract/chasm_storage/storage in range(5, fishing_spot)) + for(var/obj/effect/abstract/chasm_storage/storage in range(5, fishing_spot)) for (var/thing as anything in storage.contents) . += thing @@ -76,7 +75,7 @@ GLOBAL_LIST_INIT_TYPED(chasm_detritus_types, /datum/chasm_detritus, init_chasm_d /datum/chasm_detritus/restricted/get_chasm_contents(turf/fishing_spot) . = list() - for (var/obj/effect/abstract/chasm_storage/storage in range(5, fishing_spot)) + for(var/obj/effect/abstract/chasm_storage/storage in range(5, fishing_spot)) for (var/thing as anything in storage.contents) if(!istype(thing, chasm_storage_restricted_type)) continue diff --git a/code/modules/fishing/fish/fish_traits.dm b/code/modules/fishing/fish/fish_traits.dm index 6c7fb38e279bab..bec868ad24e77f 100644 --- a/code/modules/fishing/fish/fish_traits.dm +++ b/code/modules/fishing/fish/fish_traits.dm @@ -23,9 +23,9 @@ GLOBAL_LIST_INIT(fish_traits, init_subtypes_w_path_keys(/datum/fish_trait, list( SHOULD_CALL_PARENT(TRUE) return list(ADDITIVE_FISHING_MOD = 0, MULTIPLICATIVE_FISHING_MOD = 1) -/// Returns special minigame rules applied by this trait -/datum/fish_trait/proc/minigame_mod(obj/item/fishing_rod/rod, mob/fisherman) - return list() +/// Returns special minigame rules and effects applied by this trait +/datum/fish_trait/proc/minigame_mod(obj/item/fishing_rod/rod, mob/fisherman, datum/fishing_challenge/minigame) + return /// Applies some special qualities to the fish that has been spawned /datum/fish_trait/proc/apply_to_fish(obj/item/fish/fish) @@ -100,8 +100,8 @@ GLOBAL_LIST_INIT(fish_traits, init_subtypes_w_path_keys(/datum/fish_trait, list( name = "Heavy" catalog_description = "This fish tends to stay near the waterbed."; -/datum/fish_trait/heavy/minigame_mod(obj/item/fishing_rod/rod, mob/fisherman) - return list(FISHING_MINIGAME_RULE_HEAVY_FISH) +/datum/fish_trait/heavy/minigame_mod(obj/item/fishing_rod/rod, mob/fisherman, datum/fishing_challenge/minigame) + minigame.fish_idle_velocity -= 10 /datum/fish_trait/carnivore name = "Carnivore" @@ -338,8 +338,9 @@ GLOBAL_LIST_INIT(fish_traits, init_subtypes_w_path_keys(/datum/fish_trait, list( /datum/fish_trait/lubed/apply_to_fish(obj/item/fish/fish) fish.AddComponent(/datum/component/slippery, 8 SECONDS, SLIDE|GALOSHES_DONT_HELP) -/datum/fish_trait/lubed/minigame_mod(obj/item/fishing_rod/rod, mob/fisherman) - return list(FISHING_MINIGAME_RULE_LUBED_FISH) +/datum/fish_trait/lubed/minigame_mod(obj/item/fishing_rod/rod, mob/fisherman, datum/fishing_challenge/minigame) + minigame.reeling_velocity *= 1.4 + minigame.gravity_velocity *= 1.4 /datum/fish_trait/amphibious name = "Amphibious" diff --git a/code/modules/fishing/fish/fish_types.dm b/code/modules/fishing/fish/fish_types.dm index e8752acb1de754..652b0aba8aa495 100644 --- a/code/modules/fishing/fish/fish_types.dm +++ b/code/modules/fishing/fish/fish_types.dm @@ -465,6 +465,7 @@ /obj/item/fish/holo/puffer name = "holographic pufferfish" desc ="A holographic representation of 100% safe-to-eat pufferfish... that is, if holographic fishes were even edible." + icon_state = "pufferfish" sprite_width = 8 sprite_height = 8 average_size = 60 diff --git a/code/modules/fishing/fishing_equipment.dm b/code/modules/fishing/fishing_equipment.dm index e94e13ed4e8c3c..6169b41fd88fce 100644 --- a/code/modules/fishing/fishing_equipment.dm +++ b/code/modules/fishing/fishing_equipment.dm @@ -162,14 +162,14 @@ /obj/item/fishing_hook/stabilized name = "gyro-stabilized hook" - desc = "A quirky hook that grants the user a better control of the tool, allowing them to move the hook both and up and down when reeling in, otherwise keeping it stabilized." + desc = "A quirky hook that grants the user a better control of the tool, allowing them to move the bait both and up and down when reeling in, otherwise keeping it in place." icon_state = "gyro" fishing_hook_traits = FISHING_HOOK_BIDIRECTIONAL rod_overlay_icon_state = "hook_gyro_overlay" /obj/item/fishing_hook/stabilized/examine(mob/user) . = ..() - . += span_notice("While fishing, you can hold the Ctrl key to move the bait down, rather than up.") + . += span_notice("While fishing, you can hold the Right Mouse Button to move the bait down, rather than up.") /obj/item/fishing_hook/jaws name = "jawed hook" diff --git a/code/modules/fishing/fishing_minigame.dm b/code/modules/fishing/fishing_minigame.dm index cdec5c54be6beb..478279749e406e 100644 --- a/code/modules/fishing/fishing_minigame.dm +++ b/code/modules/fishing/fishing_minigame.dm @@ -5,6 +5,35 @@ // UI minigame phase #define MINIGAME_PHASE 3 +/// The height of the minigame slider. Not in pixels, but minigame units. +#define FISHING_MINIGAME_AREA 1000 +/// Any lower than this, and the target position of the fish is considered null +#define FISH_TARGET_MIN_DISTANCE 6 +/// The friction applied to fish jumps, so that it decelerates over time +#define FISH_FRICTION_MULT 0.9 +/// Used to decide whether the fish can jump in a certain direction +#define FISH_SHORT_JUMP_MIN_DISTANCE 100 +/// The maximum distance for a short jump +#define FISH_SHORT_JUMP_MAX_DISTANCE 200 +// Acceleration mod when bait is over fish +#define FISH_ON_BAIT_ACCELERATION_MULT 0.6 +/// The minimum velocity required for the bait to bounce +#define BAIT_MIN_VELOCITY_BOUNCE 200 +/// The extra deceleration of velocity that happens when the bait switches direction +#define BAIT_DECELERATION_MULT 2 + +///Defines to know how the bait is moving on the minigame slider. +#define REELING_STATE_IDLE 0 +#define REELING_STATE_UP 1 +#define REELING_STATE_DOWN 2 + +///The pixel height of the minigame bar +#define MINIGAME_SLIDER_HEIGHT 76 +///The standard pixel height of the bait +#define MINIGAME_BAIT_HEIGHT 24 +///The standard pixel height of the fish (minus a pixel on each direction for the sake of a better looking sprite) +#define MINIGAME_FISH_HEIGHT 4 + /datum/fishing_challenge /// When the ui minigame phase started var/start_time @@ -13,7 +42,7 @@ /// Fish AI type to use var/fish_ai = FISH_AI_DUMB /// Rule modifiers (eg weighted bait) - var/list/special_effects = list() + var/special_effects = NONE /// Did the game get past the baiting phase, used to track if bait should be consumed afterwards var/bait_taken = FALSE /// Result path @@ -30,14 +59,67 @@ var/obj/item/fishing_rod/used_rod /// Lure visual var/obj/effect/fishing_lure/lure - /// Background image from /datum/asset/simple/fishing_minigame - var/background = "default" + /// Background icon state from fishing_hud.dmi + var/background = "background_default" /// Fishing line visual var/datum/beam/fishing_line var/experience_multiplier = 1 + /// How much space the fish takes on the minigame slider + var/fish_height = 50 + /// How much space the bait takes on the minigame slider + var/bait_height = 320 + /// The height in pixels of the bait bar + var/bait_pixel_height = MINIGAME_BAIT_HEIGHT + /// The height in pixels of the fish + var/fish_pixel_height = MINIGAME_FISH_HEIGHT + /// The position of the fish on the minigame slider + var/fish_position = 0 + /// The position of the bait on the minigame slider + var/bait_position = 0 + /// The current speed the fish is moving at + var/fish_velocity = 0 + /// The current speed the bait is moving at + var/bait_velocity = 0 + + /// The completion score. If it reaches 100, it's a win. If it reaches 0, it's a loss. + var/completion = 30 + /// How much completion is lost per second when the bait area is not intersecting with the fish's + var/completion_loss = 6 + /// How much completion is gained per second when the bait area is intersecting with the fish's + var/completion_gain = 5 + + /// How likely the fish is to perform a standard jump, then multiplied by difficulty + var/short_jump_chance = 2.25 + /// How likely the fish is to perform a long jump, then multiplied by difficulty + var/long_jump_chance = 0.0625 + /// The speed limit for the short jump + var/short_jump_velocity_limit = 400 + /// The speed limit for the long jump + var/long_jump_velocity_limit = 200 + /// The current speed limit used + var/current_velocity_limit = 200 + /// The base velocity of the fish, which may affect jump distances and falling speed. + var/fish_idle_velocity = 0 + /// A position on the slider the fish wants to get to + var/target_position + /// If true, the fish can jump while a target position is set, thus overriding it + var/can_interrupt_move = TRUE + + /// Whether the bait is idle or reeling up or down (left and right click) + var/reeling_state = REELING_STATE_IDLE + /// The acceleration of the bait while not reeling + var/gravity_velocity = -800 + /// The acceleration of the bait while reeling + var/reeling_velocity = 1200 + /// By how much the bait recoils back when hitting the bounds of the slider while idle + var/bait_bounce_mult = 0.6 + + ///The background as shown in the minigame, and the holder of the other visual overlays + var/atom/movable/screen/fishing_hud/fishing_hud + /datum/fishing_challenge/New(datum/component/fishing_spot/comp, reward_path, obj/item/fishing_rod/rod, mob/user) src.user = user src.reward_path = reward_path @@ -52,32 +134,61 @@ if(ispath(reward_path,/obj/item/fish)) var/obj/item/fish/fish = reward_path fish_ai = initial(fish.fish_ai_type) + switch(fish_ai) + if(FISH_AI_ZIPPY) // Keeps on jumping + short_jump_chance *= 3 + if(FISH_AI_SLOW) // Only does long jump, and doesn't change direction until it gets there + short_jump_chance = 0 + long_jump_chance = 1.5 + long_jump_velocity_limit = 150 + long_jump_velocity_limit = FALSE // Apply fish trait modifiers var/list/fish_list_properties = collect_fish_properties() var/list/fish_traits = fish_list_properties[fish][NAMEOF(fish, fish_traits)] for(var/fish_trait in fish_traits) var/datum/fish_trait/trait = GLOB.fish_traits[fish_trait] - special_effects += trait.minigame_mod(rod, user) + trait.minigame_mod(rod, user, src) /// Enable special parameters if(rod.line) if(rod.line.fishing_line_traits & FISHING_LINE_BOUNCY) - special_effects |= FISHING_MINIGAME_RULE_LIMIT_LOSS + completion_loss -= 2 if(rod.hook) if(rod.hook.fishing_hook_traits & FISHING_HOOK_WEIGHTED) - special_effects |= FISHING_MINIGAME_RULE_WEIGHTED_BAIT + bait_bounce_mult = 0.1 if(rod.hook.fishing_hook_traits & FISHING_HOOK_BIDIRECTIONAL) special_effects |= FISHING_MINIGAME_RULE_BIDIRECTIONAL if(rod.hook.fishing_hook_traits & FISHING_HOOK_NO_ESCAPE) special_effects |= FISHING_MINIGAME_RULE_NO_ESCAPE if(rod.hook.fishing_hook_traits & FISHING_HOOK_ENSNARE) - special_effects |= FISHING_MINIGAME_RULE_LIMIT_LOSS + completion_loss -= 2 if(rod.hook.fishing_hook_traits & FISHING_HOOK_KILL) special_effects |= FISHING_MINIGAME_RULE_KILL - if((FISHING_MINIGAME_RULE_KILL in special_effects) && ispath(reward_path,/obj/item/fish)) + if(special_effects & FISHING_MINIGAME_RULE_KILL && ispath(reward_path,/obj/item/fish)) RegisterSignal(user, COMSIG_MOB_FISHING_REWARD_DISPENSED, PROC_REF(hurt_fish)) difficulty += comp.fish_source.calculate_difficulty(reward_path, rod, user, src) + difficulty = round(difficulty) + + /** + * If the chances are higher than 1% (100% at maximum difficulty), they'll scale + * less than proportionally (exponent less than 1) instead. + * This way we ensure fish with high jump chances won't get TOO jumpy until + * they near the maximum difficulty, at which they hit 100% + */ + var/square_angle_rad = TORADIANS(90) + var/zero_one_difficulty = difficulty/100 + if(short_jump_chance > 1) + short_jump_chance = (zero_one_difficulty**(square_angle_rad-TORADIANS(arctan(short_jump_chance * 1/square_angle_rad))))*100 + else + short_jump_chance *= difficulty + if(long_jump_chance > 1) + long_jump_chance = (zero_one_difficulty**(square_angle_rad-TORADIANS(arctan(long_jump_chance * 1/square_angle_rad))))*100 + else + long_jump_chance *= difficulty + + bait_height -= difficulty + bait_pixel_height = round(MINIGAME_BAIT_HEIGHT * (bait_height/initial(bait_height)), 1) /datum/fishing_challenge/Destroy(force, ...) if(!completed) @@ -86,6 +197,7 @@ QDEL_NULL(fishing_line) if(lure) QDEL_NULL(lure) + SStgui.close_uis(src) user = null used_rod = null return ..() @@ -119,13 +231,13 @@ /datum/fishing_challenge/proc/handle_click(mob/source, atom/target, modifiers) SIGNAL_HANDLER //You need to be holding the rod to use it. - if(!source.get_active_held_item(used_rod) || LAZYACCESS(modifiers, SHIFT_CLICK)) + if(!source.get_active_held_item(used_rod) || LAZYACCESS(modifiers, SHIFT_CLICK) || LAZYACCESS(modifiers, CTRL_CLICK) || LAZYACCESS(modifiers, ALT_CLICK)) return if(phase == WAIT_PHASE) //Reset wait send_alert("miss!") start_baiting_phase() else if(phase == BITING_PHASE) - INVOKE_ASYNC(src, PROC_REF(start_minigame_phase)) + start_minigame_phase() return COMSIG_MOB_CANCEL_CLICKON /// Challenge interrupted by something external @@ -147,16 +259,20 @@ send_alert("stopped fishing") complete(FALSE) -/datum/fishing_challenge/proc/complete(win = FALSE, perfect_win = FALSE) +/datum/fishing_challenge/proc/complete(win = FALSE) + if(completed) + return deltimer(next_phase_timer) completed = TRUE + if(phase == MINIGAME_PHASE) + remove_minigame_hud() if(user) REMOVE_TRAIT(user, TRAIT_GONE_FISHING, REF(src)) if(start_time) var/seconds_spent = (world.time - start_time) * 0.1 - if(!(FISHING_MINIGAME_RULE_NO_EXP in special_effects)) + if(!(special_effects & FISHING_MINIGAME_RULE_NO_EXP)) user.mind?.adjust_experience(/datum/skill/fishing, round(seconds_spent * FISHING_SKILL_EXP_PER_SECOND * experience_multiplier)) - if(win && user.mind?.get_skill_level(/datum/skill/fishing) >= SKILL_LEVEL_LEGENDARY) + if(user.mind?.get_skill_level(/datum/skill/fishing) >= SKILL_LEVEL_LEGENDARY) user.client?.give_award(/datum/award/achievement/skill/legendary_fisher, user) if(win) if(reward_path != FISHING_DUD) @@ -188,16 +304,10 @@ ///The damage dealt per second to the fish when FISHING_MINIGAME_RULE_KILL is active. #define FISH_DAMAGE_PER_SECOND 2 -/datum/fishing_challenge/proc/start_minigame_phase() - phase = MINIGAME_PHASE - deltimer(next_phase_timer) - if((FISHING_MINIGAME_RULE_KILL in special_effects) && ispath(reward_path,/obj/item/fish)) - var/obj/item/fish/fish = reward_path - var/wait_time = (initial(fish.health) / FISH_DAMAGE_PER_SECOND) SECONDS - addtimer(CALLBACK(src, PROC_REF(win_anyway)), wait_time) - start_time = world.time - experience_multiplier += difficulty * FISHING_SKILL_DIFFIULTY_EXP_MULT - ui_interact(user) +///The player is no longer around to play the minigame, so we interrupt it. +/datum/fishing_challenge/proc/on_user_logout(datum/source) + SIGNAL_HANDLER + interrupt(balloon_alert = FALSE) /datum/fishing_challenge/proc/win_anyway() if(!completed) @@ -211,57 +321,251 @@ var/damage = CEILING((world.time - start_time)/10 * FISH_DAMAGE_PER_SECOND, 1) reward.adjust_health(reward.health - damage) -#undef FISH_DAMAGE_PER_SECOND +/datum/fishing_challenge/proc/start_minigame_phase() + if(!prepare_minigame_hud()) + return + phase = MINIGAME_PHASE + deltimer(next_phase_timer) + if((FISHING_MINIGAME_RULE_KILL in special_effects) && ispath(reward_path,/obj/item/fish)) + var/obj/item/fish/fish = reward_path + var/wait_time = (initial(fish.health) / FISH_DAMAGE_PER_SECOND) SECONDS + addtimer(CALLBACK(src, PROC_REF(win_anyway)), wait_time) + start_time = world.time + experience_multiplier += difficulty * FISHING_SKILL_DIFFIULTY_EXP_MULT -/datum/fishing_challenge/ui_interact(mob/user, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "Fishing") - ui.set_autoupdate(FALSE) - ui.set_mouse_hook(TRUE) - ui.open() +#undef FISH_DAMAGE_PER_SECOND -/datum/fishing_challenge/ui_host(mob/user) - return lure //Could be the target really +///Initialize the minigame hud and register some signals to make it work. +/datum/fishing_challenge/proc/prepare_minigame_hud() + if(!user.client || user.incapacitated()) + return FALSE + . = TRUE + fishing_hud = new + fishing_hud.prepare_minigame(src) + RegisterSignal(user.client, COMSIG_CLIENT_MOUSEDOWN, PROC_REF(start_reeling)) + RegisterSignal(user.client, COMSIG_CLIENT_MOUSEUP, PROC_REF(stop_reeling)) + RegisterSignal(user, COMSIG_MOB_LOGOUT, PROC_REF(on_user_logout)) + START_PROCESSING(SSfishing, src) + +///Stop processing and remove references to the minigame hud +/datum/fishing_challenge/proc/remove_minigame_hud() + STOP_PROCESSING(SSfishing, src) + QDEL_NULL(fishing_hud) + +///While the mouse button is held down, the bait will be reeling up (or down on r-click if the bidirectional rule is enabled) +/datum/fishing_challenge/proc/start_reeling(client/source, datum/object, location, control, params) + SIGNAL_HANDLER + var/bidirectional = special_effects & FISHING_MINIGAME_RULE_BIDIRECTIONAL + var/list/modifiers = params2list(params) + if(bidirectional && LAZYACCESS(modifiers, RIGHT_CLICK)) + reeling_state = REELING_STATE_DOWN + else + reeling_state = REELING_STATE_UP + +///Reset the reeling state to idle once the mouse button is released +/datum/fishing_challenge/proc/stop_reeling(client/source, datum/object, location, control, params) + SIGNAL_HANDLER + reeling_state = REELING_STATE_IDLE + +///Update the state of the fish, the bait and the hud +/datum/fishing_challenge/process(seconds_per_tick) + move_fish(seconds_per_tick) + move_bait(seconds_per_tick) + if(!QDELETED(fishing_hud)) + update_visuals() + +///The proc that moves the fish around, just like in the old TGUI, mostly. +/datum/fishing_challenge/proc/move_fish(seconds_per_tick) + var/long_chance = long_jump_chance * seconds_per_tick * 10 + var/short_chance = short_jump_chance * seconds_per_tick * 10 + + // If we have the target but we're close enough, mark as target reached + if(abs(target_position - fish_position) < FISH_TARGET_MIN_DISTANCE) + target_position = null + + // Switching to new long jump target can interrupt any other + if((can_interrupt_move || isnull(target_position)) && prob(long_chance)) + /** + * Move at least 0.75 to full of the availible bar in given direction, + * and more likely to move in the direction where there's more space + */ + var/distance_from_top = FISHING_MINIGAME_AREA - fish_position - fish_height + var/distance_from_bottom = fish_position + var/top_chance + if(distance_from_top < FISH_SHORT_JUMP_MIN_DISTANCE) + top_chance = 0 + else + top_chance = (distance_from_top/max(distance_from_bottom, 1)) * 100 + var/new_target = fish_position + if(prob(top_chance)) + new_target += distance_from_top * rand(75, 100)/100 + else + new_target -= distance_from_bottom * rand(75, 100)/100 + target_position = round(new_target) + current_velocity_limit = long_jump_velocity_limit + + // Move towards target + if(!isnull(target_position)) + var/distance = target_position - fish_position + // about 5 at diff 15 , 10 at diff 30, 30 at diff 100 + var/acceleration_mult = 0.3 * difficulty + 0.5 + var/target_acceleration = distance * acceleration_mult * seconds_per_tick + + fish_velocity = fish_velocity * FISH_FRICTION_MULT + target_acceleration + else if(prob(short_chance)) + var/distance_from_top = FISHING_MINIGAME_AREA - fish_position - fish_height + var/distance_from_bottom = fish_position + var/jump_length + if(distance_from_top >= FISH_SHORT_JUMP_MIN_DISTANCE) + jump_length = rand(FISH_SHORT_JUMP_MIN_DISTANCE, FISH_SHORT_JUMP_MAX_DISTANCE) + if(distance_from_bottom >= FISH_SHORT_JUMP_MIN_DISTANCE && (!jump_length || prob(50))) + jump_length = -rand(FISH_SHORT_JUMP_MIN_DISTANCE, FISH_SHORT_JUMP_MAX_DISTANCE) + target_position = clamp(fish_position + jump_length, 0, FISHING_MINIGAME_AREA - fish_height) + current_velocity_limit = short_jump_velocity_limit + + fish_velocity = clamp(fish_velocity + fish_idle_velocity, -current_velocity_limit, current_velocity_limit) + fish_position = clamp(fish_position + fish_velocity * seconds_per_tick, 0, FISHING_MINIGAME_AREA - fish_height) + +///The proc that moves the bait around, just like in the old TGUI, mostly. +/datum/fishing_challenge/proc/move_bait(seconds_per_tick) + var/should_bounce = abs(bait_velocity) > BAIT_MIN_VELOCITY_BOUNCE + bait_position += bait_velocity * seconds_per_tick + // Hitting the top bound + if(bait_position > FISHING_MINIGAME_AREA - bait_height) + bait_position = FISHING_MINIGAME_AREA - bait_height + if(reeling_state == REELING_STATE_UP || !should_bounce) + bait_velocity = 0 + else + bait_velocity = -bait_velocity * bait_bounce_mult + // Hitting rock bottom + else if(bait_position < 0) + bait_position = 0 + if(reeling_state == REELING_STATE_DOWN || !should_bounce) + bait_velocity = 0 + else + bait_velocity = -bait_velocity * bait_bounce_mult + + var/fish_on_bait = (fish_position + fish_height >= bait_position) && (bait_position + bait_height >= fish_position) + + var/bidirectional = special_effects & FISHING_MINIGAME_RULE_BIDIRECTIONAL + + var/velocity_change + switch(reeling_state) + if(REELING_STATE_UP) + velocity_change = reeling_velocity + if(REELING_STATE_DOWN) + velocity_change = -reeling_velocity + if(REELING_STATE_IDLE) + if(!bidirectional || bait_velocity > 0) + velocity_change = gravity_velocity + else + velocity_change = -gravity_velocity + velocity_change *= (fish_on_bait ? FISH_ON_BAIT_ACCELERATION_MULT : 1) * seconds_per_tick + + velocity_change = round(velocity_change) + + /** + * Pull the brake on the velocity if the current velocity and the acceleration + * have different directions, making the bait less slippery, thus easier to control + */ + if(bait_velocity > 0 && velocity_change < 0) + bait_velocity += max(-bait_velocity, velocity_change * BAIT_DECELERATION_MULT) + else if(bait_velocity < 0 && velocity_change > 0) + bait_velocity += min(-bait_velocity, velocity_change * BAIT_DECELERATION_MULT) + + ///bidirectional baits stay bouyant while idle + if(bidirectional && reeling_state == REELING_STATE_IDLE) + if(velocity_change < 0) + bait_velocity = max(bait_velocity + velocity_change, 0) + else if(velocity_change > 0) + bait_velocity = min(bait_velocity + velocity_change, 0) + else + bait_velocity += velocity_change + + //check that the fish area is still intersecting the bait now that it has moved + fish_on_bait = (fish_position + fish_height >= bait_position) && (bait_position + bait_height >= fish_position) + + if(fish_on_bait) + completion += completion_gain * seconds_per_tick + if(completion >= 100) + complete(TRUE) + else + completion -= completion_loss * seconds_per_tick + if(completion <= 0 && !(special_effects & FISHING_MINIGAME_RULE_NO_ESCAPE)) + user.balloon_alert(user, "it got away!") + complete(FALSE) + + completion = clamp(completion, 0, 100) + +///update the vertical pixel position of both fish and bait, and the icon state of the completion bar +/datum/fishing_challenge/proc/update_visuals() + var/bait_offset_mult = bait_position/FISHING_MINIGAME_AREA + fishing_hud.hud_bait.pixel_y = round(MINIGAME_SLIDER_HEIGHT * bait_offset_mult, 1) + var/fish_offset_mult = fish_position/FISHING_MINIGAME_AREA + fishing_hud.hud_fish.pixel_y = round(MINIGAME_SLIDER_HEIGHT * fish_offset_mult, 1) + fishing_hud.hud_completion.icon_state = "completion_[FLOOR(completion, 5)]" + +///The screen object which bait, fish, and completion bar are visually attached to. +/atom/movable/screen/fishing_hud + icon = 'icons/hud/fishing_hud.dmi' + screen_loc = "CENTER+1:8,CENTER:2" + name = "fishing minigame" + appearance_flags = APPEARANCE_UI|KEEP_TOGETHER + alpha = 230 + ///The fish as shown in the minigame + var/atom/movable/screen/hud_fish/hud_fish + ///The bait as shown in the minigame + var/atom/movable/screen/hud_bait/hud_bait + ///The completion bar as shown in the minigame + var/atom/movable/screen/hud_completion/hud_completion + +///Initialize bait, fish and completion bar and add them to the visual appearance of this screen object. +/atom/movable/screen/fishing_hud/proc/prepare_minigame(datum/fishing_challenge/challenge) + icon_state = challenge.background + add_overlay("frame") + hud_bait = new(null, null, challenge) + hud_fish = new + hud_completion = new(null, null, challenge) + vis_contents += list(hud_bait, hud_fish, hud_completion) + challenge.user.client.screen += src + +/atom/movable/screen/fishing_hud/Destroy() + QDEL_NULL(hud_fish) + QDEL_NULL(hud_bait) + QDEL_NULL(hud_completion) + return ..() -// Manually closing the ui is treated as lose -/datum/fishing_challenge/ui_close(mob/user) - . = ..() - if(!completed) - send_alert("stopped fishing") - complete(FALSE) +/atom/movable/screen/hud_bait + icon = 'icons/hud/fishing_hud.dmi' + icon_state = "bait" + vis_flags = VIS_INHERIT_ID -/datum/fishing_challenge/ui_static_data(mob/user) - . = ..() - .["difficulty"] = clamp(difficulty, 1, 100) - .["fish_ai"] = fish_ai - .["special_effects"] = special_effects - .["background_image"] = background - -/datum/fishing_challenge/ui_assets(mob/user) - return list(get_asset_datum(/datum/asset/simple/fishing_minigame)) //preset screens - -/datum/fishing_challenge/ui_status(mob/user, datum/ui_state/state) - return min( - get_dist(user, lure) > 5 ? UI_CLOSE : UI_INTERACTIVE, - ui_status_user_has_free_hands(user), - ui_status_user_is_abled(user, lure), - ) - -/datum/fishing_challenge/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) +/atom/movable/screen/hud_bait/Initialize(mapload, datum/hud/hud_owner, datum/fishing_challenge/challenge) . = ..() - if(.) + if(!challenge || challenge.bait_pixel_height == MINIGAME_BAIT_HEIGHT) return - - if(phase != MINIGAME_PHASE) - return - - switch(action) - if("win") - complete(win = TRUE) - if("lose") - send_alert("it got away") - complete(win = FALSE) + var/static/icon_height + if(!icon_height) + var/list/icon_dimensions = get_icon_dimensions(icon) + icon_height = icon_dimensions["height"] + var/height_percent_diff = challenge.bait_pixel_height/MINIGAME_BAIT_HEIGHT + transform = transform.Scale(1, height_percent_diff) + pixel_z = -icon_height * (1 - height_percent_diff) * 0.5 + +/atom/movable/screen/hud_fish + icon = 'icons/hud/fishing_hud.dmi' + icon_state = "fish" + vis_flags = VIS_INHERIT_ID + +/atom/movable/screen/hud_completion + icon = 'icons/hud/fishing_hud.dmi' + icon_state = "completion_0" + vis_flags = VIS_INHERIT_ID + +/atom/movable/screen/hud_completion/Initialize(mapload, datum/hud/hud_owner, datum/fishing_challenge/challenge) + . = ..() + if(challenge) + icon_state = "completion_[FLOOR(challenge.completion, 5)]" /// The visual that appears over the fishing spot /obj/effect/fishing_lure @@ -280,3 +584,21 @@ #undef WAIT_PHASE #undef BITING_PHASE #undef MINIGAME_PHASE + +#undef FISHING_MINIGAME_AREA +#undef FISH_TARGET_MIN_DISTANCE +#undef FISH_FRICTION_MULT +#undef FISH_SHORT_JUMP_MIN_DISTANCE +#undef FISH_SHORT_JUMP_MAX_DISTANCE +#undef FISH_ON_BAIT_ACCELERATION_MULT +#undef BAIT_MIN_VELOCITY_BOUNCE +#undef BAIT_DECELERATION_MULT + +#undef MINIGAME_SLIDER_HEIGHT +#undef MINIGAME_BAIT_HEIGHT +#undef MINIGAME_FISH_HEIGHT + +#undef REELING_STATE_IDLE +#undef REELING_STATE_UP +#undef REELING_STATE_DOWN + diff --git a/code/modules/fishing/fishing_rod.dm b/code/modules/fishing/fishing_rod.dm index 58936d29534c13..3d1090447a3982 100644 --- a/code/modules/fishing/fishing_rod.dm +++ b/code/modules/fishing/fishing_rod.dm @@ -118,11 +118,14 @@ return hook?.reason_we_cant_fish(target_fish_source) /obj/item/fishing_rod/proc/consume_bait(atom/movable/reward) - if(!reward) + // catching things that aren't fish or alive mobs doesn't consume baits. + if(isnull(reward) || isnull(bait)) return - var/mob/living/caught_mob = isliving(reward) ? reward : null - // catching non-fish, non-mob movables, or dead mobs (probably from a chasm) doesn't consume baits. - if(!bait || !isfish(reward) || !caught_mob || (caught_mob && caught_mob.stat == DEAD)) + if(isliving(reward)) + var/mob/living/caught_mob = reward + if(caught_mob.stat == DEAD) + return + else if(!isfish(reward)) return QDEL_NULL(bait) update_icon() @@ -208,7 +211,7 @@ SIGNAL_HANDLER . = NONE - if(!CheckToolReach(src, source.target, cast_range)) + if(!isturf(source.origin.loc) || !isturf(source.target.loc) || !CheckToolReach(src, source.target, cast_range)) SEND_SIGNAL(source, COMSIG_FISHING_LINE_SNAPPED) //Stepped out of range or los interrupted return BEAM_CANCEL_DRAW diff --git a/code/modules/fishing/sources/_fish_source.dm b/code/modules/fishing/sources/_fish_source.dm index e8156f26cba73f..5a34db9ce5fbeb 100644 --- a/code/modules/fishing/sources/_fish_source.dm +++ b/code/modules/fishing/sources/_fish_source.dm @@ -16,7 +16,7 @@ GLOBAL_LIST_INIT(preset_fish_sources, init_subtypes_w_path_keys(/datum/fish_sour /// How the spot type is described in fish catalog section about fish sources, will be skipped if null var/catalog_description /// Background image name from /datum/asset/simple/fishing_minigame - var/background = "fishing_background_default" + var/background = "background_default" /datum/fish_source/New() if(!PERFORM_ALL_TESTS(focus_only/fish_sources_tables)) @@ -45,7 +45,7 @@ GLOBAL_LIST_INIT(preset_fish_sources, init_subtypes_w_path_keys(/datum/fish_sour . += SETTLER_DIFFICULTY_MOD // Difficulty modifier added by the fisher's skill level - if(!challenge || !(FISHING_MINIGAME_RULE_NO_EXP in challenge.special_effects)) + if(!challenge || !(challenge.special_effects & FISHING_MINIGAME_RULE_NO_EXP)) . += fisherman.mind?.get_skill_modifier(/datum/skill/fishing, SKILL_VALUE_MODIFIER) // Difficulty modifier added by the rod @@ -127,21 +127,24 @@ GLOBAL_LIST_INIT(preset_fish_sources, init_subtypes_w_path_keys(/datum/fish_sour fish_table -= reward_path var/atom/movable/reward = spawn_reward(reward_path, fisherman, fishing_spot) - if(!reward) //baloon alert instead + if(!reward) //balloon alert instead fisherman.balloon_alert(fisherman,pick(duds)) return if(isitem(reward)) //Try to put it in hand INVOKE_ASYNC(fisherman, TYPE_PROC_REF(/mob, put_in_hands), reward) + else // for fishing things like corpses, move them to the turf of the fisherman + INVOKE_ASYNC(reward, TYPE_PROC_REF(/atom/movable, forceMove), get_turf(fisherman)) fisherman.balloon_alert(fisherman, "caught [reward]!") + SEND_SIGNAL(fisherman, COMSIG_MOB_FISHING_REWARD_DISPENSED, reward) return reward /// Spawns a reward from a atom path right where the fisherman is. Part of the dispense_reward() logic. -/datum/fish_source/proc/spawn_reward(reward_path, mob/fisherman, turf/fishing_spot) +/datum/fish_source/proc/spawn_reward(reward_path, mob/fisherman, turf/fishing_spot) if(reward_path == FISHING_DUD) return if(ispath(reward_path, /datum/chasm_detritus)) - return GLOB.chasm_detritus_types[reward_path].dispense_reward(fishing_spot, get_turf(fisherman)) + return GLOB.chasm_detritus_types[reward_path].dispense_detritus(fisherman, fishing_spot) if(!ispath(reward_path, /atom/movable)) CRASH("Unsupported /datum path [reward_path] passed to fish_source/proc/spawn_reward()") var/atom/movable/reward = new reward_path(get_turf(fisherman)) diff --git a/code/modules/fishing/sources/source_types.dm b/code/modules/fishing/sources/source_types.dm index cea97005f281ce..ffb37753881d56 100644 --- a/code/modules/fishing/sources/source_types.dm +++ b/code/modules/fishing/sources/source_types.dm @@ -24,9 +24,10 @@ /obj/item/fish/guppy = 10, ) catalog_description = "Fish dimension (Fishing portal generator)" + /datum/fish_source/chasm catalog_description = "Chasm depths" - background = "fishing_background_lavaland" + background = "background_lavaland" fish_table = list( FISHING_DUD = 5, /obj/item/fish/chasm_crab = 15, @@ -45,7 +46,7 @@ /datum/fish_source/lavaland catalog_description = "Lava vents" - background = "fishing_background_lavaland" + background = "background_lavaland" fish_table = list( FISHING_DUD = 5, /obj/item/stack/ore/slag = 20, diff --git a/code/modules/food_and_drinks/machinery/monkeyrecycler.dm b/code/modules/food_and_drinks/machinery/monkeyrecycler.dm index 5bb772c739855f..8978c975c5ecf1 100644 --- a/code/modules/food_and_drinks/machinery/monkeyrecycler.dm +++ b/code/modules/food_and_drinks/machinery/monkeyrecycler.dm @@ -98,6 +98,6 @@ GLOBAL_LIST_EMPTY(monkey_recyclers) /obj/machinery/monkey_recycler/multitool_act(mob/living/user, obj/item/multitool/I) . = ..() if(istype(I)) - to_chat(user, span_notice("You log [src] in the multitool's buffer.")) I.set_buffer(src) + balloon_alert(user, "saved to multitool buffer") return TRUE diff --git a/code/modules/food_and_drinks/machinery/processor.dm b/code/modules/food_and_drinks/machinery/processor.dm index 5057dbfe08acb7..2c1b0b9d3b3475 100644 --- a/code/modules/food_and_drinks/machinery/processor.dm +++ b/code/modules/food_and_drinks/machinery/processor.dm @@ -68,11 +68,8 @@ var/list/cached_mats = recipe.preserve_materials && what.custom_materials var/cached_multiplier = (recipe.food_multiplier * rating_amount) for(var/i in 1 to cached_multiplier) - var/atom/processed_food = new recipe.output( - drop_location(), - /* starting_reagent_purity = */ null, - /* no_base_reagents = */ TRUE, - ) + var/atom/processed_food = new recipe.output(drop_location()) + processed_food.reagents.clear_reagents() what.reagents.copy_to(processed_food, what.reagents.total_volume, multiplier = 1 / cached_multiplier) if(cached_mats) processed_food.set_custom_materials(cached_mats, 1 / cached_multiplier) diff --git a/code/modules/food_and_drinks/pizzabox.dm b/code/modules/food_and_drinks/pizzabox.dm index a32928723623e8..1454f1e6917f19 100644 --- a/code/modules/food_and_drinks/pizzabox.dm +++ b/code/modules/food_and_drinks/pizzabox.dm @@ -100,7 +100,7 @@ pizza_overlay.pixel_y = -2 . += pizza_overlay if(bomb) - var/mutable_appearance/bomb_overlay = mutable_appearance(bomb.icon, bomb.icon_state) + var/mutable_appearance/bomb_overlay = mutable_appearance(bomb.icon, bomb.icon_state, layer = layer + 0.01) bomb_overlay.pixel_y = 8 . += bomb_overlay return @@ -109,13 +109,13 @@ for(var/stacked_box in boxes) box_offset += 3 var/obj/item/pizzabox/box = stacked_box - var/mutable_appearance/box_overlay = mutable_appearance(box.icon, box.icon_state) + var/mutable_appearance/box_overlay = mutable_appearance(box.icon, box.icon_state, layer = layer + (box_offset * 0.01)) box_overlay.pixel_y = box_offset . += box_overlay var/obj/item/pizzabox/box = LAZYLEN(length(boxes)) ? boxes[length(boxes)] : src if(box.boxtag != "") - var/mutable_appearance/tag_overlay = mutable_appearance(icon, "pizzabox_tag") + var/mutable_appearance/tag_overlay = mutable_appearance(icon, "pizzabox_tag", layer = layer + (box_offset * 0.02)) tag_overlay.pixel_y = box_offset . += tag_overlay @@ -306,8 +306,9 @@ /obj/item/pizzabox/bomb/Initialize(mapload) . = ..() if(!pizza) - var/randompizza = pick(subtypesof(/obj/item/food/pizza)) + var/randompizza = pick(subtypesof(/obj/item/food/pizza) - /obj/item/food/pizza/flatbread) //also disincludes another base type pizza = new randompizza(src) + update_appearance() register_bomb(new /obj/item/bombcore/miniature/pizza(src)) set_wires(new /datum/wires/explosive/pizza(src)) diff --git a/code/modules/food_and_drinks/recipes/drinks/drinks_alcoholic.dm b/code/modules/food_and_drinks/recipes/drinks/drinks_alcoholic.dm index 7e84fe4f5c07c6..1da96fc0aae706 100644 --- a/code/modules/food_and_drinks/recipes/drinks/drinks_alcoholic.dm +++ b/code/modules/food_and_drinks/recipes/drinks/drinks_alcoholic.dm @@ -410,7 +410,7 @@ /datum/chemical_reaction/drink/squirt_cider results = list(/datum/reagent/consumable/ethanol/squirt_cider = 4) - required_reagents = list(/datum/reagent/water = 2, /datum/reagent/consumable/tomatojuice = 2, /datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/salt = 1) + required_reagents = list(/datum/reagent/water/salt = 2, /datum/reagent/consumable/tomatojuice = 2, /datum/reagent/consumable/nutriment = 1) mix_message = "The mix swirls and turns a bright red that reminds you of an apple's skin." reaction_tags = REACTION_TAG_DRINK | REACTION_TAG_EASY | REACTION_TAG_OTHER diff --git a/code/modules/food_and_drinks/recipes/food_mixtures.dm b/code/modules/food_and_drinks/recipes/food_mixtures.dm index cf1a1edfa63632..24cb557b239191 100644 --- a/code/modules/food_and_drinks/recipes/food_mixtures.dm +++ b/code/modules/food_and_drinks/recipes/food_mixtures.dm @@ -97,6 +97,10 @@ required_reagents = list(/datum/reagent/consumable/corn_starch = 1, /datum/reagent/toxin/acid = 1) required_temp = 374 +/datum/chemical_reaction/food/rice_flour + results = list(/datum/reagent/consumable/rice_flour = 10) + required_reagents = list(/datum/reagent/consumable/flour = 5,/datum/reagent/consumable/rice = 5) + /datum/chemical_reaction/food/caramel results = list(/datum/reagent/consumable/caramel = 1) required_reagents = list(/datum/reagent/consumable/sugar = 1) @@ -154,6 +158,12 @@ reaction_flags = REACTION_INSTANT resulting_food_path = /obj/item/food/dough +/datum/chemical_reaction/food/rice_dough + required_reagents = list(/datum/reagent/consumable/rice_flour = 20,/datum/reagent/water = 10) + mix_message = "The ingredients form a rice dough." + reaction_flags = REACTION_INSTANT + resulting_food_path = /obj/item/food/rice_dough + /datum/chemical_reaction/food/cakebatter required_reagents = list(/datum/reagent/consumable/eggyolk = 6, /datum/reagent/consumable/eggwhite = 12, /datum/reagent/consumable/flour = 15, /datum/reagent/consumable/sugar = 5) mix_message = "The ingredients form a cake batter." @@ -247,7 +257,8 @@ reaction_flags = REACTION_INSTANT /datum/chemical_reaction/food/olive_oil_upconvert - required_reagents = list(/datum/reagent/consumable/nutriment/fat/oil/olive = 1, /datum/reagent/consumable/nutriment/fat/oil = 2) + required_catalysts = list(/datum/reagent/consumable/nutriment/fat/oil/olive = 1) + required_reagents = list( /datum/reagent/consumable/nutriment/fat/oil = 2) results = list(/datum/reagent/consumable/nutriment/fat/oil/olive = 2) mix_message = "The cooking oil dilutes the quality oil- how delightfully devilish..." reaction_flags = REACTION_INSTANT diff --git a/code/modules/food_and_drinks/recipes/soup_mixtures.dm b/code/modules/food_and_drinks/recipes/soup_mixtures.dm index 6e78c0f5f2f563..ad2caa84ca6252 100644 --- a/code/modules/food_and_drinks/recipes/soup_mixtures.dm +++ b/code/modules/food_and_drinks/recipes/soup_mixtures.dm @@ -85,6 +85,34 @@ if(!length(required_ingredients)) return + // If a food item is supposed to be made, remove relevant ingredients from the pot, then make the item + if(!isnull(resulting_food_path)) + var/list/tracked_ingredients + LAZYINITLIST(tracked_ingredients) + var/ingredient_max_multiplier = INFINITY + var/obj/item/reagent_containers/cup/soup_pot/pot = holder.my_atom + + // Tracked ingredients are indexed by type and point to a list containing the actual items + for(var/obj/item/ingredient as anything in pot.added_ingredients) + if(is_type_in_list(ingredient, required_ingredients)) + LAZYADD(tracked_ingredients[ingredient.type],ingredient) + // Find the max number of ingredients that may be used for making the food item + for(var/list/ingredient_type as anything in tracked_ingredients) + ingredient_max_multiplier = min(ingredient_max_multiplier,LAZYLEN(tracked_ingredients[ingredient_type])) + // Create the food items, removing the relavent ingredients at the same time + for(var/i in 1 to (min(created_volume,ingredient_max_multiplier))) + for(var/list/ingredient_type as anything in tracked_ingredients) + var/ingredient = tracked_ingredients[ingredient_type][i] + LAZYREMOVE(pot.added_ingredients,ingredient) + qdel(ingredient) + var/obj/item/created = new resulting_food_path(get_turf(pot)) + created.pixel_y += 8 + // Re-add required reagents that were not used in this step + if(created_volume > ingredient_max_multiplier) + for(var/reagent_path as anything in required_reagents) + holder.add_reagent(reagent_path,(required_reagents[reagent_path])*(created_volume-ingredient_max_multiplier)) + + // This only happens if we're being instant reacted so let's just skip to what we really want if(isnull(reaction)) testing("Soup reaction of type [type] instant reacted, cleaning up.") @@ -113,7 +141,6 @@ /datum/chemical_reaction/food/soup/reaction_step(datum/reagents/holder, datum/equilibrium/reaction, delta_t, delta_ph, step_reaction_vol) if(!length(required_ingredients)) return - testing("Soup reaction step progressing with an increment volume of [step_reaction_vol] and delta_t of [delta_t].") var/obj/item/reagent_containers/cup/soup_pot/pot = holder.my_atom var/list/cached_ingredients = reaction.data["ingredients"] @@ -171,7 +198,7 @@ /** * Cleans up the ingredients and adds whatever leftover reagents to the mixture * - * * holder: The sou ppot + * * holder: The soup pot * * reaction: The reaction being cleaned up, note this CAN be null if being instant reacted * * react_vol: How much soup was produced */ @@ -180,29 +207,26 @@ reaction?.data["ingredients"] = null - for(var/obj/item/ingredient as anything in pot.added_ingredients) - // Let's not mess with indestructible items. - // Chef doesn't need more ways to delete things with cooking. - if(ingredient.resistance_flags & INDESTRUCTIBLE) - continue + // If soup is made, remove ingredients as their reagents were added to the soup + if(react_vol) + for(var/obj/item/ingredient as anything in pot.added_ingredients) + // Let's not mess with indestructible items. + // Chef doesn't need more ways to delete things with cooking. + if(ingredient.resistance_flags & INDESTRUCTIBLE) + continue - // Things that had reagents or ingredients in the soup will get deleted - else if(!isnull(ingredient.reagents) || is_type_in_list(ingredient, required_ingredients)) + // Everything else will just get fried + if(isnull(ingredient.reagents) && !is_type_in_list(ingredient, required_ingredients)) + ingredient.AddElement(/datum/element/fried_item, 30) + continue + + // Things that had reagents or ingredients in the soup will get deleted LAZYREMOVE(pot.added_ingredients, ingredient) // Send everything left behind transfer_ingredient_reagents(ingredient, holder) // Delete, it's done qdel(ingredient) - // Everything else will just get fried - else - ingredient.AddElement(/datum/element/fried_item, 30) - - // Spawning physical food results - if(resulting_food_path) - var/obj/item/created = new resulting_food_path(get_turf(pot)) - created.pixel_y += 8 - // Anything left in the ingredient list will get dumped out pot.dump_ingredients(get_turf(pot), y_offset = 8) // Blackbox log the chemical reaction used, to account for soup reaction that don't produce typical results @@ -560,8 +584,8 @@ /datum/chemical_reaction/food/soup/chili_sin_carne required_reagents = list( - /datum/reagent/water = 40, - /datum/reagent/consumable/salt = 5, + /datum/reagent/water = 30, + /datum/reagent/water/salt = 10, ) required_ingredients = list( /obj/item/food/grown/chili = 1, @@ -1097,8 +1121,8 @@ /datum/chemical_reaction/food/soup/electron required_reagents = list( - /datum/reagent/water = 45, - /datum/reagent/consumable/salt = 5, + /datum/reagent/water = 40, + /datum/reagent/water/salt = 10, ) required_ingredients = list( /obj/item/food/grown/mushroom/jupitercup = 1, @@ -1661,8 +1685,8 @@ /datum/chemical_reaction/food/soup/rice_porridge required_reagents = list( - /datum/reagent/water = 30, - /datum/reagent/consumable/salt = 5, + /datum/reagent/water = 20, + /datum/reagent/water/salt = 10, ) required_ingredients = list( /obj/item/food/boiledrice = 1, @@ -1803,7 +1827,7 @@ /obj/item/food/spaghetti/rawnoodles = 1 ) required_catalysts = list( - /datum/reagent/water = 30 + /datum/reagent/water/salt = 10, ) resulting_food_path = /obj/item/food/spaghetti/boilednoodles ingredient_reagent_multiplier = 0 diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm index ea2c1270303b97..47bd455cd858a1 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm @@ -422,8 +422,7 @@ reqs = list( /obj/item/reagent_containers/cup/beaker/large = 1, /obj/item/food/grown/cucumber = 10, - /datum/reagent/water = 10, - /datum/reagent/consumable/salt = 10, + /datum/reagent/water/salt = 20, ) result = /obj/item/storage/fancy/pickles_jar category = CAT_MISCFOOD diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm index 8a8946fa836900..c2b1165f74c747 100644 --- a/code/modules/holiday/holidays.dm +++ b/code/modules/holiday/holidays.dm @@ -18,8 +18,8 @@ var/year_offset = 0 ///Timezones this holiday is celebrated in (defaults to three timezones spanning a 50 hour window covering all timezones) var/list/timezones = list(TIMEZONE_LINT, TIMEZONE_UTC, TIMEZONE_ANYWHERE_ON_EARTH) - ///If this is defined, drones without a default hat will spawn with this one during the holiday; check drones_as_items.dm to see this used - var/obj/item/drone_hat + ///If this is defined, drones/assistants without a default hat will spawn with this item in their head clothing slot. + var/obj/item/holiday_hat ///When this holiday is active, does this prevent mail from arriving to cargo? Try not to use this for longer holidays. var/mail_holiday = FALSE var/poster_name = "generic celebration poster" @@ -109,6 +109,7 @@ name = "Fleet Day" begin_month = JANUARY begin_day = 19 + holiday_hat = /obj/item/clothing/head/mothcap /datum/holiday/fleet_day/greet() return "This day commemorates another year of successful survival aboard the Mothic Grand Nomad Fleet. Moths galaxywide are encouraged to eat, drink, and be merry." @@ -155,7 +156,7 @@ name = "Birthday of Space Station 13" begin_day = 16 begin_month = FEBRUARY - drone_hat = /obj/item/clothing/head/costume/festive + holiday_hat = /obj/item/clothing/head/costume/festive poster_name = "station birthday poster" poster_desc = "A poster celebrating another year of the station's operation. Why anyone would be happy to be here is byond you." poster_icon = "holiday_cake" // is a lie @@ -220,7 +221,7 @@ name = "St. Patrick's Day" begin_day = 17 begin_month = MARCH - drone_hat = /obj/item/clothing/head/soft/green + holiday_hat = /obj/item/clothing/head/soft/green /datum/holiday/no_this_is_patrick/getStationPrefix() return pick("Blarney","Green","Leprechaun","Booze") @@ -235,6 +236,7 @@ begin_month = APRIL begin_day = 1 end_day = 2 + holiday_hat = /obj/item/clothing/head/chameleon/broken /datum/holiday/april_fools/celebrate() . = ..() @@ -252,7 +254,7 @@ name = "Cosmonautics Day" begin_day = 12 begin_month = APRIL - drone_hat = /obj/item/clothing/head/syndicatefake + holiday_hat = /obj/item/clothing/head/syndicatefake /datum/holiday/spess/greet() return "On this day over 600 years ago, Comrade Yuri Gagarin first ventured into space!" @@ -261,6 +263,7 @@ name = "Four-Twenty" begin_day = 20 begin_month = APRIL + holiday_hat = /obj/item/clothing/head/rasta /datum/holiday/fourtwenty/getStationPrefix() return pick("Snoop","Blunt","Toke","Dank","Cheech","Chong") @@ -283,7 +286,7 @@ timezones = list(TIMEZONE_TKT, TIMEZONE_TOT, TIMEZONE_NZST, TIMEZONE_NFT, TIMEZONE_LHST, TIMEZONE_AEST, TIMEZONE_ACST, TIMEZONE_ACWST, TIMEZONE_AWST, TIMEZONE_CXT, TIMEZONE_CCT, TIMEZONE_CKT, TIMEZONE_NUT) begin_day = 25 begin_month = APRIL - drone_hat = /obj/item/food/grown/poppy + holiday_hat = /obj/item/food/grown/poppy /datum/holiday/anz/getStationPrefix() return pick("Australian","New Zealand","Poppy", "Southern Cross") @@ -294,7 +297,7 @@ name = "Labor Day" begin_day = 1 begin_month = MAY - drone_hat = /obj/item/clothing/head/utility/hardhat + holiday_hat = /obj/item/clothing/head/utility/hardhat mail_holiday = TRUE //Draconic Day is celebrated on May 3rd, the date on which the Draconic language was merged (#26780) @@ -313,7 +316,7 @@ name = "Firefighter's Day" begin_day = 4 begin_month = MAY - drone_hat = /obj/item/clothing/head/utility/hardhat/red + holiday_hat = /obj/item/clothing/head/utility/hardhat/red /datum/holiday/firefighter/getStationPrefix() return pick("Burning","Blazing","Plasma","Fire") @@ -322,7 +325,6 @@ name = "Bee Day" begin_day = 20 begin_month = MAY - drone_hat = /obj/item/clothing/mask/animal/small/bee /datum/holiday/bee/getStationPrefix() return pick("Bee","Honey","Hive","Africanized","Mead","Buzz") @@ -355,6 +357,7 @@ name = "Summer Solstice" begin_day = 21 begin_month = JUNE + holiday_hat = /obj/item/clothing/head/costume/garland /datum/holiday/pride_week name = PRIDE_WEEK @@ -377,13 +380,13 @@ name = "Doctor's Day" begin_day = 1 begin_month = JULY - drone_hat = /obj/item/clothing/head/costume/nursehat + holiday_hat = /obj/item/clothing/head/costume/nursehat /datum/holiday/ufo name = "UFO Day" begin_day = 2 begin_month = JULY - drone_hat = /obj/item/clothing/mask/facehugger/dead + holiday_hat = /obj/item/clothing/head/collectable/xenom /datum/holiday/ufo/getStationPrefix() //Is such a thing even possible? return pick("Ayy","Truth","Tsoukalos","Mulder","Scully") //Yes it is! @@ -394,6 +397,7 @@ begin_day = 4 begin_month = JULY mail_holiday = TRUE + holiday_hat = /obj/item/clothing/head/cowboy/brown /datum/holiday/usa/getStationPrefix() return pick("Independent","American","Burger","Bald Eagle","Star-Spangled", "Fireworks") @@ -408,7 +412,7 @@ timezones = list(TIMEZONE_CEST) begin_day = 14 begin_month = JULY - drone_hat = /obj/item/clothing/head/beret + holiday_hat = /obj/item/clothing/head/beret mail_holiday = TRUE /datum/holiday/france/getStationPrefix() @@ -430,7 +434,7 @@ name = "Wizard's Day" begin_month = JULY begin_day = 27 - drone_hat = /obj/item/clothing/head/wizard + holiday_hat = /obj/item/clothing/head/wizard /datum/holiday/wizards_day/getStationPrefix() return pick("Dungeon", "Elf", "Magic", "D20", "Edition") @@ -470,6 +474,7 @@ name = "Tiziran Unification Day" begin_month = SEPTEMBER begin_day = 1 + holiday_hat = /obj/item/clothing/head/costume/lizard /datum/holiday/tiziran_unification/greet() return "On this day over 400 years ago, Lizardkind first united under a single banner, ready to face the stars as one unified people." @@ -493,7 +498,7 @@ name = "Talk-Like-a-Pirate Day" begin_day = 19 begin_month = SEPTEMBER - drone_hat = /obj/item/clothing/head/costume/pirate + holiday_hat = /obj/item/clothing/head/costume/pirate /datum/holiday/pirate/greet() return "Ye be talkin' like a pirate today or else ye'r walkin' tha plank, matey!" @@ -523,13 +528,13 @@ name = "Smiling Day" begin_day = 7 begin_month = OCTOBER - drone_hat = /obj/item/clothing/head/costume/papersack/smiley + holiday_hat = /obj/item/clothing/head/costume/papersack/smiley /datum/holiday/boss name = "Boss' Day" begin_day = 16 begin_month = OCTOBER - drone_hat = /obj/item/clothing/head/hats/tophat + holiday_hat = /obj/item/clothing/head/hats/tophat /datum/holiday/un_day name = "Anniversary of the Foundation of the United Nations" @@ -578,7 +583,7 @@ name = "Remembrance Day" begin_month = NOVEMBER begin_day = 11 - drone_hat = /obj/item/food/grown/poppy + holiday_hat = /obj/item/food/grown/poppy /datum/holiday/remembrance_day/getStationPrefix() return pick("Peace", "Armistice", "Poppy") @@ -600,7 +605,7 @@ name = "Flowers Day" begin_day = 19 begin_month = NOVEMBER - drone_hat = /obj/item/food/grown/moonflower + holiday_hat = /obj/item/food/grown/moonflower /datum/holiday/hello name = "Saying-'Hello' Day" @@ -629,7 +634,7 @@ begin_day = 1 begin_month = DECEMBER end_day = 31 - drone_hat = /obj/item/clothing/head/costume/santa + holiday_hat = /obj/item/clothing/head/costume/santa /datum/holiday/festive_season/greet() return "Have a nice festive season!" @@ -643,20 +648,18 @@ name = MONKEYDAY begin_day = 14 begin_month = DECEMBER - drone_hat = /obj/item/clothing/mask/gas/monkeymask /datum/holiday/doomsday name = "Mayan Doomsday Anniversary" begin_day = 21 begin_month = DECEMBER - drone_hat = /obj/item/clothing/mask/animal/small/tribal /datum/holiday/xmas name = CHRISTMAS begin_day = 23 begin_month = DECEMBER end_day = 27 - drone_hat = /obj/item/clothing/head/costume/santa + holiday_hat = /obj/item/clothing/head/costume/santa mail_holiday = TRUE /datum/holiday/xmas/getStationPrefix() @@ -693,7 +696,7 @@ begin_month = DECEMBER end_day = 2 end_month = JANUARY - drone_hat = /obj/item/clothing/head/costume/festive + holiday_hat = /obj/item/clothing/head/costume/festive mail_holiday = TRUE /datum/holiday/new_year/getStationPrefix() @@ -808,7 +811,7 @@ /datum/holiday/easter name = EASTER - drone_hat = /obj/item/clothing/head/costume/rabbitears + holiday_hat = /obj/item/clothing/head/costume/rabbitears var/const/days_early = 1 //to make editing the holiday easier var/const/days_extra = 1 diff --git a/code/modules/holiday/nth_week.dm b/code/modules/holiday/nth_week.dm index 55cfec74be6e2f..ef4815de066467 100644 --- a/code/modules/holiday/nth_week.dm +++ b/code/modules/holiday/nth_week.dm @@ -35,7 +35,7 @@ begin_week = 4 begin_month = NOVEMBER begin_weekday = THURSDAY - drone_hat = /obj/item/clothing/head/hats/tophat //This is the closest we can get to a pilgrim's hat + holiday_hat = /obj/item/clothing/head/hats/tophat //This is the closest we can get to a pilgrim's hat /datum/holiday/nth_week/thanksgiving/canada name = "Thanksgiving in Canada" diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 86a8dbc409529e..098c6e81ce6a98 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -38,11 +38,14 @@ var/wine_power = 10 /// Color of the grown object, for use in coloring greyscale splats. var/filling_color - /// If the grown food has an alternaitve icon state to use in places. + /// If the grown food has an alternative icon state to use in places. var/alt_icon /// Should we pixel offset ourselves at init? for mapping var/offset_at_init = TRUE +/obj/item/food/grown/New(loc, obj/item/seeds/new_seed) + return ..() + /obj/item/food/grown/Initialize(mapload, obj/item/seeds/new_seed) if(!tastes) tastes = list("[name]" = 1) //This happens first else the component already inits @@ -75,6 +78,7 @@ . = ..() //Only call it here because we want all the genes and shit to be applied before we add edibility. God this code is a mess. + reagents.clear_reagents() seed.prepare_result(src) transform *= TRANSFORM_USING_VARIABLE(seed.potency, 100) + 0.5 //Makes the resulting produce's sprite larger or smaller based on potency! @@ -125,7 +129,7 @@ else var/data = list() data["names"] = list("[initial(name)]" = 1) - data["color"] = filling_color + data["color"] = filling_color || reagent.color // filling_color is not guaranteed to be set for every plant. try to use it if we have it, otherwise use the reagent's color var data["boozepwr"] = round(wine_power * reagent_purity * 2) // default boozepwr at 50% purity data["quality"] = quality if(wine_flavor) diff --git a/code/modules/hydroponics/grown/banana.dm b/code/modules/hydroponics/grown/banana.dm index fca26ebe97861b..1b9b16d485cb5e 100644 --- a/code/modules/hydroponics/grown/banana.dm +++ b/code/modules/hydroponics/grown/banana.dm @@ -169,6 +169,7 @@ /obj/item/food/grown/banana/bunch/Initialize(mapload, obj/item/seeds/new_seed) . = ..() + reagents.clear_reagents() reagents.add_reagent(/datum/reagent/consumable/monkey_energy, 10) reagents.add_reagent(/datum/reagent/consumable/banana, 10) diff --git a/code/modules/hydroponics/growninedible.dm b/code/modules/hydroponics/growninedible.dm index 26fb90236a30d2..2b2556790e2b2c 100644 --- a/code/modules/hydroponics/growninedible.dm +++ b/code/modules/hydroponics/growninedible.dm @@ -10,6 +10,12 @@ var/obj/item/seeds/seed = null // type path, gets converted to item on New(). It's safe to assume it's always a seed item. /// Should we pixel offset ourselves at init? for mapping var/offset_at_init = TRUE + /// The reagent this plant distill to. If NULL, it uses a generic fruit_wine reagent and adjusts its variables. + var/distill_reagent + +// This may look like it's doing nothing but it's necessary, we do this to have kwargs work in New (for passing into Initialize) +/obj/item/grown/New(loc, obj/item/seeds/new_seed) + return ..() /obj/item/grown/Initialize(mapload, obj/item/seeds/new_seed) . = ..() diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm index 52be3e98f0c66b..36653ebafb9ffe 100644 --- a/code/modules/hydroponics/seeds.dm +++ b/code/modules/hydroponics/seeds.dm @@ -223,7 +223,7 @@ for(var/datum/plant_gene/trait/trait in parent.myseed.genes) if((trait.mutability_flags & PLANT_GENE_MUTATABLE) && trait.can_add(mutated_seed)) mutated_seed.genes += trait.Copy() - t_prod = new t_prod(output_loc, mutated_seed) + t_prod = new t_prod(output_loc, new_seed = mutated_seed) t_prod.transform = initial(t_prod.transform) t_prod.transform *= TRANSFORM_USING_VARIABLE(t_prod.seed.potency, 100) + 0.5 ADD_TRAIT(t_prod, TRAIT_PLANT_WILDMUTATE, INNATE_TRAIT) @@ -232,7 +232,7 @@ t_prod.seed.set_instability(round(instability * 0.5)) continue else - t_prod = new product(output_loc, src) + t_prod = new product(output_loc, new_seed = src) if(parent.myseed.plantname != initial(parent.myseed.plantname)) t_prod.name = lowertext(parent.myseed.plantname) if(productdesc) diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm index 2a5a14b066d2bd..5b64770175cbef 100644 --- a/code/modules/jobs/access.dm +++ b/code/modules/jobs/access.dm @@ -5,6 +5,8 @@ return TRUE if(result_bitflags & COMPONENT_OBJ_DISALLOW) // override all other checks return FALSE + if(HAS_TRAIT(accessor, TRAIT_ALWAYS_NO_ACCESS)) + return FALSE //check if it doesn't require any access at all if(check_access(null)) return TRUE diff --git a/code/modules/jobs/job_types/assistant.dm b/code/modules/jobs/job_types/assistant.dm index a5a68b7152aa4b..89e7d04742c7cd 100644 --- a/code/modules/jobs/job_types/assistant.dm +++ b/code/modules/jobs/job_types/assistant.dm @@ -48,6 +48,12 @@ Assistant /datum/outfit/job/assistant/pre_equip(mob/living/carbon/human/target) ..() + for(var/holidayname in GLOB.holidays) + var/datum/holiday/holiday_today = GLOB.holidays[holidayname] + var/obj/item/special_hat = holiday_today.holiday_hat + if(prob(HOLIDAY_HAT_CHANCE) && !isnull(special_hat) && isnull(head)) + head = special_hat + give_jumpsuit(target) /datum/outfit/job/assistant/proc/give_jumpsuit(mob/living/carbon/human/target) diff --git a/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm b/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm index 15dd39861a4118..3e752910a29d76 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm @@ -21,7 +21,7 @@ If the scythe isn't empowered when you sheath it, you take a heap of damage and return FALSE var/obj/item/bodypart/part = hand - if(isnull(part) || scythe.empowerment > SCYTHE_SATED) + if(isnull(part) || scythe.empowerment >= SCYTHE_SATED) return ..() to_chat(owner, span_userdanger("[scythe] tears into you for your unworthy display of arrogance!")) diff --git a/code/modules/mafia/controller.dm b/code/modules/mafia/controller.dm index a0e5b26b5d94be..1916a65f7b17a2 100644 --- a/code/modules/mafia/controller.dm +++ b/code/modules/mafia/controller.dm @@ -369,7 +369,7 @@ GLOBAL_LIST_INIT(mafia_role_by_alignment, setup_mafia_role_by_alignment()) * * role: mafia_role datum to reward. */ /datum/mafia_controller/proc/award_role(award, datum/mafia_role/rewarded) - var/client/role_client = GLOB.directory[rewarded.body.client] + var/client/role_client = rewarded.body.client role_client?.give_award(award, rewarded.body) /** diff --git a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm index 6ab0ed2f3876ad..424e1db299ec57 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm @@ -112,9 +112,10 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) if(!storageTurf) //Blame subsystems for not allowing this to be in Initialize if(!GLOB.hhStorageTurf) var/datum/map_template/hilbertshotelstorage/storageTemp = new() - var/datum/turf_reservation/storageReservation = SSmapping.RequestBlockReservation(3, 3) - storageTemp.load(locate(storageReservation.bottom_left_coords[1], storageReservation.bottom_left_coords[2], storageReservation.bottom_left_coords[3])) - GLOB.hhStorageTurf = locate(storageReservation.bottom_left_coords[1]+1, storageReservation.bottom_left_coords[2]+1, storageReservation.bottom_left_coords[3]) + var/datum/turf_reservation/storageReservation = SSmapping.request_turf_block_reservation(1, 1, 1) + var/turf/storage_turf = storageReservation.bottom_left_turfs[1] + storageTemp.load(storage_turf) + GLOB.hhStorageTurf = storage_turf else storageTurf = GLOB.hhStorageTurf if(tryActiveRoom(chosenRoomNumber, target)) @@ -127,20 +128,30 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) if(activeRooms["[roomNumber]"]) var/datum/turf_reservation/roomReservation = activeRooms["[roomNumber]"] do_sparks(3, FALSE, get_turf(user)) - user.forceMove(locate(roomReservation.bottom_left_coords[1] + hotelRoomTemp.landingZoneRelativeX, roomReservation.bottom_left_coords[2] + hotelRoomTemp.landingZoneRelativeY, roomReservation.bottom_left_coords[3])) + var/turf/room_bottom_left = roomReservation.bottom_left_turfs[1] + user.forceMove(locate( + room_bottom_left.x + hotelRoomTemp.landingZoneRelativeX, + room_bottom_left.y + hotelRoomTemp.landingZoneRelativeY, + room_bottom_left.z, + )) return TRUE return FALSE /obj/item/hilbertshotel/proc/tryStoredRoom(roomNumber, mob/user) if(storedRooms["[roomNumber]"]) - var/datum/turf_reservation/roomReservation = SSmapping.RequestBlockReservation(hotelRoomTemp.width, hotelRoomTemp.height) - hotelRoomTempEmpty.load(locate(roomReservation.bottom_left_coords[1], roomReservation.bottom_left_coords[2], roomReservation.bottom_left_coords[3])) + var/datum/turf_reservation/roomReservation = SSmapping.request_turf_block_reservation(hotelRoomTemp.width, hotelRoomTemp.height, 1) + var/turf/room_turf = roomReservation.bottom_left_turfs[1] + hotelRoomTempEmpty.load(room_turf) var/turfNumber = 1 for(var/x in 0 to hotelRoomTemp.width-1) for(var/y in 0 to hotelRoomTemp.height-1) for(var/atom/movable/A in storedRooms["[roomNumber]"][turfNumber]) if(istype(A.loc, /obj/item/abstracthotelstorage))//Don't want to recall something thats been moved - A.forceMove(locate(roomReservation.bottom_left_coords[1] + x, roomReservation.bottom_left_coords[2] + y, roomReservation.bottom_left_coords[3])) + A.forceMove(locate( + room_turf.x + x, + room_turf.y + y, + room_turf.z, + )) turfNumber++ for(var/obj/item/abstracthotelstorage/S in storageTurf) if((S.roomNumber == roomNumber) && (S.parentSphere == src)) @@ -149,29 +160,39 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) activeRooms["[roomNumber]"] = roomReservation linkTurfs(roomReservation, roomNumber) do_sparks(3, FALSE, get_turf(user)) - user.forceMove(locate(roomReservation.bottom_left_coords[1] + hotelRoomTemp.landingZoneRelativeX, roomReservation.bottom_left_coords[2] + hotelRoomTemp.landingZoneRelativeY, roomReservation.bottom_left_coords[3])) + user.forceMove(locate( + room_turf.x + hotelRoomTemp.landingZoneRelativeX, + room_turf.y + hotelRoomTemp.landingZoneRelativeY, + room_turf.z, + )) return TRUE return FALSE -/obj/item/hilbertshotel/proc/sendToNewRoom(roomNumber, mob/user, chosen_room) //SKYRAT EDIT ADDITION - GHOST HOTEL UPDATE. Was sendToNewRoom(chosenRoomNumber, target) - var/datum/turf_reservation/roomReservation = SSmapping.RequestBlockReservation(hotelRoomTemp.width, hotelRoomTemp.height) +/obj/item/hilbertshotel/proc/sendToNewRoom(roomNumber, mob/user, chosen_room) //SKYRAT EDIT ADDITION - GHOST HOTEL UPDATE. Was sendToNewRoom(roomNumber, mob/user) + var/datum/turf_reservation/roomReservation = SSmapping.request_turf_block_reservation(hotelRoomTemp.width, hotelRoomTemp.height, 1) + var/turf/bottom_left = roomReservation.bottom_left_turfs[1] + var/datum/map_template/load_from = hotelRoomTemp + if(ruinSpawned && roomNumber == GLOB.hhMysteryRoomNumber) - hotelRoomTempLore.load(locate(roomReservation.bottom_left_coords[1], roomReservation.bottom_left_coords[2], roomReservation.bottom_left_coords[3])) - else - //SKYRAT EDIT ADDITION - GHOST HOTEL UPDATE - switch(chosen_room) - if("Apartment") - ghost_cafe_rooms_apartment.load(locate(roomReservation.bottom_left_coords[1], roomReservation.bottom_left_coords[2], roomReservation.bottom_left_coords[3])) - else - //SKYRAT EDIT END - hotelRoomTemp.load(locate(roomReservation.bottom_left_coords[1], roomReservation.bottom_left_coords[2], roomReservation.bottom_left_coords[3])) + load_from = hotelRoomTempLore + //SKYRAT EDIT ADDITION START - GHOST HOTEL UPDATE + else if(chosen_room == "Apartment") + load_from = ghost_cafe_rooms_apartment + //SKYRAT EDIT ADDITION END + + load_from.load(bottom_left) activeRooms["[roomNumber]"] = roomReservation linkTurfs(roomReservation, roomNumber) do_sparks(3, FALSE, get_turf(user)) - user.forceMove(locate(roomReservation.bottom_left_coords[1] + hotelRoomTemp.landingZoneRelativeX, roomReservation.bottom_left_coords[2] + hotelRoomTemp.landingZoneRelativeY, roomReservation.bottom_left_coords[3])) + user.forceMove(locate( + bottom_left.x + hotelRoomTemp.landingZoneRelativeX, + bottom_left.y + hotelRoomTemp.landingZoneRelativeY, + bottom_left.z, + )) /obj/item/hilbertshotel/proc/linkTurfs(datum/turf_reservation/currentReservation, currentRoomnumber) - var/area/misc/hilbertshotel/currentArea = get_area(locate(currentReservation.bottom_left_coords[1], currentReservation.bottom_left_coords[2], currentReservation.bottom_left_coords[3])) + var/turf/room_bottom_left = currentReservation.bottom_left_turfs[1] + var/area/misc/hilbertshotel/currentArea = get_area(room_bottom_left) currentArea.name = "Hilbert's Hotel Room [currentRoomnumber]" currentArea.parentSphere = src currentArea.storageTurf = storageTurf @@ -187,9 +208,10 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) if(activeRooms.len) for(var/x in activeRooms) var/datum/turf_reservation/room = activeRooms[x] + var/turf/room_bottom_left = room.bottom_left_turfs[1] for(var/i in 0 to hotelRoomTemp.width-1) for(var/j in 0 to hotelRoomTemp.height-1) - for(var/atom/movable/A in locate(room.bottom_left_coords[1] + i, room.bottom_left_coords[2] + j, room.bottom_left_coords[3])) + for(var/atom/movable/A in locate(room_bottom_left.x + i, room_bottom_left.y + j, room_bottom_left.z)) if(ismob(A)) var/mob/M = A if(M.mind) @@ -271,7 +293,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) icon_state = "bluespace" base_icon_state = "bluespace" baseturfs = /turf/open/space/bluespace - flags_1 = NOJAUNT + turf_flags = NOJAUNT explosive_resistance = INFINITY var/obj/item/hilbertshotel/parentSphere @@ -437,7 +459,11 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) storeRoom() /area/misc/hilbertshotel/proc/storeRoom() - var/roomSize = (reservation.top_right_coords[1]-reservation.bottom_left_coords[1]+1)*(reservation.top_right_coords[2]-reservation.bottom_left_coords[2]+1) + var/turf/room_bottom_left = reservation.bottom_left_turfs[1] + var/turf/room_top_right = reservation.top_right_turfs[1] + var/roomSize = \ + ((room_top_right.x - room_bottom_left.x) + 1) * \ + ((room_top_right.y - room_bottom_left.y) + 1) var/storage[roomSize] var/turfNumber = 1 var/obj/item/abstracthotelstorage/storageObj = new(storageTurf) @@ -447,7 +473,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) for(var/x in 0 to parentSphere.hotelRoomTemp.width-1) for(var/y in 0 to parentSphere.hotelRoomTemp.height-1) var/list/turfContents = list() - for(var/atom/movable/A in locate(reservation.bottom_left_coords[1] + x, reservation.bottom_left_coords[2] + y, reservation.bottom_left_coords[3])) + for(var/atom/movable/A in locate(room_bottom_left.x + x, room_bottom_left.y + y, room_bottom_left.z)) if(ismob(A) && !isliving(A)) continue //Don't want to store ghosts turfContents += A diff --git a/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm b/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm index ca2b6ec39c9f28..fc79c82e780efb 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm @@ -13,8 +13,12 @@ /obj/effect/mob_spawn/corpse/human/tigercultist/perforated/special(mob/living/carbon/human/spawned_human) . = ..() - var/datum/wound/pierce/bleed/critical/exit_hole = new() - exit_hole.apply_wound(spawned_human.get_bodypart(BODY_ZONE_CHEST)) + + var/obj/item/bodypart/chest/their_chest = spawned_human.get_bodypart(BODY_ZONE_CHEST) + if (!their_chest) + return + + spawned_human.cause_wound_of_type_and_severity(WOUND_PIERCE, their_chest, WOUND_SEVERITY_CRITICAL) /// A fun drink enjoyed by the tiger cooperative, might corrode your brain if you drink the whole bottle /obj/item/reagent_containers/cup/glass/bottle/ritual_wine diff --git a/code/modules/mapping/map_template.dm b/code/modules/mapping/map_template.dm index 30477657ab5fcb..237ae9f2d52e4e 100644 --- a/code/modules/mapping/map_template.dm +++ b/code/modules/mapping/map_template.dm @@ -133,7 +133,15 @@ var/y = round((world.maxy - height) * 0.5) + 1 var/datum/space_level/level = SSmapping.add_new_zlevel(name, secret ? ZTRAITS_AWAY_SECRET : ZTRAITS_AWAY, contain_turfs = FALSE) - var/datum/parsed_map/parsed = load_map(file(mappath), x, y, level.z_value, no_changeturf=(SSatoms.initialized == INITIALIZATION_INSSATOMS), placeOnTop=should_place_on_top, new_z = TRUE) + var/datum/parsed_map/parsed = load_map( + file(mappath), + x, + y, + level.z_value, + no_changeturf = (SSatoms.initialized == INITIALIZATION_INSSATOMS), + place_on_top = should_place_on_top, + new_z = TRUE, + ) var/list/bounds = parsed.bounds if(!bounds) return FALSE @@ -177,7 +185,14 @@ UNSETEMPTY(turf_blacklist) parsed.turf_blacklist = turf_blacklist - if(!parsed.load(T.x, T.y, T.z, cropMap=TRUE, no_changeturf=(SSatoms.initialized == INITIALIZATION_INSSATOMS), placeOnTop=should_place_on_top)) + if(!parsed.load( + T.x, + T.y, + T.z, + crop_map = TRUE, + no_changeturf = (SSatoms.initialized == INITIALIZATION_INSSATOMS), + place_on_top = should_place_on_top, + )) return var/list/bounds = parsed.bounds diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index d1fc4a79cf7e27..cec7932f4f556c 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -1359,3 +1359,19 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava) engraved_wall.AddComponent(/datum/component/engraved, engraving["story"], FALSE, engraving["story_value"]) qdel(src) + +/// Apply to a wall (or floor, technically) to ensure it is instantly destroyed by any explosion, even if usually invulnerable +/obj/effect/mapping_helpers/bombable_wall + name = "bombable wall helper" + icon = 'icons/turf/overlays.dmi' + icon_state = "explodable" + +/obj/effect/mapping_helpers/bombable_wall/Initialize(mapload) + . = ..() + if(!mapload) + log_mapping("[src] spawned outside of mapload!") + return + + var/turf/our_turf = get_turf(src) // In case a locker ate us or something + our_turf.AddElement(/datum/element/bombable_turf) + return INITIALIZE_HINT_QDEL diff --git a/code/modules/mapping/reader.dm b/code/modules/mapping/reader.dm index 96b555457d78df..14a8fdf6b94003 100644 --- a/code/modules/mapping/reader.dm +++ b/code/modules/mapping/reader.dm @@ -114,26 +114,72 @@ var/turfsSkipped = 0 #endif +/datum/parsed_map/proc/copy() + // Avoids duped work just in case + build_cache() + var/datum/parsed_map/newfriend = new() + newfriend.original_path = original_path + newfriend.map_format = map_format + newfriend.key_len = key_len + newfriend.line_len = line_len + newfriend.grid_models = grid_models.Copy() + newfriend.gridSets = gridSets.Copy() + newfriend.modelCache = modelCache.Copy() + newfriend.parsed_bounds = parsed_bounds.Copy() + // Copy parsed bounds to reset to initial values + newfriend.bounds = parsed_bounds.Copy() + newfriend.turf_blacklist = turf_blacklist?.Copy() + return newfriend + //text trimming (both directions) helper macro #define TRIM_TEXT(text) (trim_reduced(text)) -/// Shortcut function to parse a map and apply it to the world. -/// -/// - `dmm_file`: A .dmm file to load (Required). -/// - `x_offset`, `y_offset`, `z_offset`: Positions representign where to load the map (Optional). -/// - `cropMap`: When true, the map will be cropped to fit the existing world dimensions (Optional). -/// - `measureOnly`: When true, no changes will be made to the world (Optional). -/// - `no_changeturf`: When true, [/turf/proc/AfterChange] won't be called on loaded turfs -/// - `x_lower`, `x_upper`, `y_lower`, `y_upper`: Coordinates (relative to the map) to crop to (Optional). -/// - `placeOnTop`: Whether to use [/turf/proc/PlaceOnTop] rather than [/turf/proc/ChangeTurf] (Optional). -/proc/load_map(dmm_file as file, x_offset as num, y_offset as num, z_offset as num, cropMap as num, measureOnly as num, no_changeturf as num, x_lower = -INFINITY as num, x_upper = INFINITY as num, y_lower = -INFINITY as num, y_upper = INFINITY as num, placeOnTop = FALSE as num, new_z) - var/datum/parsed_map/parsed = new(dmm_file, x_lower, x_upper, y_lower, y_upper, measureOnly) - if(parsed.bounds && !measureOnly) - parsed.load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, new_z = new_z) - return parsed +/** + * Helper and recommened way to load a map file + * - dmm_file: The path to the map file + * - x_offset: The x offset to load the map at + * - y_offset: The y offset to load the map at + * - z_offset: The z offset to load the map at + * - crop_map: If true, the map will be cropped to the world bounds + * - measure_only: If true, the map will not be loaded, but the bounds will be calculated + * - no_changeturf: If true, the map will not call /turf/AfterChange + * - x_lower: The minimum x coordinate to load + * - x_upper: The maximum x coordinate to load + * - y_lower: The minimum y coordinate to load + * - y_upper: The maximum y coordinate to load + * - z_lower: The minimum z coordinate to load + * - z_upper: The maximum z coordinate to load + * - place_on_top: Whether to use /turf/proc/PlaceOnTop rather than /turf/proc/ChangeTurf + * - new_z: If true, a new z level will be created for the map + */ +/proc/load_map( + dmm_file, + x_offset = 0, + y_offset = 0, + z_offset = 0, + crop_map = FALSE, + measure_only = FALSE, + no_changeturf = FALSE, + x_lower = -INFINITY, + x_upper = INFINITY, + y_lower = -INFINITY, + y_upper = INFINITY, + z_lower = -INFINITY, + z_upper = INFINITY, + place_on_top = FALSE, + new_z = FALSE, +) + if(!(dmm_file in GLOB.cached_maps)) + GLOB.cached_maps[dmm_file] = new /datum/parsed_map(dmm_file) + + var/datum/parsed_map/parsed_map = GLOB.cached_maps[dmm_file] + parsed_map = parsed_map.copy() + if(!measure_only && !isnull(parsed_map.bounds)) + parsed_map.load(x_offset, y_offset, z_offset, crop_map, no_changeturf, x_lower, x_upper, y_lower, y_upper, z_lower, z_upper, place_on_top, new_z) + return parsed_map /// Parse a map, possibly cropping it. -/datum/parsed_map/New(tfile, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper=INFINITY, measureOnly=FALSE) +/datum/parsed_map/New(tfile, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper=INFINITY, z_lower = -INFINITY, z_upper=INFINITY, measureOnly=FALSE) // This proc sleeps for like 6 seconds. why? // Is it file accesses? if so, can those be done ahead of time, async to save on time here? I wonder. // Love ya :) @@ -184,20 +230,26 @@ CRASH("Coords before model definition in DMM") var/curr_x = text2num(regexOutput[3]) - if(curr_x < x_lower || curr_x > x_upper) continue + var/curr_y = text2num(regexOutput[4]) + if(curr_y < y_lower || curr_y > y_upper) + continue + + var/curr_z = text2num(regexOutput[5]) + if(curr_z < z_lower || curr_z > z_upper) + continue + var/datum/grid_set/gridSet = new gridSet.xcrd = curr_x - //position of the currently processed square - gridSet.ycrd = text2num(regexOutput[4]) - gridSet.zcrd = text2num(regexOutput[5]) + gridSet.ycrd = curr_y + gridSet.zcrd = curr_z bounds[MAP_MINX] = min(bounds[MAP_MINX], curr_x) - bounds[MAP_MINZ] = min(bounds[MAP_MINZ], gridSet.zcrd) - bounds[MAP_MAXZ] = max(bounds[MAP_MAXZ], gridSet.zcrd) + bounds[MAP_MINZ] = min(bounds[MAP_MINZ], curr_y) + bounds[MAP_MAXZ] = max(bounds[MAP_MAXZ], curr_z) var/list/gridLines = splittext(regexOutput[6], "\n") gridSet.gridLines = gridLines @@ -238,16 +290,29 @@ bounds[MAP_MAXX] = clamp(bounds[MAP_MAXX], x_lower, x_upper) bounds[MAP_MINY] = clamp(bounds[MAP_MINY], y_lower, y_upper) bounds[MAP_MAXY] = clamp(bounds[MAP_MAXY], y_lower, y_upper) + bounds[MAP_MINZ] = clamp(bounds[MAP_MINZ], z_lower, z_upper) + bounds[MAP_MAXZ] = clamp(bounds[MAP_MAXZ], z_lower, z_upper) parsed_bounds = src.bounds src.key_len = key_len src.line_len = line_len -/// Load the parsed map into the world. See [/proc/load_map] for arguments. -/datum/parsed_map/proc/load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, whitelist = FALSE, new_z) +/// Iterates over all grid sets and returns ones with z values within the given bounds. Inclusive +/datum/parsed_map/proc/filter_grid_sets_based_on_z_bounds(lower_z, upper_z) + var/list/filtered_sets = list() + for(var/datum/grid_set/grid_set as anything in gridSets) + if(grid_set.zcrd < lower_z) + continue + if(grid_set.zcrd > upper_z) + continue + filtered_sets += grid_set + return filtered_sets + +/// Load the parsed map into the world. You probably want [/proc/load_map]. Keep the signature the same. +/datum/parsed_map/proc/load(x_offset = 0, y_offset = 0, z_offset = 0, crop_map = FALSE, no_changeturf = FALSE, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper = INFINITY, z_lower = -INFINITY, z_upper = INFINITY, place_on_top = FALSE, new_z = FALSE) //How I wish for RAII Master.StartLoadingMap() - . = _load_impl(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, new_z) + . = _load_impl(x_offset, y_offset, z_offset, crop_map, no_changeturf, x_lower, x_upper, y_lower, y_upper, z_lower, z_upper, place_on_top, new_z) Master.StopLoadingMap() #define MAPLOADING_CHECK_TICK \ @@ -262,7 +327,7 @@ } // Do not call except via load() above. -/datum/parsed_map/proc/_load_impl(x_offset = 1, y_offset = 1, z_offset = world.maxz + 1, cropMap = FALSE, no_changeturf = FALSE, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper = INFINITY, placeOnTop = FALSE, new_z = FALSE) +/datum/parsed_map/proc/_load_impl(x_offset, y_offset, z_offset, crop_map, no_changeturf, x_lower, x_upper, y_lower, y_upper, z_lower, z_upper, place_on_top, new_z) PRIVATE_PROC(TRUE) // Tell ss atoms that we're doing maploading // We'll have to account for this in the following tick_checks so it doesn't overflow @@ -275,9 +340,9 @@ var/sucessful = FALSE switch(map_format) if(MAP_TGM) - sucessful = _tgm_load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, new_z) + sucessful = _tgm_load(x_offset, y_offset, z_offset, crop_map, no_changeturf, x_lower, x_upper, y_lower, y_upper, z_lower, z_upper, place_on_top, new_z) else - sucessful = _dmm_load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, new_z) + sucessful = _dmm_load(x_offset, y_offset, z_offset, crop_map, no_changeturf, x_lower, x_upper, y_lower, y_upper, z_lower, z_upper, place_on_top, new_z) // And we are done lads, call it off SSatoms.map_loader_stop(REF(src)) @@ -309,7 +374,7 @@ // In the tgm format, each gridset contains 255 lines, each line representing one tile, with 255 total gridsets // In the dmm format, each gridset contains 255 lines, each line representing one row of tiles, containing 255 * line length characters, with one gridset per z // You can think of dmm as storing maps in rows, whereas tgm stores them in columns -/datum/parsed_map/proc/_tgm_load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, new_z) +/datum/parsed_map/proc/_tgm_load(x_offset, y_offset, z_offset, crop_map, no_changeturf, x_lower, x_upper, y_lower, y_upper, z_lower, z_upper, place_on_top, new_z) // setup var/list/modelCache = build_cache(no_changeturf) var/space_key = modelCache[SPACE_KEY] @@ -330,12 +395,12 @@ var/relative_y = first_column.ycrd var/highest_y = relative_y + y_relative_to_absolute - if(!cropMap && highest_y > world.maxy) + if(!crop_map && highest_y > world.maxy) if(new_z) // Need to avoid improperly loaded area/turf_contents - world.increaseMaxY(highest_y, max_zs_to_load = z_offset - 1) + world.increase_max_y(highest_y, map_load_z_cutoff = z_offset - 1) else - world.increaseMaxY(highest_y) + world.increase_max_y(highest_y) expanded_y = TRUE // Skip Y coords that are above the smallest of the three params @@ -345,7 +410,6 @@ var/y_starting_skip = relative_y - y_skip_above highest_y -= y_starting_skip - // Y is the LOWEST it will ever be here, so we can easily set a threshold for how low to go var/line_count = length(first_column.gridLines) var/lowest_y = relative_y - (line_count - 1) // -1 because we decrement at the end of the loop, not the start @@ -353,7 +417,7 @@ // X setup var/x_delta_with = x_upper - if(cropMap) + if(crop_map) // Take our smaller crop threshold yes? x_delta_with = min(x_delta_with, world.maxx) @@ -367,33 +431,51 @@ // If our relative x is greater then X upper, well then we've gotta limit our expansion var/delta = max(final_x - x_delta_with, 0) final_x -= delta - if(final_x > world.maxx && !cropMap) + if(final_x > world.maxx && !crop_map) if(new_z) // Need to avoid improperly loaded area/turf_contents - world.increaseMaxX(final_x, max_zs_to_load = z_offset - 1) + world.increase_max_x(final_x, map_load_z_cutoff = z_offset - 1) else - world.increaseMaxX(final_x) + world.increase_max_x(final_x) expanded_x = TRUE var/lowest_x = max(x_lower, 1 - x_relative_to_absolute) + // Amount we offset the grid zcrd to get the true zcrd + var/grid_z_offset = z_offset - 1 + var/z_upper_set = z_upper < INFINITY + var/z_lower_set = z_lower > -INFINITY + // We make the assumption that the last block of turfs will have the highest embedded z in it - var/highest_z = last_column.zcrd + z_offset - 1 // Lets not just make a new z level each time we increment maxz + // true max zcrd + var/map_bounds_z_max = last_column.zcrd + var/z_upper_parsed = map_bounds_z_max + z_offset - 1 + if(z_upper_set) + z_upper_parsed -= map_bounds_z_max - z_upper + if(z_lower_set) + var/offset_amount = z_lower - 1 + z_upper_parsed -= offset_amount + grid_z_offset -= offset_amount + + var/list/target_grid_sets = gridSets + if(z_lower_set || z_upper_set) // bounds are set, filter out gridsets for z levels we don't want + target_grid_sets = filter_grid_sets_based_on_z_bounds(z_lower, z_upper) + var/z_threshold = world.maxz - if(highest_z > z_threshold && cropMap) - for(var/i in z_threshold + 1 to highest_z) //create a new z_level if needed + if(z_upper_parsed > z_threshold && crop_map) + for(var/i in z_threshold + 1 to z_upper_parsed) //create a new z_level if needed world.incrementMaxZ() if(!no_changeturf) WARNING("Z-level expansion occurred without no_changeturf set, this may cause problems when /turf/AfterChange is called") - for(var/datum/grid_set/gset as anything in gridSets) + for(var/datum/grid_set/gset as anything in target_grid_sets) var/true_xcrd = gset.xcrd + x_relative_to_absolute // any cutoff of x means we just shouldn't iterate this gridset if(final_x < true_xcrd || lowest_x > gset.xcrd) continue - var/zcrd = gset.zcrd + z_offset - 1 + var/zcrd = gset.zcrd + grid_z_offset // If we're using changeturf, we disable it if we load into a z level we JUST created var/no_afterchange = no_changeturf || zcrd > z_threshold @@ -420,7 +502,7 @@ if(!cache) SSatoms.map_loader_stop(REF(src)) CRASH("Undefined model key in DMM: [gset.gridLines[i]]") - build_coordinate(cache, locate(true_xcrd, ycrd, zcrd), no_afterchange, placeOnTop, new_z) + build_coordinate(cache, locate(true_xcrd, ycrd, zcrd), no_afterchange, place_on_top, new_z) // only bother with bounds that actually exist if(!first_found) @@ -444,7 +526,7 @@ /// Stanrdard loading, not used in production /// Doesn't take advantage of any tgm optimizations, which makes it slower but also more general /// Use this if for some reason your map format is messy -/datum/parsed_map/proc/_dmm_load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, new_z) +/datum/parsed_map/proc/_dmm_load(x_offset, y_offset, z_offset, crop_map, no_changeturf, x_lower, x_upper, y_lower, y_upper, z_lower, z_upper, place_on_top, new_z) // setup var/list/modelCache = build_cache(no_changeturf) var/space_key = modelCache[SPACE_KEY] @@ -455,23 +537,46 @@ var/y_relative_to_absolute = y_offset - 1 var/x_relative_to_absolute = x_offset - 1 var/line_len = src.line_len - for(var/datum/grid_set/gset as anything in gridSets) + + // Amount we offset the grid zcrd to get the true zcrd + var/grid_z_offset = z_offset - 1 + var/z_upper_set = z_upper < INFINITY + var/z_lower_set = z_lower > -INFINITY + + // we now need to find the maximum z, fun! + var/map_bounds_z_max = 1 + for(var/datum/grid_set/grid_set as anything in gridSets) + map_bounds_z_max = max(map_bounds_z_max, grid_set.zcrd) + + var/z_upper_parsed = map_bounds_z_max + z_offset - 1 + if(z_upper_set) + z_upper_parsed -= map_bounds_z_max - z_upper + if(z_lower_set) + var/offset_amount = z_lower - 1 + z_upper_parsed -= offset_amount + grid_z_offset -= offset_amount + + var/list/target_grid_sets = gridSets + if(z_lower_set || z_upper_set) // bounds are set, filter out gridsets for z levels we don't want + target_grid_sets = filter_grid_sets_based_on_z_bounds(z_lower, z_upper) + + for(var/datum/grid_set/gset as anything in target_grid_sets) var/relative_x = gset.xcrd var/relative_y = gset.ycrd var/true_xcrd = relative_x + x_relative_to_absolute var/ycrd = relative_y + y_relative_to_absolute - var/zcrd = gset.zcrd + z_offset - 1 - if(!cropMap && ycrd > world.maxy) + var/zcrd = gset.zcrd + grid_z_offset + if(!crop_map && ycrd > world.maxy) if(new_z) // Need to avoid improperly loaded area/turf_contents - world.increaseMaxY(ycrd, max_zs_to_load = z_offset - 1) + world.increase_max_y(ycrd, map_load_z_cutoff = z_offset - 1) else - world.increaseMaxY(ycrd) + world.increase_max_y(ycrd) expanded_y = TRUE var/zexpansion = zcrd > world.maxz var/no_afterchange = no_changeturf if(zexpansion) - if(cropMap) + if(crop_map) continue else while (zcrd > world.maxz) //create a new z_level if needed @@ -508,7 +613,7 @@ var/x_step_count = ROUND_UP(x_target / key_len) var/final_x = relative_x + (x_step_count - 1) var/x_delta_with = x_upper - if(cropMap) + if(crop_map) // Take our smaller crop threshold yes? x_delta_with = min(x_delta_with, world.maxx) if(final_x > x_delta_with) @@ -517,12 +622,12 @@ x_step_count -= delta final_x -= delta x_target = x_step_count * key_len - if(final_x > world.maxx && !cropMap) + if(final_x > world.maxx && !crop_map) if(new_z) // Need to avoid improperly loaded area/turf_contents - world.increaseMaxX(final_x, max_zs_to_load = z_offset - 1) + world.increase_max_x(final_x, map_load_z_cutoff = z_offset - 1) else - world.increaseMaxX(final_x) + world.increase_max_x(final_x) expanded_x = TRUE // We're gonna track the first and last pairs of coords we find @@ -553,7 +658,7 @@ if(!cache) SSatoms.map_loader_stop(REF(src)) CRASH("Undefined model key in DMM: [model_key]") - build_coordinate(cache, locate(xcrd, ycrd, zcrd), no_afterchange, placeOnTop, new_z) + build_coordinate(cache, locate(xcrd, ycrd, zcrd), no_afterchange, place_on_top, new_z) // only bother with bounds that actually exist if(!first_found) diff --git a/code/modules/mapping/ruins.dm b/code/modules/mapping/ruins.dm index 01a91a10c2a11f..a7b9480a34e4af 100644 --- a/code/modules/mapping/ruins.dm +++ b/code/modules/mapping/ruins.dm @@ -51,10 +51,10 @@ return central_turf /datum/map_template/ruin/proc/place_on_isolated_level(z) - var/datum/turf_reservation/reservation = SSmapping.RequestBlockReservation(width, height, z) //Make the new level creation work with different traits. + var/datum/turf_reservation/reservation = SSmapping.request_turf_block_reservation(width, height, 1, z) //Make the new level creation work with different traits. if(!reservation) return - var/turf/placement = locate(reservation.bottom_left_coords[1],reservation.bottom_left_coords[2],reservation.bottom_left_coords[3]) + var/turf/placement = reservation.bottom_left_turfs[1] load(placement) loaded++ for(var/turf/T in get_affected_turfs(placement)) diff --git a/code/modules/mapping/space_management/multiz_helpers.dm b/code/modules/mapping/space_management/multiz_helpers.dm index f2331eb514613d..b0e2ff7fa06568 100644 --- a/code/modules/mapping/space_management/multiz_helpers.dm +++ b/code/modules/mapping/space_management/multiz_helpers.dm @@ -1,10 +1,11 @@ /proc/get_step_multiz(ref, dir) + var/turf/us = get_turf(ref) if(dir & UP) dir &= ~UP - return get_step(GET_TURF_ABOVE(get_turf(ref)), dir) + return get_step(GET_TURF_ABOVE(us), dir) if(dir & DOWN) dir &= ~DOWN - return get_step(GET_TURF_BELOW(get_turf(ref)), dir) + return get_step(GET_TURF_BELOW(us), dir) return get_step(ref, dir) /proc/get_dir_multiz(turf/us, turf/them) @@ -15,27 +16,21 @@ if(us.z == them.z) return get_dir(us, them) else - var/turf/T = us.above() + var/turf/T = GET_TURF_ABOVE(us) var/dir = NONE if(T && (T.z == them.z)) dir = UP else - T = us.below() + T = GET_TURF_BELOW(us) if(T && (T.z == them.z)) dir = DOWN else return get_dir(us, them) return (dir | get_dir(us, them)) -/turf/proc/above() - return GET_TURF_ABOVE(src) - -/turf/proc/below() - return GET_TURF_BELOW(src) - /proc/get_lowest_turf(atom/ref) var/turf/us = get_turf(ref) - var/next = GET_TURF_BELOW(us) + var/turf/next = GET_TURF_BELOW(us) while(next) us = next next = GET_TURF_BELOW(us) @@ -44,7 +39,7 @@ // I wish this was lisp /proc/get_highest_turf(atom/ref) var/turf/us = get_turf(ref) - var/next = GET_TURF_ABOVE(us) + var/turf/next = GET_TURF_ABOVE(us) while(next) us = next next = GET_TURF_ABOVE(us) diff --git a/code/modules/mapping/space_management/space_reservation.dm b/code/modules/mapping/space_management/space_reservation.dm index 52ac76e343aa58..2809ae65e6c2e1 100644 --- a/code/modules/mapping/space_management/space_reservation.dm +++ b/code/modules/mapping/space_management/space_reservation.dm @@ -1,16 +1,33 @@ //Yes, they can only be rectangular. //Yes, I'm sorry. /datum/turf_reservation + /// All turfs that we've reserved var/list/reserved_turfs = list() - ///Turfs around the reservation for cordoning + + /// Turfs around the reservation for cordoning var/list/cordon_turfs = list() - ///Area of turfs next to the cordon to fill with pre_cordon_area's + + /// Area of turfs next to the cordon to fill with pre_cordon_area's var/list/pre_cordon_turfs = list() + + /// The width of the reservation var/width = 0 + + /// The height of the reservation var/height = 0 - var/bottom_left_coords[3] - var/top_right_coords[3] + + /// The z stack size of the reservation. Note that reservations are ALWAYS reserved from the bottom up + var/z_size = 0 + + /// List of the bottom left turfs. Indexed by what their z index for this reservation is + var/list/bottom_left_turfs = list() + + /// List of the top right turfs. Indexed by what their z index for this reservation is + var/list/top_right_turfs = list() + + /// The turf type the reservation is initially made with var/turf_type = /turf/open/space + ///Distance away from the cordon where we can put a "sort-cordon" and run some extra code (see make_repel). 0 makes nothing happen var/pre_cordon_distance = 0 @@ -19,6 +36,9 @@ pre_cordon_distance = 7 /datum/turf_reservation/proc/Release() + bottom_left_turfs.Cut() + top_right_turfs.Cut() + var/list/reserved_copy = reserved_turfs.Copy() SSmapping.used_turfs -= reserved_turfs reserved_turfs = list() @@ -36,20 +56,20 @@ INVOKE_ASYNC(SSmapping, TYPE_PROC_REF(/datum/controller/subsystem/mapping, reserve_turfs), release_turfs) /// Attempts to calaculate and store a list of turfs around the reservation for cordoning. Returns whether a valid cordon was calculated -/datum/turf_reservation/proc/calculate_cordon_turfs(turf/BL, turf/TR) - if(BL.x < 2 || BL.y < 2 || TR.x > (world.maxx - 2) || TR.y > (world.maxy - 2)) +/datum/turf_reservation/proc/calculate_cordon_turfs(turf/bottom_left, turf/top_right) + if(bottom_left.x < 2 || bottom_left.y < 2 || top_right.x > (world.maxx - 2) || top_right.y > (world.maxy - 2)) return FALSE // no space for a cordon here - var/list/possible_turfs = CORNER_OUTLINE(BL, width, height) + var/list/possible_turfs = CORNER_OUTLINE(bottom_left, width, height) + // if they're our cordon turfs, accept them + possible_turfs -= cordon_turfs for(var/turf/cordon_turf as anything in possible_turfs) - if(!(cordon_turf.flags_1 & UNUSED_RESERVATION_TURF)) + if(!(cordon_turf.turf_flags & UNUSED_RESERVATION_TURF)) return FALSE - cordon_turfs = possible_turfs - - pre_cordon_turfs.Cut() + cordon_turfs |= possible_turfs if(pre_cordon_distance) - var/turf/offset_turf = locate(BL.x + pre_cordon_distance, BL.y + pre_cordon_distance, BL.z) + var/turf/offset_turf = locate(bottom_left.x + pre_cordon_distance, bottom_left.y + pre_cordon_distance, bottom_left.z) var/list/to_add = CORNER_OUTLINE(offset_turf, width - pre_cordon_distance * 2, height - pre_cordon_distance * 2) //we step-by-stop move inwards from the outer cordon for(var/turf/turf_being_added as anything in to_add) pre_cordon_turfs |= turf_being_added //add one by one so we can filter out duplicates @@ -64,10 +84,11 @@ old_area.turfs_to_uncontain += cordon_turf cordon_area.contained_turfs += cordon_turf cordon_area.contents += cordon_turf + // Its no longer unused, but its also not "used" + cordon_turf.turf_flags &= ~UNUSED_RESERVATION_TURF cordon_turf.ChangeTurf(/turf/cordon, /turf/cordon) - - cordon_turf.flags_1 &= ~UNUSED_RESERVATION_TURF SSmapping.unused_turfs["[cordon_turf.z]"] -= cordon_turf + // still gets linked to us though SSmapping.used_turfs[cordon_turf] = src //swap the area with the pre-cordoning area @@ -113,7 +134,8 @@ if(!HAS_TRAIT(enterer, TRAIT_FREE_HYPERSPACE_SOFTCORDON_MOVEMENT)) space_dump(source, enterer) -/datum/turf_reservation/proc/Reserve(width, height, zlevel) +/// Internal proc which handles reserving the area for the reservation. +/datum/turf_reservation/proc/_reserve_area(width, height, zlevel) src.width = width src.height = height if(width > world.maxx || height > world.maxy || width < 1 || height < 1) @@ -126,12 +148,12 @@ for(var/i in avail) CHECK_TICK BL = i - if(!(BL.flags_1 & UNUSED_RESERVATION_TURF)) + if(!(BL.turf_flags & UNUSED_RESERVATION_TURF)) continue if(BL.x + width > world.maxx || BL.y + height > world.maxy) continue TR = locate(BL.x + width - 1, BL.y + height - 1, BL.z) - if(!(TR.flags_1 & UNUSED_RESERVATION_TURF)) + if(!(TR.turf_flags & UNUSED_RESERVATION_TURF)) continue final = block(BL, TR) if(!final) @@ -139,7 +161,7 @@ passing = TRUE for(var/I in final) var/turf/checking = I - if(!(checking.flags_1 & UNUSED_RESERVATION_TURF)) + if(!(checking.turf_flags & UNUSED_RESERVATION_TURF)) passing = FALSE break if(passing) // found a potentially valid area, now try to calculate its cordon @@ -149,18 +171,94 @@ break if(!passing || !istype(BL) || !istype(TR)) return FALSE - bottom_left_coords = list(BL.x, BL.y, BL.z) - top_right_coords = list(TR.x, TR.y, TR.z) for(var/i in final) var/turf/T = i reserved_turfs |= T - T.flags_1 &= ~UNUSED_RESERVATION_TURF SSmapping.unused_turfs["[T.z]"] -= T SSmapping.used_turfs[T] = src + T.turf_flags = (T.turf_flags | RESERVATION_TURF) & ~UNUSED_RESERVATION_TURF T.ChangeTurf(turf_type, turf_type) + + bottom_left_turfs += BL + top_right_turfs += TR + return TRUE + +/datum/turf_reservation/proc/reserve(width, height, z_size, z_reservation) + src.z_size = z_size + var/failed_reservation = FALSE + for(var/_ in 1 to z_size) + if(!_reserve_area(width, height, z_reservation)) + failed_reservation = TRUE + break + + if(failed_reservation) + Release() + return FALSE + generate_cordon() return TRUE +/// Calculates the effective bounds information for the given turf. Returns a list of the information, or null if not applicable. +/datum/turf_reservation/proc/calculate_turf_bounds_information(turf/target) + for(var/z_idx in 1 to z_size) + var/turf/bottom_left = bottom_left_turfs[z_idx] + var/turf/top_right = top_right_turfs[z_idx] + var/bl_x = bottom_left.x + var/bl_y = bottom_left.y + var/tr_x = top_right.x + var/tr_y = top_right.y + + if(target.x < bl_x) + continue + + if(target.y < bl_y) + continue + + if(target.x > tr_x) + continue + + if(target.y > tr_y) + continue + + var/list/return_information = list() + return_information["z_idx"] = z_idx + return_information["offset_x"] = target.x - bl_x + return_information["offset_y"] = target.y - bl_y + return return_information + return null + +/// Gets the turf below the given target. Returns null if there is no turf below the target +/datum/turf_reservation/proc/get_turf_below(turf/target) + var/list/bounds_info = calculate_turf_bounds_information(target) + if(isnull(bounds_info)) + return null + + var/z_idx = bounds_info["z_idx"] + // check what z level, if its the max, then there is no turf below + if(z_idx == z_size) + return null + + var/offset_x = bounds_info["offset_x"] + var/offset_y = bounds_info["offset_y"] + var/turf/bottom_left = bottom_left_turfs[z_idx + 1] + return locate(bottom_left.x + offset_x, bottom_left.y + offset_y, bottom_left.z) + +/// Gets the turf above the given target. Returns null if there is no turf above the target +/datum/turf_reservation/proc/get_turf_above(turf/target) + var/list/bounds_info = calculate_turf_bounds_information(target) + if(isnull(bounds_info)) + return null + + var/z_idx = bounds_info["z_idx"] + // check what z level, if its the min, then there is no turf above + if(z_idx == 1) + return null + + var/offset_x = bounds_info["offset_x"] + var/offset_y = bounds_info["offset_y"] + var/turf/bottom_left = bottom_left_turfs[z_idx - 1] + return locate(bottom_left.x + offset_x, bottom_left.y + offset_y, bottom_left.z) + /datum/turf_reservation/New() LAZYADD(SSmapping.turf_reservations, src) diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index a1edd69ba3e6ac..caee1bbac8d2bb 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -38,6 +38,7 @@ ) //technically it's huge and bulky, but this provides an incentive to use it AddComponent(/datum/component/two_handed, force_unwielded=0, force_wielded=20) + RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) /obj/item/kinetic_crusher/Destroy() QDEL_LIST(trophies) @@ -165,6 +166,10 @@ playsound(user, 'sound/weapons/empty.ogg', 100, TRUE) update_appearance() +/obj/item/kinetic_crusher/proc/on_saboteur(datum/source, disrupt_duration) + set_light_on(FALSE) + playsound(src, 'sound/weapons/empty.ogg', 100, TRUE) + return COMSIG_SABOTEUR_SUCCESS /obj/item/kinetic_crusher/update_icon_state() inhand_icon_state = "crusher[HAS_TRAIT(src, TRAIT_WIELDED)]" // this is not icon_state and not supported by 2hcomponent diff --git a/code/modules/mining/lavaland/megafauna_loot.dm b/code/modules/mining/lavaland/megafauna_loot.dm index ba9b3548ab873c..65d3a1ad3b3b1b 100644 --- a/code/modules/mining/lavaland/megafauna_loot.dm +++ b/code/modules/mining/lavaland/megafauna_loot.dm @@ -643,9 +643,10 @@ spirits = list() START_PROCESSING(SSobj, src) SSpoints_of_interest.make_point_of_interest(src) - AddComponent(/datum/component/butchering, \ - speed = 15 SECONDS, \ - effectiveness = 90, \ + AddComponent(\ + /datum/component/butchering, \ + speed = 15 SECONDS, \ + effectiveness = 90, \ ) /obj/item/melee/ghost_sword/Destroy() diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm index 4c0ca13dcd2fa1..ce045a81298531 100644 --- a/code/modules/mining/machine_redemption.dm +++ b/code/modules/mining/machine_redemption.dm @@ -370,7 +370,7 @@ var/amount = round(min(text2num(params["sheets"]), 50, can_smelt_alloy(alloy))) if(amount < 1) //no negative mats return - materials.use_materials(alloy.materials, action = "released", name = "sheets") + materials.use_materials(alloy.materials, multiplier = amount, action = "released", name = "sheets") var/output if(ispath(alloy.build_path, /obj/item/stack/sheet)) output = new alloy.build_path(src, amount) diff --git a/code/modules/mining/machine_silo.dm b/code/modules/mining/machine_silo.dm index dc15e28a9270ed..840c8e92900a89 100644 --- a/code/modules/mining/machine_silo.dm +++ b/code/modules/mining/machine_silo.dm @@ -165,8 +165,8 @@ GLOBAL_LIST_EMPTY(silo_access_logs) /obj/machinery/ore_silo/multitool_act(mob/living/user, obj/item/multitool/I) . = ..() if (istype(I)) - to_chat(user, span_notice("You log [src] in the multitool's buffer.")) I.set_buffer(src) + balloon_alert(user, "saved to multitool buffer") return TRUE /** diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machine_stacking.dm index d7381d48e66f3b..286317a5d74ebc 100644 --- a/code/modules/mining/machine_stacking.dm +++ b/code/modules/mining/machine_stacking.dm @@ -27,7 +27,7 @@ return var/obj/item/multitool/M = I M.set_buffer(src) - to_chat(user, span_notice("You store linkage information in [I]'s buffer.")) + balloon_alert(user, "saved to multitool buffer") return TRUE /obj/machinery/mineral/stacking_unit_console/ui_interact(mob/user, datum/tgui/ui) diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 7cb099f6585a54..a38fe1711742ec 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -125,13 +125,15 @@ if(JOB_NOT_VETERAN) return "You need to be veteran to join as [jobtitle]." if(JOB_UNAVAILABLE_QUIRK) - return "[jobtitle] is restricted from your quirks." + return "[jobtitle] is restricted due to your selected quirks." if(JOB_UNAVAILABLE_LANGUAGE) - return "[jobtitle] is restricted from your languages." + return "[jobtitle] is restricted due to your selected languages." if(JOB_UNAVAILABLE_SPECIES) - return "[jobtitle] is restricted from your species." + return "[jobtitle] is restricted due to your selected species." if(JOB_UNAVAILABLE_FLAVOUR) return "[jobtitle] requires you to have flavour text for your character." + if(JOB_UNAVAILABLE_AUGMENT) + return "[jobtitle] is restricted due to your selected body augments." //SKYRAT EDIT END if(JOB_UNAVAILABLE_ANTAG_INCOMPAT) return "[jobtitle] is not compatible with some antagonist role assigned to you." diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm index 9b8a192260fc34..a1c7c0371b0004 100644 --- a/code/modules/mob/dead/new_player/preferences_setup.dm +++ b/code/modules/mob/dead/new_player/preferences_setup.dm @@ -25,6 +25,7 @@ /datum/preferences/proc/hardcore_random_setup(mob/living/carbon/human/character) var/next_hardcore_score = select_hardcore_quirks() character.hardcore_survival_score = next_hardcore_score ** 1.2 //30 points would be about 60 score + log_admin("[character] started hardcore random with [english_list(all_quirks)], for a score of [next_hardcore_score].") //Add a sixpack because honestly var/obj/item/bodypart/chest/chest = character.get_bodypart(BODY_ZONE_CHEST) diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index ff2e414dd7013d..0688778b04840e 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -117,7 +117,7 @@ return if(user.get_timed_status_effect_duration(/datum/status_effect/confusion) > BEYBLADE_PUKE_THRESHOLD) - user.vomit(BEYBLADE_PUKE_NUTRIENT_LOSS, distance = 0) + user.vomit(VOMIT_CATEGORY_KNOCKDOWN, lost_nutrition = BEYBLADE_PUKE_NUTRIENT_LOSS, distance = 0) return if(prob(BEYBLADE_DIZZINESS_PROBABILITY)) diff --git a/code/modules/mob/living/basic/basic.dm b/code/modules/mob/living/basic/basic.dm index 44c11bdc056707..155321805c621e 100644 --- a/code/modules/mob/living/basic/basic.dm +++ b/code/modules/mob/living/basic/basic.dm @@ -35,6 +35,8 @@ var/attack_vis_effect ///Played when someone punches the creature. var/attacked_sound = SFX_PUNCH //This should be an element + /// How often can you melee attack? + var/melee_attack_cooldown = 2 SECONDS /// Variable maintained for compatibility with attack_animal procs until simple animals can be refactored away. Use element instead of setting manually. var/environment_smash = ENVIRONMENT_SMASH_STRUCTURES @@ -191,8 +193,10 @@ return . += span_deadsay("Upon closer examination, [p_they()] appear[p_s()] to be [HAS_TRAIT(user.mind, TRAIT_NAIVE) ? "asleep" : "dead"].") -/mob/living/basic/proc/melee_attack(atom/target, list/modifiers) +/mob/living/basic/proc/melee_attack(atom/target, list/modifiers, ignore_cooldown = FALSE) face_atom(target) + if (!ignore_cooldown) + changeNext_move(melee_attack_cooldown) if(SEND_SIGNAL(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, target) & COMPONENT_HOSTILE_NO_ATTACK) return FALSE //but more importantly return before attack_animal called var/result = target.attack_basic_mob(src, modifiers) diff --git a/code/modules/mob/living/basic/farm_animals/pony.dm b/code/modules/mob/living/basic/farm_animals/pony.dm index 434caa5ef51924..4bc09391cb7183 100644 --- a/code/modules/mob/living/basic/farm_animals/pony.dm +++ b/code/modules/mob/living/basic/farm_animals/pony.dm @@ -62,7 +62,7 @@ if (prob(33)) whinny_angrily() -/mob/living/basic/pony/melee_attack(atom/target, list/modifiers) +/mob/living/basic/pony/melee_attack(atom/target, list/modifiers, ignore_cooldown = FALSE) . = ..() if (!.) diff --git a/code/modules/mob/living/basic/heretic/star_gazer.dm b/code/modules/mob/living/basic/heretic/star_gazer.dm index 099efd80172c34..b739da0831a210 100644 --- a/code/modules/mob/living/basic/heretic/star_gazer.dm +++ b/code/modules/mob/living/basic/heretic/star_gazer.dm @@ -6,7 +6,7 @@ icon_living = "star_gazer" pixel_x = -32 base_pixel_x = -32 - mob_biotypes = MOB_HUMANOID | MOB_EPIC + mob_biotypes = MOB_HUMANOID | MOB_SPECIAL response_help_continuous = "passes through" response_help_simple = "pass through" speed = -0.2 @@ -22,6 +22,7 @@ attack_verb_simple = "ravage" attack_vis_effect = ATTACK_EFFECT_SLASH attack_sound = 'sound/weapons/bladeslice.ogg' + melee_attack_cooldown = 0.6 SECONDS speak_emote = list("growls") damage_coeff = list(BRUTE = 1, BURN = 0.5, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) death_sound = 'sound/magic/cosmic_expansion.ogg' @@ -57,6 +58,24 @@ ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, INNATE_TRAIT) set_light(4, l_color = "#dcaa5b") +// Star gazer attacks everything around itself applies a spooky mark +/mob/living/basic/heretic_summon/star_gazer/melee_attack(mob/living/target, list/modifiers, ignore_cooldown) + . = ..() + if (!. || !isliving(target)) + return + + target.apply_status_effect(/datum/status_effect/star_mark) + target.apply_damage(damage = 5, damagetype = CLONE) + var/datum/targetting_datum/target_confirmer = ai_controller.blackboard[BB_TARGETTING_DATUM] + for(var/mob/living/nearby_mob in range(1, src)) + if(target == nearby_mob || !target_confirmer?.can_attack(src, nearby_mob)) + continue + nearby_mob.apply_status_effect(/datum/status_effect/star_mark) + nearby_mob.apply_damage(10) + to_chat(nearby_mob, span_userdanger("\The [src] [attack_verb_continuous] you!")) + do_attack_animation(nearby_mob, ATTACK_EFFECT_SLASH) + log_combat(src, nearby_mob, "slashed") + /datum/ai_controller/basic_controller/star_gazer blackboard = list( BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/star_gazer(), @@ -70,39 +89,12 @@ /datum/ai_planning_subtree/pet_planning, /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/attack_obstacle_in_path/star_gazer, - /datum/ai_planning_subtree/basic_melee_attack_subtree/star_gazer, + /datum/ai_planning_subtree/basic_melee_attack_subtree, ) /datum/targetting_datum/basic/star_gazer stat_attack = HARD_CRIT -/datum/ai_planning_subtree/basic_melee_attack_subtree/star_gazer - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/star_gazer - -/datum/ai_behavior/basic_melee_attack/star_gazer - action_cooldown = 0.6 SECONDS - -/datum/ai_behavior/basic_melee_attack/star_gazer/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) - . = ..() - var/atom/target = controller.blackboard[target_key] - var/mob/living/living_pawn = controller.pawn - - if(!isliving(target)) - return - var/mob/living/living_target = target - living_target.apply_status_effect(/datum/status_effect/star_mark) - living_target.apply_damage_type(damage = 5, damagetype = CLONE) - if(living_target.pulledby != living_pawn) - if(living_pawn.Adjacent(living_target) && isturf(living_target.loc) && living_target.stat == SOFT_CRIT) - living_target.grabbedby(living_pawn) - for(var/mob/living/nearby_mob in range(1, living_pawn)) - if(nearby_mob.stat == DEAD || living_target == nearby_mob || faction_check(nearby_mob.faction, list(FACTION_HERETIC))) - continue - nearby_mob.apply_status_effect(/datum/status_effect/star_mark) - nearby_mob.adjustBruteLoss(10) - living_pawn.do_attack_animation(nearby_mob, ATTACK_EFFECT_SLASH) - log_combat(living_pawn, nearby_mob, "slashed") - /datum/ai_planning_subtree/attack_obstacle_in_path/star_gazer attack_behaviour = /datum/ai_behavior/attack_obstructions/star_gazer @@ -119,4 +111,4 @@ command_feedback = "stares!" pointed_reaction = "stares intensely!" refuse_reaction = "..." - attack_behaviour = /datum/ai_behavior/basic_melee_attack/star_gazer + attack_behaviour = /datum/ai_behavior/basic_melee_attack diff --git a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm index 465d724944b2f9..292766be07bf90 100644 --- a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm +++ b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm @@ -69,6 +69,7 @@ INVOKE_ASYNC(src, PROC_REF(cannibalize_victim), victim) return COMPONENT_HOSTILE_NO_ATTACK +/// Carve a stone into a beautiful self-portrait /mob/living/basic/mining/ice_whelp/proc/create_sculpture(atom/target) balloon_alert(src, "sculpting...") if(!do_after(src, 5 SECONDS, target = target)) @@ -80,7 +81,9 @@ dragon_statue.set_anchored(TRUE) qdel(target) +/// Gib and consume our fellow ice drakes /mob/living/basic/mining/ice_whelp/proc/cannibalize_victim(mob/living/target) + start_pulling(target) balloon_alert(src, "devouring...") if(!do_after(src, 5 SECONDS, target)) return diff --git a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm index 08c5fda3fd89e0..9885ba3da590f6 100644 --- a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm +++ b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm @@ -58,7 +58,6 @@ finish_action(controller, FALSE) return - living_pawn.start_pulling(target) living_pawn.melee_attack(target) finish_action(controller, TRUE) diff --git a/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm b/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm index 83369de8862d61..c433ec936ad5ba 100644 --- a/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm +++ b/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm @@ -9,7 +9,7 @@ ai_movement = /datum/ai_movement/basic_avoidance idle_behavior = /datum/idle_behavior/idle_random_walk planning_subtrees = list( - /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/target_retaliate/check_faction, /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/find_food, /datum/ai_planning_subtree/targeted_mob_ability/goliath_tentacles, diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm index 6463fc94979840..18cd73219362e9 100644 --- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm +++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm @@ -18,6 +18,7 @@ attack_verb_simple = "snip" attack_sound = 'sound/weapons/bite.ogg' attack_vis_effect = ATTACK_EFFECT_BITE // Closer than a scratch to a crustacean pinching effect + melee_attack_cooldown = 1 SECONDS butcher_results = list( /obj/item/food/meat/crab = 2, /obj/item/stack/sheet/bone = 2, @@ -35,6 +36,7 @@ /mob/living/basic/mining/lobstrosity/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_SNOWSTORM_IMMUNE, INNATE_TRAIT) + AddElement(/datum/element/mob_grabber) AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW) AddElement(/datum/element/basic_eating, food_types = target_foods) AddElement(\ @@ -73,7 +75,7 @@ return var/mob/living/basic/basic_source = source var/mob/living/living_target = target - basic_source.melee_attack(living_target) + basic_source.melee_attack(living_target, ignore_cooldown = TRUE) basic_source.ai_controller?.set_blackboard_key(BB_BASIC_MOB_FLEEING, FALSE) basic_source.start_pulling(living_target) diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm index dcbeb1e670ca6d..8e4dfe9e29463f 100644 --- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm +++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm @@ -36,7 +36,6 @@ return ..() /datum/ai_behavior/basic_melee_attack/lobster - action_cooldown = 1 SECONDS /datum/ai_behavior/basic_melee_attack/lobster/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) var/mob/living/target = controller.blackboard[target_key] @@ -53,9 +52,6 @@ if (controller.blackboard[BB_BASIC_MOB_FLEEING]) finish_action(controller = controller, succeeded = TRUE, target_key = target_key) // We don't want to clear our target return - var/mob/living/living_pawn = controller.pawn - if (target.stat != CONSCIOUS) - living_pawn.start_pulling(target) // No crawling away return ..() /datum/ai_planning_subtree/flee_target/lobster @@ -75,6 +71,10 @@ finish_action(controller, succeeded = FALSE) return + var/mob/living/us = controller.pawn + if (us.pulling == target) + us.stop_pulling() // If we're running away from someone, best not to bring them with us + return ..() /// Don't use charge ability on an adjacent target, and make sure you're visible before you start diff --git a/code/modules/mob/living/basic/lavaland/watcher/watcher.dm b/code/modules/mob/living/basic/lavaland/watcher/watcher.dm index b94ba9142980c9..28ed712d06127a 100644 --- a/code/modules/mob/living/basic/lavaland/watcher/watcher.dm +++ b/code/modules/mob/living/basic/lavaland/watcher/watcher.dm @@ -1,4 +1,4 @@ -/// A floating eyeball which keeps its distance and plays red light/green light with you. +/// A floating eyeball which keeps its distance and sometimes make you look away. /mob/living/basic/mining/watcher name = "watcher" desc = "A levitating, monocular creature held aloft by wing-like veins. A sharp spine of crystal protrudes from its body." @@ -59,14 +59,10 @@ ) update_appearance(UPDATE_OVERLAYS) - var/datum/action/cooldown/mob_cooldown/watcher_overwatch/overwatch = new(src) - overwatch.Grant(src) - overwatch.projectile_type = projectile_type - ai_controller.set_blackboard_key(BB_WATCHER_OVERWATCH, overwatch) - var/datum/action/cooldown/mob_cooldown/watcher_gaze/gaze = new gaze_attack(src) gaze.Grant(src) - ai_controller.set_blackboard_key(BB_WATCHER_GAZE, gaze) + ai_controller.set_blackboard_key(BB_GENERIC_ACTION, gaze) + AddComponent(/datum/component/revenge_ability, gaze, targetting = ai_controller.blackboard[BB_TARGETTING_DATUM]) /mob/living/basic/mining/watcher/update_overlays() . = ..() diff --git a/code/modules/mob/living/basic/lavaland/watcher/watcher_ai.dm b/code/modules/mob/living/basic/lavaland/watcher/watcher_ai.dm index b08245963f43b9..9b2972a398fb3f 100644 --- a/code/modules/mob/living/basic/lavaland/watcher/watcher_ai.dm +++ b/code/modules/mob/living/basic/lavaland/watcher/watcher_ai.dm @@ -6,41 +6,23 @@ ai_movement = /datum/ai_movement/basic_avoidance idle_behavior = /datum/idle_behavior/idle_random_walk planning_subtrees = list( - /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/target_retaliate/check_faction, /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/use_mob_ability/gaze, - /datum/ai_planning_subtree/targeted_mob_ability/overwatch, /datum/ai_planning_subtree/ranged_skirmish/watcher, /datum/ai_planning_subtree/maintain_distance, ) -/datum/ai_planning_subtree/targeted_mob_ability/overwatch - ability_key = BB_WATCHER_OVERWATCH - operational_datums = list(/datum/component/ai_target_timer) - -/datum/ai_planning_subtree/targeted_mob_ability/overwatch/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - var/mob/living/living_pawn = controller.pawn - if (living_pawn.do_after_count()) - return // Don't interrupt our other ability - var/atom/target = controller.blackboard[target_key] - if (QDELETED(target) || HAS_TRAIT(target, TRAIT_OVERWATCH_IMMUNE)) - return // We should probably let miners move sometimes - var/time_on_target = controller.blackboard[BB_BASIC_MOB_HAS_TARGET_TIME] || 0 - if (time_on_target < 5 SECONDS) - return // We need to spend some time acquiring our target first - return ..() - /datum/ai_planning_subtree/use_mob_ability/gaze - ability_key = BB_WATCHER_GAZE finish_planning = TRUE /datum/ai_planning_subtree/use_mob_ability/gaze/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - var/mob/living/watcher = controller.pawn - if (watcher.health > watcher.maxHealth * 0.66) // When we're a little hurt - return var/mob/living/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] if (!isliving(target)) return // Don't do this if there's nothing hostile around or if our target is a mech + var/time_on_target = controller.blackboard[BB_BASIC_MOB_HAS_TARGET_TIME] || 0 + if (time_on_target < 5 SECONDS) + return // We need to spend some time acquiring our target first return ..() /datum/ai_planning_subtree/ranged_skirmish/watcher diff --git a/code/modules/mob/living/basic/lavaland/watcher/watcher_gaze.dm b/code/modules/mob/living/basic/lavaland/watcher/watcher_gaze.dm index e4eb9562f5336e..9426db41cca60d 100644 --- a/code/modules/mob/living/basic/lavaland/watcher/watcher_gaze.dm +++ b/code/modules/mob/living/basic/lavaland/watcher/watcher_gaze.dm @@ -8,7 +8,7 @@ button_icon_state = "gaze" background_icon_state = "bg_demon" overlay_icon_state = "bg_demon_border" - cooldown_time = 30 SECONDS + cooldown_time = 20 SECONDS check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_INCAPACITATED click_to_activate = FALSE shared_cooldown = NONE diff --git a/code/modules/mob/living/basic/lavaland/watcher/watcher_overwatch.dm b/code/modules/mob/living/basic/lavaland/watcher/watcher_overwatch.dm index 36ad2d61b4cf64..0c8194c524a938 100644 --- a/code/modules/mob/living/basic/lavaland/watcher/watcher_overwatch.dm +++ b/code/modules/mob/living/basic/lavaland/watcher/watcher_overwatch.dm @@ -1,5 +1,6 @@ /** * Automatically shoot at a target if they do anything while this is active on them. + * Currently not given to any mob, but retained so admins can use it. */ /datum/action/cooldown/mob_cooldown/watcher_overwatch name = "Overwatch" diff --git a/code/modules/mob/living/basic/pets/dog/_dog.dm b/code/modules/mob/living/basic/pets/dog/_dog.dm index 93947173cd922d..dd3b3b3a4634c6 100644 --- a/code/modules/mob/living/basic/pets/dog/_dog.dm +++ b/code/modules/mob/living/basic/pets/dog/_dog.dm @@ -33,6 +33,7 @@ attack_verb_simple = "bite" attack_sound = 'sound/weapons/bite.ogg' attack_vis_effect = ATTACK_EFFECT_BITE + melee_attack_cooldown = 0.8 SECONDS /// Instructions you can give to dogs var/static/list/pet_commands = list( /datum/pet_command/idle, diff --git a/code/modules/mob/living/basic/pets/dog/corgi.dm b/code/modules/mob/living/basic/pets/dog/corgi.dm index d072a1c897e18e..cb0df08d198b9e 100644 --- a/code/modules/mob/living/basic/pets/dog/corgi.dm +++ b/code/modules/mob/living/basic/pets/dog/corgi.dm @@ -44,27 +44,29 @@ /mob/living/basic/pet/dog/corgi/Exited(atom/movable/gone, direction) . = ..() + var/dropped_something = FALSE if(gone == inventory_head) + dropped_something = TRUE inventory_head = null - update_corgi_fluff() - update_appearance(UPDATE_OVERLAYS) if(gone == inventory_back) + dropped_something = TRUE inventory_back = null + if(dropped_something) update_corgi_fluff() update_appearance(UPDATE_OVERLAYS) /mob/living/basic/pet/dog/corgi/gib() - if(inventory_head) - inventory_head.forceMove(drop_location()) - inventory_head = null - if(inventory_back) - inventory_back.forceMove(drop_location()) - inventory_back = null + undress_dog() if(access_card) access_card.forceMove(drop_location()) access_card = null return ..() +/// Removes the hat and shirt (but not ID) of this corgi +/mob/living/basic/pet/dog/corgi/proc/undress_dog() + inventory_head?.forceMove(drop_location()) + inventory_back?.forceMove(drop_location()) + /mob/living/basic/pet/dog/corgi/examine(mob/user) . = ..() if(access_card) @@ -194,44 +196,42 @@ /mob/living/basic/pet/dog/corgi/proc/place_on_head(obj/item/item_to_add, mob/living/user) if(inventory_head) if(user) - to_chat(user, span_warning("You can't put more than one hat on [src]!")) - return - if(!item_to_add) - user.visible_message(span_notice("[user] pets [src]."), span_notice("You rest your hand on [src]'s head for a moment.")) - if(flags_1 & HOLOGRAM_1) - return - user.add_mood_event(REF(src), /datum/mood_event/pet_animal, src) - return + balloon_alert(user, "already wearing a hat!") + return FALSE + + if(isnull(item_to_add)) + if (!isnull(user)) + user.visible_message(span_notice("[user] pets [src]."), span_notice("You rest your hand on [src]'s head for a moment.")) + if(flags_1 & HOLOGRAM_1) + return + user.add_mood_event(REF(src), /datum/mood_event/pet_animal, src) + return FALSE if(user && !user.temporarilyRemoveItemFromInventory(item_to_add)) to_chat(user, span_warning("\The [item_to_add] is stuck to your hand, you cannot put it on [src]'s head!")) - return - - var/valid = FALSE - if(ispath(item_to_add.dog_fashion, /datum/dog_fashion/head)) - valid = TRUE + return FALSE //Various hats and items (worn on his head) change Ian's behaviour. His attributes are reset when a hat is removed. - - if(valid) - if(user && (stat == DEAD || HAS_TRAIT(src, TRAIT_FAKEDEATH))) - to_chat(user, span_notice("There is merely a dull, lifeless look in [real_name]'s eyes as you put \the [item_to_add] on [p_them()].")) - else if(user) - user.visible_message(span_notice("[user] puts [item_to_add] on [real_name]'s head. [src] looks at [user] and barks once."), - span_notice("You put [item_to_add] on [real_name]'s head. [src] gives you a peculiar look, then wags [p_their()] tail once and barks."), - span_hear("You hear a friendly-sounding bark.")) - item_to_add.forceMove(src) - inventory_head = item_to_add - update_corgi_fluff() - update_appearance(UPDATE_OVERLAYS) - else + if(!ispath(item_to_add.dog_fashion, /datum/dog_fashion/head)) to_chat(user, span_warning("You set [item_to_add] on [src]'s head, but it falls off!")) item_to_add.forceMove(drop_location()) if(prob(25)) step_rand(item_to_add) dance_rotate(src, set_original_dir = TRUE) + return FALSE - return valid + if (user) + if(stat == DEAD || HAS_TRAIT(src, TRAIT_FAKEDEATH)) + to_chat(user, span_notice("There is merely a dull, lifeless look in [real_name]'s eyes as you put \the [item_to_add] on [p_them()].")) + else + user.visible_message(span_notice("[user] puts [item_to_add] on [real_name]'s head. [src] looks at [user] and barks once."), + span_notice("You put [item_to_add] on [real_name]'s head. [src] gives you a peculiar look, then wags [p_their()] tail once and barks."), + span_hear("You hear a friendly-sounding bark.")) + item_to_add.forceMove(src) + inventory_head = item_to_add + update_corgi_fluff() + update_appearance(UPDATE_OVERLAYS) + return TRUE /mob/living/basic/pet/dog/corgi/proc/update_corgi_fluff() // First, change back to defaults @@ -380,6 +380,14 @@ Write_Memory(TRUE) return ..() +/mob/living/basic/pet/dog/corgi/ian/revive(full_heal_flags, excess_healing, force_grab_ghost) + . = ..() + if (!.) + return + if (!istype(inventory_head, /obj/item/clothing/glasses/eyepatch)) + inventory_head?.forceMove(drop_location()) + place_on_head(new /obj/item/clothing/glasses/eyepatch/medical) + /mob/living/basic/pet/dog/corgi/ian/narsie_act() playsound(src, 'sound/magic/demon_dies.ogg', 75, TRUE) var/mob/living/basic/pet/dog/corgi/narsie/narsIan = new(loc) @@ -453,30 +461,30 @@ can_be_shaved = FALSE unique_pet = TRUE held_state = "narsian" + /// Mobs we will consume in the name of Nar'Sie + var/static/list/edible_types = list(/mob/living/simple_animal/pet, /mob/living/basic/pet) -//this could maybe be turned into an element -/mob/living/basic/pet/dog/corgi/narsie/Life(seconds_per_tick = SSMOBS_DT, times_fired) +/mob/living/basic/pet/dog/corgi/narsie/Initialize(mapload) . = ..() - //consume simple_animal pets - for(var/mob/living/simple_animal/pet/simple_pet in range(1, src)) - if(simple_pet != src && !istype(simple_pet, /mob/living/basic/pet/dog/corgi/narsie)) - visible_message(span_warning("Dark magic resonating from [src] devours [simple_pet]!"), \ - "DELICIOUS SOULS") - playsound(src, 'sound/magic/demon_attack1.ogg', 75, TRUE) - new /obj/effect/temp_visual/cult/sac(get_turf(simple_pet)) - narsie_act() - simple_pet.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS) - simple_pet.gib() - //consume basic pets - for(var/mob/living/basic/pet/basic_pet in range(1, src)) - if(basic_pet != src && !istype(basic_pet, /mob/living/basic/pet/dog/corgi/narsie)) - visible_message(span_warning("Dark magic resonating from [src] devours [basic_pet]!"), \ - "DELICIOUS SOULS") - playsound(src, 'sound/magic/demon_attack1.ogg', 75, TRUE) - new /obj/effect/temp_visual/cult/sac(get_turf(basic_pet)) - narsie_act() - basic_pet.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS) - basic_pet.gib() + var/static/list/connections = list(COMSIG_ATOM_ENTERED = PROC_REF(on_prey_approached)) + AddComponent(/datum/component/connect_range, tracked = src, connections = connections, range = 1, works_in_containers = FALSE) + +/// Attempt to eat a pet we get near +/mob/living/basic/pet/dog/corgi/narsie/proc/on_prey_approached(atom/movable/dog, atom/movable/prey) + SIGNAL_HANDLER + if (!is_type_in_list(prey, edible_types) || istype(prey, type)) + return + visible_message(span_warning("Dark magic resonating from [src] devours [prey]!"), \ + "DELICIOUS SOULS") + playsound(src, 'sound/magic/demon_attack1.ogg', 75, TRUE) + new /obj/effect/temp_visual/cult/sac(get_turf(prey)) + narsie_act() + prey.investigate_log("has been sacrificed by [src].", INVESTIGATE_DEATHS) + if (isliving(prey)) + var/mob/living/living_sacrifice = prey + living_sacrifice.gib() + else + qdel(prey) /mob/living/basic/pet/dog/corgi/narsie/update_corgi_fluff() . = ..() diff --git a/code/modules/mob/living/basic/ruin_defender/stickman.dm b/code/modules/mob/living/basic/ruin_defender/stickman.dm index 8d0a5ab0cdedfc..107973135c78c1 100644 --- a/code/modules/mob/living/basic/ruin_defender/stickman.dm +++ b/code/modules/mob/living/basic/ruin_defender/stickman.dm @@ -13,6 +13,7 @@ attack_verb_simple = "punch" melee_damage_lower = 10 melee_damage_upper = 10 + melee_attack_cooldown = 1.5 SECONDS attack_sound = 'sound/weapons/punch1.ogg' combat_mode = TRUE faction = list(FACTION_STICKMAN) @@ -39,15 +40,9 @@ idle_behavior = /datum/idle_behavior/idle_random_walk planning_subtrees = list( /datum/ai_planning_subtree/simple_find_target, - /datum/ai_planning_subtree/basic_melee_attack_subtree/stickman + /datum/ai_planning_subtree/basic_melee_attack_subtree ) -/datum/ai_planning_subtree/basic_melee_attack_subtree/stickman - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/stickman - -/datum/ai_behavior/basic_melee_attack/stickman - action_cooldown = 1.5 SECONDS - /mob/living/basic/stickman/dog name = "Angry Stick Dog" desc = "Stickman's best friend, if he could see him at least." diff --git a/code/modules/mob/living/basic/space_fauna/bear/bear_ai_behavior.dm b/code/modules/mob/living/basic/space_fauna/bear/bear_ai_behavior.dm index 6e716ddf411b25..7c57349524fec0 100644 --- a/code/modules/mob/living/basic/space_fauna/bear/bear_ai_behavior.dm +++ b/code/modules/mob/living/basic/space_fauna/bear/bear_ai_behavior.dm @@ -1,6 +1,3 @@ -/datum/ai_behavior/basic_melee_attack/bear - action_cooldown = 2 SECONDS - /datum/ai_behavior/find_hunt_target/find_hive /datum/ai_behavior/find_hunt_target/find_hive/valid_dinner(mob/living/source, obj/structure/beebox/hive, radius) diff --git a/code/modules/mob/living/basic/space_fauna/bear/bear_ai_subtree.dm b/code/modules/mob/living/basic/space_fauna/bear/bear_ai_subtree.dm index 244c600d89fb43..851c0bb80290b2 100644 --- a/code/modules/mob/living/basic/space_fauna/bear/bear_ai_subtree.dm +++ b/code/modules/mob/living/basic/space_fauna/bear/bear_ai_subtree.dm @@ -8,16 +8,13 @@ planning_subtrees = list( /datum/ai_planning_subtree/target_retaliate, /datum/ai_planning_subtree/simple_find_target, - /datum/ai_planning_subtree/basic_melee_attack_subtree/bear, + /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/climb_trees, /datum/ai_planning_subtree/find_and_hunt_target/find_hive, /datum/ai_planning_subtree/find_and_hunt_target/find_honeycomb, /datum/ai_planning_subtree/random_speech/bear, ) -/datum/ai_planning_subtree/basic_melee_attack_subtree/bear - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/bear - /datum/ai_planning_subtree/find_and_hunt_target/find_hive target_key = BB_FOUND_HONEY hunting_behavior = /datum/ai_behavior/hunt_target/find_hive diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp.dm b/code/modules/mob/living/basic/space_fauna/carp/carp.dm index 6ce40d8c1a3b38..9a4b149fd1a003 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp.dm @@ -32,6 +32,7 @@ attack_vis_effect = ATTACK_EFFECT_BITE attack_verb_continuous = "bites" attack_verb_simple = "bite" + melee_attack_cooldown = 1.5 SECONDS response_help_continuous = "pets" response_help_simple = "pet" response_disarm_continuous = "gently pushes aside" @@ -57,7 +58,7 @@ /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targetting/attack/carp + /datum/pet_command/point_targetting/attack ) /// Carp want to eat raw meat var/static/list/desired_food = list(/obj/item/food/meat/slab, /obj/item/food/meat/rawcutlet) diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm index c0f5143f18c22f..b2dc866ce7cec7 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm @@ -1,17 +1,8 @@ #define MAGICARP_SPELL_TARGET_SEEK_RANGE 4 -/datum/pet_command/point_targetting/attack/carp - attack_behaviour = /datum/ai_behavior/basic_melee_attack/carp - /datum/pet_command/point_targetting/use_ability/magicarp pet_ability_key = BB_MAGICARP_SPELL -/datum/ai_planning_subtree/basic_melee_attack_subtree/carp - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/carp - -/datum/ai_behavior/basic_melee_attack/carp - action_cooldown = 1.5 SECONDS - /datum/ai_planning_subtree/attack_obstacle_in_path/carp attack_behaviour = /datum/ai_behavior/attack_obstructions/carp @@ -20,12 +11,12 @@ /// As basic attack tree but interrupt if your health gets low or if your spell is off cooldown /datum/ai_planning_subtree/basic_melee_attack_subtree/magicarp - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/carp/magic + melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/magicarp /// Interrupt your attack chain if: you have a spell, it's not on cooldown, and it has a target -/datum/ai_behavior/basic_melee_attack/carp/magic +/datum/ai_behavior/basic_melee_attack/magicarp -/datum/ai_behavior/basic_melee_attack/carp/magic/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key, health_ratio_key) +/datum/ai_behavior/basic_melee_attack/magicarp/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key, health_ratio_key) var/datum/action/cooldown/using_action = controller.blackboard[BB_MAGICARP_SPELL] if (QDELETED(using_action)) return ..() diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm index f4c446d088b960..b30970145352bc 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm @@ -25,7 +25,7 @@ /datum/ai_planning_subtree/attack_obstacle_in_path/carp, /datum/ai_planning_subtree/shortcut_to_target_through_carp_rift, /datum/ai_planning_subtree/make_carp_rift/aggressive_teleport, - /datum/ai_planning_subtree/basic_melee_attack_subtree/carp, + /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/carp_migration, ) @@ -48,7 +48,7 @@ /datum/ai_planning_subtree/attack_obstacle_in_path/carp, /datum/ai_planning_subtree/shortcut_to_target_through_carp_rift, /datum/ai_planning_subtree/make_carp_rift/aggressive_teleport, - /datum/ai_planning_subtree/basic_melee_attack_subtree/carp, + /datum/ai_planning_subtree/basic_melee_attack_subtree, ) /** @@ -91,6 +91,6 @@ /datum/ai_planning_subtree/attack_obstacle_in_path/carp, /datum/ai_planning_subtree/shortcut_to_target_through_carp_rift, /datum/ai_planning_subtree/make_carp_rift/aggressive_teleport, - /datum/ai_planning_subtree/basic_melee_attack_subtree/carp, + /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/carp_migration, ) diff --git a/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm b/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm index 5051335a5571e3..32f02b880dba40 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm @@ -56,7 +56,7 @@ GLOBAL_LIST_INIT(magicarp_spell_colours, list( /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targetting/attack/carp, + /datum/pet_command/point_targetting/attack, /datum/pet_command/point_targetting/use_ability/magicarp, ) /// List of all projectiles we can fire. diff --git a/code/modules/mob/living/basic/space_fauna/faithless.dm b/code/modules/mob/living/basic/space_fauna/faithless.dm index b279856412c3b7..c1dc297ea46a6e 100644 --- a/code/modules/mob/living/basic/space_fauna/faithless.dm +++ b/code/modules/mob/living/basic/space_fauna/faithless.dm @@ -18,6 +18,7 @@ attack_verb_continuous = "grips" attack_verb_simple = "grip" attack_sound = 'sound/hallucinations/growl1.ogg' + melee_attack_cooldown = 1 SECONDS speak_emote = list("growls") unsuitable_atmos_damage = 0 @@ -29,12 +30,29 @@ ai_controller = /datum/ai_controller/basic_controller/faithless + /// What are the odds we paralyze a target on attack + var/paralyze_chance = 12 + /// How long do we paralyze a target for if we attack them + var/paralyze_duration = 2 SECONDS + /mob/living/basic/faithless/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) AddElement(/datum/element/footstep, FOOTSTEP_MOB_SHOE) + AddElement(/datum/element/mob_grabber, steal_from_others = FALSE) AddComponent(/datum/component/pry_open_door) +/mob/living/basic/faithless/melee_attack(atom/target, list/modifiers, ignore_cooldown) + . = ..() + if (!. || !isliving(target)) + return + + var/mob/living/living_target = target + if (prob(paralyze_chance)) + living_target.Paralyze(paralyze_duration) + living_target.visible_message(span_danger("\The [src] knocks \the [target] down!"), \ + span_userdanger("\The [src] knocks you down!")) + /datum/ai_controller/basic_controller/faithless blackboard = list( BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/faithless(), @@ -47,37 +65,10 @@ /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/attack_obstacle_in_path, /datum/ai_planning_subtree/attack_obstacle_in_path/low_priority_target, - /datum/ai_planning_subtree/basic_melee_attack_subtree/faithless, + /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/find_and_hunt_target/look_for_light_fixtures, /datum/ai_planning_subtree/random_speech/faithless, ) /datum/targetting_datum/basic/faithless stat_attack = UNCONSCIOUS - -/datum/ai_planning_subtree/basic_melee_attack_subtree/faithless - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/faithless - -/datum/ai_behavior/basic_melee_attack/faithless - action_cooldown = 1 SECONDS - /// What are the odds we paralyze a target - var/paralyze_chance = 12 - /// How long do we paralyze a target for if we attack them - var/paralyze_duration = 2 SECONDS - -/datum/ai_behavior/basic_melee_attack/faithless/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) - . = ..() - var/atom/target = controller.blackboard[target_key] - var/mob/living/living_pawn = controller.pawn - - if(!isliving(target)) - return - var/mob/living/living_target = target - if(living_target.pulledby != living_pawn && !HAS_AI_CONTROLLER_TYPE(living_target.pulledby, /datum/ai_controller/basic_controller/faithless)) //Dont steal from my fellow faithless. - if(living_pawn.Adjacent(living_target) && isturf(living_target.loc) && living_target.stat == SOFT_CRIT) - living_target.grabbedby(living_pawn) //Drag their bodies around as a menace. - if(prob(paralyze_chance) && iscarbon(target)) - var/mob/living/carbon/carbon_target = target - carbon_target.Paralyze(paralyze_duration) - carbon_target.visible_message(span_danger("\The [living_pawn] knocks down \the [carbon_target]!"), \ - span_userdanger("\The [living_pawn] knocks you down!")) diff --git a/code/modules/mob/living/basic/space_fauna/garden_gnome.dm b/code/modules/mob/living/basic/space_fauna/garden_gnome.dm index 9b57eba8fe233e..d9dfc3c5343286 100644 --- a/code/modules/mob/living/basic/space_fauna/garden_gnome.dm +++ b/code/modules/mob/living/basic/space_fauna/garden_gnome.dm @@ -17,6 +17,7 @@ attack_verb_continuous = "punches" attack_verb_simple = "punch" attack_sound = 'sound/weapons/punch1.ogg' + melee_attack_cooldown = 1.2 SECONDS damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) speak_emote = list("announces") @@ -132,12 +133,6 @@ planning_subtrees = list( /datum/ai_planning_subtree/target_retaliate, /datum/ai_planning_subtree/attack_obstacle_in_path, - /datum/ai_planning_subtree/basic_melee_attack_subtree/garden_gnome, + /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/random_speech/garden_gnome, ) - -/datum/ai_planning_subtree/basic_melee_attack_subtree/garden_gnome - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/garden_gnome - -/datum/ai_behavior/basic_melee_attack/garden_gnome - action_cooldown = 1.2 SECONDS diff --git a/code/modules/mob/living/basic/space_fauna/headslug.dm b/code/modules/mob/living/basic/space_fauna/headslug.dm index b0fba4fadc1534..a417b6c13942b8 100644 --- a/code/modules/mob/living/basic/space_fauna/headslug.dm +++ b/code/modules/mob/living/basic/space_fauna/headslug.dm @@ -18,6 +18,7 @@ attack_verb_simple = "chomp" attack_sound = 'sound/weapons/bite.ogg' attack_vis_effect = ATTACK_EFFECT_BITE + mob_biotypes = MOB_ORGANIC|MOB_SPECIAL faction = list(FACTION_CREATURE) obj_damage = 0 environment_smash = ENVIRONMENT_SMASH_NONE @@ -39,10 +40,11 @@ /mob/living/basic/headslug/examine(mob/user) . = ..() - if(isnull(client)) - . += span_notice("It appears to be moving around listlessly.") - else - . += span_warning("It's moving around intelligently!") + if(stat != DEAD) + if(isnull(client)) + . += span_notice("It appears to be moving around listlessly.") + else + . += span_warning("It's moving around intelligently!") if (egg_lain) . += span_notice("Its reproductive equipment appears to have withered.") diff --git a/code/modules/mob/living/basic/space_fauna/lightgeist.dm b/code/modules/mob/living/basic/space_fauna/lightgeist.dm index 28debb6c0a1301..c70588f4502b45 100644 --- a/code/modules/mob/living/basic/space_fauna/lightgeist.dm +++ b/code/modules/mob/living/basic/space_fauna/lightgeist.dm @@ -21,6 +21,7 @@ health = 2 melee_damage_lower = 5 melee_damage_upper = 5 + melee_attack_cooldown = 5 SECONDS friendly_verb_continuous = "taps" friendly_verb_simple = "tap" density = FALSE @@ -65,10 +66,10 @@ complete_text = "%TARGET%'s wounds mend together.",\ ) -/mob/living/basic/lightgeist/melee_attack(atom/target, list/modifiers) - if (isliving(target)) +/mob/living/basic/lightgeist/melee_attack(atom/target, list/modifiers, ignore_cooldown = FALSE) + . = ..() + if (. && isliving(target)) faction |= REF(target) // Anyone we heal will treat us as a friend - return ..() /mob/living/basic/lightgeist/ghost() . = ..() @@ -86,7 +87,7 @@ planning_subtrees = list( /datum/ai_planning_subtree/simple_find_target, - /datum/ai_planning_subtree/basic_melee_attack_subtree/lightgeist, // We heal things by attacking them + /datum/ai_planning_subtree/basic_melee_attack_subtree, // We heal things by attacking them ) /// Attack only mobs who have damage that we can heal, I think this is specific enough not to be a generic type @@ -111,9 +112,3 @@ continue return TRUE return FALSE - -/datum/ai_planning_subtree/basic_melee_attack_subtree/lightgeist - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/lightgeist - -/datum/ai_behavior/basic_melee_attack/lightgeist - action_cooldown = 5 SECONDS diff --git a/code/modules/mob/living/basic/space_fauna/mushroom.dm b/code/modules/mob/living/basic/space_fauna/mushroom.dm index 5e52dabae7511f..e6d47e2db5cc9e 100644 --- a/code/modules/mob/living/basic/space_fauna/mushroom.dm +++ b/code/modules/mob/living/basic/space_fauna/mushroom.dm @@ -64,7 +64,7 @@ idle_behavior = /datum/idle_behavior/idle_random_walk planning_subtrees = list( /datum/ai_planning_subtree/simple_find_target, - /datum/ai_planning_subtree/basic_melee_attack_subtree/mushroom, + /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/find_and_hunt_target/mushroom_food, ) @@ -76,13 +76,6 @@ /datum/targetting_datum/basic/mushroom/faction_check(mob/living/living_mob, mob/living/the_target) return !living_mob.faction_check_mob(the_target, exact_match = check_factions_exactly) - -/datum/ai_planning_subtree/basic_melee_attack_subtree/mushroom - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/mushroom - -/datum/ai_behavior/basic_melee_attack/mushroom - action_cooldown = 2 SECONDS - /datum/ai_planning_subtree/find_and_hunt_target/mushroom_food target_key = BB_LOW_PRIORITY_HUNTING_TARGET hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/mushroom_food diff --git a/code/modules/mob/living/basic/space_fauna/netherworld/blankbody.dm b/code/modules/mob/living/basic/space_fauna/netherworld/blankbody.dm index 35d597e53ca9ae..5a7bb075f19c9d 100644 --- a/code/modules/mob/living/basic/space_fauna/netherworld/blankbody.dm +++ b/code/modules/mob/living/basic/space_fauna/netherworld/blankbody.dm @@ -14,6 +14,7 @@ attack_verb_simple = "punch" attack_sound = 'sound/weapons/bladeslice.ogg' attack_vis_effect = ATTACK_EFFECT_SLASH + melee_attack_cooldown = 1 SECONDS faction = list(FACTION_NETHER) speak_emote = list("screams") death_message = "falls apart into a fine dust." @@ -42,5 +43,5 @@ planning_subtrees = list( /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/attack_obstacle_in_path, - /datum/ai_planning_subtree/basic_melee_attack_subtree/average_speed, + /datum/ai_planning_subtree/basic_melee_attack_subtree, ) diff --git a/code/modules/mob/living/basic/space_fauna/netherworld/creature.dm b/code/modules/mob/living/basic/space_fauna/netherworld/creature.dm index 5fabbf2afb2e42..b38ada0f6e14a4 100644 --- a/code/modules/mob/living/basic/space_fauna/netherworld/creature.dm +++ b/code/modules/mob/living/basic/space_fauna/netherworld/creature.dm @@ -15,6 +15,7 @@ gold_core_spawnable = HOSTILE_SPAWN attack_sound = 'sound/weapons/bite.ogg' attack_vis_effect = ATTACK_EFFECT_BITE + melee_attack_cooldown = 1 SECONDS faction = list(FACTION_NETHER) speak_emote = list("screams") death_message = "gets his head split open." @@ -111,5 +112,5 @@ planning_subtrees = list( /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/attack_obstacle_in_path, - /datum/ai_planning_subtree/basic_melee_attack_subtree/average_speed, + /datum/ai_planning_subtree/basic_melee_attack_subtree, ) 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 57d90da264ab09..18dca95013e47f 100644 --- a/code/modules/mob/living/basic/space_fauna/netherworld/migo.dm +++ b/code/modules/mob/living/basic/space_fauna/netherworld/migo.dm @@ -12,6 +12,7 @@ speed = 1 attack_verb_continuous = "lacerates" attack_verb_simple = "lacerate" + melee_attack_cooldown = 1 SECONDS gold_core_spawnable = HOSTILE_SPAWN attack_sound = 'sound/weapons/bladeslice.ogg' attack_vis_effect = ATTACK_EFFECT_SLASH @@ -81,5 +82,5 @@ planning_subtrees = list( /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/attack_obstacle_in_path, - /datum/ai_planning_subtree/basic_melee_attack_subtree/average_speed, + /datum/ai_planning_subtree/basic_melee_attack_subtree, ) diff --git a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm index e423b5ff852d0f..7a30f88b4c27b4 100644 --- a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm @@ -161,6 +161,7 @@ nearby_roach.melee_damage_upper += 4 nearby_roach.obj_damage += 5 nearby_roach.ai_controller = new /datum/ai_controller/basic_controller/cockroach/sewer(nearby_roach) + nearby_roach.melee_attack_cooldown = 0.8 SECONDS nearby_roach.icon_state += "_sewer" nearby_roach.maxHealth += 1 @@ -232,7 +233,7 @@ if (istype(victim) && !(FACTION_RAT in victim.faction)) to_chat(victim, span_userdanger("With this last sip, you feel your body convulsing horribly from the contents you've ingested. As you contemplate your actions, you sense an awakened kinship with rat-kind and their newly risen leader!")) victim.faction |= FACTION_RAT - victim.vomit() + victim.vomit(VOMIT_CATEGORY_DEFAULT) metabolization_rate = 10 * REAGENTS_METABOLISM /datum/reagent/rat_spit/on_mob_life(mob/living/carbon/C) @@ -243,7 +244,7 @@ to_chat(C, span_warning("That food does not sit up well!")) C.adjust_disgust(5) else if(prob(5)) - C.vomit() + C.vomit(VOMIT_CATEGORY_DEFAULT) return ..() /datum/pet_command/protect_owner/glockroach diff --git a/code/modules/mob/living/basic/space_fauna/statue/statue.dm b/code/modules/mob/living/basic/space_fauna/statue/statue.dm index 7d13ee9a1abff8..bce35146ecfc69 100644 --- a/code/modules/mob/living/basic/space_fauna/statue/statue.dm +++ b/code/modules/mob/living/basic/space_fauna/statue/statue.dm @@ -27,6 +27,7 @@ attack_verb_simple = "claw" attack_sound = 'sound/hallucinations/growl1.ogg' attack_vis_effect = ATTACK_EFFECT_CLAW + melee_attack_cooldown = 1 SECONDS faction = list(FACTION_STATUE) speak_emote = list("screams") @@ -147,16 +148,10 @@ ai_movement = /datum/ai_movement/basic_avoidance planning_subtrees = list( /datum/ai_planning_subtree/simple_find_target, - /datum/ai_planning_subtree/basic_melee_attack_subtree/statue, + /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/find_and_hunt_target/look_for_light_fixtures, ) -/datum/ai_planning_subtree/basic_melee_attack_subtree/statue - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/statue - -/datum/ai_behavior/basic_melee_attack/statue - action_cooldown = 1 SECONDS - /mob/living/basic/statue/frosty name = "Frosty" desc = "Just a snowman. Just a snowman. Oh god, it's just a snowman." diff --git a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_ai.dm b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_ai.dm index f632a38dc1b20c..9d3a09c5348f2c 100644 --- a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_ai.dm +++ b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_ai.dm @@ -1,5 +1,3 @@ -#define WUMBO_ATTACK_COOLDOWN 2.5 SECONDS - /// Cowardly when small, aggressive when big. Tries to transform whenever possible. /datum/ai_controller/basic_controller/wumborian_fugu blackboard = list( @@ -15,23 +13,15 @@ /datum/ai_planning_subtree/targeted_mob_ability/inflate, /datum/ai_planning_subtree/flee_target, /datum/ai_planning_subtree/attack_obstacle_in_path/wumborian_fugu, - /datum/ai_planning_subtree/basic_melee_attack_subtree/wumborian_fugu, + /datum/ai_planning_subtree/basic_melee_attack_subtree, ) -/datum/ai_planning_subtree/basic_melee_attack_subtree/wumborian_fugu - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/wumborian_fugu - -/datum/ai_behavior/basic_melee_attack/wumborian_fugu - action_cooldown = WUMBO_ATTACK_COOLDOWN - /datum/ai_planning_subtree/attack_obstacle_in_path/wumborian_fugu attack_behaviour = /datum/ai_behavior/attack_obstructions/wumborian_fugu /datum/ai_behavior/attack_obstructions/wumborian_fugu can_attack_turfs = TRUE - action_cooldown = WUMBO_ATTACK_COOLDOWN + action_cooldown = 2.5 SECONDS /datum/ai_planning_subtree/targeted_mob_ability/inflate ability_key = BB_FUGU_INFLATE - -#undef WUMBO_ATTACK_COOLDOWN diff --git a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_fugu.dm b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_fugu.dm index e13bef354823ea..bf8be2051d8c14 100644 --- a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_fugu.dm +++ b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_fugu.dm @@ -29,6 +29,7 @@ melee_damage_upper = 0 attack_sound = 'sound/weapons/punch1.ogg' attack_vis_effect = ATTACK_EFFECT_BITE + melee_attack_cooldown = 2.5 SECONDS attack_verb_continuous = "chomps" attack_verb_simple = "chomp" friendly_verb_continuous = "floats near" diff --git a/code/modules/mob/living/basic/syndicate/syndicate.dm b/code/modules/mob/living/basic/syndicate/syndicate.dm index c11d592cd3b544..a4fd0981198de9 100644 --- a/code/modules/mob/living/basic/syndicate/syndicate.dm +++ b/code/modules/mob/living/basic/syndicate/syndicate.dm @@ -15,6 +15,7 @@ attack_verb_continuous = "punches" attack_verb_simple = "punch" attack_sound = 'sound/weapons/punch1.ogg' + melee_attack_cooldown = 1.2 SECONDS combat_mode = TRUE unsuitable_atmos_damage = 7.5 unsuitable_cold_damage = 7.5 diff --git a/code/modules/mob/living/basic/syndicate/syndicate_ai.dm b/code/modules/mob/living/basic/syndicate/syndicate_ai.dm index be24b37441a8c3..393ef19287e1f4 100644 --- a/code/modules/mob/living/basic/syndicate/syndicate_ai.dm +++ b/code/modules/mob/living/basic/syndicate/syndicate_ai.dm @@ -8,18 +8,12 @@ planning_subtrees = list( /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/attack_obstacle_in_path/syndicate, - /datum/ai_planning_subtree/basic_melee_attack_subtree/syndicate + /datum/ai_planning_subtree/basic_melee_attack_subtree, ) /datum/targetting_datum/basic/syndicate stat_attack = HARD_CRIT -/datum/ai_planning_subtree/basic_melee_attack_subtree/syndicate - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/syndicate - -/datum/ai_behavior/basic_melee_attack/syndicate - action_cooldown = 1.2 SECONDS - /datum/ai_planning_subtree/attack_obstacle_in_path/syndicate attack_behaviour = /datum/ai_behavior/attack_obstructions/syndicate diff --git a/code/modules/mob/living/basic/tree.dm b/code/modules/mob/living/basic/tree.dm index f93ab14a37f4ce..2a0806b105c983 100644 --- a/code/modules/mob/living/basic/tree.dm +++ b/code/modules/mob/living/basic/tree.dm @@ -74,7 +74,7 @@ our_turf.air.gases[/datum/gas/carbon_dioxide][MOLES] -= amt our_turf.atmos_spawn_air("[GAS_O2]=[amt]") -/mob/living/basic/tree/melee_attack(atom/target, list/modifiers) +/mob/living/basic/tree/melee_attack(atom/target, list/modifiers, ignore_cooldown = FALSE) . = ..() if(!.) @@ -107,12 +107,6 @@ idle_behavior = /datum/idle_behavior/idle_random_walk/less_walking planning_subtrees = list( /datum/ai_planning_subtree/simple_find_target, - /datum/ai_planning_subtree/basic_melee_attack_subtree/tree, + /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/random_speech/tree, ) - -/datum/ai_planning_subtree/basic_melee_attack_subtree/tree - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/tree - -/datum/ai_behavior/basic_melee_attack/tree - action_cooldown = 2 SECONDS diff --git a/code/modules/mob/living/basic/vermin/cockroach.dm b/code/modules/mob/living/basic/vermin/cockroach.dm index 7aff4a844d3da2..5c69ad904474f0 100644 --- a/code/modules/mob/living/basic/vermin/cockroach.dm +++ b/code/modules/mob/living/basic/vermin/cockroach.dm @@ -131,6 +131,7 @@ melee_damage_lower = 2.5 melee_damage_upper = 10 obj_damage = 10 + melee_attack_cooldown = 1 SECONDS gold_core_spawnable = HOSTILE_SPAWN attack_sound = 'sound/weapons/bladeslice.ogg' attack_vis_effect = ATTACK_EFFECT_SLASH @@ -165,31 +166,19 @@ /datum/ai_planning_subtree/pet_planning, /datum/ai_planning_subtree/random_speech/insect, /datum/ai_planning_subtree/simple_find_target, - /datum/ai_planning_subtree/basic_melee_attack_subtree/hauberoach, //If we are attacking someone, this will prevent us from hunting + /datum/ai_planning_subtree/basic_melee_attack_subtree, //If we are attacking someone, this will prevent us from hunting /datum/ai_planning_subtree/find_and_hunt_target/roach, ) -/datum/ai_planning_subtree/basic_melee_attack_subtree/hauberoach - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/hauberoach - -/datum/ai_behavior/basic_melee_attack/hauberoach //Slightly slower, as this is being made in feature freeze ;) - action_cooldown = 1 SECONDS - /datum/ai_controller/basic_controller/cockroach/sewer planning_subtrees = list( /datum/ai_planning_subtree/pet_planning, /datum/ai_planning_subtree/random_speech/insect, /datum/ai_planning_subtree/simple_find_target, - /datum/ai_planning_subtree/basic_melee_attack_subtree/sewer, + /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/find_and_hunt_target/roach, ) -/datum/ai_planning_subtree/basic_melee_attack_subtree/sewer - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/sewer - -/datum/ai_behavior/basic_melee_attack/sewer - action_cooldown = 0.8 SECONDS - /mob/living/basic/cockroach/glockroach/mobroach name = "mobroach" desc = "WE'RE FUCKED, THAT GLOCKROACH HAS A TOMMYGUN!" diff --git a/code/modules/mob/living/basic/vermin/frog.dm b/code/modules/mob/living/basic/vermin/frog.dm index 282ed17b00c261..191ea12b4df33c 100644 --- a/code/modules/mob/living/basic/vermin/frog.dm +++ b/code/modules/mob/living/basic/vermin/frog.dm @@ -17,6 +17,7 @@ obj_damage = 10 attack_verb_continuous = "bites" attack_verb_simple = "bite" + melee_attack_cooldown = 2.5 SECONDS response_help_continuous = "pets" response_help_simple = "pet" response_disarm_continuous = "pokes" @@ -85,19 +86,13 @@ planning_subtrees = list( /datum/ai_planning_subtree/target_retaliate, /datum/ai_planning_subtree/random_speech/frog, - /datum/ai_planning_subtree/basic_melee_attack_subtree/frog, + /datum/ai_planning_subtree/basic_melee_attack_subtree, ) -/datum/ai_planning_subtree/basic_melee_attack_subtree/frog - melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/frog - -/datum/ai_behavior/basic_melee_attack/frog - action_cooldown = 2.5 SECONDS - /datum/ai_controller/basic_controller/frog/trash planning_subtrees = list( /datum/ai_planning_subtree/pet_planning, /datum/ai_planning_subtree/random_speech/frog, /datum/ai_planning_subtree/simple_find_target, - /datum/ai_planning_subtree/basic_melee_attack_subtree/frog, + /datum/ai_planning_subtree/basic_melee_attack_subtree, ) diff --git a/code/modules/mob/living/basic/vermin/mouse.dm b/code/modules/mob/living/basic/vermin/mouse.dm index 1f2a5c7e41e3f3..0b3645b3e0f639 100644 --- a/code/modules/mob/living/basic/vermin/mouse.dm +++ b/code/modules/mob/living/basic/vermin/mouse.dm @@ -57,6 +57,7 @@ ) AddElement(/datum/element/connect_loc, loc_connections) make_tameable() + AddComponent(/datum/component/swarming, 16, 16) //max_x, max_y /mob/living/basic/mouse/proc/make_tameable() if (tame) @@ -116,7 +117,8 @@ . = ..(TRUE) // Now if we were't ACTUALLY gibbed, spawn the dead mouse if(!gibbed) - var/obj/item/food/deadmouse/mouse = new(loc, /* starting_reagent_purity = */ null, /* no_base_reagents = */ FALSE, /* dead_critter = */ src) + var/obj/item/food/deadmouse/mouse = new(loc) + mouse.copy_corpse(src) if(HAS_TRAIT(src, TRAIT_BEING_SHOCKED)) mouse.desc = "They're toast." mouse.add_atom_colour("#3A3A3A", FIXED_COLOUR_PRIORITY) @@ -301,16 +303,18 @@ var/body_color = "gray" var/critter_type = /mob/living/basic/mouse -/obj/item/food/deadmouse/Initialize(mapload, starting_reagent_purity, no_base_reagents, mob/living/basic/mouse/dead_critter) +/obj/item/food/deadmouse/Initialize(mapload) . = ..() - if(dead_critter) - body_color = dead_critter.body_color - critter_type = dead_critter.type - name = dead_critter.name - icon_state = dead_critter.icon_dead AddElement(/datum/element/swabable, CELL_LINE_TABLE_MOUSE, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 10) RegisterSignal(src, COMSIG_ATOM_ON_LAZARUS_INJECTOR, PROC_REF(use_lazarus)) +/// Copy properties from an imminently dead mouse +/obj/item/food/deadmouse/proc/copy_corpse(mob/living/basic/mouse/dead_critter) + body_color = dead_critter.body_color + critter_type = dead_critter.type + name = dead_critter.name + icon_state = dead_critter.icon_dead + /obj/item/food/deadmouse/examine(mob/user) . = ..() if (reagents?.has_reagent(/datum/reagent/yuck) || reagents?.has_reagent(/datum/reagent/fuel)) diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index 9608db4d4c613a..9354f02e2b2df9 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -88,7 +88,7 @@ //Makes a blood drop, leaking amt units of blood from the mob /mob/living/carbon/proc/bleed(amt) - if(!blood_volume) + if(!blood_volume || (status_flags & GODMODE)) return blood_volume = max(blood_volume - amt, 0) diff --git a/code/modules/mob/living/carbon/alien/organs.dm b/code/modules/mob/living/carbon/alien/organs.dm index 00c8a617c64fe4..5ef9b23c418212 100644 --- a/code/modules/mob/living/carbon/alien/organs.dm +++ b/code/modules/mob/living/carbon/alien/organs.dm @@ -51,21 +51,24 @@ actions_types = list(/datum/action/cooldown/alien/transfer) /obj/item/organ/internal/alien/plasmavessel/on_life(seconds_per_tick, times_fired) + var/delta_time = DELTA_WORLD_TIME(SSmobs) + //Instantly healing to max health in a single tick would be silly. If it takes 8 seconds to fire, then something's fucked. + var/delta_time_capped = min(delta_time, 8) //If there are alien weeds on the ground then heal if needed or give some plasma if(locate(/obj/structure/alien/weeds) in owner.loc) if(owner.health >= owner.maxHealth) - owner.adjustPlasma(plasma_rate * seconds_per_tick) + owner.adjustPlasma(plasma_rate * delta_time) else var/heal_amt = heal_rate if(!isalien(owner)) heal_amt *= 0.2 - owner.adjustPlasma(0.5 * plasma_rate * seconds_per_tick) - owner.adjustBruteLoss(-heal_amt * seconds_per_tick) - owner.adjustFireLoss(-heal_amt * seconds_per_tick) - owner.adjustOxyLoss(-heal_amt * seconds_per_tick) - owner.adjustCloneLoss(-heal_amt * seconds_per_tick) + owner.adjustPlasma(0.5 * plasma_rate * delta_time_capped) + owner.adjustBruteLoss(-heal_amt * delta_time_capped) + owner.adjustFireLoss(-heal_amt * delta_time_capped) + owner.adjustOxyLoss(-heal_amt * delta_time_capped) + owner.adjustCloneLoss(-heal_amt * delta_time_capped) else - owner.adjustPlasma(0.1 * plasma_rate * seconds_per_tick) + owner.adjustPlasma(0.1 * plasma_rate * delta_time) /obj/item/organ/internal/alien/plasmavessel/on_insert(mob/living/carbon/organ_owner) . = ..() diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 36399dbc71d4ff..b0a2f8018cc056 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -416,53 +416,76 @@ return 0 return ..() -/mob/living/carbon/proc/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, vomit_type = VOMIT_TOXIC, harm = TRUE, force = FALSE, purge_ratio = 0.1) +/// Proc that compels the mob to throw up. Returns TRUE if the mob actually threw up. +/mob/living/carbon/proc/vomit(vomit_flags = VOMIT_CATEGORY_DEFAULT, vomit_type = /obj/effect/decal/cleanable/vomit/toxic, lost_nutrition = 10, distance = 1, purge_ratio = 0.1) + var/force = (vomit_flags & MOB_VOMIT_FORCE) if((HAS_TRAIT(src, TRAIT_NOHUNGER) || HAS_TRAIT(src, TRAIT_TOXINLOVER)) && !force) return TRUE SEND_SIGNAL(src, COMSIG_CARBON_VOMITED, distance, force) + + // cache some stuff that we'll need later (at least multiple times) var/starting_dir = dir - if(nutrition < 100 && !blood && !force) + var/message = (vomit_flags & MOB_VOMIT_MESSAGE) + var/stun = (vomit_flags & MOB_VOMIT_STUN) + var/knockdown = (vomit_flags & MOB_VOMIT_KNOCKDOWN) + var/blood = (vomit_flags & MOB_VOMIT_BLOOD) + + if(!force && !blood && (nutrition < 100)) if(message) - visible_message(span_warning("[src] dry heaves!"), \ - span_userdanger("You try to throw up, but there's nothing in your stomach!")) + visible_message( + span_warning("[src] dry heaves!"), + span_userdanger("You try to throw up, but there's nothing in your stomach!"), + ) if(stun) Stun(20 SECONDS) + if(knockdown) + Knockdown(20 SECONDS) return TRUE if(is_mouth_covered()) //make this add a blood/vomit overlay later it'll be hilarious if(message) - visible_message(span_danger("[src] throws up all over [p_them()]self!"), \ - span_userdanger("You throw up all over yourself!")) + visible_message( + span_danger("[src] throws up all over [p_them()]self!"), + span_userdanger("You throw up all over yourself!"), + ) add_mood_event("vomit", /datum/mood_event/vomitself) distance = 0 else if(message) - visible_message(span_danger("[src] throws up!"), span_userdanger("You throw up!")) + visible_message( + span_danger("[src] throws up!"), + span_userdanger("You throw up!"), + ) if(!isflyperson(src)) add_mood_event("vomit", /datum/mood_event/vomit) if(stun) Stun(8 SECONDS) + if(knockdown) + Knockdown(8 SECONDS) playsound(get_turf(src), 'sound/effects/splat.ogg', 50, TRUE) - var/turf/T = get_turf(src) + + var/turf/location = get_turf(src) if(!blood) adjust_nutrition(-lost_nutrition) adjustToxLoss(-3) - for(var/i=0 to distance) + for(var/i = 0 to distance) if(blood) - if(T) - add_splatter_floor(T) - if(harm) + if(location) + add_splatter_floor(location) + if(vomit_flags & MOB_VOMIT_HARM) adjustBruteLoss(3) else - if(T) - T.add_vomit_floor(src, vomit_type, purge_ratio) //toxic barf looks different || call purge when doing detoxicfication to pump more chems out of the stomach. - T = get_step(T, starting_dir) - if (T?.is_blocked_turf()) + if(location) + location.add_vomit_floor(src, vomit_type, vomit_flags, purge_ratio) // call purge when doing detoxicfication to pump more chems out of the stomach. + + location = get_step(location, starting_dir) + if (location?.is_blocked_turf()) break + return TRUE /** @@ -1180,7 +1203,7 @@ /mob/living/carbon/proc/hypnosis_vulnerable() if(HAS_TRAIT(src, TRAIT_MINDSHIELD)) return FALSE - if(has_status_effect(/datum/status_effect/hallucination)) + if(has_status_effect(/datum/status_effect/hallucination) || has_status_effect(/datum/status_effect/drugginess)) return TRUE if(IsSleeping() || IsUnconscious()) return TRUE diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 3ab34e70230295..8a704a277b7dcc 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -31,7 +31,7 @@ /mob/living/carbon/is_mouth_covered(check_flags = ALL) if((check_flags & ITEM_SLOT_HEAD) && head && (head.flags_cover & HEADCOVERSMOUTH)) return head - if((check_flags & ITEM_SLOT_MASK) && wear_mask && (wear_mask.flags_cover & HEADCOVERSMOUTH)) + if((check_flags & ITEM_SLOT_MASK) && wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH)) return wear_mask return null @@ -102,7 +102,7 @@ if(I.force) var/attack_direction = get_dir(user, src) apply_damage(I.force, I.damtype, affecting, wound_bonus = I.wound_bonus, bare_wound_bonus = I.bare_wound_bonus, sharpness = I.get_sharpness(), attack_direction = attack_direction, attacking_item = I) - if(I.damtype == BRUTE && IS_ORGANIC_LIMB(affecting)) + if(I.damtype == BRUTE && affecting.can_bleed()) if(prob(33)) I.add_mob_blood(src) var/turf/location = get_turf(src) @@ -140,22 +140,35 @@ //SKYRAT EDIT ADDITION END var/extra_wound_details = "" + if(I.damtype == BRUTE && hit_bodypart.can_dismember()) + var/mangled_state = hit_bodypart.get_mangled_state() - var/bio_state = hit_bodypart.biological_state - if((mangled_state & BODYPART_MANGLED_FLESH) && (mangled_state & BODYPART_MANGLED_BONE)) + + var/bio_status = hit_bodypart.get_bio_state_status() + + var/has_exterior = ((bio_status & ANATOMY_EXTERIOR)) + var/has_interior = ((bio_status & ANATOMY_INTERIOR)) + + var/exterior_ready_to_dismember = (!has_exterior || ((mangled_state & BODYPART_MANGLED_EXTERIOR))) + var/interior_ready_to_dismember = (!has_interior || ((mangled_state & BODYPART_MANGLED_INTERIOR))) + + var/dismemberable = ((hit_bodypart.dismemberable_by_wound()) || hit_bodypart.dismemberable_by_total_damage()) + if (dismemberable) extra_wound_details = ", threatening to sever it entirely" - else if((mangled_state & BODYPART_MANGLED_FLESH && I.get_sharpness()) || ((mangled_state & BODYPART_MANGLED_BONE) && (bio_state & BIO_BONE) && !(bio_state & BIO_FLESH))) - extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] through to the bone" - else if((mangled_state & BODYPART_MANGLED_BONE && I.get_sharpness()) || ((mangled_state & BODYPART_MANGLED_FLESH) && (bio_state & BIO_FLESH) && !(bio_state & BIO_BONE))) - extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] at the remaining tissue" + else if((has_interior && (has_exterior && exterior_ready_to_dismember) && I.get_sharpness())) + var/bone_text = hit_bodypart.get_internal_description() + extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] through to the [bone_text]" + else if(has_exterior && ((has_interior && interior_ready_to_dismember) && I.get_sharpness())) + var/tissue_text = hit_bodypart.get_external_description() + extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] at the remaining [tissue_text]" var/message_hit_area = "" if(hit_area) message_hit_area = " in the [hit_area]" var/attack_message_spectator = "[src] [message_verb_continuous][message_hit_area] with [I][extra_wound_details]!" var/attack_message_victim = "You're [message_verb_continuous][message_hit_area] with [I][extra_wound_details]!" - var/attack_message_attacker = "You [message_verb_simple] [src][message_hit_area] with [I]!" + var/attack_message_attacker = "You [message_verb_simple] [src][message_hit_area] with [I][extra_wound_details]!" if(user in viewers(src, null)) attack_message_spectator = "[user] [message_verb_continuous] [src][message_hit_area] with [I][extra_wound_details]!" attack_message_victim = "[user] [message_verb_continuous] you[message_hit_area] with [I][extra_wound_details]!" @@ -776,14 +789,16 @@ var/obj/item/bodypart/grasped_part = get_bodypart(zone_selected) /* - if(!grasped_part?.get_modified_bleed_rate()) + if(!grasped_part?.can_be_grasped()) return var/starting_hand_index = active_hand_index if(starting_hand_index == grasped_part.held_index) to_chat(src, span_danger("You can't grasp your [grasped_part.name] with itself!")) return - to_chat(src, span_warning("You try grasping at your [grasped_part.name], trying to stop the bleeding...")) + var/bleed_rate = grasped_part.get_modified_bleed_rate() + var/bleeding_text = (bleed_rate ? ", trying to stop the bleeding" : "") + to_chat(src, span_warning("You try grasping at your [grasped_part.name][bleeding_text]...")) if(!do_after(src, 0.75 SECONDS)) to_chat(src, span_danger("You fail to grasp your [grasped_part.name].")) return @@ -797,6 +812,17 @@ */ // SKYRAT EDIT REMOVAL - MODULARIZED INTO grasp.dm's self_grasp_bleeding_limb !! IF THIS PROC IS UPDATED, PUT IT IN THERE !! self_grasp_bleeding_limb(grasped_part, supress_message) +/// If TRUE, the owner of this bodypart can try grabbing it to slow bleeding, as well as various other effects. +/obj/item/bodypart/proc/can_be_grasped() + if (get_modified_bleed_rate()) + return TRUE + + for (var/datum/wound/iterated_wound as anything in wounds) + if (iterated_wound.wound_flags & CAN_BE_GRASPED) + return TRUE + + return FALSE + /// an abstract item representing you holding your own limb to staunch the bleeding, see [/mob/living/carbon/proc/grabbedby] will probably need to find somewhere else to put this. /obj/item/hand_item/self_grasp name = "self-grasp" @@ -841,7 +867,9 @@ RegisterSignal(user, COMSIG_QDELETING, PROC_REF(qdel_void)) RegisterSignals(grasped_part, list(COMSIG_CARBON_REMOVE_LIMB, COMSIG_QDELETING), PROC_REF(qdel_void)) - user.visible_message(span_danger("[user] grasps at [user.p_their()] [grasped_part.name], trying to stop the bleeding."), span_notice("You grab hold of your [grasped_part.name] tightly."), vision_distance=COMBAT_MESSAGE_RANGE) + var/bleed_rate = grasped_part.get_modified_bleed_rate() + var/bleeding_text = (bleed_rate ? ", trying to stop the bleeding" : "") + user.visible_message(span_danger("[user] grasps at [user.p_their()] [grasped_part.name][bleeding_text]."), span_notice("You grab hold of your [grasped_part.name] tightly."), vision_distance=COMBAT_MESSAGE_RANGE) playsound(get_turf(src), 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) return TRUE diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index ec44dcec13eca0..bcf5f495715a48 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -104,7 +104,7 @@ /// All of the scars a carbon has afflicted throughout their limbs var/list/all_scars - /// Assoc list of BODY_ZONE -> WOUND_TYPE. Set when a limb is dismembered, unset when one is attached. Used for determining what scar to add when it comes time to generate them. + /// Assoc list of BODY_ZONE -> wounding_type. Set when a limb is dismembered, unset when one is attached. Used for determining what scar to add when it comes time to generate them. var/list/body_zone_dismembered_by /// Simple modifier for whether this mob can handle greater or lesser skillchip complexity. See /datum/mutation/human/biotechcompat/ for example. diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm index 98827ae3ce3d33..01551ac0743b9f 100644 --- a/code/modules/mob/living/carbon/damage_procs.dm +++ b/code/modules/mob/living/carbon/damage_procs.dm @@ -1,4 +1,4 @@ -/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null, attacking_item) +/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = 0, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null, attacking_item) SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMAGE, damage, damagetype, def_zone) var/hit_percent = (100-blocked)/100 if(!damage || (!forced && hit_percent <= 0)) diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index eb4bb54ea8098c..6e9f61cdb8c24d 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -511,6 +511,7 @@ GLOBAL_LIST_EMPTY(features_by_species) C.grant_language(language, SPOKEN_LANGUAGE, LANGUAGE_SPECIES) for(var/language in gaining_holder.blocked_languages) C.add_blocked_language(language, LANGUAGE_SPECIES) + C.regenerate_icons() SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species) @@ -1086,7 +1087,7 @@ GLOBAL_LIST_EMPTY(features_by_species) to_chat(source, span_danger("You feel weak.")) if(time_since_irradiated > RAD_MOB_VOMIT && SPT_PROB(RAD_MOB_VOMIT_PROB, seconds_per_tick)) - source.vomit(10, TRUE) + source.vomit(VOMIT_CATEGORY_BLOOD, lost_nutrition = 10) if(time_since_irradiated > RAD_MOB_MUTATE && SPT_PROB(RAD_MOB_MUTATE_PROB, seconds_per_tick)) to_chat(source, span_danger("You mutate!")) @@ -1706,19 +1707,26 @@ GLOBAL_LIST_EMPTY(features_by_species) // Lets pick a random body part and check for an existing burn var/obj/item/bodypart/bodypart = pick(humi.bodyparts) - var/datum/wound/burn/flesh/existing_burn = locate(/datum/wound/burn) in bodypart.wounds - + var/datum/wound/existing_burn + for (var/datum/wound/iterated_wound as anything in bodypart.wounds) + var/datum/wound_pregen_data/pregen_data = iterated_wound.get_pregen_data() + if (pregen_data.wound_series in GLOB.wounding_types_to_series[WOUND_BURN]) + existing_burn = iterated_wound + break // If we have an existing burn try to upgrade it + var/severity if(existing_burn) switch(existing_burn.severity) if(WOUND_SEVERITY_MODERATE) if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT + 400) // 800k - bodypart.force_wound_upwards(/datum/wound/burn/flesh/severe, wound_source = "hot temperatures") + severity = WOUND_SEVERITY_SEVERE if(WOUND_SEVERITY_SEVERE) if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT + 2800) // 3200k - bodypart.force_wound_upwards(/datum/wound/burn/flesh/critical, wound_source = "hot temperatures") + severity = WOUND_SEVERITY_CRITICAL else // If we have no burn apply the lowest level burn - bodypart.force_wound_upwards(/datum/wound/burn/flesh/moderate, wound_source = "hot temperatures") + severity = WOUND_SEVERITY_MODERATE + + humi.cause_wound_of_type_and_severity(WOUND_BURN, bodypart, severity, wound_source = "hot temperatures") // always take some burn damage var/burn_damage = HEAT_DAMAGE_LEVEL_1 diff --git a/code/modules/mob/living/carbon/human/damage_procs.dm b/code/modules/mob/living/carbon/human/damage_procs.dm index 47cbbe12188e51..d4fc0b403656a3 100644 --- a/code/modules/mob/living/carbon/human/damage_procs.dm +++ b/code/modules/mob/living/carbon/human/damage_procs.dm @@ -1,4 +1,4 @@ /// depending on the species, it will run the corresponding apply_damage code there -/mob/living/carbon/human/apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null, attacking_item) +/mob/living/carbon/human/apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = 0, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null, attacking_item) return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src, forced, spread_damage, wound_bonus, bare_wound_bonus, sharpness, attack_direction, attacking_item) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 2601aed8731aa4..1fc148e7b640a2 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -514,10 +514,10 @@ //Temporary flavor text addition: if(temporary_flavor_text) - if(length_char(temporary_flavor_text) <= 40) + if(length_char(temporary_flavor_text) < TEMPORARY_FLAVOR_PREVIEW_LIMIT) . += span_notice("They look different than usual: [temporary_flavor_text]") else - . += span_notice("They look different than usual: [copytext_char(temporary_flavor_text, 1, 37)]... More...") + . += span_notice("They look different than usual: [copytext_char(temporary_flavor_text, 1, TEMPORARY_FLAVOR_PREVIEW_LIMIT)]... More...") . += "" SEND_SIGNAL(src, COMSIG_ATOM_EXAMINE, user, .) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 427d9cf1003995..40e4bf095d507b 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -741,15 +741,21 @@ return ..() -/mob/living/carbon/human/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, vomit_type = VOMIT_TOXIC, harm = TRUE, force = FALSE, purge_ratio = 0.1) - if(blood && HAS_TRAIT(src, TRAIT_NOBLOOD) && !HAS_TRAIT(src, TRAIT_TOXINLOVER)) - if(message) - visible_message(span_warning("[src] dry heaves!"), \ - span_userdanger("You try to throw up, but there's nothing in your stomach!")) - if(stun) - Stun(20 SECONDS) - return 1 - ..() +/mob/living/carbon/human/vomit(vomit_flags = VOMIT_CATEGORY_DEFAULT, vomit_type = /obj/effect/decal/cleanable/vomit/toxic, lost_nutrition = 10, distance = 1, purge_ratio = 0.1) + if(!((vomit_flags & MOB_VOMIT_BLOOD) && HAS_TRAIT(src, TRAIT_NOBLOOD) && !HAS_TRAIT(src, TRAIT_TOXINLOVER))) + return ..() + + if(vomit_flags & MOB_VOMIT_MESSAGE) + visible_message( + span_warning("[src] dry heaves!"), + span_userdanger("You try to throw up, but there's nothing in your stomach!"), + ) + if(vomit_flags & MOB_VOMIT_STUN) + Stun(20 SECONDS) + if(vomit_flags & MOB_VOMIT_KNOCKDOWN) + Knockdown(20 SECONDS) + + return TRUE /mob/living/carbon/human/vv_edit_var(var_name, var_value) if(var_name == NAMEOF(src, mob_height)) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index c468d9b750c18b..c91fc7d6638de5 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -279,7 +279,7 @@ lastpuke += SPT_PROB(30, seconds_per_tick) if(lastpuke >= 50) // about 25 second delay I guess // This is actually closer to 150 seconds - vomit(20) + vomit(VOMIT_CATEGORY_DEFAULT, lost_nutrition = 20) lastpuke = 0 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 9546a659e41da4..42c718477bce25 100644 --- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -68,6 +68,7 @@ RegisterSignal(ethereal, COMSIG_ATOM_EMAG_ACT, PROC_REF(on_emag_act)) RegisterSignal(ethereal, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp_act)) RegisterSignal(ethereal, COMSIG_LIGHT_EATER_ACT, PROC_REF(on_light_eater)) + RegisterSignal(ethereal, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) ethereal_light = ethereal.mob_light(light_type = /obj/effect/dummy/lighting_obj/moblight/species) spec_updatehealth(ethereal) new_ethereal.set_safe_hunger_level() @@ -84,6 +85,7 @@ UnregisterSignal(former_ethereal, COMSIG_ATOM_EMAG_ACT) UnregisterSignal(former_ethereal, COMSIG_ATOM_EMP_ACT) UnregisterSignal(former_ethereal, COMSIG_LIGHT_EATER_ACT) + UnregisterSignal(former_ethereal, COMSIG_HIT_BY_SABOTEUR) QDEL_NULL(ethereal_light) return ..() @@ -147,6 +149,16 @@ if(EMP_HEAVY) addtimer(CALLBACK(src, PROC_REF(stop_emp), H), 20 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 20 seconds +/datum/species/ethereal/proc/on_saboteur(datum/source, disrupt_duration) + SIGNAL_HANDLER + var/mob/living/carbon/human/our_target = source + EMPeffect = TRUE + spec_updatehealth(our_target) + to_chat(our_target, span_warning("Something inside of you crackles in a bad way.")) + our_target.take_bodypart_damage(burn = 3, wound_bonus = CANT_WOUND) + addtimer(CALLBACK(src, PROC_REF(stop_emp), our_target), disrupt_duration, TIMER_UNIQUE|TIMER_OVERRIDE) + return COMSIG_SABOTEUR_SUCCESS + /datum/species/ethereal/proc/on_emag_act(mob/living/carbon/human/H, mob/user) SIGNAL_HANDLER if(emageffect) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 45c441a13c2012..e66d72a2c44367 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -375,13 +375,13 @@ if(prob(5)) to_chat(src, span_warning("The stench of rotting carcasses is unbearable!")) add_mood_event("smell", /datum/mood_event/disgust/nauseating_stench) - vomit() + vomit(VOMIT_CATEGORY_DEFAULT) if(30 to INFINITY) //Higher chance to vomit. Let the horror start if(prob(25)) to_chat(src, span_warning("The stench of rotting carcasses is unbearable!")) add_mood_event("smell", /datum/mood_event/disgust/nauseating_stench) - vomit() + vomit(VOMIT_CATEGORY_DEFAULT) else clear_mood_event("smell") diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index 439101151c61aa..786e781a58433c 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -14,7 +14,7 @@ * * Returns TRUE if damage applied */ -/mob/living/proc/apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null, attacking_item) +/mob/living/proc/apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = 0, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null, attacking_item) SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMAGE, damage, damagetype, def_zone) var/hit_percent = (100-blocked)/100 if(!damage || (!forced && hit_percent <= 0)) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 6c3f397f6bac9a..c157603ea8305e 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -131,6 +131,8 @@ for (var/law in laws.inherent) lawcheck += law + create_eye() + if(target_ai.mind) target_ai.mind.transfer_to(src) if(mind.special_role) @@ -152,8 +154,6 @@ job = "AI" - create_eye() - create_modularInterface() // /mob/living/silicon/ai/apply_prefs_job() uses these to set these procs at mapload @@ -205,10 +205,6 @@ interaction_range = 1 sprint = 5 -/mob/living/silicon/ai/weak_syndie/Initialize(mapload, datum/ai_laws/L, mob/target_ai) - . = ..() - laws = new /datum/ai_laws/syndicate_override - /mob/living/silicon/ai/key_down(_key, client/user) if(findtext(_key, "numpad")) //if it's a numpad number, we can convert it to just the number _key = _key[7] //strings, lists, same thing really @@ -866,24 +862,25 @@ /mob/living/silicon/ai/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/aicard/card) if(!..()) return - if(interaction == AI_TRANS_TO_CARD)//The only possible interaction. Upload AI mob to a card. - if(!can_be_carded) - to_chat(user, span_boldwarning("Transfer failed.")) - return - disconnect_shell() //If the AI is controlling a borg, force the player back to core! - if(!mind) - to_chat(user, span_warning("No intelligence patterns detected.")) - return - ShutOffDoomsdayDevice() - var/obj/structure/ai_core/new_core = new /obj/structure/ai_core/deactivated(loc, posibrain_inside)//Spawns a deactivated terminal at AI location. - new_core.circuit.battery = battery - ai_restore_power()//So the AI initially has power. - control_disabled = TRUE //Can't control things remotely if you're stuck in a card! - radio_enabled = FALSE //No talking on the built-in radio for you either! - forceMove(card) - card.AI = src - to_chat(src, "You have been downloaded to a mobile storage device. Remote device connection severed.") - to_chat(user, "[span_boldnotice("Transfer successful")]: [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory.") + if(interaction != AI_TRANS_TO_CARD)//The only possible interaction. Upload AI mob to a card. + return + if(!can_be_carded) + balloon_alert(user, "transfer failed!") + return + disconnect_shell() //If the AI is controlling a borg, force the player back to core! + if(!mind) + balloon_alert(user, "no intelligence detected!") // average tg coder am i right + return + ShutOffDoomsdayDevice() + var/obj/structure/ai_core/new_core = new /obj/structure/ai_core/deactivated(loc, posibrain_inside)//Spawns a deactivated terminal at AI location. + new_core.circuit.battery = battery + ai_restore_power()//So the AI initially has power. + control_disabled = TRUE //Can't control things remotely if you're stuck in a card! + radio_enabled = FALSE //No talking on the built-in radio for you either! + forceMove(card) + card.AI = src + to_chat(src, "You have been downloaded to a mobile storage device. Remote device connection severed.") + to_chat(user, "[span_boldnotice("Transfer successful")]: [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory.") /mob/living/silicon/ai/can_perform_action(atom/movable/target, action_bitflags) if(control_disabled) diff --git a/code/modules/mob/living/silicon/ai/multicam.dm b/code/modules/mob/living/silicon/ai/multicam.dm index e5bcd813b7e071..45924e2fe981f4 100644 --- a/code/modules/mob/living/silicon/ai/multicam.dm +++ b/code/modules/mob/living/silicon/ai/multicam.dm @@ -86,7 +86,7 @@ name = "" icon = 'icons/misc/pic_in_pic.dmi' icon_state = "room_background" - flags_1 = NOJAUNT + turf_flags = NOJAUNT /turf/open/ai_visible/Initialize(mapload) . = ..() diff --git a/code/modules/mob/living/silicon/damage_procs.dm b/code/modules/mob/living/silicon/damage_procs.dm index 59db1264a30a31..8ee146508a4149 100644 --- a/code/modules/mob/living/silicon/damage_procs.dm +++ b/code/modules/mob/living/silicon/damage_procs.dm @@ -1,5 +1,5 @@ -/mob/living/silicon/apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null, attacking_item) +/mob/living/silicon/apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = 0, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null, attacking_item) var/hit_percent = (100-blocked)/100 if((!damage || (!forced && hit_percent <= 0))) return 0 diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 9732222f0cf5eb..30559e616b569d 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -19,6 +19,7 @@ AddElement(/datum/element/ridable, /datum/component/riding/creature/cyborg) RegisterSignal(src, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, PROC_REF(charge)) RegisterSignal(src, COMSIG_LIGHT_EATER_ACT, PROC_REF(on_light_eater)) + RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) robot_modules_background = new() robot_modules_background.icon_state = "block" @@ -470,6 +471,13 @@ smash_headlamp() return COMPONENT_BLOCK_LIGHT_EATER +/// special handling for getting shot with a light disruptor/saboteur e.g. the fisher +/mob/living/silicon/robot/proc/on_saboteur(datum/source, disrupt_duration) + SIGNAL_HANDLER + if(lamp_enabled) + toggle_headlamp(TRUE) + to_chat(src, span_warning("Your headlamp was forcibly turned off. Restarting it should fix it, though.")) + return COMSIG_SABOTEUR_SUCCESS /** * Handles headlamp smashing diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index b4b4dd80f7fa69..710085884658af 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -92,7 +92,7 @@ ) /mob/living/simple_animal/bot/cleanbot/autopatrol - bot_mode_flags = BOT_MODE_ON | BOT_MODE_AUTOPATROL | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT + bot_mode_flags = BOT_MODE_ON | BOT_MODE_AUTOPATROL | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT | BOT_MODE_ROUNDSTART_POSSESSION /mob/living/simple_animal/bot/cleanbot/medbay name = "Scrubs, MD" diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index d01e36c334bbbc..12f33dec723ff9 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -273,6 +273,10 @@ switch(build_step) if(ASSEMBLY_FIRST_STEP) if(istype(W, /obj/item/healthanalyzer)) + var/obj/item/healthanalyzer/analyzer = W // SKYRAT EDIT ADDITION BEGIN -- EXTRA ROBOTICS HEALTH ANALYZERS + if (!analyzer.can_be_used_in_medibot()) + user?.balloon_alert(user, "no attachment ports!") + return // SKYRAT EDIT ADDITION END if(!user.temporarilyRemoveItemFromInventory(W)) return healthanalyzer = W.type diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm index 8c46d8bec9c810..220c4a5cccea12 100644 --- a/code/modules/mob/living/simple_animal/bot/honkbot.dm +++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm @@ -9,7 +9,7 @@ radio_key = /obj/item/encryptionkey/headset_service //doesn't have security key radio_channel = RADIO_CHANNEL_SERVICE //Doesn't even use the radio anyway. bot_type = HONK_BOT - bot_mode_flags = BOT_MODE_ON | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT | BOT_MODE_AUTOPATROL + bot_mode_flags = BOT_MODE_ON | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT | BOT_MODE_AUTOPATROL | BOT_MODE_ROUNDSTART_POSSESSION hackables = "sound control systems" path_image_color = "#FF69B4" data_hud_type = DATA_HUD_SECURITY_BASIC //show jobs diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm index 5af3e6ebad471f..9c06465b8a5655 100644 --- a/code/modules/mob/living/simple_animal/bot/medbot.dm +++ b/code/modules/mob/living/simple_animal/bot/medbot.dm @@ -102,6 +102,8 @@ var/tipped_status = MEDBOT_PANIC_NONE ///The name we got when we were tipped var/tipper_name + ///The trim type that will grant additional access to this medibot + var/datum/id_trim/additional_access = /datum/id_trim/job/paramedic ///Last announced healing a person in critical condition COOLDOWN_DECLARE(last_patient_message) @@ -111,7 +113,7 @@ COOLDOWN_DECLARE(last_tipping_action_voice) /mob/living/simple_animal/bot/medbot/autopatrol - bot_mode_flags = BOT_MODE_ON | BOT_MODE_AUTOPATROL | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT + bot_mode_flags = BOT_MODE_ON | BOT_MODE_AUTOPATROL | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT | BOT_MODE_ROUNDSTART_POSSESSION /mob/living/simple_animal/bot/medbot/stationary medical_mode_flags = MEDBOT_DECLARE_CRIT | MEDBOT_STATIONARY_MODE | MEDBOT_SPEAK_MODE @@ -144,6 +146,7 @@ damagetype_healer = "all" heal_threshold = 0 heal_amount = 5 + additional_access = /datum/id_trim/syndicom/crew /mob/living/simple_animal/bot/medbot/nukie/Initialize(mapload, new_skin) . = ..() @@ -152,6 +155,7 @@ RegisterSignal(SSdcs, COMSIG_GLOB_NUKE_DEVICE_DETONATING, PROC_REF(nuke_detonate)) internal_radio.set_frequency(FREQ_SYNDICATE) internal_radio.freqlock = RADIO_FREQENCY_LOCKED + faction += ROLE_SYNDICATE //one of us /mob/living/simple_animal/bot/medbot/nukie/proc/nuke_disarm() SIGNAL_HANDLER @@ -204,14 +208,21 @@ . = ..() // Doing this hurts my soul, but simplebot access reworks are for another day. - var/datum/id_trim/job/para_trim = SSid_access.trim_singletons_by_path[/datum/id_trim/job/paramedic] - access_card.add_access(para_trim.access + para_trim.wildcard_access) + var/datum/id_trim/additional_trim = SSid_access.trim_singletons_by_path[additional_access] + access_card.add_access(additional_trim.access + additional_trim.wildcard_access) prev_access = access_card.access.Copy() if(!isnull(new_skin)) skin = new_skin update_appearance() + if(HAS_TRAIT(SSstation, STATION_TRAIT_MEDBOT_MANIA) && mapload && is_station_level(z)) + skin = "advanced" + update_appearance(UPDATE_OVERLAYS) + damagetype_healer = "all" + if(prob(50)) + name += ", PhD." + AddComponent(/datum/component/tippable, \ tip_time = 3 SECONDS, \ untip_time = 3 SECONDS, \ diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index b095016827fe6f..a0f078acd92e85 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -74,7 +74,7 @@ /// Default [/mob/living/simple_animal/drone/var/internal_storage] item var/obj/item/default_storage = /obj/item/storage/drone_tools /// Default [/mob/living/simple_animal/drone/var/head] item - var/obj/item/default_hatmask + var/obj/item/default_headwear /** * icon_state of drone from icons/mobs/drone.dmi * @@ -181,9 +181,16 @@ if(default_storage) var/obj/item/I = new default_storage(src) equip_to_slot_or_del(I, ITEM_SLOT_DEX_STORAGE) - if(default_hatmask) - var/obj/item/I = new default_hatmask(src) - equip_to_slot_or_del(I, ITEM_SLOT_HEAD) + + for(var/holiday_name in GLOB.holidays) + var/datum/holiday/holiday_today = GLOB.holidays[holiday_name] + var/obj/item/potential_hat = holiday_today.holiday_hat + if(!isnull(potential_hat) && isnull(default_headwear)) //If our drone type doesn't start with a hat, we take the holiday one. + default_headwear = potential_hat + + if(default_headwear) + var/obj/item/new_hat = new default_headwear(src) + equip_to_slot_or_del(new_hat, ITEM_SLOT_HEAD) ADD_TRAIT(access_card, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT) diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm index 38c3585271ab4b..d4353c95c824ad 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm @@ -27,7 +27,7 @@ "2. Kill.\n"+\ "3. Destroy." default_storage = /obj/item/uplink - default_hatmask = /obj/item/clothing/head/helmet/swat + default_headwear = /obj/item/clothing/head/helmet/swat hacked = TRUE shy = FALSE flavortext = null @@ -49,7 +49,7 @@ W.implant(src, force = TRUE) /mob/living/simple_animal/drone/snowflake - default_hatmask = /obj/item/clothing/head/chameleon/drone + default_headwear = /obj/item/clothing/head/chameleon/drone /mob/living/simple_animal/drone/snowflake/Initialize(mapload) . = ..() @@ -87,7 +87,7 @@ /mob/living/simple_animal/drone/polymorphed default_storage = null - default_hatmask = null + default_headwear = null picked = TRUE flavortext = null @@ -132,7 +132,7 @@ /mob/living/simple_animal/drone/derelict name = "derelict drone" - default_hatmask = /obj/item/clothing/head/costume/ushanka + default_headwear = /obj/item/clothing/head/costume/ushanka laws = \ "1. You may not involve yourself in the matters of another sentient being outside the station that housed your activation, even if such matters conflict with Law Two or Law Three, unless the other being is another Drone.\n"+\ "2. You may not harm any sentient being, regardless of intent or circumstance.\n"+\ diff --git a/code/modules/mob/living/simple_animal/guardian/guardian_creator.dm b/code/modules/mob/living/simple_animal/guardian/guardian_creator.dm index b57ae45e1b7ad2..ebd5658f07f4b3 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian_creator.dm +++ b/code/modules/mob/living/simple_animal/guardian/guardian_creator.dm @@ -87,9 +87,10 @@ GLOBAL_LIST_INIT(guardian_radial_images, setup_guardian_radial()) if(LAZYLEN(candidates)) var/mob/dead/observer/candidate = pick(candidates) spawn_guardian(user, candidate, guardian_path) + used = TRUE + SEND_SIGNAL(src, COMSIG_TRAITOR_ITEM_USED(type)) else to_chat(user, failure_message) - used = FALSE /obj/item/guardiancreator/proc/spawn_guardian(mob/living/user, mob/dead/candidate, guardian_path) if(QDELETED(user) || user.stat == DEAD) diff --git a/code/modules/mob/living/simple_animal/hostile/heretic_monsters.dm b/code/modules/mob/living/simple_animal/hostile/heretic_monsters.dm index 4269f847d924d6..2c0b9ba983a09f 100644 --- a/code/modules/mob/living/simple_animal/hostile/heretic_monsters.dm +++ b/code/modules/mob/living/simple_animal/hostile/heretic_monsters.dm @@ -145,7 +145,7 @@ mob_size = MOB_SIZE_HUGE sentience_type = SENTIENCE_BOSS environment_smash = ENVIRONMENT_SMASH_RWALLS - mob_biotypes = MOB_ORGANIC|MOB_EPIC + mob_biotypes = MOB_ORGANIC|MOB_SPECIAL obj_damage = 200 ranged_cooldown_time = 5 ranged = TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm index 360381c9c1c602..3484c27375da46 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm @@ -6,7 +6,7 @@ combat_mode = TRUE sentience_type = SENTIENCE_BOSS environment_smash = ENVIRONMENT_SMASH_RWALLS - mob_biotypes = MOB_ORGANIC|MOB_EPIC + mob_biotypes = MOB_ORGANIC|MOB_SPECIAL obj_damage = 400 light_range = 3 faction = list(FACTION_MINING, FACTION_BOSS) diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm index faabb633104c9d..2d92ef88a65d63 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm @@ -1,11 +1,11 @@ /mob/living/simple_animal/hostile/asteroid/hivelord name = "hivelord" - desc = "A truly alien creature, it is a mass of unknown organic material, constantly fluctuating. When attacking, pieces of it split off and attack in tandem with the original." + desc = "A levitating swarm of tiny creatures which act as a single individual. When threatened or hunting they rapidly replicate additional short-lived bodies." icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi' - icon_state = "Hivelord" - icon_living = "Hivelord" - icon_aggro = "Hivelord_alert" - icon_dead = "Hivelord_dead" + icon_state = "hivelord" + icon_living = "hivelord" + icon_aggro = "hivelord_alert" + icon_dead = "hivelord_dead" icon_gib = "syndicate_gib" mob_biotypes = MOB_ORGANIC move_to_delay = 14 @@ -18,11 +18,11 @@ harm_intent_damage = 5 melee_damage_lower = 0 melee_damage_upper = 0 - attack_verb_continuous = "lashes out at" - attack_verb_simple = "lash out at" + attack_verb_continuous = "weakly tackles" + attack_verb_simple = "weakly tackles" speak_emote = list("telepathically cries") attack_sound = 'sound/weapons/pierce.ogg' - throw_message = "falls right through the strange body of the" + throw_message = "passes between the bodies of the" ranged_cooldown = 0 ranged_cooldown_time = 20 obj_damage = 0 @@ -40,14 +40,14 @@ AddComponent(/datum/component/clickbox, icon_state = "hivelord", max_scale = INFINITY, dead_state = "hivelord_dead") //they writhe so much. /mob/living/simple_animal/hostile/asteroid/hivelord/OpenFire(the_target) - if(world.time >= ranged_cooldown) - var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/A = new brood_type(src.loc) - - A.flags_1 |= (flags_1 & ADMIN_SPAWNED_1) - A.GiveTarget(target) - A.friends = friends - A.faction = faction.Copy() - ranged_cooldown = world.time + ranged_cooldown_time + if(world.time < ranged_cooldown) + return + var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/brood = new brood_type(src.loc) + brood.flags_1 |= (flags_1 & ADMIN_SPAWNED_1) + brood.GiveTarget(target) + brood.friends = friends + brood.faction = faction.Copy() + ranged_cooldown = world.time + ranged_cooldown_time /mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget() OpenFire() @@ -55,17 +55,17 @@ /mob/living/simple_animal/hostile/asteroid/hivelord/death(gibbed) mouse_opacity = MOUSE_OPACITY_ICON - ..(gibbed) + return ..() //A fragile but rapidly produced creature /mob/living/simple_animal/hostile/asteroid/hivelordbrood name = "hivelord brood" - desc = "A fragment of the original Hivelord, rallying behind its original. One isn't much of a threat, but..." + desc = "Short-lived attack form of the hivelord. One isn't much of a threat, but..." icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi' - icon_state = "Hivelordbrood" - icon_living = "Hivelordbrood" - icon_aggro = "Hivelordbrood" - icon_dead = "Hivelordbrood" + icon_state = "hivelord_brood" + icon_living = "hivelord_brood" + icon_aggro = "hivelord_brood" + icon_dead = "hivelord_brood" icon_gib = "syndicate_gib" move_to_delay = 1 friendly_verb_continuous = "buzzes near" @@ -93,11 +93,16 @@ /mob/living/simple_animal/hostile/asteroid/hivelordbrood/Initialize(mapload) . = ..() - addtimer(CALLBACK(src, PROC_REF(death)), 100) + addtimer(CALLBACK(src, PROC_REF(death)), 10 SECONDS) AddElement(/datum/element/simple_flying) AddComponent(/datum/component/swarming) AddComponent(/datum/component/clickbox, icon_state = clickbox_state, max_scale = clickbox_max_scale) +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/death(gibbed) + if (!gibbed) + new /obj/effect/temp_visual/hive_spawn_wither(get_turf(src), /* copy_from = */ src) + return ..() + //Legion /mob/living/simple_animal/hostile/asteroid/hivelord/legion name = "legion" diff --git a/code/modules/mob/living/simple_animal/revenant.dm b/code/modules/mob/living/simple_animal/revenant.dm index 82c2be6920abc8..6e2ec11afeac8a 100644 --- a/code/modules/mob/living/simple_animal/revenant.dm +++ b/code/modules/mob/living/simple_animal/revenant.dm @@ -132,6 +132,7 @@ /mob/living/simple_animal/revenant/Life(seconds_per_tick = SSMOBS_DT, times_fired) if(stasis) return + var/delta_time = DELTA_WORLD_TIME(SSmobs) if(revealed && essence <= 0) death() if(unreveal_time && world.time >= unreveal_time) @@ -145,7 +146,7 @@ REMOVE_TRAIT(src, TRAIT_NO_TRANSFORM, REVENANT_STUNNED_TRAIT) to_chat(src, span_revenboldnotice("You can move again!")) if(essence_regenerating && !inhibited && essence < essence_regen_cap) //While inhibited, essence will not regenerate - essence = min(essence + (essence_regen_amount * seconds_per_tick), essence_regen_cap) + essence = min(essence + (essence_regen_amount * delta_time), essence_regen_cap) update_mob_action_buttons() //because we update something required by our spells in life, we need to update our buttons update_spooky_icon() update_health_hud() diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index cefd88c72ef001..09ce3b3c65c8ce 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -36,7 +36,6 @@ set_name() SEND_SIGNAL(src, COMSIG_HUMAN_MONKEYIZE) uncuff() - regenerate_icons() return src ////////////////////////// Humanize ////////////////////////////// @@ -71,7 +70,6 @@ invisibility = 0 set_species(species) SEND_SIGNAL(src, COMSIG_MONKEY_HUMANIZE) - regenerate_icons() return src /mob/proc/AIize(client/preference_source, move = TRUE) diff --git a/code/modules/mod/mod_actions.dm b/code/modules/mod/mod_actions.dm index d82912055e2c80..111ea425b6a6e5 100644 --- a/code/modules/mod/mod_actions.dm +++ b/code/modules/mod/mod_actions.dm @@ -125,6 +125,8 @@ var/obj/item/mod/module/module /// A reference to the mob we are pinned to. var/mob/pinner + /// Timer until we remove our cooldown overlay + var/cooldown_timer /datum/action/item_action/mod/pinned_module/New(Target, obj/item/mod/module/linked_module, mob/user) var/obj/item/mod/control/mod = Target @@ -141,11 +143,22 @@ check_flags = NONE name = "Activate [capitalize(linked_module.name)]" desc = "Quickly activate [linked_module]." - RegisterSignals(linked_module, list(COMSIG_MODULE_ACTIVATED, COMSIG_MODULE_DEACTIVATED, COMSIG_MODULE_USED), PROC_REF(module_interacted_with)) + RegisterSignals(linked_module, list( + COMSIG_MODULE_ACTIVATED, + COMSIG_MODULE_DEACTIVATED, + COMSIG_MODULE_USED, + ), PROC_REF(module_interacted_with)) + RegisterSignal(linked_module, COMSIG_MODULE_COOLDOWN_STARTED, PROC_REF(cooldown_started)) RegisterSignal(user, COMSIG_QDELETING, PROC_REF(pinner_deleted)) /datum/action/item_action/mod/pinned_module/Destroy() - UnregisterSignal(module, list(COMSIG_MODULE_ACTIVATED, COMSIG_MODULE_DEACTIVATED, COMSIG_MODULE_USED)) + deltimer(cooldown_timer) + UnregisterSignal(module, list( + COMSIG_MODULE_ACTIVATED, + COMSIG_MODULE_DEACTIVATED, + COMSIG_MODULE_COOLDOWN_STARTED, + COMSIG_MODULE_USED, + )) module.pinned_to -= REF(pinner) module = null pinner = null @@ -178,12 +191,19 @@ else if(module.active) current_button.add_overlay(image(icon = 'icons/hud/radial.dmi', icon_state = "module_active", layer = FLOAT_LAYER-0.1)) if(!COOLDOWN_FINISHED(module, cooldown_timer)) - var/image/cooldown_image = image(icon = 'icons/hud/radial.dmi', icon_state = "module_cooldown") - current_button.add_overlay(cooldown_image) - addtimer(CALLBACK(current_button, TYPE_PROC_REF(/image, cut_overlay), cooldown_image), COOLDOWN_TIMELEFT(module, cooldown_timer)) + current_button.add_overlay(image(icon = 'icons/hud/radial.dmi', icon_state = "module_cooldown")) return ..() /datum/action/item_action/mod/pinned_module/proc/module_interacted_with(datum/source) SIGNAL_HANDLER build_all_button_icons(UPDATE_BUTTON_OVERLAY|UPDATE_BUTTON_STATUS) + +/datum/action/item_action/mod/pinned_module/proc/cooldown_started(datum/source, cooldown_time) + SIGNAL_HANDLER + + deltimer(cooldown_timer) + build_all_button_icons(UPDATE_BUTTON_OVERLAY) + if (cooldown_time == 0) + return + cooldown_timer = addtimer(CALLBACK(src, PROC_REF(build_all_button_icons), UPDATE_BUTTON_OVERLAY), cooldown_time + 1, TIMER_STOPPABLE) diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm index 521dd6f024011a..9adaaf4f14680e 100644 --- a/code/modules/mod/mod_theme.dm +++ b/code/modules/mod/mod_theme.dm @@ -949,6 +949,7 @@ default_skin = "syndicate" armor_type = /datum/armor/mod_theme_syndicate atom_flags = PREVENT_CONTENTS_EXPLOSION_1 + complexity_max = DEFAULT_MAX_COMPLEXITY + 3 max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT siemens_coefficient = 0 slowdown_inactive = 1 @@ -1043,6 +1044,7 @@ resistance_flags = FIRE_PROOF|ACID_PROOF atom_flags = PREVENT_CONTENTS_EXPLOSION_1 max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + complexity_max = DEFAULT_MAX_COMPLEXITY + 3 siemens_coefficient = 0 slowdown_inactive = 1 slowdown_active = 0.5 diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm index 2f2be1dc86e479..f11c6b9b4b904b 100644 --- a/code/modules/mod/mod_types.dm +++ b/code/modules/mod/mod_types.dm @@ -231,12 +231,14 @@ /obj/item/mod/module/emp_shield, /obj/item/mod/module/magnetic_harness, /obj/item/mod/module/jetpack/advanced, + /obj/item/mod/module/jump_jet, /obj/item/mod/module/flashlight, /obj/item/mod/module/dna_lock, ) default_pins = list( /obj/item/mod/module/armor_booster, /obj/item/mod/module/jetpack/advanced, + /obj/item/mod/module/jump_jet, ) /obj/item/mod/control/pre_equipped/nuclear @@ -249,11 +251,13 @@ /obj/item/mod/module/emp_shield, /obj/item/mod/module/magnetic_harness, /obj/item/mod/module/jetpack/advanced, + /obj/item/mod/module/jump_jet, /obj/item/mod/module/flashlight, ) default_pins = list( /obj/item/mod/module/armor_booster, /obj/item/mod/module/jetpack/advanced, + /obj/item/mod/module/jump_jet, ) /obj/item/mod/control/pre_equipped/nuclear/plasmaman @@ -275,11 +279,13 @@ /obj/item/mod/module/emp_shield, /obj/item/mod/module/magnetic_harness, /obj/item/mod/module/jetpack/advanced, + /obj/item/mod/module/jump_jet, /obj/item/mod/module/flashlight, ) default_pins = list( /obj/item/mod/module/armor_booster, /obj/item/mod/module/jetpack/advanced, + /obj/item/mod/module/jump_jet, ) /obj/item/mod/control/pre_equipped/elite/flamethrower @@ -289,12 +295,14 @@ /obj/item/mod/module/magnetic_harness, /obj/item/mod/module/thermal_regulator, /obj/item/mod/module/jetpack/advanced, + /obj/item/mod/module/jump_jet, /obj/item/mod/module/flashlight, /obj/item/mod/module/flamethrower, ) default_pins = list( /obj/item/mod/module/armor_booster, /obj/item/mod/module/jetpack/advanced, + /obj/item/mod/module/jump_jet, /obj/item/mod/module/flamethrower, ) diff --git a/code/modules/mod/modules/_module.dm b/code/modules/mod/modules/_module.dm index d5699986ee9405..a3067e0c150540 100644 --- a/code/modules/mod/modules/_module.dm +++ b/code/modules/mod/modules/_module.dm @@ -89,6 +89,13 @@ on_use() SEND_SIGNAL(mod, COMSIG_MOD_MODULE_SELECTED, src) +/// Apply a cooldown until this item can be used again +/obj/item/mod/module/proc/start_cooldown(applied_cooldown) + if (isnull(applied_cooldown)) + applied_cooldown = cooldown_time + COOLDOWN_START(src, cooldown_timer, applied_cooldown) + SEND_SIGNAL(src, COMSIG_MODULE_COOLDOWN_STARTED, applied_cooldown) + /// Called when the module is activated /obj/item/mod/module/proc/on_activation() if(!COOLDOWN_FINISHED(src, cooldown_timer)) @@ -129,8 +136,8 @@ update_signal(used_button) balloon_alert(mod.wearer, "[src] activated, [used_button]-click to use") active = TRUE - COOLDOWN_START(src, cooldown_timer, cooldown_time) mod.wearer.update_clothing(mod.slot_flags) + start_cooldown() SEND_SIGNAL(src, COMSIG_MODULE_ACTIVATED) return TRUE @@ -166,7 +173,7 @@ return FALSE if(SEND_SIGNAL(src, COMSIG_MODULE_TRIGGERED, mod.wearer) & MOD_ABORT_USE) return FALSE - COOLDOWN_START(src, cooldown_timer, cooldown_time) + start_cooldown() addtimer(CALLBACK(mod.wearer, TYPE_PROC_REF(/mob, update_clothing), mod.slot_flags), cooldown_time+1) //need to run it a bit after the cooldown starts to avoid conflicts mod.wearer.update_clothing(mod.slot_flags) SEND_SIGNAL(src, COMSIG_MODULE_USED) diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index f64d808b7a7301..6d47a5b60ba3ba 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -169,12 +169,53 @@ /obj/item/mod/module/jetpack/advanced name = "MOD advanced ion jetpack module" desc = "An improvement on the previous model of electric thrusters. This one achieves higher speeds through \ - mounting of more jets and a red paint applied on it." + mounting of more jets and application of red paint." icon_state = "jetpack_advanced" overlay_state_inactive = "module_jetpackadv" overlay_state_active = "module_jetpackadv_on" full_speed = TRUE +/// Cooldown to use if we didn't actually launch a jump jet +#define FAILED_ACTIVATION_COOLDOWN 3 SECONDS + +///Jump Jet - Briefly removes the effect of gravity and pushes you up one z-level if possible. +/obj/item/mod/module/jump_jet + name = "MOD ionic jump jet module" + desc = "A specialised ionic thruster which provides a short but powerful boost capable of pushing against gravity, \ + after which time it needs to recharge." + icon_state = "jump_jet" + module_type = MODULE_USABLE + complexity = 3 + cooldown_time = 30 SECONDS + use_power_cost = DEFAULT_CHARGE_DRAIN * 5 + incompatible_modules = list(/obj/item/mod/module/jump_jet) + +/obj/item/mod/module/jump_jet/on_use() + . = ..() + if (!.) + return FALSE + if (DOING_INTERACTION(mod.wearer, mod.wearer)) + balloon_alert(mod.wearer, "busy!") + return + balloon_alert(mod.wearer, "launching...") + mod.wearer.Shake(duration = 1 SECONDS) + if (!do_after(mod.wearer, 1 SECONDS, target = mod.wearer)) + start_cooldown(FAILED_ACTIVATION_COOLDOWN) // Don't go on full cooldown if we failed to launch + return FALSE + playsound(mod.wearer, 'sound/vehicles/rocketlaunch.ogg', 100, TRUE) + mod.wearer.apply_status_effect(/datum/status_effect/jump_jet) + var/turf/launch_from = get_turf(mod.wearer) + if (mod.wearer.zMove(UP, z_move_flags = ZMOVE_CHECK_PULLS)) + launch_from.visible_message(span_warning("[mod.wearer] rockets into the air!")) + new /obj/effect/temp_visual/jet_plume(launch_from) + + var/obj/item/mod/module/jetpack/linked_jetpack = locate() in mod.modules + if (!isnull(linked_jetpack) && !linked_jetpack.active) + linked_jetpack.on_activation() + return TRUE + +#undef FAILED_ACTIVATION_COOLDOWN + ///Status Readout - Puts a lot of information including health, nutrition, fingerprints, temperature to the suit TGUI. /obj/item/mod/module/status_readout name = "MOD status readout module" diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index da83445a641087..21d2b8352fb925 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -65,6 +65,8 @@ ///If the computer has a flashlight/LED light built-in. var/has_light = FALSE + /// If the computer's flashlight/LED light has forcibly disabled for a temporary amount of time. + COOLDOWN_DECLARE(disabled_time) /// How far the computer's light can reach, is not editable by players. var/comp_light_luminosity = 3 /// The built-in light's color, editable by players. @@ -127,6 +129,7 @@ UpdateDisplay() if(has_light) add_item_action(/datum/action/item_action/toggle_computer_light) + RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) if(inserted_disk) inserted_disk = new inserted_disk(src) if(internal_cell) @@ -657,7 +660,7 @@ /obj/item/modular_computer/ui_action_click(mob/user, actiontype) if(istype(actiontype, /datum/action/item_action/toggle_computer_light)) - toggle_flashlight() + toggle_flashlight(user) return return ..() @@ -668,14 +671,32 @@ * Called from ui_act(), does as the name implies. * It is separated from ui_act() to be overwritten as needed. */ -/obj/item/modular_computer/proc/toggle_flashlight() +/obj/item/modular_computer/proc/toggle_flashlight(mob/user) if(!has_light) return FALSE + if(!COOLDOWN_FINISHED(src, disabled_time)) + balloon_alert(user, "disrupted!") + return FALSE set_light_on(!light_on) update_appearance() update_item_action_buttons(force = TRUE) //force it because we added an overlay, not changed its icon return TRUE +/** + * Disables the computer's flashlight/LED light, if it has one, for a given disrupt_duration. + * + * Called when sent COMSIG_HIT_BY_SABOTEUR. + */ +/obj/item/modular_computer/proc/on_saboteur(datum/source, disrupt_duration) + SIGNAL_HANDLER + if(!has_light) + return + set_light_on(FALSE) + update_appearance() + update_item_action_buttons(force = TRUE) //force it because we added an overlay, not changed its icon + COOLDOWN_START(src, disabled_time, disrupt_duration) + return COMSIG_SABOTEUR_SUCCESS + /** * Sets the computer's light color, if it has a light. * diff --git a/code/modules/modular_computers/computers/item/pda.dm b/code/modules/modular_computers/computers/item/pda.dm index bc57f3597846f4..a4b08f2d90f6db 100644 --- a/code/modules/modular_computers/computers/item/pda.dm +++ b/code/modules/modular_computers/computers/item/pda.dm @@ -379,7 +379,7 @@ .["comp_light_color"] = robo.lamp_color //Makes the flashlight button affect the borg rather than the tablet -/obj/item/modular_computer/pda/silicon/toggle_flashlight() +/obj/item/modular_computer/pda/silicon/toggle_flashlight(mob/user) if(!silicon_owner || QDELETED(silicon_owner)) return FALSE if(iscyborg(silicon_owner)) diff --git a/code/modules/modular_computers/file_system/programs/notepad.dm b/code/modules/modular_computers/file_system/programs/notepad.dm index 2e1eb52add5e8d..01afaa08c19e07 100644 --- a/code/modules/modular_computers/file_system/programs/notepad.dm +++ b/code/modules/modular_computers/file_system/programs/notepad.dm @@ -10,7 +10,14 @@ usage_flags = PROGRAM_TABLET var/written_note = "Congratulations on your station upgrading to the new NtOS and Thinktronic based collaboration effort, \ - bringing you the best in electronics and software since 2467!" + bringing you the best in electronics and software since 2467!\n\ + To help with navigation, we have provided the following definitions:\n\ + Fore - Toward front of ship\n\ + Aft - Toward back of ship\n\ + Port - Left side of ship\n\ + Starboard - Right side of ship\n\ + Quarter - Either sides of Aft\n\ + Bow - Either sides of Fore" /datum/computer_file/program/notepad/ui_act(action, list/params, datum/tgui/ui) switch(action) diff --git a/code/modules/modular_computers/laptop_vendor.dm b/code/modules/modular_computers/laptop_vendor.dm deleted file mode 100644 index 28a6e12843f1a6..00000000000000 --- a/code/modules/modular_computers/laptop_vendor.dm +++ /dev/null @@ -1,152 +0,0 @@ -// A vendor machine for modular computer portable devices - Laptops and Tablets - -/obj/machinery/lapvend - name = "computer vendor" - desc = "A vending machine with microfabricator capable of dispensing various NT-branded computers." - icon = 'icons/obj/machines/vending.dmi' - icon_state = "robotics" - layer = 2.9 - density = TRUE - - // The actual laptop/tablet - var/obj/item/modular_computer/laptop/fabricated_laptop - var/obj/item/modular_computer/pda/fabricated_tablet - - // Utility vars - var/state = 0 // 0: Select device type, 1: Select loadout, 2: Payment, 3: Thankyou screen - var/devtype = 0 // 0: None(unselected), 1: Laptop, 2: Tablet - var/total_price = 0 // Price of currently vended device. - var/credits = 0 - -// Removes all traces of old order and allows you to begin configuration from scratch. -/obj/machinery/lapvend/proc/reset_order() - state = 0 - devtype = 0 - if(fabricated_laptop) - qdel(fabricated_laptop) - fabricated_laptop = null - if(fabricated_tablet) - qdel(fabricated_tablet) - fabricated_tablet = null - -// Recalculates the price and optionally even fabricates the device. -/obj/machinery/lapvend/proc/fabricate_and_recalc_price(fabricate = FALSE) - total_price = 0 - if(devtype == 1) // Laptop, generally cheaper to make it accessible for most station roles - if(fabricate) - fabricated_laptop = new /obj/item/modular_computer/laptop/buildable(src) - total_price = 99 - - return total_price - else if(devtype == 2) // Tablet, more expensive, not everyone could probably afford this. - if(fabricate) - fabricated_tablet = new(src) - total_price = 199 - return FALSE - -/obj/machinery/lapvend/ui_act(action, params) - . = ..() - if(.) - return - - switch(action) - if("pick_device") - if(state) // We've already picked a device type - return FALSE - devtype = text2num(params["pick"]) - state = 1 - fabricate_and_recalc_price(FALSE) - return TRUE - if("clean_order") - reset_order() - return TRUE - if("purchase") - try_purchase() - return TRUE - if((state != 1) && devtype) // Following IFs should only be usable when in the Select Loadout mode - return FALSE - switch(action) - if("confirm_order") - state = 2 // Wait for ID swipe for payment processing - fabricate_and_recalc_price(FALSE) - return TRUE - return FALSE - -/obj/machinery/lapvend/ui_interact(mob/user, datum/tgui/ui) - if(machine_stat & (BROKEN | NOPOWER | MAINT)) - if(ui) - ui.close() - return FALSE - - ui = SStgui.try_update_ui(user, src, ui) - if (!ui) - ui = new(user, src, "ComputerFabricator") - ui.open() - -/obj/machinery/lapvend/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/stack/spacecash)) - var/obj/item/stack/spacecash/c = I - if(!user.temporarilyRemoveItemFromInventory(c)) - return - credits += c.value - visible_message(span_info("[span_name("[user]")] inserts [c.value] cr into [src].")) - qdel(c) - return - else if(istype(I, /obj/item/holochip)) - var/obj/item/holochip/HC = I - credits += HC.credits - visible_message(span_info("[user] inserts a [HC.credits] cr holocredit chip into [src].")) - qdel(HC) - return - else if(isidcard(I)) - if(state != 2) - return - var/obj/item/card/id/ID = I - var/datum/bank_account/account = ID.registered_account - var/target_credits = total_price - credits - if(!account.adjust_money(-target_credits, "Vending: Laptop Vendor")) - say("Insufficient credits on card to purchase!") - return - credits += target_credits - say("[target_credits] cr have been withdrawn from your account.") - return - return ..() - -// Simplified payment processing, returns 1 on success. -/obj/machinery/lapvend/proc/process_payment() - if(total_price > credits) - say("Insufficient credits.") - return FALSE - else - return TRUE - -/obj/machinery/lapvend/ui_data(mob/user) - - var/list/data = list() - data["state"] = state - if(state == 1) - data["devtype"] = devtype - if(state == 1 || state == 2) - data["totalprice"] = total_price - data["credits"] = credits - - return data - - -/obj/machinery/lapvend/proc/try_purchase() - // Awaiting payment state - if(state == 2) - if(process_payment()) - fabricate_and_recalc_price(1) - if((devtype == 1) && fabricated_laptop) - fabricated_laptop.forceMove(src.loc) - fabricated_laptop = null - else if((devtype == 2) && fabricated_tablet) - fabricated_tablet.forceMove(src.loc) - fabricated_tablet = null - credits -= total_price - say("Enjoy your new product!") - state = 3 - addtimer(CALLBACK(src, PROC_REF(reset_order)), 100) - return TRUE - return FALSE diff --git a/code/modules/paperwork/paper_cutter.dm b/code/modules/paperwork/paper_cutter.dm index 31cbe153f9e862..9586ec6e861841 100644 --- a/code/modules/paperwork/paper_cutter.dm +++ b/code/modules/paperwork/paper_cutter.dm @@ -171,8 +171,9 @@ to_chat(user, span_userdanger("You neatly cut [stored_paper][clumsy ? "... and your finger in the process!" : "."]")) if(clumsy) var/obj/item/bodypart/finger = user.get_active_hand() - var/datum/wound/slash/flesh/moderate/papercut = new - papercut.apply_wound(finger, wound_source = "paper cut") + if (iscarbon(user)) + var/mob/living/carbon/carbon_user = user + carbon_user.cause_wound_of_type_and_severity(WOUND_SLASH, finger, WOUND_SEVERITY_MODERATE, wound_source = "paper cut") stored_paper = null qdel(stored_paper) new /obj/item/paper/paperslip(get_turf(src)) diff --git a/code/modules/paperwork/ticketmachine.dm b/code/modules/paperwork/ticketmachine.dm index 8d62bf784cbd90..a5902a9df5a20a 100644 --- a/code/modules/paperwork/ticketmachine.dm +++ b/code/modules/paperwork/ticketmachine.dm @@ -31,6 +31,7 @@ /obj/machinery/ticket_machine/Initialize(mapload) . = ..() update_appearance() + find_and_hang_on_wall() /obj/machinery/ticket_machine/Destroy() for(var/obj/item/ticket_machine_ticket/ticket in tickets) @@ -55,7 +56,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/ticket_machine, 32) return var/obj/item/multitool/M = I M.set_buffer(src) - to_chat(user, span_notice("You store linkage information in [I]'s buffer.")) + balloon_alert(user, "saved to multitool buffer") return TRUE /obj/machinery/ticket_machine/emag_act(mob/user, obj/item/card/emag/emag_card) //Emag the ticket machine to dispense burning tickets, as well as randomize its number to destroy the HoP's mind. diff --git a/code/modules/photography/camera/camera.dm b/code/modules/photography/camera/camera.dm index 33c22c66aef16b..1c0e360ed75853 100644 --- a/code/modules/photography/camera/camera.dm +++ b/code/modules/photography/camera/camera.dm @@ -187,7 +187,7 @@ var/list/turfs = list() var/list/mobs = list() var/blueprints = FALSE - var/clone_area = SSmapping.RequestBlockReservation(size_x * 2 + 1, size_y * 2 + 1) + var/clone_area = SSmapping.request_turf_block_reservation(size_x * 2 + 1, size_y * 2 + 1, 1) var/width = size_x * 2 + 1 var/height = size_y * 2 + 1 diff --git a/code/modules/photography/camera/camera_image_capturing.dm b/code/modules/photography/camera/camera_image_capturing.dm index 6b48e29da52ed3..d928164ff014df 100644 --- a/code/modules/photography/camera/camera_image_capturing.dm +++ b/code/modules/photography/camera/camera_image_capturing.dm @@ -16,13 +16,14 @@ var/wipe_atoms = FALSE if(istype(clone_area) && total_x == clone_area.width && total_y == clone_area.height && size_x >= 0 && size_y > 0) - var/cloned_center_x = round(clone_area.bottom_left_coords[1] + ((total_x - 1) / 2)) - var/cloned_center_y = round(clone_area.bottom_left_coords[2] + ((total_y - 1) / 2)) + var/turf/bottom_left = clone_area.bottom_left_turfs[1] + var/cloned_center_x = round(bottom_left.x + ((total_x - 1) / 2)) + var/cloned_center_y = round(bottom_left.y + ((total_y - 1) / 2)) for(var/t in turfs) var/turf/T = t var/offset_x = T.x - center.x var/offset_y = T.y - center.y - var/turf/newT = locate(cloned_center_x + offset_x, cloned_center_y + offset_y, clone_area.bottom_left_coords[3]) + var/turf/newT = locate(cloned_center_x + offset_x, cloned_center_y + offset_y, bottom_left.z) if(!(newT in clone_area.reserved_turfs)) //sanity check so we don't overwrite other areas somehow continue atoms += new /obj/effect/appearance_clone(newT, T) @@ -34,7 +35,7 @@ atoms += new /obj/effect/appearance_clone(newT, A) skip_normal = TRUE wipe_atoms = TRUE - center = locate(cloned_center_x, cloned_center_y, clone_area.bottom_left_coords[3]) + center = locate(cloned_center_x, cloned_center_y, bottom_left.z) if(!skip_normal) for(var/i in turfs) diff --git a/code/modules/plumbing/plumbers/grinder_chemical.dm b/code/modules/plumbing/plumbers/grinder_chemical.dm index 5e3c3b0f5d3ab9..e70977bc1f4450 100644 --- a/code/modules/plumbing/plumbers/grinder_chemical.dm +++ b/code/modules/plumbing/plumbers/grinder_chemical.dm @@ -1,6 +1,6 @@ /obj/machinery/plumbing/grinder_chemical name = "chemical grinder" - desc = "chemical grinder." + desc = "Chemical grinder. Can either grind or juice stuff you put in." icon_state = "grinder_chemical" layer = ABOVE_ALL_MOB_LAYER plane = ABOVE_GAME_PLANE @@ -8,7 +8,6 @@ reagent_flags = TRANSPARENT | DRAINABLE buffer = 400 active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 2 - var/eat_dir = SOUTH /obj/machinery/plumbing/grinder_chemical/Initialize(mapload, bolt, layer) . = ..() @@ -18,21 +17,35 @@ ) AddElement(/datum/element/connect_loc, loc_connections) -/obj/machinery/plumbing/grinder_chemical/setDir(newdir) - . = ..() - eat_dir = newdir +/obj/machinery/plumbing/grinder_chemical/attackby(obj/item/weapon, mob/user, params) + if(istype(weapon, /obj/item/storage/bag)) + to_chat(user, span_notice("You dump items from [weapon] into the grinder.")) + for(var/obj/item/obj_item in weapon.contents) + grind(obj_item) + else + to_chat(user, span_notice("You attempt to grind [weapon].")) + grind(weapon) + + return TRUE /obj/machinery/plumbing/grinder_chemical/CanAllowThrough(atom/movable/mover, border_dir) . = ..() if(!anchored) return - if(border_dir == eat_dir) - return TRUE + if(!istype(mover, /obj/item)) + return FALSE + return TRUE /obj/machinery/plumbing/grinder_chemical/proc/on_entered(datum/source, atom/movable/AM) SIGNAL_HANDLER + grind(AM) +/** + * Grinds/Juices the atom + * Arguments + * * [AM][atom] - the atom to grind or juice + */ /obj/machinery/plumbing/grinder_chemical/proc/grind(atom/AM) if(machine_stat & NOPOWER) return @@ -40,11 +53,14 @@ return if(!isitem(AM)) return + var/obj/item/I = AM + var/result if(I.grind_results || I.juice_typepath) use_power(active_power_usage) if(I.grind_results) - I.grind(src, src) + result = I.grind(reagents, usr) else if (I.juice_typepath) - I.juice(src, src) - qdel(I) + result = I.juice(reagents, usr) + if(result) + qdel(I) diff --git a/code/modules/plumbing/plumbers/teleporter.dm b/code/modules/plumbing/plumbers/teleporter.dm index 7b3a62c9939862..a8e6e7ae3ac554 100644 --- a/code/modules/plumbing/plumbers/teleporter.dm +++ b/code/modules/plumbing/plumbers/teleporter.dm @@ -73,7 +73,7 @@ var/obj/item/multitool/M = I M.set_buffer(src) - to_chat(user, span_notice("You store linkage information in [I]'s buffer.")) + balloon_alert(user, "saved to multitool buffer") return TRUE /obj/machinery/plumbing/receiver/process(seconds_per_tick) diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm index b9f60aea016883..fb9fd389c1777f 100644 --- a/code/modules/power/apc/apc_main.dm +++ b/code/modules/power/apc/apc_main.dm @@ -212,6 +212,7 @@ AddElement(/datum/element/contextual_screentip_bare_hands, rmb_text = "Toggle interface lock") AddElement(/datum/element/contextual_screentip_mob_typechecks, hovering_mob_typechecks) + find_and_hang_on_wall() /obj/machinery/power/apc/Destroy() if(malfai && operating) diff --git a/code/modules/power/floodlight.dm b/code/modules/power/floodlight.dm index 3ab8ece250f071..f36c9b1303866d 100644 --- a/code/modules/power/floodlight.dm +++ b/code/modules/power/floodlight.dm @@ -144,6 +144,7 @@ /obj/machinery/power/floodlight/Initialize(mapload) . = ..() RegisterSignal(src, COMSIG_OBJ_PAINTED, TYPE_PROC_REF(/obj/machinery/power/floodlight, on_color_change)) //update light color when color changes + RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) register_context() /obj/machinery/power/floodlight/proc/on_color_change(obj/machinery/power/flood_light, mob/user, obj/item/toy/crayon/spraycan/spraycan, is_dark_color) @@ -289,6 +290,11 @@ /obj/machinery/power/floodlight/attack_ai(mob/user) return attack_hand(user) +/obj/machinery/power/floodlight/proc/on_saboteur(datum/source, disrupt_duration) + SIGNAL_HANDLER + atom_break(ENERGY) // technically, + return COMSIG_SABOTEUR_SUCCESS + /obj/machinery/power/floodlight/atom_break(damage_flag) . = ..() if(!.) @@ -297,7 +303,8 @@ var/obj/structure/floodlight_frame/floodlight_frame = new(loc) floodlight_frame.state = FLOODLIGHT_NEEDS_LIGHTS - new /obj/item/light/tube(loc) + var/obj/item/light/tube/our_light = new(loc) + our_light.shatter() qdel(src) diff --git a/code/modules/power/lighting/light.dm b/code/modules/power/lighting/light.dm index 2486a6500c148d..ed4b2159cab6fc 100644 --- a/code/modules/power/lighting/light.dm +++ b/code/modules/power/lighting/light.dm @@ -114,7 +114,9 @@ // Light projects out backwards from the dir of the light set_light(l_dir = REVERSE_DIR(dir)) RegisterSignal(src, COMSIG_LIGHT_EATER_ACT, PROC_REF(on_light_eater)) + RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) AddElement(/datum/element/atmos_sensitive, mapload) + find_and_hang_on_wall(custom_drop_callback = CALLBACK(src, PROC_REF(knock_down))) return INITIALIZE_HINT_LATELOAD /obj/machinery/light/LateInitialize() @@ -706,6 +708,11 @@ tube?.burn() return +/obj/machinery/light/proc/on_saboteur(datum/source, disrupt_duration) + SIGNAL_HANDLER + break_light_tube() + return COMSIG_SABOTEUR_SUCCESS + /obj/machinery/light/proc/grey_tide(datum/source, list/grey_tide_areas) SIGNAL_HANDLER @@ -714,6 +721,20 @@ continue INVOKE_ASYNC(src, PROC_REF(flicker)) +/** + * All the effects that occur when a light falls off a wall that it was hung onto. + */ +/obj/machinery/light/proc/knock_down() + new /obj/item/wallframe/light_fixture(drop_location()) + new /obj/item/stack/cable_coil(drop_location(), 1, "red") + if(status != LIGHT_BROKEN) + break_light_tube(FALSE) + if(status != LIGHT_EMPTY) + drop_light_tube() + if(cell) + cell.forceMove(drop_location()) + qdel(src) + /obj/machinery/light/floor name = "floor light" desc = "A lightbulb you can walk on without breaking it, amazing." diff --git a/code/modules/power/lighting/light_construct.dm b/code/modules/power/lighting/light_construct.dm index 5a8f406b86c7b4..05d9533c79ea76 100644 --- a/code/modules/power/lighting/light_construct.dm +++ b/code/modules/power/lighting/light_construct.dm @@ -33,6 +33,7 @@ . = ..() if(building) setDir(ndir) + find_and_hang_on_wall() /obj/structure/light_construct/Destroy() QDEL_NULL(cell) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index d3e4fe9e808ef7..0a797a2d7d6816 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -14,6 +14,7 @@ /// the prepended string to the icon state (singularity_s1, dark_matter_s1, etc) var/singularity_icon_variant = "singularity" + /// The singularity component itself. /// A weak ref in case an admin removes the component to preserve the functionality. var/datum/weakref/singularity_component @@ -55,6 +56,8 @@ /obj/singularity/Initialize(mapload, starting_energy = 50) . = ..() + energy = starting_energy + START_PROCESSING(SSsinguloprocess, src) SSpoints_of_interest.make_point_of_interest(src) @@ -212,7 +215,7 @@ if(STAGE_TWO) if(check_cardinals_range(1, TRUE)) current_size = STAGE_TWO - icon = 'icons/obj/machines/engine/singularity.dmi' + icon = 'icons/effects/96x96.dmi' icon_state = "[singularity_icon_variant]_s3" pixel_x = -32 pixel_y = -32 @@ -224,7 +227,7 @@ if(STAGE_THREE) if(check_cardinals_range(2, TRUE)) current_size = STAGE_THREE - icon = 'icons/obj/machines/engine/singularity.dmi' + icon = 'icons/effects/160x160.dmi' icon_state = "[singularity_icon_variant]_s5" pixel_x = -64 pixel_y = -64 @@ -236,7 +239,7 @@ if(STAGE_FOUR) if(check_cardinals_range(3, TRUE)) current_size = STAGE_FOUR - icon = 'icons/obj/machines/engine/singularity.dmi' + icon = 'icons/effects/224x224.dmi' icon_state = "[singularity_icon_variant]_s7" pixel_x = -96 pixel_y = -96 @@ -247,7 +250,7 @@ dissipate_strength = 10 if(STAGE_FIVE)//this one also lacks a check for gens because it eats everything current_size = STAGE_FIVE - icon = 'icons/obj/machines/engine/singularity.dmi' + icon = 'icons/effects/288x288.dmi' icon_state = "[singularity_icon_variant]_s9" pixel_x = -128 pixel_y = -128 diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 15fba3cc8fe6e6..654ea8054400fe 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -39,6 +39,8 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) var/absorption_ratio = 0.15 /// The gasmix we just recently absorbed. Tile's air multiplied by absorption_ratio var/datum/gas_mixture/absorbed_gasmix + /// The current gas behaviors for this particular crystal + var/list/current_gas_behavior ///Refered to as EER on the monitor. This value effects gas output, damage, and power generation. var/internal_energy = 0 @@ -109,7 +111,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) ///The cutoff for a bolt jumping, grows with heat, lowers with higher mol count, var/zap_cutoff = 1500 ///How much the bullets damage should be multiplied by when it is added to the internal variables - var/bullet_energy = 2 + var/bullet_energy = SUPERMATTER_DEFAULT_BULLET_ENERGY ///How much hallucination should we produce per unit of power? var/hallucination_power = 0.1 @@ -172,11 +174,14 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) /// Lazy list of the crazy engineers who managed to turn a cascading engine around. var/list/datum/weakref/saviors = null + /// If a sliver of the supermatter has been removed. Almost certainly by a traitor. Lowers the delamination countdown time. + var/supermatter_sliver_removed = FALSE /// Cooldown for sending emergency alerts to the common radio channel COOLDOWN_DECLARE(common_radio_cooldown) /obj/machinery/power/supermatter_crystal/Initialize(mapload) . = ..() + current_gas_behavior = init_sm_gas() gas_percentage = list() absorbed_gasmix = new() uid = gl_uid++ @@ -265,22 +270,25 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) // Some extra effects like [/datum/sm_gas/carbon_dioxide/extra_effects] // needs more than one gas and rely on a fully parsed gas_percentage. for (var/gas_path in absorbed_gasmix.gases) - var/datum/sm_gas/sm_gas = GLOB.sm_gas_behavior[gas_path] + var/datum/sm_gas/sm_gas = current_gas_behavior[gas_path] sm_gas?.extra_effects(src) // PART 3: POWER PROCESSING internal_energy_factors = calculate_internal_energy() zap_factors = calculate_zap_multiplier() - if(internal_energy && (last_power_zap + 4 SECONDS - (internal_energy * 0.001)) < world.time) + if(internal_energy && (last_power_zap + (4 - internal_energy * 0.001) SECONDS) < world.time) playsound(src, 'sound/weapons/emitter2.ogg', 70, TRUE) hue_angle_shift = clamp(903 * log(10, (internal_energy + 8000)) - 3590, -50, 240) var/zap_color = color_matrix_rotate_hue(hue_angle_shift) + //Scale the strength of the zap with the world's time elapsed between zaps in seconds. + //Capped at 16 seconds to prevent a crazy burst of energy if atmos was halted for a long time. + var/delta_time = min((world.time - last_power_zap) * 0.1, 16) supermatter_zap( zapstart = src, range = 3, - zap_str = 5 * internal_energy * zap_multiplier, + zap_str = 1.25 * internal_energy * zap_multiplier * delta_time, zap_flags = ZAP_SUPERMATTER_FLAGS, - zap_cutoff = 300, + zap_cutoff = 300 * delta_time, power_level = internal_energy, color = zap_color, ) @@ -505,10 +513,23 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) radio.talk_into( src, count_down_messages[1], - emergency_channel + emergency_channel, + list(SPAN_COMMAND) ) - for(var/i in SUPERMATTER_COUNTDOWN_TIME to 0 step -10) + var/delamination_countdown_time = SUPERMATTER_COUNTDOWN_TIME + // If a sliver was removed from the supermatter, the countdown time is significantly decreased + if (supermatter_sliver_removed == TRUE) + delamination_countdown_time = SUPERMATTER_SLIVER_REMOVED_COUNTDOWN_TIME + radio.talk_into( + src, + "WARNING: Projected time until full crystal delamination significantly lower than expected. \ + Please inspect crystal for structural abnormalities or sabotage!", + emergency_channel, + list(SPAN_COMMAND) + ) + + for(var/i in delamination_countdown_time to 0 step -10) if(last_delamination_strategy != delamination_strategy) count_down_messages = delamination_strategy.count_down_messages() last_delamination_strategy = delamination_strategy @@ -583,7 +604,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) if(mole_count < MINIMUM_MOLE_COUNT) //save processing power from small amounts like these continue gas_percentage[gas_path] = mole_count / total_moles - var/datum/sm_gas/sm_gas = GLOB.sm_gas_behavior[gas_path] + var/datum/sm_gas/sm_gas = current_gas_behavior[gas_path] if(!sm_gas) continue gas_power_transmission += sm_gas.power_transmission * gas_percentage[gas_path] @@ -919,7 +940,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) multi = 8 if(zap_flags & ZAP_SUPERMATTER_FLAGS) var/remaining_power = target.zap_act(zap_str * multi, zap_flags) - zap_str = remaining_power * 0.5 //Coils should take a lot out of the power of the zap + zap_str = remaining_power / multi //Coils should take a lot out of the power of the zap else zap_str /= 3 diff --git a/code/modules/power/supermatter/supermatter_hit_procs.dm b/code/modules/power/supermatter/supermatter_hit_procs.dm index 5c68669e6e245e..452b37e054100e 100644 --- a/code/modules/power/supermatter/supermatter_hit_procs.dm +++ b/code/modules/power/supermatter/supermatter_hit_procs.dm @@ -67,6 +67,7 @@ if (scalpel.usesLeft) to_chat(user, span_danger("You extract a sliver from \the [src]. \The [src] begins to react violently!")) new /obj/item/nuke_core/supermatter_sliver(src.drop_location()) + supermatter_sliver_removed = TRUE external_power_trickle += 800 log_activation(who = user, how = scalpel) scalpel.usesLeft-- diff --git a/code/modules/procedural_mapping/mapGenerators/repair.dm b/code/modules/procedural_mapping/mapGenerators/repair.dm index c9df8496389d15..505dc36f02c12a 100644 --- a/code/modules/procedural_mapping/mapGenerators/repair.dm +++ b/code/modules/procedural_mapping/mapGenerators/repair.dm @@ -28,7 +28,18 @@ var/z_offset = SSmapping.station_start var/list/bounds for (var/path in SSmapping.config.GetFullMapPaths()) - var/datum/parsed_map/parsed = load_map(file(path), 1, 1, z_offset, measureOnly = FALSE, no_changeturf = FALSE, cropMap=TRUE, x_lower = mother1.x_low, y_lower = mother1.y_low, x_upper = mother1.x_high, y_upper = mother1.y_high) + var/datum/parsed_map/parsed = load_map( + file(path), + 1, + 1, + z_offset, + no_changeturf = FALSE, + crop_map = TRUE, + x_lower = mother1.x_low, + y_lower = mother1.y_low, + x_upper = mother1.x_high, + y_upper = mother1.y_high, + ) bounds = parsed?.bounds z_offset += bounds[MAP_MAXZ] - bounds[MAP_MINZ] + 1 diff --git a/code/modules/projectiles/ammunition/_ammunition.dm b/code/modules/projectiles/ammunition/_ammunition.dm index 9641adc29b56e7..e492afb776b752 100644 --- a/code/modules/projectiles/ammunition/_ammunition.dm +++ b/code/modules/projectiles/ammunition/_ammunition.dm @@ -30,8 +30,6 @@ var/click_cooldown_override = 0 ///the visual effect appearing when the ammo is fired. var/firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect - ///Does this leave a casing behind? - var/is_cased_ammo = TRUE ///pacifism check for boolet, set to FALSE if bullet is non-lethal var/harmful = TRUE @@ -148,8 +146,6 @@ return ..() /obj/item/ammo_casing/proc/bounce_away(still_warm = FALSE, bounce_delay = 3) - if(!is_cased_ammo) - return update_appearance() SpinAnimation(10, 1) var/turf/T = get_turf(src) diff --git a/code/modules/projectiles/ammunition/ballistic/shotgun.dm b/code/modules/projectiles/ammunition/ballistic/shotgun.dm index e1f233d51f862e..53ff1f8a350419 100644 --- a/code/modules/projectiles/ammunition/ballistic/shotgun.dm +++ b/code/modules/projectiles/ammunition/ballistic/shotgun.dm @@ -106,12 +106,12 @@ /obj/item/ammo_casing/shotgun/improvised name = "improvised shell" - desc = "An extremely weak shotgun shell with multiple small pellets made out of metal shards." + desc = "A homemade shotgun casing filled with crushed glass, used to commmit vandalism and property damage." icon_state = "improvshell" projectile_type = /obj/projectile/bullet/pellet/shotgun_improvised - custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*2.5) - pellets = 10 - variance = 25 + custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*2, /datum/material/glass=SMALL_MATERIAL_AMOUNT*1) + pellets = 6 + variance = 30 /obj/item/ammo_casing/shotgun/ion name = "ion shell" diff --git a/code/modules/projectiles/ammunition/energy/_energy.dm b/code/modules/projectiles/ammunition/energy/_energy.dm index 788c0f7810ddc8..808cbdfbfe77c9 100644 --- a/code/modules/projectiles/ammunition/energy/_energy.dm +++ b/code/modules/projectiles/ammunition/energy/_energy.dm @@ -8,8 +8,4 @@ var/select_name = CALIBER_ENERGY fire_sound = 'sound/weapons/laser.ogg' firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect/energy - is_cased_ammo = FALSE - - //SKYRAT EDIT ADD - CELL LOADED GUNS - var/select_color = FALSE //This is the color that shows up when selecting an ammo type. Disabled by default - //SKYRAT EDIT ADD END + var/select_color = FALSE //SKYRAT EDIT ADDITION - This is the color that shows up when selecting an ammo type. Disabled by default diff --git a/code/modules/projectiles/ammunition/energy/special.dm b/code/modules/projectiles/ammunition/energy/special.dm index bedfab7b23574a..24fba4b9ba492a 100644 --- a/code/modules/projectiles/ammunition/energy/special.dm +++ b/code/modules/projectiles/ammunition/energy/special.dm @@ -74,3 +74,9 @@ select_name = "marksman nanoshot" e_cost = 0 fire_sound = 'sound/weapons/gun/revolver/shot_alt.ogg' + +/obj/item/ammo_casing/energy/fisher + projectile_type = /obj/projectile/energy/fisher + select_name = "light-buster" + e_cost = 250 + fire_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg' // fwip fwip fwip fwip diff --git a/code/modules/projectiles/ammunition/special/magic.dm b/code/modules/projectiles/ammunition/special/magic.dm index c6737fd3cabbbe..9135e3ec5b9475 100644 --- a/code/modules/projectiles/ammunition/special/magic.dm +++ b/code/modules/projectiles/ammunition/special/magic.dm @@ -4,7 +4,6 @@ slot_flags = null projectile_type = /obj/projectile/magic firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect/magic - is_cased_ammo = FALSE /obj/item/ammo_casing/magic/change projectile_type = /obj/projectile/magic/change diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 969004589228b5..e76af741a1840b 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -26,6 +26,7 @@ var/vary_fire_sound = TRUE var/fire_sound_volume = 50 var/dry_fire_sound = 'sound/weapons/gun/general/dry_fire.ogg' + var/dry_fire_sound_volume = 30 var/suppressed = null //whether or not a message is displayed when fired var/can_suppress = FALSE var/suppressed_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg' @@ -44,7 +45,7 @@ var/weapon_weight = WEAPON_LIGHT var/dual_wield_spread = 24 //additional spread when dual wielding ///Can we hold up our target with this? Default to yes - var/can_hold_up = TRUE + var/can_hold_up = FALSE // SKYRAT EDIT - DISABLED ORIGINAL: TRUE /// Just 'slightly' snowflakey way to modify projectile damage for projectiles fired from this gun. var/projectile_damage_multiplier = 1 @@ -169,7 +170,7 @@ /obj/item/gun/proc/shoot_with_empty_chamber(mob/living/user as mob|obj) balloon_alert_to_viewers("*click*") - playsound(src, dry_fire_sound, 30, TRUE) + playsound(src, dry_fire_sound, dry_fire_sound_volume, TRUE) /obj/item/gun/proc/fire_sounds() if(suppressed) diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index 61dcb1748e4528..576ba6395be72e 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -441,9 +441,6 @@ if (sawn_off) bonus_spread += SAWN_OFF_ACC_PENALTY - if(magazine && !chambered.is_cased_ammo) - magazine.stored_ammo -= chambered - return ..() /obj/item/gun/ballistic/shoot_live_shot(mob/living/user, pointblank = 0, atom/pbtarget = null, message = 1) diff --git a/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm b/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm index d9443719a7e3ef..5d33b3fce5170f 100644 --- a/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm +++ b/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm @@ -11,7 +11,6 @@ throwforce = 1 firing_effect_type = null caliber = CALIBER_ARROW - is_cased_ammo = FALSE ///Whether the bullet type spawns another casing of the same type or not. var/reusable = TRUE diff --git a/code/modules/projectiles/guns/energy/beam_rifle.dm b/code/modules/projectiles/guns/energy/beam_rifle.dm index 68479abbf47d7a..8869da14a59e33 100644 --- a/code/modules/projectiles/guns/energy/beam_rifle.dm +++ b/code/modules/projectiles/guns/energy/beam_rifle.dm @@ -30,7 +30,6 @@ ammo_type = list(/obj/item/ammo_casing/energy/beam_rifle/hitscan) actions_types = list(/datum/action/item_action/zoom_lock_action) cell_type = /obj/item/stock_parts/cell/beam_rifle - canMouseDown = TRUE var/aiming = FALSE var/aiming_time = 12 var/aiming_time_fire_threshold = 5 @@ -72,8 +71,6 @@ var/current_zoom_x = 0 var/current_zoom_y = 0 - var/mob/listeningTo - /obj/item/gun/energy/beam_rifle/apply_fantasy_bonuses(bonus) . = ..() delay = modify_fantasy_variable("delay", delay, -bonus * 2) @@ -179,7 +176,6 @@ STOP_PROCESSING(SSfastprocess, src) set_user(null) QDEL_LIST(current_tracers) - listeningTo = null return ..() /obj/item/gun/energy/beam_rifle/emp_act(severity) @@ -232,30 +228,28 @@ if(!istype(current_user) || !isturf(current_user.loc) || !(src in current_user.held_items) || current_user.incapacitated()) //Doesn't work if you're not holding it! if(automatic_cleanup) stop_aiming() - set_user(null) return FALSE return TRUE -/obj/item/gun/energy/beam_rifle/proc/process_aim() - if(istype(current_user) && current_user.client && current_user.client.mouseParams) - var/angle = mouse_angle_from_client(current_user.client) - current_user.setDir(angle2dir_cardinal(angle)) - var/difference = abs(closer_angle_difference(lastangle, angle)) - delay_penalty(difference * aiming_time_increase_angle_multiplier) - lastangle = angle +/obj/item/gun/energy/beam_rifle/proc/process_aim(params) + var/angle = mouse_angle_from_client(current_user?.client, params) + current_user.setDir(angle2dir_cardinal(angle)) + var/difference = abs(closer_angle_difference(lastangle, angle)) + delay_penalty(difference * aiming_time_increase_angle_multiplier) + lastangle = angle /obj/item/gun/energy/beam_rifle/proc/on_mob_move() SIGNAL_HANDLER check_user() if(aiming) delay_penalty(aiming_time_increase_user_movement) - process_aim() + process_aim(current_user?.client?.mouseParams) INVOKE_ASYNC(src, PROC_REF(aiming_beam), TRUE) -/obj/item/gun/energy/beam_rifle/proc/start_aiming() +/obj/item/gun/energy/beam_rifle/proc/start_aiming(params) aiming_time_left = aiming_time aiming = TRUE - process_aim() + process_aim(params) aiming_beam(TRUE) zooming_angle = lastangle start_zooming() @@ -271,47 +265,65 @@ if(user == current_user) return stop_aiming(current_user) - if(listeningTo) - UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) - listeningTo = null if(istype(current_user)) + unregister_client_signals(current_user) + UnregisterSignal(current_user, list(COMSIG_MOVABLE_MOVED, COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT)) current_user = null - if(istype(user)) - current_user = user - RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(on_mob_move)) - listeningTo = user + if(!istype(user)) + return + current_user = user + RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(on_mob_move)) + RegisterSignal(user, COMSIG_MOB_LOGIN, PROC_REF(register_client_signals)) + RegisterSignal(user, COMSIG_MOB_LOGOUT, PROC_REF(unregister_client_signals)) + if(user.client) + register_client_signals(user) + +/obj/item/gun/energy/beam_rifle/proc/register_client_signals(mob/source) + SIGNAL_HANDLER + RegisterSignal(source.client, COMSIG_CLIENT_MOUSEDOWN, PROC_REF(on_mouse_down)) + +/obj/item/gun/energy/beam_rifle/proc/unregister_client_signals(mob/source) + SIGNAL_HANDLER + stop_aiming() + if(QDELETED(source.client)) + return + UnregisterSignal(source.client, list(COMSIG_CLIENT_MOUSEDOWN, COMSIG_CLIENT_MOUSEUP, COMSIG_CLIENT_MOUSEDRAG)) -/obj/item/gun/energy/beam_rifle/onMouseDrag(src_object, over_object, src_location, over_location, params, mob) +///change the aiming beam angle to that of the mouse cursor. +/obj/item/gun/energy/beam_rifle/proc/on_mouse_drag(client/source, src_object, over_object, src_location, over_location, src_control, over_control, params) + SIGNAL_HANDLER if(aiming) - process_aim() - aiming_beam() + process_aim(params) + INVOKE_ASYNC(src, PROC_REF(aiming_beam)) if(zoom_lock == ZOOM_LOCK_AUTOZOOM_FREEMOVE) zooming_angle = lastangle set_autozoom_pixel_offsets_immediate(zooming_angle) - return ..() -/obj/item/gun/energy/beam_rifle/onMouseDown(object, location, params, mob/mob) - if(istype(mob)) - set_user(mob) - if(istype(object, /atom/movable/screen) && !istype(object, /atom/movable/screen/click_catcher)) +///Start aiming and charging the beam +/obj/item/gun/energy/beam_rifle/proc/on_mouse_down(client/source, atom/movable/object, location, control, params) + SIGNAL_HANDLER + if(source.mob.get_active_held_item() != src) return - if((object in mob.contents) || (object == mob)) + if(!object.IsAutoclickable() || (object in source.mob.contents) || (object == source.mob)) return - start_aiming() - return ..() + INVOKE_ASYNC(src, PROC_REF(start_aiming), params) + RegisterSignal(source, COMSIG_CLIENT_MOUSEDRAG, PROC_REF(on_mouse_drag)) + RegisterSignal(source, COMSIG_CLIENT_MOUSEUP, PROC_REF(on_mouse_up)) -/obj/item/gun/energy/beam_rifle/onMouseUp(object, location, params, mob/M) - if(istype(object, /atom/movable/screen) && !istype(object, /atom/movable/screen/click_catcher)) +///Stop aiming and fire the beam if charged enough +/obj/item/gun/energy/beam_rifle/proc/on_mouse_up(client/source, atom/movable/object, location, control, params) + SIGNAL_HANDLER + if(!object.IsAutoclickable()) return - process_aim() + process_aim(params) + UnregisterSignal(source, list(COMSIG_CLIENT_MOUSEDRAG, COMSIG_CLIENT_MOUSEUP)) if(aiming_time_left <= aiming_time_fire_threshold && check_user()) sync_ammo() - var/atom/target = M.client.mouse_object_ref?.resolve() + var/atom/target = source.mouse_object_ref?.resolve() if(target) - afterattack(target, M, FALSE, M.client.mouseParams, passthrough = TRUE) + INVOKE_ASYNC(src, PROC_REF(afterattack), target, source.mob, FALSE, source.mouseParams, passthrough = TRUE) stop_aiming() QDEL_LIST(current_tracers) - return ..() /obj/item/gun/energy/beam_rifle/afterattack(atom/target, mob/living/user, flag, params, passthrough = FALSE) . |= AFTERATTACK_PROCESSED_ITEM diff --git a/code/modules/projectiles/guns/energy/recharge.dm b/code/modules/projectiles/guns/energy/recharge.dm index 6644accd8a579c..eed27478755480 100644 --- a/code/modules/projectiles/guns/energy/recharge.dm +++ b/code/modules/projectiles/guns/energy/recharge.dm @@ -135,3 +135,36 @@ custom_materials = list(/datum/material/iron=SHEET_MATERIAL_AMOUNT*2) suppressed = null ammo_type = list(/obj/item/ammo_casing/energy/bolt/large) + +/// A silly gun that does literally zero damage, but disrupts electrical sources of light, like flashlights. +/obj/item/gun/energy/recharge/fisher + name = "\improper SC/FISHER disruptor" + desc = "A self-recharging, permanently suppressed, and very haphazardly modified accelerator handgun that does literally nothing to anything except light fixtures and cameras. \ + Can fire twice before requiring a recharge, with bolts passing through machinery, but demands precision." + icon_state = "fisher" + base_icon_state = "fisher" + dry_fire_sound_volume = 10 + w_class = WEIGHT_CLASS_SMALL + holds_charge = TRUE + suppressed = TRUE + recharge_time = 1.2 SECONDS + ammo_type = list(/obj/item/ammo_casing/energy/fisher) + +/obj/item/gun/energy/recharge/fisher/examine_more(mob/user) + . = ..() + . += span_notice("The SC/FISHER is an illegally-modified kinetic accelerator cut down and refit into a disassembled miniature energy gun chassis, with its pressure chamber \ + attenuated to launch kinetic bolts that disrupt flashlights and cameras, if only temporarily. This effect also works on cyborg headlamps, and works longer in melee.

\ + While some would argue that this is a really terrible design choice, others argue that it is very funny to be able to shoot at light sources. Caveat emptor.") + +/obj/item/gun/energy/recharge/fisher/afterattack(atom/target, mob/living/user, flag, params) + // you should just shoot them, but in case you can't/wont + . = ..() + if(user.Adjacent(target)) + var/obj/projectile/energy/fisher/melee/simulated_hit = new + simulated_hit.on_hit(target) + +/obj/item/gun/energy/recharge/fisher/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) + // ...you reeeeeally just shoot them, but in case you can't/won't + . = ..() + var/obj/projectile/energy/fisher/melee/simulated_hit = new + simulated_hit.on_hit(hit_atom) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 60bec6ac3b0803..2f5fa84c4419c5 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -231,12 +231,12 @@ SEND_SIGNAL(src, COMSIG_PROJECTILE_RANGE_OUT) qdel(src) -//to get the correct limb (if any) for the projectile hit message -/mob/living/proc/check_limb_hit(hit_zone) +/// Returns the string form of the def_zone we have hit. +/mob/living/proc/check_hit_limb_zone_name(hit_zone) if(has_limbs) return hit_zone -/mob/living/carbon/check_limb_hit(hit_zone) +/mob/living/carbon/check_hit_limb_zone_name(hit_zone) if(get_bodypart(hit_zone)) return hit_zone else //when a limb is missing the damage is actually passed to the chest @@ -250,21 +250,20 @@ * blocked - percentage of hit blocked * pierce_hit - are we piercing through or regular hitting */ -/* SKYRAT EDIT REMOVAL - MOVED TO MASTER_FILES PROJECTILE.DM /obj/projectile/proc/on_hit(atom/target, blocked = FALSE, pierce_hit) // i know that this is probably more with wands and gun mods in mind, but it's a bit silly that the projectile on_hit signal doesn't ping the projectile itself. // maybe we care what the projectile thinks! See about combining these via args some time when it's not 5AM - var/obj/item/bodypart/hit_limb + var/hit_limb_zone if(isliving(target)) var/mob/living/L = target - hit_limb = L.check_limb_hit(def_zone) + hit_limb_zone = L.check_hit_limb_zone_name(def_zone) if(fired_from) - SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle, hit_limb) - SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle, hit_limb) + SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle, hit_limb_zone) + SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle, hit_limb_zone) if(QDELETED(src)) // in case one of the above signals deleted the projectile for whatever reason return - var/turf/target_loca = get_turf(target) + var/turf/target_turf = get_turf(target) var/hitx var/hity @@ -275,66 +274,89 @@ hitx = target.pixel_x + rand(-8, 8) hity = target.pixel_y + rand(-8, 8) - if(damage > 0 && (damage_type == BRUTE || damage_type == BURN) && iswallturf(target_loca) && prob(75)) - var/turf/closed/wall/W = target_loca + // SKYRAT EDIT ADDITION BEGIN - IMPACT SOUNDS + var/impact_sound + if(hitsound) + impact_sound = hitsound + else + impact_sound = target.impact_sound + get_sfx() + playsound(src, get_sfx_skyrat(impact_sound), vol_by_damage(), TRUE, -1) + // SKYRAT EDIT ADDITION END + + if(damage > 0 && (damage_type == BRUTE || damage_type == BURN) && iswallturf(target_turf) && prob(75)) + var/turf/closed/wall/target_wall = target_turf if(impact_effect_type && !hitscan) - new impact_effect_type(target_loca, hitx, hity) + new impact_effect_type(target_wall, hitx, hity) - W.add_dent(WALL_DENT_SHOT, hitx, hity) + target_wall.add_dent(WALL_DENT_SHOT, hitx, hity) return BULLET_ACT_HIT if(!isliving(target)) if(impact_effect_type && !hitscan) - new impact_effect_type(target_loca, hitx, hity) + new impact_effect_type(target_turf, hitx, hity) + /* SKYRAT EDIT REMOVAL - IMPACT SOUNDS if(isturf(target) && hitsound_wall) var/volume = clamp(vol_by_damage() + 20, 0, 100) if(suppressed) volume = 5 playsound(loc, hitsound_wall, volume, TRUE, -1) + SKYRAT EDIT REMOVAL END */ return BULLET_ACT_HIT - var/mob/living/L = target + var/mob/living/living_target = target if(blocked != 100) // not completely blocked - if(damage && L.blood_volume && damage_type == BRUTE) - var/splatter_dir = dir - if(starting) - splatter_dir = get_dir(starting, target_loca) - if(isalien(L)) - new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target_loca, splatter_dir) - else - new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir) - if(prob(33)) - L.add_splatter_floor(target_loca) + var/obj/item/bodypart/hit_bodypart = living_target.get_bodypart(hit_limb_zone) + if (damage) + if (living_target.blood_volume && damage_type == BRUTE && (isnull(hit_bodypart) || hit_bodypart.can_bleed())) + var/splatter_dir = dir + if(starting) + splatter_dir = get_dir(starting, target_turf) + if(isalien(living_target)) + new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target_turf, splatter_dir) + else + new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_turf, splatter_dir) + if(prob(33)) + living_target.add_splatter_floor(target_turf) + else if (!isnull(hit_bodypart) && (hit_bodypart.biological_state & (BIO_METAL|BIO_WIRED))) + var/random_damage_mult = RANDOM_DECIMAL(0.85, 1.15) // SOMETIMES you can get more or less sparks + var/damage_dealt = ((damage / (1 - (blocked / 100))) * random_damage_mult) + + var/spark_amount = round((damage_dealt / PROJECTILE_DAMAGE_PER_ROBOTIC_SPARK)) + if (spark_amount > 0) + do_sparks(spark_amount, FALSE, living_target) + else if(impact_effect_type && !hitscan) - new impact_effect_type(target_loca, hitx, hity) + new impact_effect_type(target_turf, hitx, hity) var/organ_hit_text = "" - var/limb_hit = hit_limb - if(limb_hit) - organ_hit_text = " in \the [parse_zone(limb_hit)]" + if(hit_limb_zone) + organ_hit_text = " in \the [parse_zone(hit_limb_zone)]" if(suppressed == SUPPRESSED_VERY) - playsound(loc, hitsound, 5, TRUE, -1) + //playsound(loc, hitsound, 5, TRUE, -1) SKYRAT EDIT REMOVAL - IMPACT SOUNDS else if(suppressed) - playsound(loc, hitsound, 5, TRUE, -1) - to_chat(L, span_userdanger("You're shot by \a [src][organ_hit_text]!")) + //playsound(loc, hitsound, 5, TRUE, -1) SKYRAT EDIT REMOVAL - IMPACT SOUNDS + to_chat(living_target, span_userdanger("You're shot by \a [src][organ_hit_text]!")) else + /* SKYRAT EDIT REMOVAL - IMPACT SOUNDS if(hitsound) var/volume = vol_by_damage() playsound(src, hitsound, volume, TRUE, -1) - L.visible_message(span_danger("[L] is hit by \a [src][organ_hit_text]!"), \ + SKYRAT EDIT REMOVAL END */ + living_target.visible_message(span_danger("[living_target] is hit by \a [src][organ_hit_text]!"), \ span_userdanger("You're hit by \a [src][organ_hit_text]!"), null, COMBAT_MESSAGE_RANGE) - if(L.is_blind()) - to_chat(L, span_userdanger("You feel something hit you[organ_hit_text]!")) - L.on_hit(src) + if(living_target.is_blind()) + to_chat(living_target, span_userdanger("You feel something hit you[organ_hit_text]!")) + living_target.on_hit(src) var/reagent_note if(reagents?.reagent_list) reagent_note = "REAGENTS: [pretty_string_from_reagent_list(reagents.reagent_list)]" if(ismob(firer)) - log_combat(firer, L, "shot", src, reagent_note) + log_combat(firer, living_target, "shot", src, reagent_note) return BULLET_ACT_HIT if(isvehicle(firer)) @@ -344,12 +366,12 @@ if(!LAZYLEN(logging_mobs)) logging_mobs = firing_vehicle.return_drivers() for(var/mob/logged_mob as anything in logging_mobs) - log_combat(logged_mob, L, "shot", src, "from inside [firing_vehicle][logging_mobs.len > 1 ? " with multiple occupants" : null][reagent_note ? " and contained [reagent_note]" : null]") + log_combat(logged_mob, living_target, "shot", src, "from inside [firing_vehicle][logging_mobs.len > 1 ? " with multiple occupants" : null][reagent_note ? " and contained [reagent_note]" : null]") return BULLET_ACT_HIT - L.log_message("has been shot by [firer] with [src][reagent_note ? " containing [reagent_note]" : null]", LOG_VICTIM, color="orange") + living_target.log_message("has been shot by [firer] with [src][reagent_note ? " containing [reagent_note]" : null]", LOG_ATTACK, color="orange") return BULLET_ACT_HIT -*/ + /obj/projectile/proc/vol_by_damage() if(src.damage) return clamp((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then CLAMP the value between 30 and 100 diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm index 446654a3489b7d..639939e150fb78 100644 --- a/code/modules/projectiles/projectile/bullets/shotgun.dm +++ b/code/modules/projectiles/projectile/bullets/shotgun.dm @@ -118,14 +118,13 @@ embedding = null /obj/projectile/bullet/pellet/shotgun_improvised - tile_dropoff = 0.35 //Come on it does 6 damage don't be like that. - damage = 6 - wound_bonus = 0 - bare_wound_bonus = 7.5 + damage = 5 + wound_bonus = -5 + demolition_mod = 3 //Very good at acts of vandalism /obj/projectile/bullet/pellet/shotgun_improvised/Initialize(mapload) . = ..() - range = rand(1, 8) + range = rand(3, 8) /obj/projectile/bullet/pellet/shotgun_improvised/on_range() do_sparks(1, TRUE, src) diff --git a/code/modules/projectiles/projectile/special/lightbreaker.dm b/code/modules/projectiles/projectile/special/lightbreaker.dm new file mode 100644 index 00000000000000..fd7d3d89e7a97e --- /dev/null +++ b/code/modules/projectiles/projectile/special/lightbreaker.dm @@ -0,0 +1,35 @@ +/obj/projectile/energy/fisher + name = "attenuated kinetic force" + alpha = 0 + damage = 0 + damage_type = BRUTE + armor_flag = BOMB + range = 14 + projectile_phasing = PASSTABLE | PASSMOB | PASSMACHINE | PASSSTRUCTURE + hitscan = TRUE + var/disrupt_duration = 10 SECONDS + +/obj/projectile/energy/fisher/on_hit(atom/target, blocked, pierce_hit) + . = ..() + var/lights_flickered = 0 + if(SEND_SIGNAL(target, COMSIG_HIT_BY_SABOTEUR, disrupt_duration) & COMSIG_SABOTEUR_SUCCESS) + lights_flickered++ + if(!isliving(target)) + return + var/list/things_to_disrupt = list() + if(ishuman(target)) + var/mob/living/carbon/human/human_target = target + things_to_disrupt = human_target.get_all_gear() + else + var/mob/living/living_target = target // i guess this covers borgs too? + things_to_disrupt = living_target.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE) + for(var/obj/item/thingy as anything in things_to_disrupt) + if(SEND_SIGNAL(thingy, COMSIG_HIT_BY_SABOTEUR, disrupt_duration) & COMSIG_SABOTEUR_SUCCESS) + lights_flickered++ + if(lights_flickered) + to_chat(target, span_warning("Your light [lights_flickered > 1 ? "sources flick" : "source flicks"] off.")) + +/obj/projectile/energy/fisher/melee + range = 1 + suppressed = SUPPRESSED_VERY + disrupt_duration = 20 SECONDS diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index cb8a30f61b83c9..902ccf35e6ac43 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -82,10 +82,10 @@ if(reagent_to_react_count[reagent_id] < reagent_to_react_count[preferred_id]) preferred_id = reagent_id continue - - if(!reaction_lookup[preferred_id]) - reaction_lookup[preferred_id] = list() - reaction_lookup[preferred_id] += reaction + if (preferred_id != null) + if(!reaction_lookup[preferred_id]) + reaction_lookup[preferred_id] = list() + reaction_lookup[preferred_id] += reaction for(var/datum/chemical_reaction/reaction as anything in reactions) var/list/product_ids = list() @@ -1391,9 +1391,7 @@ /// Is this holder full or not /datum/reagents/proc/holder_full() - if(total_volume >= maximum_volume) - return TRUE - return FALSE + return total_volume >= maximum_volume /// Get the amount of this reagent /datum/reagents/proc/get_reagent_amount(reagent, include_subtypes = FALSE) @@ -1420,6 +1418,12 @@ return round(cached_reagent.purity, 0.01) return 0 +/// Directly set the purity of all contained reagents to a new value +/datum/reagents/proc/set_all_reagents_purity(new_purity = 0) + var/list/cached_reagents = reagent_list + for(var/datum/reagent/cached_reagent as anything in cached_reagents) + cached_reagent.purity = max(0, new_purity) + /// Get the average purity of all reagents (or all subtypes of provided typepath) /datum/reagents/proc/get_average_purity(parent_type = null) var/total_amount diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm index dc0c51edd533a8..26ebfa1d18d9fc 100644 --- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm +++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm @@ -99,11 +99,9 @@ . = ..() if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) return - if(!can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH|FORBID_TELEKINESIS_REACH)) + if(operating || !user.can_perform_action(src, ALLOW_SILICON_REACH | FORBID_TELEKINESIS_REACH)) return - if(operating) - return - replace_beaker(user) + eject(user) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN /obj/machinery/reagentgrinder/attack_robot_secondary(mob/user, list/modifiers) @@ -146,24 +144,28 @@ default_unfasten_wrench(user, tool) return TOOL_ACT_TOOLTYPE_SUCCESS -/obj/machinery/reagentgrinder/attackby(obj/item/I, mob/living/user, params) - //You can only screw open empty grinder - if(!beaker && !length(holdingitems) && default_deconstruction_screwdriver(user, icon_state, icon_state, I)) - return +/obj/machinery/reagentgrinder/screwdriver_act(mob/living/user, obj/item/tool) + . = TOOL_ACT_TOOLTYPE_SUCCESS + if(!beaker && !length(holdingitems)) + return default_deconstruction_screwdriver(user, icon_state, icon_state, tool) - if(default_deconstruction_crowbar(I)) - return +/obj/machinery/reagentgrinder/crowbar_act(mob/living/user, obj/item/tool) + return default_deconstruction_crowbar(tool) +/obj/machinery/reagentgrinder/attackby(obj/item/weapon, mob/living/user, params) if(panel_open) //Can't insert objects when its screwed open return TRUE - if (is_reagent_container(I) && !(I.item_flags & ABSTRACT) && I.is_open_container()) - var/obj/item/reagent_containers/B = I + if(!weapon.grind_requirements(src)) //Error messages should be in the objects' definitions + return + + if (is_reagent_container(weapon) && !(weapon.item_flags & ABSTRACT) && weapon.is_open_container()) + var/obj/item/reagent_containers/container = weapon . = TRUE //no afterattack - if(!user.transferItemToLoc(B, src)) + if(!user.transferItemToLoc(container, src)) return - replace_beaker(user, B) - to_chat(user, span_notice("You add [B] to [src].")) + replace_beaker(user, container) + to_chat(user, span_notice("You add [container] to [src].")) update_appearance() return TRUE //no afterattack @@ -172,39 +174,36 @@ return TRUE //Fill machine with a bag! - if(istype(I, /obj/item/storage/bag)) - if(!I.contents.len) - to_chat(user, span_notice("[I] is empty!")) + if(istype(weapon, /obj/item/storage/bag)) + if(!weapon.contents.len) + to_chat(user, span_notice("[weapon] is empty!")) return TRUE var/list/inserted = list() - if(I.atom_storage.remove_type(/obj/item/food/grown, src, limit - length(holdingitems), TRUE, FALSE, user, inserted)) + if(weapon.atom_storage.remove_type(/obj/item/food/grown, src, limit - length(holdingitems), TRUE, FALSE, user, inserted)) for(var/i in inserted) holdingitems[i] = TRUE inserted = list() - if(I.atom_storage.remove_type(/obj/item/food/honeycomb, src, limit - length(holdingitems), TRUE, FALSE, user, inserted)) + if(weapon.atom_storage.remove_type(/obj/item/food/honeycomb, src, limit - length(holdingitems), TRUE, FALSE, user, inserted)) for(var/i in inserted) holdingitems[i] = TRUE - if(!I.contents.len) - to_chat(user, span_notice("You empty [I] into [src].")) + if(!weapon.contents.len) + to_chat(user, span_notice("You empty [weapon] into [src].")) else to_chat(user, span_notice("You fill [src] to the brim.")) return TRUE - if(!I.grind_results && !I.juice_typepath) + if(!weapon.grind_results && !weapon.juice_typepath) if(user.combat_mode) return ..() else - to_chat(user, span_warning("You cannot grind [I] into reagents!")) + to_chat(user, span_warning("You cannot grind/juice [weapon] into reagents!")) return TRUE - if(!I.grind_requirements(src)) //Error messages should be in the objects' definitions - return - - if(user.transferItemToLoc(I, src)) - to_chat(user, span_notice("You add [I] to [src].")) - holdingitems[I] = TRUE + if(user.transferItemToLoc(weapon, src)) + to_chat(user, span_notice("You add [weapon] to [src].")) + holdingitems[weapon] = TRUE return FALSE /obj/machinery/reagentgrinder/ui_interact(mob/user) // The microwave Menu //I am reasonably certain that this is not a microwave @@ -261,9 +260,9 @@ if(beaker) replace_beaker(user) -/obj/machinery/reagentgrinder/proc/remove_object(obj/item/O) - holdingitems -= O - qdel(O) +/obj/machinery/reagentgrinder/proc/remove_object(obj/item/weapon) + holdingitems -= weapon + qdel(weapon) /obj/machinery/reagentgrinder/proc/start_shaking() var/static/list/transforms @@ -306,11 +305,11 @@ /obj/machinery/reagentgrinder/proc/juice(mob/user) power_change() - if(!beaker || machine_stat & (NOPOWER|BROKEN) || beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + if(!beaker || machine_stat & (NOPOWER|BROKEN) || beaker.reagents.holder_full()) return operate_for(50, juicing = TRUE) for(var/obj/item/i in holdingitems) - if(beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + if(beaker.reagents.holder_full()) break var/obj/item/I = i if(I.juice_typepath) @@ -324,12 +323,12 @@ /obj/machinery/reagentgrinder/proc/grind(mob/user) power_change() - if(!beaker || machine_stat & (NOPOWER|BROKEN) || beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + if(!beaker || machine_stat & (NOPOWER|BROKEN) || beaker.reagents.holder_full()) return operate_for(60) warn_of_dust() // don't breathe this. for(var/i in holdingitems) - if(beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + if(beaker.reagents.holder_full()) break var/obj/item/I = i if(I.grind_results) @@ -337,7 +336,10 @@ /obj/machinery/reagentgrinder/proc/grind_item(obj/item/I, mob/user) //Grind results can be found in respective object definitions if(!I.grind(beaker.reagents, user)) - to_chat(usr, span_danger("[src] shorts out as it tries to grind up [I], and transfers it back to storage.")) + if(isstack(I)) + to_chat(usr, span_notice("[src] attempts to grind as many pieces of [I] as possible.")) + else + to_chat(usr, span_danger("[src] shorts out as it tries to grind up [I], and transfers it back to storage.")) return remove_object(I) @@ -347,19 +349,21 @@ if(!beaker || machine_stat & (NOPOWER|BROKEN)) return operate_for(50, juicing = TRUE) - addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/reagentgrinder, mix_complete)), 50) + addtimer(CALLBACK(src, PROC_REF(mix_complete)), 50 / speed) /obj/machinery/reagentgrinder/proc/mix_complete() - if(beaker?.reagents.total_volume) - //Recipe to make Butter - var/butter_amt = FLOOR(beaker.reagents.get_reagent_amount(/datum/reagent/consumable/milk) / MILK_TO_BUTTER_COEFF, 1) - var/purity = beaker.reagents.get_reagent_purity(/datum/reagent/consumable/milk) - beaker.reagents.remove_reagent(/datum/reagent/consumable/milk, MILK_TO_BUTTER_COEFF * butter_amt) - for(var/i in 1 to butter_amt) - new /obj/item/food/butter(/* loc = */ drop_location(), /* starting_reagent_purity = */ purity) - //Recipe to make Mayonnaise - if (beaker.reagents.has_reagent(/datum/reagent/consumable/eggyolk)) - beaker.reagents.convert_reagent(/datum/reagent/consumable/eggyolk, /datum/reagent/consumable/mayonnaise) - //Recipe to make whipped cream - if (beaker.reagents.has_reagent(/datum/reagent/consumable/cream)) - beaker.reagents.convert_reagent(/datum/reagent/consumable/cream, /datum/reagent/consumable/whipped_cream) + if(beaker?.reagents.total_volume <= 0) + return + //Recipe to make Butter + var/butter_amt = FLOOR(beaker.reagents.get_reagent_amount(/datum/reagent/consumable/milk) / MILK_TO_BUTTER_COEFF, 1) + var/purity = beaker.reagents.get_reagent_purity(/datum/reagent/consumable/milk) + beaker.reagents.remove_reagent(/datum/reagent/consumable/milk, MILK_TO_BUTTER_COEFF * butter_amt) + for(var/i in 1 to butter_amt) + var/obj/item/food/butter/tasty_butter = new(drop_location()) + tasty_butter.reagents.set_all_reagents_purity(purity) + //Recipe to make Mayonnaise + if (beaker.reagents.has_reagent(/datum/reagent/consumable/eggyolk)) + beaker.reagents.convert_reagent(/datum/reagent/consumable/eggyolk, /datum/reagent/consumable/mayonnaise) + //Recipe to make whipped cream + if (beaker.reagents.has_reagent(/datum/reagent/consumable/cream)) + beaker.reagents.convert_reagent(/datum/reagent/consumable/cream, /datum/reagent/consumable/whipped_cream) diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index 016253baa3e900..8de1d98cc2e4e3 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -162,6 +162,10 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) return holder.remove_reagent(type, metabolization_rate * M.metabolism_efficiency * seconds_per_tick) //By default it slowly disappears. +/// Called in burns.dm *if* the reagent has the REAGENT_AFFECTS_WOUNDS process flag +/datum/reagent/proc/on_burn_wound_processing(datum/wound/burn/flesh/burn_wound) + return + /* Used to run functions before a reagent is transferred. Returning TRUE will block the transfer attempt. Primarily used in reagents/reaction_agents diff --git a/code/modules/reagents/chemistry/reagents/atmos_gas_reagents.dm b/code/modules/reagents/chemistry/reagents/atmos_gas_reagents.dm index 2299cab54933e8..817e5ed98bfe55 100644 --- a/code/modules/reagents/chemistry/reagents/atmos_gas_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/atmos_gas_reagents.dm @@ -52,7 +52,8 @@ breather.adjustFireLoss(-2 * REM * seconds_per_tick, FALSE, required_bodytype = affected_bodytype) breather.adjustToxLoss(-5 * REM * seconds_per_tick, FALSE, required_biotype = affected_biotype) breather.adjustBruteLoss(-2 * REM * seconds_per_tick, FALSE, required_bodytype = affected_bodytype) - return ..() + . = ..() + return TRUE /datum/reagent/hypernoblium name = "Hyper-Noblium" @@ -90,7 +91,8 @@ /datum/reagent/nitrium_high_metabolization/on_mob_life(mob/living/carbon/breather, seconds_per_tick, times_fired) breather.adjustStaminaLoss(-2 * REM * seconds_per_tick, FALSE, required_biotype = affected_biotype) breather.adjustToxLoss(0.1 * current_cycle * REM * seconds_per_tick, FALSE, required_biotype = affected_biotype) // 1 toxin damage per cycle at cycle 10 - return ..() + . = ..() + return TRUE /datum/reagent/nitrium_low_metabolization name = "Nitrium" @@ -123,13 +125,15 @@ if(!HAS_TRAIT(breather, TRAIT_KNOCKEDOUT)) return ..() + . = ..() for(var/obj/item/organ/organ_being_healed as anything in breather.organs) if(!organ_being_healed.damage) continue organ_being_healed.apply_organ_damage(-0.5 * REM * seconds_per_tick, required_organ_flag = ORGAN_ORGANIC) + . = TRUE - return ..() + return . /datum/reagent/zauker name = "Zauker" @@ -147,4 +151,5 @@ breather.adjustOxyLoss(1 * REM * seconds_per_tick, FALSE, required_biotype = affected_biotype, required_respiration_type = affected_respiration_type) breather.adjustFireLoss(2 * REM * seconds_per_tick, FALSE, required_bodytype = affected_bodytype) breather.adjustToxLoss(2 * REM * seconds_per_tick, FALSE, required_biotype = affected_biotype) - return ..() + ..() + return TRUE diff --git a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm index 665ecb2577e2a5..693404431faa10 100644 --- a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm @@ -46,12 +46,11 @@ if(good_kind_of_healing && !reaping && SPT_PROB(0.00005, seconds_per_tick)) //janken with the grim reaper! notify_ghosts("[affected_mob] has entered a game of rock-paper-scissors with death!", source = affected_mob, action = NOTIFY_ORBIT, header = "Who Will Win?") reaping = TRUE - var/list/RockPaperScissors = list("rock" = "paper", "paper" = "scissors", "scissors" = "rock") //choice = loses to if(affected_mob.apply_status_effect(/datum/status_effect/necropolis_curse, CURSE_BLINDING)) helbent = TRUE to_chat(affected_mob, span_hierophant("Malevolent spirits appear before you, bartering your life in a 'friendly' game of rock, paper, scissors. Which do you choose?")) var/timeisticking = world.time - var/RPSchoice = tgui_alert(affected_mob, "Janken Time! You have 60 Seconds to Choose!", "Rock Paper Scissors", RockPaperScissors, 60) + var/RPSchoice = tgui_alert(affected_mob, "Janken Time! You have 60 Seconds to Choose!", "Rock Paper Scissors", list("rock" , "paper" , "scissors"), 60) if(QDELETED(affected_mob) || (timeisticking+(1.1 MINUTES) < world.time)) reaping = FALSE return //good job, you ruined it @@ -59,21 +58,21 @@ to_chat(affected_mob, span_hierophant("You decide to not press your luck, but the spirits remain... hopefully they'll go away soon.")) reaping = FALSE return - var/grim = pick(RockPaperScissors) - if(grim == RPSchoice) //You Tied! - to_chat(affected_mob, span_hierophant("You tie, and the malevolent spirits disappear... for now.")) - reaping = FALSE - else if(RockPaperScissors[RPSchoice] == grim) //You lost! - to_chat(affected_mob, span_hierophant("You lose, and the malevolent spirits smirk eerily as they surround your body.")) - affected_mob.investigate_log("has lost rock paper scissors with the grim reaper and been dusted.", INVESTIGATE_DEATHS) - affected_mob.dust() - return - else //VICTORY ROYALE - to_chat(affected_mob, span_hierophant("You win, and the malevolent spirits fade away as well as your wounds.")) - affected_mob.client.give_award(/datum/award/achievement/jobs/helbitaljanken, affected_mob) - affected_mob.revive(HEAL_ALL) - holder.del_reagent(type) - return + switch(rand(1,3)) + if(1) //You Tied! + to_chat(affected_mob, span_hierophant("You tie, and the malevolent spirits disappear... for now.")) + reaping = FALSE + if(2) //You lost! + to_chat(affected_mob, span_hierophant("You lose, and the malevolent spirits smirk eerily as they surround your body.")) + affected_mob.investigate_log("has lost rock paper scissors with the grim reaper and been dusted.", INVESTIGATE_DEATHS) + affected_mob.dust() + return + if(3) //VICTORY ROYALE + to_chat(affected_mob, span_hierophant("You win, and the malevolent spirits fade away as well as your wounds.")) + affected_mob.client.give_award(/datum/award/achievement/jobs/helbitaljanken, affected_mob) + affected_mob.revive(HEAL_ALL) + holder.del_reagent(type) + return ..() return @@ -554,6 +553,7 @@ H.set_heartattack(TRUE) volume = 0 . = ..() + return TRUE /datum/reagent/medicine/c2/penthrite/on_mob_end_metabolize(mob/living/user) user.clear_alert("penthrite") diff --git a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm index d40ca4fd85b15d..f67b813be0ccf1 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm @@ -8,6 +8,7 @@ nutriment_factor = 0 taste_description = "alcohol" metabolization_rate = 0.5 * REAGENTS_METABOLISM + creation_purity = 1 // impure base reagents are a big no-no ph = 7.33 burning_temperature = 2193//ethanol burns at 1970C (at it's peak) burning_volume = 0.1 @@ -2143,7 +2144,7 @@ if(SPT_PROB(5, seconds_per_tick)) stored_teleports += rand(2, 6) if(prob(70)) - drinker.vomit(vomit_type = VOMIT_PURPLE) + drinker.vomit(vomit_flags = VOMIT_CATEGORY_DEFAULT, vomit_type = /obj/effect/decal/cleanable/vomit/purple) return ..() /datum/reagent/consumable/ethanol/planet_cracker diff --git a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm index 83aa18eebb51c1..36444d6229b812 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm @@ -296,10 +296,39 @@ affected_mob.AdjustSleeping(-20 * REM * seconds_per_tick) if(affected_mob.getToxLoss() && SPT_PROB(10, seconds_per_tick)) affected_mob.adjustToxLoss(-1, FALSE, required_biotype = affected_biotype) + var/to_chatted = FALSE + for(var/datum/wound/iter_wound as anything in affected_mob.all_wounds) + if(SPT_PROB(10, seconds_per_tick)) + var/helped = iter_wound.tea_life_process() + if(!to_chatted && helped) + to_chat(affected_mob, span_notice("A calm, relaxed feeling suffuses you. Your wounds feel a little healthier.")) + to_chatted = TRUE affected_mob.adjust_bodytemperature(20 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, affected_mob.get_body_temp_normal()) ..() . = TRUE +// Different handling, different name. +// Returns FALSE by default so broken bones and 'loss' wounds don't give a false message +/datum/wound/proc/tea_life_process() + return FALSE + +// Slowly increase (gauzed) clot rate +/datum/wound/pierce/bleed/tea_life_process() + gauzed_clot_rate += 0.1 + return TRUE + +// Slowly increase clot rate +/datum/wound/slash/flesh/tea_life_process() + clot_rate += 0.2 + return TRUE + +// There's a designated burn process, but I felt this would be better for consistency with the rest of the reagent's procs +/datum/wound/burn/flesh/tea_life_process() + // Sanitizes and heals, but with a limit + flesh_healing = (flesh_healing > 0.1) ? flesh_healing : flesh_healing + 0.02 + infestation_rate = max(infestation_rate - 0.005, 0) + return TRUE + /datum/reagent/consumable/lemonade name = "Lemonade" description = "Sweet, tangy lemonade. Good for the soul." diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm index 060351a8c88ca1..23d6010f1a94bb 100644 --- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm @@ -122,6 +122,7 @@ affected_human.set_hairstyle("Bald", update = FALSE) affected_mob.set_species(/datum/species/human/krokodil_addict) affected_mob.adjustBruteLoss(50 * REM, FALSE, required_bodytype = affected_bodytype) // holy shit your skin just FELL THE FUCK OFF + . = TRUE ..() /datum/reagent/drug/krokodil/overdose_process(mob/living/affected_mob, seconds_per_tick, times_fired) @@ -324,17 +325,17 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED addiction_types = list(/datum/addiction/stimulants = 6) //2.6 per 2 seconds -/datum/reagent/drug/pumpup/on_mob_metabolize(mob/living/carbon/L) - ..() - ADD_TRAIT(L, TRAIT_BATON_RESISTANCE, type) - var/obj/item/organ/internal/liver/liver = L.get_organ_slot(ORGAN_SLOT_LIVER) - if(HAS_TRAIT(liver, TRAIT_MAINTENANCE_METABOLISM)) - L.add_mood_event("maintenance_fun", /datum/mood_event/maintenance_high) +/datum/reagent/drug/pumpup/on_mob_metabolize(mob/living/carbon/affected_mob) + . = ..() + ADD_TRAIT(affected_mob, TRAIT_BATON_RESISTANCE, type) + var/obj/item/organ/internal/liver/liver = affected_mob.get_organ_slot(ORGAN_SLOT_LIVER) + if(liver && HAS_TRAIT(liver, TRAIT_MAINTENANCE_METABOLISM)) + affected_mob.add_mood_event("maintenance_fun", /datum/mood_event/maintenance_high) metabolization_rate *= 0.8 -/datum/reagent/drug/pumpup/on_mob_end_metabolize(mob/living/L) - REMOVE_TRAIT(L, TRAIT_BATON_RESISTANCE, type) - ..() +/datum/reagent/drug/pumpup/on_mob_end_metabolize(mob/living/affected_mob) + REMOVE_TRAIT(affected_mob, TRAIT_BATON_RESISTANCE, type) + return ..() /datum/reagent/drug/pumpup/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) affected_mob.set_jitter_if_lower(10 SECONDS * REM * seconds_per_tick) @@ -344,8 +345,9 @@ if(SPT_PROB(7.5, seconds_per_tick)) affected_mob.losebreath++ affected_mob.adjustToxLoss(2, FALSE, required_biotype = affected_biotype) + . = TRUE ..() - . = TRUE + /datum/reagent/drug/pumpup/overdose_start(mob/living/affected_mob) to_chat(affected_mob, span_userdanger("You can't stop shaking, your heart beats faster and faster...")) @@ -367,7 +369,7 @@ name = "Maintenance Drugs" chemical_flags = NONE -/datum/reagent/drug/pumpup/on_mob_metabolize(mob/living/carbon/L) +/datum/reagent/drug/maint/on_mob_metabolize(mob/living/carbon/L) var/obj/item/organ/internal/liver/liver = L.get_organ_slot(ORGAN_SLOT_LIVER) if(HAS_TRAIT(liver, TRAIT_MAINTENANCE_METABOLISM)) L.add_mood_event("maintenance_fun", /datum/mood_event/maintenance_high) @@ -418,6 +420,7 @@ /datum/reagent/drug/maint/sludge/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() affected_mob.adjustToxLoss(0.5 * REM * seconds_per_tick, required_biotype = affected_biotype) + return TRUE /datum/reagent/drug/maint/sludge/on_mob_end_metabolize(mob/living/affected_mob) . = ..() @@ -432,7 +435,7 @@ carbie.adjustToxLoss(1 * REM * seconds_per_tick, required_biotype = affected_biotype) if(SPT_PROB(5, seconds_per_tick)) carbie.adjustToxLoss(5, required_biotype = affected_biotype) - carbie.vomit() + carbie.vomit(VOMIT_CATEGORY_DEFAULT) /datum/reagent/drug/maint/tar name = "Maintenance Tar" @@ -445,13 +448,13 @@ /datum/reagent/drug/maint/tar/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() - affected_mob.AdjustStun(-10 * REM * seconds_per_tick) affected_mob.AdjustKnockdown(-10 * REM * seconds_per_tick) affected_mob.AdjustUnconscious(-10 * REM * seconds_per_tick) affected_mob.AdjustParalyzed(-10 * REM * seconds_per_tick) affected_mob.AdjustImmobilized(-10 * REM * seconds_per_tick) affected_mob.adjustOrganLoss(ORGAN_SLOT_LIVER, 1.5 * REM * seconds_per_tick, required_organ_flag = affected_organ_flags) + return TRUE /datum/reagent/drug/maint/tar/overdose_process(mob/living/affected_mob, seconds_per_tick, times_fired) . = ..() @@ -603,6 +606,7 @@ if(SPT_PROB(BLASTOFF_DANCE_MOVE_CHANCE_PER_UNIT * volume, seconds_per_tick)) dancer.emote("flip") + return TRUE /datum/reagent/drug/blastoff/overdose_process(mob/living/dancer, seconds_per_tick, times_fired) . = ..() @@ -670,6 +674,7 @@ /datum/reagent/drug/saturnx/on_mob_life(mob/living/carbon/invisible_man, seconds_per_tick, times_fired) . = ..() invisible_man.adjustOrganLoss(ORGAN_SLOT_LIVER, 0.3 * REM * seconds_per_tick, required_organ_flag = affected_organ_flags) + return TRUE /datum/reagent/drug/saturnx/on_mob_metabolize(mob/living/invisible_man) . = ..() @@ -785,7 +790,7 @@ //I wish i could give it some kind of bonus when smoked, but we don't have an INHALE method. /datum/reagent/drug/kronkaine/on_mob_life(mob/living/carbon/kronkaine_fiend, seconds_per_tick, times_fired) - . = ..() + . = ..() || TRUE kronkaine_fiend.add_mood_event("tweaking", /datum/mood_event/stimulant_medium, name) kronkaine_fiend.adjustOrganLoss(ORGAN_SLOT_HEART, 0.4 * REM * seconds_per_tick, required_organ_flag = affected_organ_flags) kronkaine_fiend.set_jitter_if_lower(20 SECONDS * REM * seconds_per_tick) diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index 3d9e8c40f82200..1e0559d60345ad 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -273,6 +273,7 @@ taste_mult = 1.5 // stop sugar drowning out other flavours nutriment_factor = 2 metabolization_rate = 2 * REAGENTS_METABOLISM + creation_purity = 1 // impure base reagents are a big no-no overdose_threshold = 100 // Hyperglycaemic shock taste_description = "sweetness" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED @@ -448,7 +449,7 @@ if(prob(10)) victim.set_dizzy_if_lower(2 SECONDS) if(prob(5)) - victim.vomit() + victim.vomit(VOMIT_CATEGORY_DEFAULT) /datum/reagent/consumable/condensedcapsaicin/on_mob_life(mob/living/carbon/M, seconds_per_tick, times_fired) if(!holder.has_reagent(/datum/reagent/consumable/milk)) @@ -472,6 +473,40 @@ return exposed_turf.spawn_unique_cleanable(/obj/effect/decal/cleanable/food/salt) +/datum/reagent/consumable/salt/expose_mob(mob/living/exposed_mob, methods, reac_volume) + . = ..() + var/mob/living/carbon/carbies = exposed_mob + if(!(methods & (PATCH|TOUCH|VAPOR))) + return + for(var/datum/wound/iter_wound as anything in carbies.all_wounds) + iter_wound.on_salt(reac_volume, carbies) + +// Salt can help with wounds by soaking up fluid, but undiluted salt will also cause irritation from the loose crystals, and it might soak up the body's water as well! +// A saltwater mixture would be best, but we're making improvised chems here, not real ones. +/datum/wound/proc/on_salt(reac_volume, mob/living/carbon/carbies) + return + +/datum/wound/pierce/bleed/on_salt(reac_volume, mob/living/carbon/carbies) + adjust_blood_flow(-0.06 * reac_volume, initial_flow * 0.6) // 20u of a salt shacker * 0.1 = -1.6~ blood flow, but is always clamped to, at best, third blood loss from that wound. + // Crystal irritation worsening recovery. + gauzed_clot_rate *= 0.65 + to_chat(carbies, span_notice("The salt bits seep in and stick to [lowertext(src)], painfully irritating the skin but soaking up most of the blood.")) + +/datum/wound/slash/flesh/on_salt(reac_volume, mob/living/carbon/carbies) + adjust_blood_flow(-0.1 * reac_volume, initial_flow * 0.5) // 20u of a salt shacker * 0.1 = -2~ blood flow, but is always clamped to, at best, halve blood loss from that wound. + // Crystal irritation worsening recovery. + clot_rate *= 0.75 + to_chat(carbies, span_notice("The salt bits seep in and stick to [lowertext(src)], painfully irritating the skin but soaking up most of the blood.")) + +/datum/wound/burn/flesh/on_salt(reac_volume) + // Slightly sanitizes and disinfects, but also increases infestation rate (some bacteria are aided by salt), and decreases flesh healing (can damage the skin from moisture absorption) + sanitization += VALUE_PER(0.4, 30) * reac_volume + infestation -= max(VALUE_PER(0.3, 30) * reac_volume, 0) + infestation_rate += VALUE_PER(0.12, 30) * reac_volume + flesh_healing -= max(VALUE_PER(5, 30) * reac_volume, 0) + to_chat(victim, span_notice("The salt bits seep in and stick to [lowertext(src)], painfully irritating the skin! After a few moments, it feels marginally better.")) + + /datum/reagent/consumable/blackpepper name = "Black Pepper" description = "A powder ground from peppercorns. *AAAACHOOO*" @@ -610,9 +645,38 @@ reagent_state = SOLID color = "#FFFFFF" // rgb: 0, 0, 0 taste_description = "chalky wheat" - chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_AFFECTS_WOUNDS default_container = /obj/item/reagent_containers/condiment/flour +/datum/reagent/consumable/flour/expose_mob(mob/living/exposed_mob, methods, reac_volume) + . = ..() + var/mob/living/carbon/carbies = exposed_mob + if(!(methods & (PATCH|TOUCH|VAPOR))) + return + for(var/datum/wound/iter_wound as anything in carbies.all_wounds) + iter_wound.on_flour(reac_volume, carbies) + +/datum/wound/proc/on_flour(reac_volume, mob/living/carbon/carbies) + return + +/datum/wound/pierce/bleed/on_flour(reac_volume, mob/living/carbon/carbies) + adjust_blood_flow(-0.015 * reac_volume) // 30u of a flour sack * 0.015 = -0.45~ blood flow, prettay good + to_chat(carbies, span_notice("The flour seeps into [lowertext(src)], painfully drying it up and absorbing some of the blood.")) + // When some nerd adds infection for wounds, make this increase the infection + +/datum/wound/slash/flesh/on_flour(reac_volume, mob/living/carbon/carbies) + adjust_blood_flow(-0.04 * reac_volume) // 30u of a flour sack * 0.04 = -1.25~ blood flow, pretty good! + to_chat(carbies, span_notice("The flour seeps into [lowertext(src)], painfully drying some of it up and absorbing a little blood.")) + // When some nerd adds infection for wounds, make this increase the infection + +// Don't pour flour onto burn wounds, it increases infection risk! Very unwise. Backed up by REAL info from REAL professionals. +// https://www.reuters.com/article/uk-factcheck-flour-burn-idUSKCN26F2N3 +/datum/wound/burn/flesh/on_flour(reac_volume) + to_chat(victim, span_notice("The flour seeps into [lowertext(src)], spiking you with intense pain! That probably wasn't a good idea...")) + sanitization -= min(0, 1) + infestation += 0.2 + return + /datum/reagent/consumable/flour/expose_turf(turf/exposed_turf, reac_volume) . = ..() if(isspaceturf(exposed_turf)) @@ -647,6 +711,14 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED default_container = /obj/item/reagent_containers/condiment/rice +/datum/reagent/consumable/rice_flour + name = "Rice Flour" + description = "Flour mixed with Rice" + reagent_state = SOLID + color = "#FFFFFF" // rgb: 0, 0, 0 + taste_description = "chalky wheat with rice" + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + /datum/reagent/consumable/vanilla name = "Vanilla Powder" description = "A fatty, bitter paste made from vanilla pods." @@ -677,6 +749,37 @@ description = "A slippery solution." color = "#DBCE95" taste_description = "slime" + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_AFFECTS_WOUNDS + +// Starch has similar absorbing properties to flour (Stronger here because it's rarer) +/datum/reagent/consumable/corn_starch/expose_mob(mob/living/exposed_mob, methods, reac_volume) + . = ..() + var/mob/living/carbon/carbies = exposed_mob + if(!(methods & (PATCH|TOUCH|VAPOR))) + return + for(var/datum/wound/iter_wound as anything in carbies.all_wounds) + iter_wound.on_starch(reac_volume, carbies) + +/datum/wound/proc/on_starch(reac_volume, mob/living/carbon/carbies) + return + +/datum/wound/pierce/bleed/on_starch(reac_volume, mob/living/carbon/carbies) + adjust_blood_flow(-0.03 * reac_volume) + to_chat(carbies, span_notice("The slimey starch seeps into [lowertext(src)], painfully drying some of it up and absorbing a little blood.")) + // When some nerd adds infection for wounds, make this increase the infection + return + +/datum/wound/slash/flesh/on_starch(reac_volume, mob/living/carbon/carbies) + adjust_blood_flow(-0.06 * reac_volume) + to_chat(carbies, span_notice("The slimey starch seeps into [lowertext(src)], painfully drying it up and absorbing some of the blood.")) + // When some nerd adds infection for wounds, make this increase the infection + return + +/datum/wound/burn/flesh/on_starch(reac_volume, mob/living/carbon/carbies) + to_chat(carbies, span_notice("The slimey starch seeps into [lowertext(src)], spiking you with intense pain! That probably wasn't a good idea...")) + sanitization -= min(0, 0.5) + infestation += 0.1 + return /datum/reagent/consumable/corn_syrup name = "Corn Syrup" @@ -716,6 +819,7 @@ M.adjustFireLoss(-1, FALSE, required_bodytype = affected_bodytype) M.adjustOxyLoss(-1, FALSE, required_biotype = affected_biotype) M.adjustToxLoss(-1, FALSE, required_biotype = affected_biotype) + . = TRUE ..() /datum/reagent/consumable/honey/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume) diff --git a/code/modules/reagents/chemistry/reagents/impure_reagents.dm b/code/modules/reagents/chemistry/reagents/impure_reagents.dm index d14df37ce965ec..f7eaba3c211bac 100644 --- a/code/modules/reagents/chemistry/reagents/impure_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/impure_reagents.dm @@ -15,12 +15,12 @@ var/liver_damage = 0.5 /datum/reagent/impurity/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) + . = ..() var/obj/item/organ/internal/liver/liver = affected_mob.get_organ_slot(ORGAN_SLOT_LIVER) - if(!liver)//Though, lets be safe - affected_mob.adjustToxLoss(1 * REM * seconds_per_tick, FALSE, required_biotype = affected_biotype)//Incase of no liver! - return ..() + if(isnull(liver)) //Though, lets be safe + return affected_mob.adjustToxLoss(1 * REM * seconds_per_tick, FALSE, required_biotype = affected_biotype) //Incase of no liver! affected_mob.adjustOrganLoss(ORGAN_SLOT_LIVER, liver_damage * REM * seconds_per_tick, required_organ_flag = affected_organ_flags) - return ..() + return TRUE //Basically just so people don't forget to adjust metabolization_rate /datum/reagent/inverse @@ -35,8 +35,8 @@ /datum/reagent/inverse/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - affected_mob.adjustToxLoss(tox_damage * REM * seconds_per_tick, FALSE, required_biotype = affected_biotype) - return ..() + . = ..() + return affected_mob.adjustToxLoss(tox_damage * REM * seconds_per_tick, FALSE, required_biotype = affected_biotype) //Failed chems - generally use inverse if you want to use a impure subtype for it //technically not a impure chem, but it's here because it can only be made with a failed impure reaction diff --git a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm index 8e09b318d1cd03..db98ed9d622573 100644 --- a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm @@ -47,6 +47,7 @@ if("oxy") owner.adjustOxyLoss(-0.5, required_biotype = affected_biotype, required_respiration_type = affected_respiration_type) ..() + return TRUE // C2 medications // Helbital @@ -198,7 +199,8 @@ Basically, we fill the time between now and 2s from now with hands based off the /datum/reagent/peptides_failed/on_mob_life(mob/living/carbon/owner, seconds_per_tick, times_fired) owner.adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.25 * seconds_per_tick, 170) owner.adjust_nutrition(-5 * REAGENTS_METABOLISM * seconds_per_tick) - . = ..() + ..() + return TRUE //Lenturi //impure @@ -233,6 +235,7 @@ Basically, we fill the time between now and 2s from now with hands based off the //Just the removed itching mechanism - omage to it's origins. /datum/reagent/inverse/ichiyuri/on_mob_life(mob/living/carbon/owner, seconds_per_tick, times_fired) if(prob(resetting_probability) && !(HAS_TRAIT(owner, TRAIT_RESTRAINED) || owner.incapacitated())) + . = TRUE if(spammer < world.time) to_chat(owner,span_warning("You can't help but itch yourself.")) spammer = world.time + (10 SECONDS) @@ -242,7 +245,7 @@ Basically, we fill the time between now and 2s from now with hands based off the resetting_probability = 0 resetting_probability += (5*(current_cycle/10) * seconds_per_tick) // 10 iterations = >51% to itch ..() - return TRUE + return . //Aiuri //impure @@ -441,7 +444,7 @@ Basically, we fill the time between now and 2s from now with hands based off the if (time_until_next_poison <= 0) time_until_next_poison = poison_interval owner.adjustToxLoss(creation_purity * 1, required_biotype = affected_biotype) - + . = TRUE ..() //Kind of a healing effect, Presumably you're using syrinver to purge so this helps that @@ -561,7 +564,8 @@ Basically, we fill the time between now and 2s from now with hands based off the if(!heart || heart.organ_flags & ORGAN_FAILING) remove_buffs(affected_mob) ..() - + return TRUE + /datum/reagent/inverse/penthrite/on_mob_delete(mob/living/carbon/affected_mob) remove_buffs(affected_mob) var/obj/item/organ/internal/heart/heart = affected_mob.get_organ_slot(ORGAN_SLOT_HEART) diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index 86978985ff8c3b..6e2b12a95eb031 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -70,7 +70,8 @@ affected_mob.adjustToxLoss(-5 * REM * seconds_per_tick, FALSE, TRUE, affected_biotype) // Heal everything! That we want to. But really don't heal reagents. Otherwise we'll lose ... us. affected_mob.fully_heal(full_heal_flags & ~HEAL_ALL_REAGENTS) - return ..() + ..() + return TRUE /datum/reagent/medicine/adminordrazine/quantum_heal name = "Quantum Medicine" @@ -136,6 +137,7 @@ if(prob(30)) SEND_SOUND(affected_mob, sound('sound/weapons/flash_ring.ogg')) ..() + return TRUE /datum/reagent/medicine/cryoxadone name = "Cryoxadone" @@ -346,7 +348,7 @@ color = "#6D6374" metabolization_rate = 0.4 * REAGENTS_METABOLISM ph = 2.6 - chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_AFFECTS_WOUNDS /datum/reagent/medicine/mine_salve/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) affected_mob.adjustBruteLoss(-0.25 * REM * seconds_per_tick, FALSE, required_bodytype = affected_bodytype) @@ -380,6 +382,10 @@ . = ..() metabolizer.remove_status_effect(/datum/status_effect/grouped/screwy_hud/fake_healthy, type) +/datum/reagent/medicine/mine_salve/on_burn_wound_processing(datum/wound/burn/flesh/burn_wound) + burn_wound.sanitization += 0.3 + burn_wound.flesh_healing += 0.5 + /datum/reagent/medicine/omnizine name = "Omnizine" description = "Slowly heals all damage types. Overdose will cause damage in all types instead." @@ -496,6 +502,7 @@ affected_mob.adjustToxLoss(-1 * REM * seconds_per_tick, required_biotype = affected_biotype) ..() + return TRUE /datum/reagent/medicine/pen_acid name = "Pentetic Acid" @@ -726,20 +733,22 @@ affected_mob.adjust_temp_blindness(-4 SECONDS * REM * seconds_per_tick * normalized_purity) affected_mob.adjust_eye_blur(-4 SECONDS * REM * seconds_per_tick * normalized_purity) var/obj/item/organ/internal/eyes/eyes = affected_mob.get_organ_slot(ORGAN_SLOT_EYES) - if(eyes) - // Healing eye damage will cure nearsightedness and blindness from ... eye damage - eyes.apply_organ_damage(-2 * REM * seconds_per_tick * normalise_creation_purity(), required_organ_flag = affected_organ_flags) - // If our eyes are seriously damaged, we have a probability of causing eye blur while healing depending on purity - if(eyes.damaged && IS_ORGANIC_ORGAN(eyes) && SPT_PROB(16 - min(normalized_purity * 6, 12), seconds_per_tick)) - // While healing, gives some eye blur - if(affected_mob.is_blind_from(EYE_DAMAGE)) - to_chat(affected_mob, span_warning("Your vision slowly returns...")) - affected_mob.adjust_eye_blur(20 SECONDS) - else if(affected_mob.is_nearsighted_from(EYE_DAMAGE)) - to_chat(affected_mob, span_warning("The blackness in your peripheral vision begins to fade.")) - affected_mob.adjust_eye_blur(5 SECONDS) + if(isnull(eyes)) + return ..() - return ..() + // Healing eye damage will cure nearsightedness and blindness from ... eye damage + eyes.apply_organ_damage(-2 * REM * seconds_per_tick * normalise_creation_purity(), required_organ_flag = affected_organ_flags) + // If our eyes are seriously damaged, we have a probability of causing eye blur while healing depending on purity + if(eyes.damaged && IS_ORGANIC_ORGAN(eyes) && SPT_PROB(16 - min(normalized_purity * 6, 12), seconds_per_tick)) + // While healing, gives some eye blur + if(affected_mob.is_blind_from(EYE_DAMAGE)) + to_chat(affected_mob, span_warning("Your vision slowly returns...")) + affected_mob.adjust_eye_blur(20 SECONDS) + else if(affected_mob.is_nearsighted_from(EYE_DAMAGE)) + to_chat(affected_mob, span_warning("The blackness in your peripheral vision begins to fade.")) + affected_mob.adjust_eye_blur(5 SECONDS) + + return ..() || TRUE /datum/reagent/medicine/oculine/on_mob_delete(mob/living/affected_mob) var/obj/item/organ/internal/eyes/eyes = affected_mob.get_organ_slot(ORGAN_SLOT_EYES) @@ -779,6 +788,7 @@ return ..() ears.adjustEarDamage(-4 * REM * seconds_per_tick * normalise_creation_purity(), -4 * REM * seconds_per_tick * normalise_creation_purity()) ..() + return TRUE /datum/reagent/medicine/inacusiate/on_mob_delete(mob/living/affected_mob) . = ..() @@ -851,7 +861,7 @@ if(SPT_PROB(10, seconds_per_tick)) holder.add_reagent(/datum/reagent/toxin/histamine, 4) ..() - return + return FALSE if(affected_mob.health <= affected_mob.crit_threshold) affected_mob.adjustToxLoss(-0.5 * REM * seconds_per_tick, FALSE, required_biotype = affected_biotype) affected_mob.adjustBruteLoss(-0.5 * REM * seconds_per_tick, FALSE, required_bodytype = affected_bodytype) @@ -867,7 +877,7 @@ affected_mob.adjustStaminaLoss(-0.5 * REM * seconds_per_tick, 0) if(SPT_PROB(10, seconds_per_tick)) affected_mob.AdjustAllImmobility(-20) - ..() + return ..() /datum/reagent/medicine/epinephrine/overdose_process(mob/living/affected_mob, seconds_per_tick, times_fired) if(SPT_PROB(18, REM * seconds_per_tick)) @@ -983,7 +993,8 @@ var/damage_at_random = rand(0, 250)/100 //0 to 2.5 affected_mob.adjustBruteLoss(damage_at_random * REM * seconds_per_tick, FALSE, required_bodytype = affected_bodytype) affected_mob.adjustFireLoss(damage_at_random * REM * seconds_per_tick, FALSE, required_bodytype = affected_bodytype) - return ..() + ..() + return TRUE /datum/reagent/medicine/mannitol name = "Mannitol" @@ -1000,6 +1011,7 @@ /datum/reagent/medicine/mannitol/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -2 * REM * seconds_per_tick * normalise_creation_purity(), required_organ_flag = affected_organ_flags) ..() + return TRUE //Having mannitol in you will pause the brain damage from brain tumor (so it heals an even 2 brain damage instead of 1.8) /datum/reagent/medicine/mannitol/on_mob_metabolize(mob/living/carbon/affected_mob) @@ -1110,6 +1122,14 @@ ..() . = TRUE +/datum/reagent/medicine/antihol/expose_mob(mob/living/carbon/exposed_carbon, methods=TOUCH, reac_volume) + . = ..() + if(!(methods & (TOUCH|VAPOR|PATCH))) + return + + for(var/datum/surgery/surgery as anything in exposed_carbon.surgeries) + surgery.speed_modifier = max(surgery.speed_modifier - 0.1, -0.9) + /datum/reagent/medicine/stimulants name = "Stimulants" description = "Increases resistance to batons and movement speed in addition to restoring minor damage and weakness. Overdose causes weakness and toxin damage." @@ -1228,7 +1248,7 @@ /datum/reagent/medicine/syndicate_nanites/overdose_process(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) //wtb flavortext messages that hint that you're vomitting up robots if(SPT_PROB(13, seconds_per_tick)) affected_mob.reagents.remove_reagent(type, metabolization_rate*15) // ~5 units at a rate of 0.4 but i wanted a nice number in code - affected_mob.vomit(20) // nanite safety protocols make your body expel them to prevent harmies + affected_mob.vomit(vomit_flags = VOMIT_CATEGORY_DEFAULT, vomit_type = /obj/effect/decal/cleanable/vomit/nanites, lost_nutrition = 20) // nanite safety protocols make your body expel them to prevent harmies ..() . = TRUE @@ -1539,7 +1559,7 @@ /datum/reagent/medicine/metafactor/overdose_process(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) if(SPT_PROB(13, seconds_per_tick)) - affected_mob.vomit() + affected_mob.vomit(VOMIT_CATEGORY_DEFAULT) ..() /datum/reagent/medicine/silibinin @@ -1731,4 +1751,5 @@ M.adjust_drowsiness(2 SECONDS * REM * seconds_per_tick) if(SPT_PROB(15, seconds_per_tick) && !M.getStaminaLoss()) M.adjustStaminaLoss(10) + . = TRUE M.adjust_disgust(-10 * REM * seconds_per_tick) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 54fa4391790959..2a46d537233004 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -299,6 +299,53 @@ //You don't belong in this world, monster! mytray.reagents.remove_reagent(type, volume) +/datum/reagent/water/salt + name = "Saltwater" + description = "Water, but salty. Smells like... the station infirmary?" + color = "#aaaaaa9d" // rgb: 170, 170, 170, 77 (alpha) + taste_description = "the sea" + cooling_temperature = 3 + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_CLEANS + default_container = /obj/item/reagent_containers/cup/glass/waterbottle + +/datum/glass_style/shot_glass/water/salt + required_drink_type = /datum/reagent/water/salt + icon_state = "shotglassclear" + +/datum/glass_style/drinking_glass/water/salt + required_drink_type = /datum/reagent/water/salt + name = "glass of saltwater" + desc = "If you have a sore throat, gargle some saltwater and watch the pain go away. Can be used as a very improvised topical medicine against wounds." + icon_state = "glass_clear" + +/datum/reagent/water/salt/expose_mob(mob/living/exposed_mob, methods, reac_volume) + . = ..() + var/mob/living/carbon/carbies = exposed_mob + if(!(methods & (PATCH|TOUCH|VAPOR))) + return + for(var/datum/wound/iter_wound as anything in carbies.all_wounds) + iter_wound.on_saltwater(reac_volume, carbies) + +// Mixed salt with water! All the help of salt with none of the irritation. Plus increased volume. +/datum/wound/proc/on_saltwater(reac_volume, mob/living/carbon/carbies) + return + +/datum/wound/pierce/bleed/on_saltwater(reac_volume, mob/living/carbon/carbies) + adjust_blood_flow(-0.06 * reac_volume, initial_flow * 0.6) + to_chat(carbies, span_notice("The salt water splashes over [lowertext(src)], soaking up the blood.")) + +/datum/wound/slash/flesh/on_saltwater(reac_volume, mob/living/carbon/carbies) + adjust_blood_flow(-0.1 * reac_volume, initial_flow * 0.5) + to_chat(carbies, span_notice("The salt water splashes over [lowertext(src)], soaking up the blood.")) + +/datum/wound/burn/flesh/on_saltwater(reac_volume) + // Similar but better stats from normal salt. + sanitization += VALUE_PER(0.6, 30) * reac_volume + infestation -= max(VALUE_PER(0.5, 30) * reac_volume, 0) + infestation_rate += VALUE_PER(0.07, 30) * reac_volume + to_chat(victim, span_notice("The salt water splashes over [lowertext(src)], soaking up the... miscellaneous fluids. It feels somewhat better afterwards.")) + return + /datum/reagent/water/holywater name = "Holy Water" description = "Water blessed by some deity." @@ -429,6 +476,7 @@ name = "Unholy Water" description = "Something that shouldn't exist on this plane of existence." taste_description = "suffering" + self_consuming = TRUE //unholy intervention won't be limited by the lack of a liver metabolization_rate = 2.5 * REAGENTS_METABOLISM //0.5u/second penetrates_skin = TOUCH|VAPOR ph = 6.5 @@ -452,6 +500,7 @@ affected_mob.adjustOxyLoss(1 * REM * seconds_per_tick, 0) affected_mob.adjustBruteLoss(1 * REM * seconds_per_tick, 0) ..() + return TRUE /datum/reagent/hellwater //if someone has this in their system they've really pissed off an eldrich god name = "Hell Water" @@ -467,6 +516,7 @@ affected_mob.adjustFireLoss(0.5*seconds_per_tick, 0) //Hence the other damages... ain't I a bastard? affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2.5*seconds_per_tick, 150) holder.remove_reagent(type, 0.5*seconds_per_tick) + return TRUE /datum/reagent/medicine/omnizine/godblood name = "Godblood" @@ -933,6 +983,7 @@ affected_mob.emote(pick("twitch","drool","moan")) affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.5*seconds_per_tick) ..() + return TRUE /datum/reagent/sulfur name = "Sulfur" @@ -1058,7 +1109,7 @@ color = "#D0EFEE" // space cleaner but lighter taste_description = "bitterness" ph = 10.5 - chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_AFFECTS_WOUNDS /datum/reagent/space_cleaner/sterilizine/expose_mob(mob/living/carbon/exposed_carbon, methods=TOUCH, reac_volume) . = ..() @@ -1068,6 +1119,9 @@ for(var/datum/surgery/surgery as anything in exposed_carbon.surgeries) surgery.speed_modifier = max(0.2, surgery.speed_modifier) +/datum/reagent/space_cleaner/sterilizine/on_burn_wound_processing(datum/wound/burn/flesh/burn_wound) + burn_wound.sanitization += 0.9 + /datum/reagent/iron name = "Iron" description = "Pure iron is a metal." @@ -1117,6 +1171,7 @@ /datum/reagent/uranium/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) affected_mob.adjustToxLoss(tox_damage * seconds_per_tick * REM) ..() + return TRUE /datum/reagent/uranium/expose_turf(turf/exposed_turf, reac_volume) . = ..() @@ -1231,14 +1286,14 @@ /datum/reagent/space_cleaner name = "Space Cleaner" - description = "A compound used to clean things. Now with 50% more sodium hypochlorite!" + description = "A compound used to clean things. Now with 50% more sodium hypochlorite! Can be used to clean wounds, but it's not really meant for that." color = "#A5F0EE" // rgb: 165, 240, 238 taste_description = "sourness" reagent_weight = 0.6 //so it sprays further - penetrates_skin = NONE + penetrates_skin = VAPOR var/clean_types = CLEAN_WASH ph = 5.5 - chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_CLEANS + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_CLEANS|REAGENT_AFFECTS_WOUNDS /datum/reagent/space_cleaner/expose_obj(obj/exposed_obj, reac_volume) . = ..() @@ -1264,6 +1319,13 @@ if(methods & (TOUCH|VAPOR)) exposed_mob.wash(clean_types) +/datum/reagent/space_cleaner/on_burn_wound_processing(datum/wound/burn/flesh/burn_wound) + burn_wound.sanitization += 0.3 + if(prob(5)) + to_chat(burn_wound.victim, span_notice("Your [burn_wound] stings and burns from the [src] covering it! It does look pretty clean though.")) + burn_wound.victim.adjustToxLoss(0.5) + burn_wound.limb.receive_damage(burn = 0.5, wound_bonus = CANT_WOUND) + /datum/reagent/space_cleaner/ez_clean name = "EZ Clean" description = "A powerful, acidic cleaner sold by Waffle Co. Affects organic matter while leaving other objects unaffected." @@ -1278,6 +1340,7 @@ affected_mob.adjustFireLoss(1.665*seconds_per_tick) affected_mob.adjustToxLoss(1.665*seconds_per_tick) ..() + return TRUE /datum/reagent/space_cleaner/ez_clean/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume) . = ..() @@ -1319,8 +1382,10 @@ /datum/reagent/impedrezene/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) affected_mob.adjust_jitter(-5 SECONDS * seconds_per_tick) + . = FALSE if(SPT_PROB(55, seconds_per_tick)) affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2) + . = TRUE if(SPT_PROB(30, seconds_per_tick)) affected_mob.adjust_drowsiness(6 SECONDS) if(SPT_PROB(5, seconds_per_tick)) @@ -2485,8 +2550,10 @@ /datum/reagent/peaceborg/tire/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) var/healthcomp = (100 - affected_mob.health) //DOES NOT ACCOUNT FOR ADMINBUS THINGS THAT MAKE YOU HAVE MORE THAN 200/210 HEALTH, OR SOMETHING OTHER THAN A HUMAN PROCESSING THIS. + . = FALSE if(affected_mob.getStaminaLoss() < (45 - healthcomp)) //At 50 health you would have 200 - 150 health meaning 50 compensation. 60 - 50 = 10, so would only do 10-19 stamina.) affected_mob.adjustStaminaLoss(10 * REM * seconds_per_tick) + . = TRUE if(SPT_PROB(16, seconds_per_tick)) to_chat(affected_mob, "You should sit down and take a rest...") ..() @@ -2546,7 +2613,10 @@ if(yuck_cycles % YUCK_PUKE_CYCLES == 0) if(yuck_cycles >= YUCK_PUKE_CYCLES * YUCK_PUKES_TO_STUN) holder.remove_reagent(type, 5) - affected_mob.vomit(rand(14, 26), stun = yuck_cycles >= YUCK_PUKE_CYCLES * YUCK_PUKES_TO_STUN) + var/passable_flags = (MOB_VOMIT_MESSAGE | MOB_VOMIT_HARM) + if(yuck_cycles >= (YUCK_PUKE_CYCLES * YUCK_PUKES_TO_STUN)) + passable_flags |= MOB_VOMIT_STUN + affected_mob.vomit(vomit_flags = passable_flags, lost_nutrition = rand(14, 26)) if(holder) return ..() #undef YUCK_PUKE_CYCLES @@ -2711,6 +2781,7 @@ It re-energizes and heals those who can see beyond this fragile reality, \ but is incredibly harmful to the closed-minded. It metabolizes very quickly." taste_description = "Ag'hsj'saje'sh" + self_consuming = TRUE //eldritch intervention won't be limited by the lack of a liver color = "#1f8016" metabolization_rate = 2.5 * REAGENTS_METABOLISM //0.5u/second chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_NO_RANDOM_RECIPE @@ -2792,7 +2863,8 @@ victim.emote("scream") if(SPT_PROB(2, seconds_per_tick)) // Stuns, but purges ants. victim.vomit(rand(5,10), FALSE, TRUE, 1, TRUE, FALSE, purge_ratio = 1) - return ..() + ..() + return TRUE /datum/reagent/ants/on_mob_end_metabolize(mob/living/living_anthill) ant_damage = 0 @@ -2842,8 +2914,9 @@ metabolization_rate = 0.4 * REAGENTS_METABOLISM /datum/reagent/lead/on_mob_life(mob/living/carbon/victim) - . = ..() victim.adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.5) + ..() + return TRUE //The main feedstock for kronkaine production, also a shitty stamina healer. /datum/reagent/kronkus_extract @@ -2855,9 +2928,10 @@ addiction_types = list(/datum/addiction/stimulants = 5) /datum/reagent/kronkus_extract/on_mob_life(mob/living/carbon/kronkus_enjoyer) - . = ..() + ..() kronkus_enjoyer.adjustOrganLoss(ORGAN_SLOT_HEART, 0.1) kronkus_enjoyer.adjustStaminaLoss(-2, FALSE) + return TRUE /datum/reagent/brimdust name = "Brimdust" @@ -2869,7 +2943,7 @@ /datum/reagent/brimdust/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() - affected_mob.adjustFireLoss((ispodperson(affected_mob) ? -1 : 1) * seconds_per_tick) + return affected_mob.adjustFireLoss((ispodperson(affected_mob) ? -1 : 1) * seconds_per_tick) /datum/reagent/brimdust/on_hydroponics_apply(obj/machinery/hydroponics/mytray, mob/user) mytray.adjust_weedlevel(-1) @@ -2951,3 +3025,4 @@ if(SPT_PROB(10, seconds_per_tick)) affected_mob.emote(pick("twitch","choke","shiver","gag")) ..() + return TRUE diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm index 0d52ca4e82545b..6f99273ad4e937 100644 --- a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm @@ -203,6 +203,7 @@ /datum/reagent/napalm/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) affected_mob.adjust_fire_stacks(1 * REM * seconds_per_tick) ..() + return TRUE /datum/reagent/napalm/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume) . = ..() diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index a9735cd7e755a6..d655698646ca28 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -64,8 +64,8 @@ exposed_mob.domutcheck() /datum/reagent/toxin/mutagen/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - affected_mob.adjustToxLoss(0.5 * seconds_per_tick * REM, required_biotype = affected_biotype) - return ..() + . = affected_mob.adjustToxLoss(0.5 * seconds_per_tick * REM, required_biotype = affected_biotype) + return ..() || . /datum/reagent/toxin/mutagen/on_hydroponics_apply(obj/machinery/hydroponics/mytray, mob/user) mytray.mutation_roll(user) @@ -513,7 +513,8 @@ if(51 to INFINITY) affected_mob.Sleeping(40 * REM * seconds_per_tick) affected_mob.adjustToxLoss(1 * (current_cycle - 50) * REM * seconds_per_tick, FALSE, required_biotype = affected_biotype) - return ..() + . = TRUE + return ..() || . /datum/reagent/toxin/coffeepowder name = "Coffee Grounds" @@ -559,7 +560,7 @@ /datum/reagent/toxin/mutetoxin/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) // Gain approximately 12 seconds * creation purity seconds of silence every metabolism tick. affected_mob.set_silence_if_lower(6 SECONDS * REM * normalise_creation_purity() * seconds_per_tick) - ..() + return ..() /datum/reagent/toxin/staminatoxin name = "Tirizene" @@ -590,8 +591,8 @@ affected_mob.AddComponent(/datum/component/irradiated) else affected_mob.adjustToxLoss(1 * REM * seconds_per_tick, required_biotype = affected_biotype) - - ..() + . = TRUE + return ..() || . /datum/reagent/toxin/histamine name = "Histamine" @@ -904,9 +905,10 @@ /datum/reagent/toxin/lipolicide/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) if(affected_mob.nutrition <= NUTRITION_LEVEL_STARVING) affected_mob.adjustToxLoss(1 * REM * seconds_per_tick, FALSE, required_biotype = affected_biotype) + . = TRUE affected_mob.adjust_nutrition(-3 * REM * normalise_creation_purity() * seconds_per_tick) // making the chef more valuable, one meme trap at a time affected_mob.overeatduration = 0 - return ..() + return ..() || . /datum/reagent/toxin/coniine name = "Coniine" @@ -936,7 +938,12 @@ /datum/reagent/toxin/spewium/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) .=..() if(current_cycle >= 11 && SPT_PROB(min(30, current_cycle), seconds_per_tick)) - affected_mob.vomit(10, prob(10), prob(50), rand(0,4), TRUE) + var/constructed_flags = (MOB_VOMIT_MESSAGE | MOB_VOMIT_HARM) + if(prob(10)) + constructed_flags |= MOB_VOMIT_BLOOD + if(prob(50)) + constructed_flags |= MOB_VOMIT_STUN + affected_mob.vomit(vomit_flags = constructed_flags, distance = rand(0,4)) for(var/datum/reagent/toxin/R in affected_mob.reagents.reagent_list) if(R != src) affected_mob.reagents.remove_reagent(R.type,1) @@ -945,7 +952,7 @@ . = ..() if(current_cycle >= 33 && SPT_PROB(7.5, seconds_per_tick)) affected_mob.spew_organ() - affected_mob.vomit(0, TRUE, TRUE, 4) + affected_mob.vomit(VOMIT_CATEGORY_BLOOD, lost_nutrition = 0, distance = 4) to_chat(affected_mob, span_userdanger("You feel something lumpy come up as you vomit.")) /datum/reagent/toxin/curare @@ -1193,7 +1200,7 @@ affected_mob.manual_emote(pick("oofs silently.", "looks like [affected_mob.p_their()] bones hurt.", "grimaces, as though [affected_mob.p_their()] bones hurt.")) if(3) to_chat(affected_mob, span_warning("Your bones hurt!")) - return ..() + return ..() || TRUE /datum/reagent/toxin/bonehurtingjuice/overdose_process(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) if(SPT_PROB(2, seconds_per_tick) && iscarbon(affected_mob)) //big oof @@ -1247,11 +1254,11 @@ /datum/reagent/toxin/leadacetate/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) affected_mob.adjustOrganLoss(ORGAN_SLOT_EARS, 1 * REM * seconds_per_tick) affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1 * REM * seconds_per_tick) + . = TRUE if(SPT_PROB(0.5, seconds_per_tick)) to_chat(affected_mob, span_notice("Ah, what was that? You thought you heard something...")) affected_mob.adjust_confusion(5 SECONDS) - return ..() - + return ..() || . /datum/reagent/toxin/hunterspider name = "Spider Toxin" description = "A toxic chemical produced by spiders to weaken prey." diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm index cd755532fb3057..e3f1fd1acef9ac 100644 --- a/code/modules/reagents/chemistry/recipes/medicine.dm +++ b/code/modules/reagents/chemistry/recipes/medicine.dm @@ -95,7 +95,7 @@ /datum/chemical_reaction/medicine/salglu_solution results = list(/datum/reagent/medicine/salglu_solution = 3) - required_reagents = list(/datum/reagent/consumable/salt = 1, /datum/reagent/water = 1, /datum/reagent/consumable/sugar = 1) + required_reagents = list(/datum/reagent/water/salt = 2, /datum/reagent/consumable/sugar = 1) reaction_tags = REACTION_TAG_EASY | REACTION_TAG_HEALING | REACTION_TAG_ORGAN /datum/chemical_reaction/medicine/mine_salve @@ -143,8 +143,8 @@ reaction_tags = REACTION_TAG_EASY | REACTION_TAG_HEALING | REACTION_TAG_OTHER /datum/chemical_reaction/medicine/pen_acid - results = list(/datum/reagent/medicine/pen_acid = 6) - required_reagents = list(/datum/reagent/fuel = 1, /datum/reagent/chlorine = 1, /datum/reagent/ammonia = 1, /datum/reagent/toxin/formaldehyde = 1, /datum/reagent/sodium = 1, /datum/reagent/toxin/cyanide = 1) + results = list(/datum/reagent/medicine/pen_acid = 5) + required_reagents = list(/datum/reagent/fuel = 1, /datum/reagent/ammonia = 1, /datum/reagent/toxin/formaldehyde = 1, /datum/reagent/consumable/salt = 1, /datum/reagent/toxin/cyanide = 1) reaction_tags = REACTION_TAG_EASY | REACTION_TAG_HEALING | REACTION_TAG_OTHER /datum/chemical_reaction/medicine/sal_acid diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index 1c77ff5f6c1059..b632bc7b6c86e9 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -35,8 +35,8 @@ reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE | REACTION_TAG_EXPLOSIVE /datum/chemical_reaction/sodiumchloride - results = list(/datum/reagent/consumable/salt = 3) - required_reagents = list(/datum/reagent/water = 1, /datum/reagent/sodium = 1, /datum/reagent/chlorine = 1) + results = list(/datum/reagent/consumable/salt = 2) + required_reagents = list(/datum/reagent/sodium = 1, /datum/reagent/chlorine = 1) // That's what I said! Sodium Chloride! reaction_tags = REACTION_TAG_EASY | REACTION_TAG_FOOD /datum/chemical_reaction/stable_plasma @@ -586,15 +586,19 @@ if(ismonkey(M)) M.gib() else - M.vomit(blood = TRUE, stun = TRUE) //not having a redo of itching powder (hopefully) + M.vomit(VOMIT_CATEGORY_BLOOD) new /mob/living/carbon/human/species/monkey(location, TRUE) //water electrolysis /datum/chemical_reaction/electrolysis - results = list(/datum/reagent/oxygen = 1.5, /datum/reagent/hydrogen = 3) - required_reagents = list(/datum/reagent/consumable/liquidelectricity/enriched = 1, /datum/reagent/water = 5) + results = list(/datum/reagent/oxygen = 2.5, /datum/reagent/hydrogen = 5) + required_reagents = list(/datum/reagent/consumable/liquidelectricity = 1, /datum/reagent/water = 5) reaction_tags = REACTION_TAG_EASY | REACTION_TAG_CHEMICAL +/datum/chemical_reaction/electrolysis2 + results = list(/datum/reagent/oxygen = 2.5, /datum/reagent/hydrogen = 5) + required_reagents = list(/datum/reagent/consumable/liquidelectricity/enriched = 1, /datum/reagent/water = 5) + reaction_tags = REACTION_TAG_EASY | REACTION_TAG_CHEMICAL //butterflium /datum/chemical_reaction/butterflium required_reagents = list(/datum/reagent/colorful_reagent = 1, /datum/reagent/medicine/omnizine = 1, /datum/reagent/medicine/strange_reagent = 1, /datum/reagent/consumable/nutriment = 1) @@ -770,6 +774,11 @@ required_catalysts = list(/datum/reagent/water/holywater = 1) reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE | REACTION_TAG_PLANT | REACTION_TAG_OTHER +/datum/chemical_reaction/saltwater + results = list(/datum/reagent/water/salt = 2) + required_reagents = list(/datum/reagent/water = 1, /datum/reagent/consumable/salt = 1) + reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DRINK | REACTION_TAG_ORGAN + /datum/chemical_reaction/exotic_stabilizer results = list(/datum/reagent/exotic_stabilizer = 2) required_reagents = list(/datum/reagent/plasma_oxide = 1,/datum/reagent/stabilizing_agent = 1) diff --git a/code/modules/reagents/chemistry/recipes/special.dm b/code/modules/reagents/chemistry/recipes/special.dm index 990ace10830a8b..592a281ed7301f 100644 --- a/code/modules/reagents/chemistry/recipes/special.dm +++ b/code/modules/reagents/chemistry/recipes/special.dm @@ -217,6 +217,9 @@ GLOBAL_LIST_INIT(medicine_reagents, build_medicine_reagents()) return FALSE required_reagents = req_reag + if (required_reagents.len == 0) + return FALSE + var/req_catalysts = unwrap_reagent_list(recipe_data["required_catalysts"]) if(!req_catalysts) return FALSE diff --git a/code/modules/reagents/chemistry/recipes/toxins.dm b/code/modules/reagents/chemistry/recipes/toxins.dm index b4e80e01cd02b7..0fcae783d89936 100644 --- a/code/modules/reagents/chemistry/recipes/toxins.dm +++ b/code/modules/reagents/chemistry/recipes/toxins.dm @@ -307,8 +307,8 @@ reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_OTHER /datum/chemical_reaction/heparin - results = list(/datum/reagent/toxin/heparin = 4) - required_reagents = list(/datum/reagent/toxin/formaldehyde = 1, /datum/reagent/sodium = 1, /datum/reagent/chlorine = 1, /datum/reagent/lithium = 1) + results = list(/datum/reagent/toxin/heparin = 3) + required_reagents = list(/datum/reagent/toxin/formaldehyde = 1, /datum/reagent/consumable/salt = 1, /datum/reagent/lithium = 1) mix_message = "The mixture thins and loses all color." is_cold_recipe = FALSE required_temp = 100 diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index ad83d2c439c95b..b5930955a3143e 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -536,15 +536,18 @@ to_chat(user, span_warning("You can't grind this!")) /obj/item/reagent_containers/cup/mortar/proc/grind_item(obj/item/item, mob/living/carbon/human/user) - if(!item.grind(src, user)) - to_chat(user, span_notice("You fail to grind [item].")) + if(!item.grind(reagents, user)) + if(isstack(item)) + to_chat(usr, span_notice("[src] attempts to grind as many pieces of [item] as possible.")) + else + to_chat(user, span_danger("You fail to grind [item].")) return to_chat(user, span_notice("You grind [item] into a nice powder.")) grinded = null QDEL_NULL(item) /obj/item/reagent_containers/cup/mortar/proc/juice_item(obj/item/item, mob/living/carbon/human/user) - if(!item.juice(src, user)) + if(!item.juice(reagents, user)) to_chat(user, span_notice("You fail to juice [item].")) return to_chat(user, span_notice("You juice [item] into a fine liquid.")) diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index a19e7fbe7f32fb..28c26c5d3568a6 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -442,6 +442,7 @@ /obj/item/reagent_containers/spray/hercuri name = "medical spray (hercuri)" - desc = "A medical spray bottle.This one contains hercuri, a medicine used to negate the effects of dangerous high-temperature environments. Careful not to freeze the patient!" - icon_state = "sprayer_large" + desc = "A medical spray bottle. This one contains hercuri, a medicine used to negate the effects of dangerous high-temperature environments. Careful not to freeze the patient!" + icon = 'icons/obj/medical/chemical.dmi' + icon_state = "sprayer_med_yellow" list_reagents = list(/datum/reagent/medicine/c2/hercuri = 100) diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 5f8ebecd990246..ef48a50af21052 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -1,3 +1,5 @@ +#define REAGENT_SPILL_DIVISOR 200 + /obj/structure/reagent_dispensers name = "Dispenser" desc = "..." @@ -206,6 +208,15 @@ return TRUE return FALSE +/obj/structure/reagent_dispensers/proc/knock_down() + var/datum/effect_system/fluid_spread/smoke/chem/smoke = new () + var/range = reagents.total_volume / REAGENT_SPILL_DIVISOR + smoke.attach(drop_location()) + smoke.set_up(round(range), holder = drop_location(), location = drop_location(), carry = reagents, silent = FALSE) + smoke.start(log = TRUE) + reagents.clear_reagents() + qdel(src) + /obj/structure/reagent_dispensers/wrench_act(mob/living/user, obj/item/tool) . = ..() if(!openable) @@ -341,6 +352,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/reagent_dispensers/wall/peppertank, 3 . = ..() if(prob(1)) desc = "IT'S PEPPER TIME, BITCH!" + find_and_hang_on_wall() /obj/structure/reagent_dispensers/water_cooler//SKYRAT EDIT - ICON OVERRIDEN BY AESTHETICS - SEE MODULE name = "liquid cooler" @@ -392,6 +404,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/reagent_dispensers/wall/peppertank, 3 MAPPING_DIRECTIONAL_HELPERS(/obj/structure/reagent_dispensers/wall/virusfood, 30) +/obj/structure/reagent_dispensers/wall/virusfood/Initialize(mapload) + . = ..() + find_and_hang_on_wall() + /obj/structure/reagent_dispensers/cooking_oil name = "vat of cooking oil" desc = "A huge metal vat with a tap on the front. Filled with cooking oil for use in frying food." @@ -454,3 +470,5 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/reagent_dispensers/wall/virusfood, 30 desc = "A stationary, plumbed, fuel tank." reagent_id = /datum/reagent/fuel accepts_rig = TRUE + +#undef REAGENT_SPILL_DIVISOR diff --git a/code/modules/recycling/conveyor.dm b/code/modules/recycling/conveyor.dm index 8417338851826c..b68230686a8aa0 100644 --- a/code/modules/recycling/conveyor.dm +++ b/code/modules/recycling/conveyor.dm @@ -42,6 +42,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) AddElement(/datum/element/footstep_override, priority = STEP_SOUND_CONVEYOR_PRIORITY) var/static/list/give_turf_traits = list(TRAIT_TURF_IGNORE_SLOWDOWN) AddElement(/datum/element/give_turf_traits, give_turf_traits) + register_context() /obj/machinery/conveyor/examine(mob/user) . = ..() @@ -50,6 +51,20 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) . += "\nLeft-click with a wrench to rotate." . += "Left-click with a screwdriver to invert its direction." . += "Right-click with a screwdriver to flip its belt around." + . += "Using another conveyor belt assembly on this will place a new conveyor belt in the direction this one is pointing." + +/obj/machinery/conveyor/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(istype(held_item, /obj/item/stack/conveyor)) + context[SCREENTIP_CONTEXT_LMB] = "Extend current conveyor belt" + return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "Rotate conveyor belt" + return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Invert conveyor belt" + context[SCREENTIP_CONTEXT_RMB] = "Flip conveyor belt" + return CONTEXTUAL_SCREENTIP_SET /obj/machinery/conveyor/centcom_auto id = "round_end_belt" @@ -282,6 +297,19 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) update_move_direction() to_chat(user, span_notice("You set [src]'s direction [inverted ? "backwards" : "back to default"].")) + else if(istype(attacking_item, /obj/item/stack/conveyor)) + // We should place a new conveyor belt machine on the output turf the conveyor is pointing to. + var/turf/target_turf = get_step(get_turf(src), forwards) + if(!target_turf) + return ..() + for(var/obj/machinery/conveyor/belt in target_turf) + to_chat(user, span_warning("You cannot place a conveyor belt on top of another conveyor belt.")) + return ..() + + var/obj/item/stack/conveyor/belt_item = attacking_item + belt_item.use(1) + new /obj/machinery/conveyor(target_turf, forwards, id) + else if(!user.combat_mode) user.transferItemToLoc(attacking_item, drop_location()) else @@ -534,6 +562,14 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) /obj/item/stack/conveyor/update_weight() return FALSE +/obj/item/stack/conveyor/examine(mob/user) + . = ..() + . += span_notice("Use a conveyor switch assembly on this before placing to connect to a lever.") + +/obj/item/stack/conveyor/use(used, transfer, check) + . = ..() + playsound(src, 'sound/weapons/genhit.ogg', 30, TRUE) + /obj/item/stack/conveyor/thirty amount = 30 diff --git a/code/modules/recycling/disposal/multiz.dm b/code/modules/recycling/disposal/multiz.dm index a4b914d66b8f51..06f4e52a31ce2b 100644 --- a/code/modules/recycling/disposal/multiz.dm +++ b/code/modules/recycling/disposal/multiz.dm @@ -21,11 +21,11 @@ return ..() //Are we a trunk that goes up? Or down? - var/turf/target = null + var/turf/target = get_turf(src) if(multiz_dir == MULTIZ_PIPE_UP) - target = GET_TURF_ABOVE(get_turf(src)) + target = GET_TURF_ABOVE(target) if(multiz_dir == MULTIZ_PIPE_DOWN) - target = GET_TURF_BELOW(get_turf(src)) + target = GET_TURF_BELOW(target) if(!target) //Nothing located. return diff --git a/code/modules/religion/rites.dm b/code/modules/religion/rites.dm index c7e38145349e0b..d907191c33ddd2 100644 --- a/code/modules/religion/rites.dm +++ b/code/modules/religion/rites.dm @@ -221,7 +221,7 @@ user.add_mood_event("maint_adaptation", /datum/mood_event/maintenance_adaptation) if(iscarbon(user)) var/mob/living/carbon/vomitorium = user - vomitorium.vomit() + vomitorium.vomit(VOMIT_CATEGORY_DEFAULT) var/datum/dna/dna = vomitorium.has_dna() dna?.add_mutation(/datum/mutation/human/stimmed) //some fluff mutations dna?.add_mutation(/datum/mutation/human/strong) diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index 6597c12fbec8bb..1c44e8bc4fb268 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -51,6 +51,16 @@ ) departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING +/datum/design/board/mass_driver + name = "Mass Driver Board" + desc = "The circuit board for a mass driver." + id = "mass_driver" + build_path = /obj/item/circuitboard/machine/mass_driver + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_ENGINEERING + ) + departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING + /datum/design/board/turbine_compressor name = "Turbine Compressor Board" desc = "The circuit board for a turbine compressor." diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index a9afd6b3a08002..0c1e3498dc1e0b 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -1173,6 +1173,17 @@ RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_SERVICE ) +/datum/design/borg_upgrade_drink_apparatus + name = "Drink Apparatus" + id = "borg_upgrade_drink_apparatus" + build_type = MECHFAB + build_path = /obj/item/borg/upgrade/drink_app + materials = list(/datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, /datum/material/glass = SHEET_MATERIAL_AMOUNT) + construction_time = 4 SECONDS + category = list( + RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_SERVICE + ) + /datum/design/borg_upgrade_service_apparatus name = "Service Apparatus" id = "borg_upgrade_service_apparatus" diff --git a/code/modules/research/server.dm b/code/modules/research/server.dm index b79bf3f8e02cb8..45a0a520fa0d4c 100644 --- a/code/modules/research/server.dm +++ b/code/modules/research/server.dm @@ -109,7 +109,7 @@ if(!stored_research) return tool.set_buffer(stored_research) - to_chat(user, span_notice("Stored [src]'s techweb information in [tool].")) + balloon_alert(user, "saved to multitool buffer") return TRUE /// Master R&D server. As long as this still exists and still holds the HDD for the theft objective, research points generate at normal speed. Destroy it or an antag steals the HDD? Half research speed. diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm index bdeeec6df4abd4..86b9f2dfafe4da 100644 --- a/code/modules/research/stock_parts.dm +++ b/code/modules/research/stock_parts.dm @@ -100,23 +100,21 @@ If you create T5+ please take a pass at mech_fabricator.dm. The parts being good */ /obj/item/storage/part_replacer/bluespace/proc/on_part_entered(datum/source, obj/item/inserted_component) SIGNAL_HANDLER + + if(istype(inserted_component, /obj/item/stock_parts/cell)) + var/obj/item/stock_parts/cell/inserted_cell = inserted_component + if(inserted_cell.rigged || inserted_cell.corrupted) + message_admins("[ADMIN_LOOKUPFLW(usr)] has inserted rigged/corrupted [inserted_cell] into [src].") + usr.log_message("has inserted rigged/corrupted [inserted_cell] into [src].", LOG_GAME) + usr.log_message("inserted rigged/corrupted [inserted_cell] into [src]", LOG_ATTACK) + return + if(inserted_component.reagents) if(length(inserted_component.reagents.reagent_list)) inserted_component.reagents.clear_reagents() to_chat(usr, span_notice("[src] churns as [inserted_component] has its reagents emptied into bluespace.")) RegisterSignal(inserted_component.reagents, COMSIG_REAGENTS_PRE_ADD_REAGENT, PROC_REF(on_insered_component_reagent_pre_add)) - - if(!istype(inserted_component, /obj/item/stock_parts/cell)) - return - - var/obj/item/stock_parts/cell/inserted_cell = inserted_component - - if(inserted_cell.rigged || inserted_cell.corrupted) - message_admins("[ADMIN_LOOKUPFLW(usr)] has inserted rigged/corrupted [inserted_cell] into [src].") - usr.log_message("has inserted rigged/corrupted [inserted_cell] into [src].", LOG_GAME) - usr.log_message("inserted rigged/corrupted [inserted_cell] into [src]", LOG_ATTACK) - /** * Signal handler for when the reagents datum of an inserted part has reagents added to it. * diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index e3fcdba9d64a1a..3a818ea940300c 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -596,6 +596,7 @@ "emergency_oxygen_engi", "emergency_oxygen", "emitter", + "mass_driver", "firealarm_electronics", "firelock_board", "generic_tank", @@ -979,6 +980,7 @@ "borg_upgrade_condiment_synthesizer", "borg_upgrade_silicon_knife", "borg_upgrade_service_apparatus", + "borg_upgrade_drink_apparatus", "borg_upgrade_service_cookbook", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000) diff --git a/code/modules/research/xenobiology/crossbreeding/_misc.dm b/code/modules/research/xenobiology/crossbreeding/_misc.dm index 8fc4d50a98cddf..8eb166bf8207fc 100644 --- a/code/modules/research/xenobiology/crossbreeding/_misc.dm +++ b/code/modules/research/xenobiology/crossbreeding/_misc.dm @@ -209,9 +209,13 @@ Slimecrossing Items else to_chat(user, span_warning("The device is empty...")) -/obj/item/capturedevice/proc/store(mob/living/M) - M.forceMove(src) +/obj/item/capturedevice/proc/store(mob/living/pokemon) + pokemon.forceMove(src) + pokemon.add_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED), ABSTRACT_ITEM_TRAIT) + pokemon.cancel_camera() /obj/item/capturedevice/proc/release() - for(var/atom/movable/M in contents) - M.forceMove(get_turf(loc)) + for(var/mob/living/pokemon in contents) + pokemon.forceMove(get_turf(loc)) + pokemon.remove_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED), ABSTRACT_ITEM_TRAIT) + pokemon.cancel_camera() diff --git a/code/modules/research/xenobiology/crossbreeding/_weapons.dm b/code/modules/research/xenobiology/crossbreeding/_weapons.dm index a728705579429c..61f4e7a72e0c89 100644 --- a/code/modules/research/xenobiology/crossbreeding/_weapons.dm +++ b/code/modules/research/xenobiology/crossbreeding/_weapons.dm @@ -96,6 +96,7 @@ Slimecrossing Weapons item_flags = ABSTRACT | DROPDEL w_class = WEIGHT_CLASS_HUGE slot_flags = NONE + antimagic_flags = NONE force = 5 max_charges = 1 //Recharging costs blood. recharge_rate = 1 diff --git a/code/modules/research/xenobiology/crossbreeding/charged.dm b/code/modules/research/xenobiology/crossbreeding/charged.dm index cb7070c83a493c..8941057453ba19 100644 --- a/code/modules/research/xenobiology/crossbreeding/charged.dm +++ b/code/modules/research/xenobiology/crossbreeding/charged.dm @@ -235,21 +235,23 @@ Charged extracts: effect_desc = "Randomizes the user's species." /obj/item/slimecross/charged/black/do_effect(mob/user) - var/mob/living/carbon/human/H = user - if(!istype(H)) - to_chat(user, span_warning("You have to be able to have a species to get your species changed.")) + var/mob/living/carbon/human/experiment_subject = user + if(!istype(experiment_subject)) + balloon_alert(experiment_subject, "incompatible biology!") return var/list/allowed_species = list() for(var/stype in subtypesof(/datum/species)) - var/datum/species/X = stype - if(initial(X.changesource_flags) & SLIME_EXTRACT) + var/datum/species/try_species = stype + if(initial(try_species.changesource_flags) & SLIME_EXTRACT) allowed_species += stype var/datum/species/changed = pick(allowed_species) - if(changed) - H.set_species(changed, icon_update = 1) - to_chat(H, span_danger("You feel very different!")) - ..() + if(isnull(changed)) + visible_message(span_notice("[src] fizzes uselessly.")) + return + experiment_subject.set_species(changed, icon_update = TRUE) + to_chat(experiment_subject, span_danger("You feel very different!")) + return ..() /obj/item/slimecross/charged/lightpink colour = SLIME_TYPE_LIGHT_PINK diff --git a/code/modules/research/xenobiology/crossbreeding/consuming.dm b/code/modules/research/xenobiology/crossbreeding/consuming.dm index 43bfd2dbe8abe3..007bacf8bb785f 100644 --- a/code/modules/research/xenobiology/crossbreeding/consuming.dm +++ b/code/modules/research/xenobiology/crossbreeding/consuming.dm @@ -355,7 +355,7 @@ Consuming extracts: /obj/item/slime_cookie/green/do_effect(mob/living/M, mob/user) if(ishuman(M)) var/mob/living/carbon/human/H = M - H.vomit(25) + H.vomit(VOMIT_CATEGORY_DEFAULT, lost_nutrition = 25) M.reagents.remove_all() /obj/item/slimecross/consuming/pink diff --git a/code/modules/security_levels/security_level_datums.dm b/code/modules/security_levels/security_level_datums.dm index 8ed94e50411380..175b79d1c8771a 100644 --- a/code/modules/security_levels/security_level_datums.dm +++ b/code/modules/security_levels/security_level_datums.dm @@ -45,7 +45,7 @@ sound = 'sound/misc/notice2.ogg' // Friendly beep number_level = SEC_LEVEL_GREEN lowering_to_configuration_key = /datum/config_entry/string/alert_green - shuttle_call_time_mod = 2 + shuttle_call_time_mod = ALERT_COEFF_GREEN /** * BLUE @@ -58,7 +58,7 @@ number_level = SEC_LEVEL_BLUE lowering_to_configuration_key = /datum/config_entry/string/alert_blue_downto elevating_to_configuration_key = /datum/config_entry/string/alert_blue_upto - shuttle_call_time_mod = 1 + shuttle_call_time_mod = ALERT_COEFF_BLUE /** * RED @@ -71,7 +71,7 @@ number_level = SEC_LEVEL_RED lowering_to_configuration_key = /datum/config_entry/string/alert_red_downto elevating_to_configuration_key = /datum/config_entry/string/alert_red_upto - shuttle_call_time_mod = 0.5 + shuttle_call_time_mod = ALERT_COEFF_RED /** * DELTA @@ -83,4 +83,4 @@ sound = 'sound/misc/airraid.ogg' // Air alarm to signify importance number_level = SEC_LEVEL_DELTA elevating_to_configuration_key = /datum/config_entry/string/alert_delta - shuttle_call_time_mod = 0.25 + shuttle_call_time_mod = ALERT_COEFF_DELTA diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index 3542102b32930d..ab2be975307576 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -339,15 +339,9 @@ /obj/docking_port/mobile/emergency/request(obj/docking_port/stationary/S, area/signal_origin, reason, red_alert, set_coefficient=null, silent=FALSE) //SKYRAT EDIT CHANGE - AUTOTRANSFER if(!isnum(set_coefficient)) - var/security_num = SSsecurity_level.get_current_level_as_number() - switch(security_num) - if(SEC_LEVEL_GREEN) - set_coefficient = 2 - if(SEC_LEVEL_BLUE) - set_coefficient = 1 - else - set_coefficient = 0.5 - var/call_time = SSshuttle.emergency_call_time * set_coefficient * engine_coeff + set_coefficient = SSsecurity_level.current_security_level.shuttle_call_time_mod + alert_coeff = set_coefficient + var/call_time = SSshuttle.emergency_call_time * alert_coeff * engine_coeff switch(mode) // The shuttle can not normally be called while "recalling", so // if this proc is called, it's via admin fiat diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 2ef513bb01552d..4ae1c241d06f37 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -382,8 +382,17 @@ /// This should be a unit test, but too much of our other code breaks during shuttle movement, so not yet, not yet. /proc/test_whiteship_sizes() var/obj/docking_port/stationary/port_type = /obj/docking_port/stationary/picked/whiteship - var/datum/turf_reservation/docking_yard = SSmapping.RequestBlockReservation(initial(port_type.width), initial(port_type.height)) - var/turf/spawnpoint = locate(docking_yard.bottom_left_coords[1] + initial(port_type.dwidth), docking_yard.bottom_left_coords[2] + initial(port_type.dheight), docking_yard.bottom_left_coords[3]) + var/datum/turf_reservation/docking_yard = SSmapping.request_turf_block_reservation( + initial(port_type.width), + initial(port_type.height), + 1, + ) + var/turf/bottom_left = docking_yard.bottom_left_turfs[1] + var/turf/spawnpoint = locate( + bottom_left.x + initial(port_type.dwidth), + bottom_left.y + initial(port_type.dheight), + bottom_left.z, + ) var/obj/docking_port/stationary/picked/whiteship/port = new(spawnpoint) var/list/ids = port.shuttlekeys @@ -439,7 +448,8 @@ var/current_engine_power = 0 ///How much engine power (thrust) the shuttle starts with at mapload. var/initial_engine_power = 0 - + ///Speed multiplier based on station alert level + var/alert_coeff = ALERT_COEFF_BLUE ///used as a timer (if you want time left to complete move, use timeLeft proc) var/timer var/last_timer_length @@ -943,6 +953,20 @@ last_timer_length *= multiple setTimer(time_remaining) +/obj/docking_port/mobile/proc/alert_coeff_change(new_coeff) + if(isnull(new_coeff)) + return + + var/time_multiplier = new_coeff / alert_coeff + var/time_remaining = timer - world.time + if(time_remaining < 0 || !last_timer_length) + return + + time_remaining *= time_multiplier + last_timer_length *= time_multiplier + alert_coeff = new_coeff + setTimer(time_remaining) + /obj/docking_port/mobile/proc/invertTimer() if(!last_timer_length) return diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm index aad6135c45a579..966f618376d781 100644 --- a/code/modules/spells/spell.dm +++ b/code/modules/spells/spell.dm @@ -209,12 +209,16 @@ // Otherwise, we can check for contents if they have wizardly apparel. This isn't *quite* perfect, but it'll do, especially since many of the edge cases (gorilla holding a wizard hat) still more or less make sense. if(spell_requirements & SPELL_REQUIRES_WIZARD_GARB) - for(var/atom/movable/item in owner.contents) - var/obj/item/clothing/clothem = item - if(istype(clothem) && clothem.clothing_flags & CASTING_CLOTHES) - return TRUE - to_chat(owner, span_warning("You don't feel strong enough without your hat!")) - return FALSE + var/any_casting = FALSE + for(var/obj/item/clothing/item in owner) + if(item.clothing_flags & CASTING_CLOTHES) + any_casting = TRUE + break + + if(!any_casting) + if(feedback) + to_chat(owner, span_warning("You don't feel strong enough without your hat!")) + return FALSE if(!(spell_requirements & SPELL_CASTABLE_AS_BRAIN) && isbrain(owner)) if(feedback) @@ -298,6 +302,31 @@ /datum/action/cooldown/spell/proc/before_cast(atom/cast_on) SHOULD_CALL_PARENT(TRUE) + // Bonus invocation check done here: + // If the caster has no tongue and it's a verbal spell, + // Or has no hands and is a gesture spell - cancel it, + // and show a funny message that they tried + if(ishuman(owner) && !(spell_requirements & SPELL_CASTABLE_WITHOUT_INVOCATION)) + var/mob/living/carbon/human/caster = owner + switch(invocation_type) + if(INVOCATION_WHISPER, INVOCATION_SHOUT) + if(!caster.get_organ_slot(ORGAN_SLOT_TONGUE)) + invocation(caster) + to_chat(caster, span_warning("Your lack of tongue is making it difficult to say the correct words to cast [src]...")) + StartCooldown(2 SECONDS) + return SPELL_CANCEL_CAST + + if(INVOCATION_EMOTE) + if(caster.usable_hands <= 0) + var/arm_describer = (caster.num_hands >= 2 ? "arms limply" : (caster.num_hands == 1 ? "arm wildly" : "arm stumps")) + caster.visible_message( + span_warning("[caster] wiggles around [caster.p_their()] [arm_describer]."), + ignored_mobs = caster, + ) + to_chat(caster, span_warning("You can't position your hands correctly to invoke [src][caster.num_hands > 0 ? "" : ", as you have none"]...")) + StartCooldown(2 SECONDS) + return SPELL_CANCEL_CAST + var/sig_return = SEND_SIGNAL(src, COMSIG_SPELL_BEFORE_CAST, cast_on) if(owner) sig_return |= SEND_SIGNAL(owner, COMSIG_MOB_BEFORE_SPELL_CAST, src, cast_on) diff --git a/code/modules/spells/spell_types/touch/scream_for_me.dm b/code/modules/spells/spell_types/touch/scream_for_me.dm index e10bdaebcc5ac7..231b6927e504be 100644 --- a/code/modules/spells/spell_types/touch/scream_for_me.dm +++ b/code/modules/spells/spell_types/touch/scream_for_me.dm @@ -21,7 +21,7 @@ span_userdanger("The spell bounces from [victim]'s skin back into your arm!"), ) var/obj/item/bodypart/to_wound = caster.get_holding_bodypart_of_item(hand) - to_wound.force_wound_upwards(/datum/wound/slash/flesh/critical) + caster.cause_wound_of_type_and_severity(WOUND_SLASH, to_wound, WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_CRITICAL) /datum/action/cooldown/spell/touch/scream_for_me/cast_on_hand_hit(obj/item/melee/touch_attack/hand, mob/living/victim, mob/living/carbon/caster) if(!ishuman(victim)) @@ -29,7 +29,7 @@ var/mob/living/carbon/human/human_victim = victim human_victim.emote("scream") for(var/obj/item/bodypart/to_wound as anything in human_victim.bodyparts) - to_wound.force_wound_upwards(/datum/wound/slash/flesh/critical) + human_victim.cause_wound_of_type_and_severity(WOUND_SLASH, to_wound, WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_CRITICAL) return TRUE /obj/item/melee/touch_attack/scream_for_me diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm index 9ac99c86b3c315..ec29b326ae9fc4 100644 --- a/code/modules/station_goals/bsa.dm +++ b/code/modules/station_goals/bsa.dm @@ -57,7 +57,7 @@ GLOBAL_VAR_INIT(bsa_unlock, FALSE) return var/obj/item/multitool/M = I M.set_buffer(src) - to_chat(user, span_notice("You store linkage information in [I]'s buffer.")) + balloon_alert(user, "saved to multitool buffer") return TRUE /obj/machinery/bsa/front @@ -74,7 +74,7 @@ GLOBAL_VAR_INIT(bsa_unlock, FALSE) return var/obj/item/multitool/M = I M.set_buffer(src) - to_chat(user, span_notice("You store linkage information in [I]'s buffer.")) + balloon_alert(user, "saved to multitool buffer") return TRUE /obj/machinery/bsa/middle diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 5967e3502dc959..4b9c0114024456 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -1,6 +1,3 @@ -#define AUGGED_LIMB_EMP_BRUTE_DAMAGE 3 -#define AUGGED_LIMB_EMP_BURN_DAMAGE 2 - /obj/item/bodypart name = "limb" desc = "Why is it detached..." @@ -31,9 +28,9 @@ /** * A bitfield of biological states, exclusively used to determine which wounds this limb will get, * as well as how easily it will happen. - * Set to BIO_STANDARD because most species have both flesh bone and blood in their limbs. + * Set to BIO_STANDARD_UNJOINTED because most species have both flesh bone and blood in their limbs. */ - var/biological_state = BIO_STANDARD + var/biological_state = BIO_STANDARD_UNJOINTED ///A bitfield of bodytypes for clothing, surgery, and misc information var/bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC ///Defines when a bodypart should not be changed. Example: BP_BLOCK_CHANGE_SPECIES prevents the limb from being overwritten on species gain @@ -195,10 +192,12 @@ var/hp_percent_to_dismemberable = 0.8 /// If true, we will use [hp_percent_to_dismemberable] even if we are dismemberable via wounds. Useful for things with extreme wound resistance. var/use_alternate_dismemberment_calc_even_if_mangleable = FALSE - /// If false, no wound that can be applied to us can mangle our flesh. Used for determining if we should use [hp_percent_to_dismemberable] instead of normal dismemberment. - var/any_existing_wound_can_mangle_our_flesh - /// If false, no wound that can be applied to us can mangle our bone. Used for determining if we should use [hp_percent_to_dismemberable] instead of normal dismemberment. - var/any_existing_wound_can_mangle_our_bone + /// If false, no wound that can be applied to us can mangle our exterior. Used for determining if we should use [hp_percent_to_dismemberable] instead of normal dismemberment. + var/any_existing_wound_can_mangle_our_exterior + /// If false, no wound that can be applied to us can mangle our interior. Used for determining if we should use [hp_percent_to_dismemberable] instead of normal dismemberment. + var/any_existing_wound_can_mangle_our_interior + /// get_damage() / total_damage must surpass this to allow our limb to be disabled, even temporarily, by an EMP. + var/robotic_emp_paralyze_damage_percent_threshold = 0.3 /obj/item/bodypart/apply_fantasy_bonuses(bonus) . = ..() @@ -499,73 +498,32 @@ var/mangled_state = get_mangled_state() var/easy_dismember = HAS_TRAIT(owner, TRAIT_EASYDISMEMBER) // if we have easydismember, we don't reduce damage when redirecting damage to different types (slashing weapons on mangled/skinless limbs attack at 100% instead of 50%) - var/has_exterior = FALSE - var/has_interior = FALSE - - for (var/state as anything in GLOB.bio_state_states) - var/flag = text2num(state) - if (!(biological_state & flag)) - continue - - var/value = GLOB.bio_state_states[state] - if (value & BIO_EXTERIOR) - has_exterior = TRUE - if (value & BIO_INTERIOR) - has_interior = TRUE - - if (has_exterior && has_interior) - break - - // We put this here so we dont increase init time by doing this all at once on initialization - // Effectively, we "lazy load" - if (isnull(any_existing_wound_can_mangle_our_bone) || isnull(any_existing_wound_can_mangle_our_flesh)) - any_existing_wound_can_mangle_our_bone = FALSE - any_existing_wound_can_mangle_our_flesh = FALSE - for (var/datum/wound/wound_type as anything in GLOB.all_wound_pregen_data) - var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[wound_type] - if (!pregen_data.can_be_applied_to(src, random_roll = TRUE)) // we only consider randoms because non-randoms are usually really specific - continue - if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_FLESH) - any_existing_wound_can_mangle_our_flesh = TRUE - if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_BONE) - any_existing_wound_can_mangle_our_bone = TRUE - - if (any_existing_wound_can_mangle_our_bone && any_existing_wound_can_mangle_our_flesh) - break + var/bio_status = get_bio_state_status() - var/can_theoretically_be_dismembered = (any_existing_wound_can_mangle_our_bone || (any_existing_wound_can_mangle_our_flesh && !has_exterior)) + var/has_exterior = ((bio_status & ANATOMY_EXTERIOR)) + var/has_interior = ((bio_status & ANATOMY_INTERIOR)) - var/exterior_ready_to_dismember = (!has_exterior || ((mangled_state & BODYPART_MANGLED_BONE) == BODYPART_MANGLED_BONE)) - var/interior_ready_to_dismember = (!has_interior || ((mangled_state & BODYPART_MANGLED_FLESH) == BODYPART_MANGLED_FLESH)) + var/exterior_ready_to_dismember = (!has_exterior || ((mangled_state & BODYPART_MANGLED_EXTERIOR))) // if we're bone only, all cutting attacks go straight to the bone - if(has_exterior && interior_ready_to_dismember) + if(!has_exterior && has_interior) if(wounding_type == WOUND_SLASH) wounding_type = WOUND_BLUNT wounding_dmg *= (easy_dismember ? 1 : 0.6) else if(wounding_type == WOUND_PIERCE) wounding_type = WOUND_BLUNT wounding_dmg *= (easy_dismember ? 1 : 0.75) - if(exterior_ready_to_dismember && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus)) - return else // if we've already mangled the skin (critical slash or piercing wound), then the bone is exposed, and we can damage it with sharp weapons at a reduced rate // So a big sharp weapon is still all you need to destroy a limb - if(has_exterior && interior_ready_to_dismember && !(mangled_state & BODYPART_MANGLED_BONE) && sharpness) - playsound(src, "sound/effects/wounds/crackandbleed.ogg", 100) + if(has_interior && exterior_ready_to_dismember && !(mangled_state & BODYPART_MANGLED_INTERIOR) && sharpness) if(wounding_type == WOUND_SLASH && !easy_dismember) wounding_dmg *= 0.6 // edged weapons pass along 60% of their wounding damage to the bone since the power is spread out over a larger area if(wounding_type == WOUND_PIERCE && !easy_dismember) wounding_dmg *= 0.75 // piercing weapons pass along 75% of their wounding damage to the bone since it's more concentrated wounding_type = WOUND_BLUNT - else if(interior_ready_to_dismember && exterior_ready_to_dismember && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus)) - return - if (use_alternate_dismemberment_calc_even_if_mangleable || !can_theoretically_be_dismembered) - var/percent_to_total_max = (get_damage() / max_damage) - if (percent_to_total_max >= hp_percent_to_dismemberable) - if (try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus)) - return - + if ((dismemberable_by_wound() || dismemberable_by_total_damage()) && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus)) + return // now we have our wounding_type and are ready to carry on with wounds and dealing the actual damage if(wounding_dmg >= WOUND_MINIMUM_DAMAGE && wound_bonus != CANT_WOUND) //SKYRAT EDIT ADDITION - MEDICAL @@ -611,6 +569,83 @@ owner.updatehealth() return update_bodypart_damage_state() || . +/// Returns a bitflag using ANATOMY_EXTERIOR or ANATOMY_INTERIOR. Used to determine if we as a whole have a interior or exterior biostate, or both. +/obj/item/bodypart/proc/get_bio_state_status() + SHOULD_BE_PURE(TRUE) + + var/bio_status = NONE + + for (var/state as anything in GLOB.bio_state_anatomy) + var/flag = text2num(state) + if (!(biological_state & flag)) + continue + + var/value = GLOB.bio_state_anatomy[state] + if (value & ANATOMY_EXTERIOR) + bio_status |= ANATOMY_EXTERIOR + if (value & ANATOMY_INTERIOR) + bio_status |= ANATOMY_INTERIOR + + if ((bio_status & ANATOMY_EXTERIOR_AND_INTERIOR) == ANATOMY_EXTERIOR_AND_INTERIOR) + break + + return bio_status + +/// Returns if our current mangling status allows us to be dismembered. Requires both no exterior/mangled exterior and no interior/mangled interior. +/obj/item/bodypart/proc/dismemberable_by_wound() + SHOULD_BE_PURE(TRUE) + + var/mangled_state = get_mangled_state() + + var/bio_status = get_bio_state_status() + + var/has_exterior = ((bio_status & ANATOMY_EXTERIOR)) + var/has_interior = ((bio_status & ANATOMY_INTERIOR)) + + var/exterior_ready_to_dismember = (!has_exterior || ((mangled_state & BODYPART_MANGLED_EXTERIOR))) + var/interior_ready_to_dismember = (!has_interior || ((mangled_state & BODYPART_MANGLED_INTERIOR))) + + return (exterior_ready_to_dismember && interior_ready_to_dismember) + +/// Returns TRUE if our total percent damage is more or equal to our dismemberable percentage, but FALSE if a wound can cause us to be dismembered. +/obj/item/bodypart/proc/dismemberable_by_total_damage() + + update_wound_theory() + + var/bio_status = get_bio_state_status() + + var/has_interior = ((bio_status & ANATOMY_INTERIOR)) + var/can_theoretically_be_dismembered_by_wound = (any_existing_wound_can_mangle_our_interior || (any_existing_wound_can_mangle_our_exterior && has_interior)) + + var/wound_dismemberable = dismemberable_by_wound() + var/ready_to_use_alternate_formula = (use_alternate_dismemberment_calc_even_if_mangleable || (!wound_dismemberable && !can_theoretically_be_dismembered_by_wound)) + + if (ready_to_use_alternate_formula) + var/percent_to_total_max = (get_damage() / max_damage) + if (percent_to_total_max >= hp_percent_to_dismemberable) + return TRUE + + return FALSE + +/// Updates our "can be theoretically dismembered by wounds" variables by iterating through all wound static data. +/obj/item/bodypart/proc/update_wound_theory() + // We put this here so we dont increase init time by doing this all at once on initialization + // Effectively, we "lazy load" + if (isnull(any_existing_wound_can_mangle_our_interior) || isnull(any_existing_wound_can_mangle_our_exterior)) + any_existing_wound_can_mangle_our_interior = FALSE + any_existing_wound_can_mangle_our_exterior = FALSE + for (var/datum/wound/wound_type as anything in GLOB.all_wound_pregen_data) + var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[wound_type] + if (!pregen_data.can_be_applied_to(src, random_roll = TRUE)) // we only consider randoms because non-randoms are usually really specific + continue + if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_EXTERIOR) + any_existing_wound_can_mangle_our_exterior = TRUE + if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_INTERIOR) + any_existing_wound_can_mangle_our_interior = TRUE + + if (any_existing_wound_can_mangle_our_interior && any_existing_wound_can_mangle_our_exterior) + break + //Heals brute and burn damage for the organ. Returns 1 if the damage-icon states changed at all. //Damage cannot go below zero. //Cannot remove negative damage (i.e. apply damage) @@ -1201,9 +1236,6 @@ for(var/datum/wound/iter_wound as anything in wounds) cached_bleed_rate += iter_wound.blood_flow - if(!cached_bleed_rate) - QDEL_NULL(grasped_by) - // Our bleed overlay is based directly off bleed_rate, so go aheead and update that would you? if(cached_bleed_rate != old_bleed_rate) update_part_wound_overlay() @@ -1355,13 +1387,13 @@ . = ..() if(. & EMP_PROTECT_WIRES || !IS_ROBOTIC_LIMB(src)) return FALSE - owner.visible_message(span_danger("[owner]'s [src.name] seems to malfunction!")) - - // with defines at the time of writing, this is 3 brute and 2 burn - // 3 + 2 = 5, with 6 limbs thats 30, on a heavy 60 - // 60 * 0.8 = 48 - var/time_needed = 10 SECONDS + // with defines at the time of writing, this is 2 brute and 1.5 burn + // 2 + 1.5 = 3,5, with 6 limbs thats 21, on a heavy 42 + // 42 * 0.8 = 33.6 + // 3 hits to crit with an ion rifle on someone fully augged at a total of 100.8 damage, although im p sure mood can boost max hp above 100 + // dont forget emps pierce armor, debilitate augs, and usually comes with splash damage e.g. ion rifles or grenades + var/time_needed = AUGGED_LIMB_EMP_PARALYZE_TIME var/brute_damage = AUGGED_LIMB_EMP_BRUTE_DAMAGE var/burn_damage = AUGGED_LIMB_EMP_BURN_DAMAGE if(severity == EMP_HEAVY) @@ -1371,9 +1403,30 @@ receive_damage(brute_damage, burn_damage) do_sparks(number = 1, cardinal_only = FALSE, source = owner) - ADD_TRAIT(src, TRAIT_PARALYSIS, EMP_TRAIT) - addtimer(CALLBACK(src, PROC_REF(un_paralyze)), time_needed) + var/damage_percent_to_max = (get_damage() / max_damage) + if (time_needed && (damage_percent_to_max >= robotic_emp_paralyze_damage_percent_threshold)) + owner.visible_message(span_danger("[owner]'s [src] seems to malfunction!")) + ADD_TRAIT(src, TRAIT_PARALYSIS, EMP_TRAIT) + addtimer(CALLBACK(src, PROC_REF(un_paralyze)), time_needed) return TRUE /obj/item/bodypart/proc/un_paralyze() REMOVE_TRAITS_IN(src, EMP_TRAIT) + +/// Returns the generic description of our BIO_EXTERNAL feature(s), prioritizing certain ones over others. Returns error on failure. +/obj/item/bodypart/proc/get_external_description() + if (biological_state & BIO_FLESH) + return "flesh" + if (biological_state & BIO_WIRED) + return "wiring" + + return "error" + +/// Returns the generic description of our BIO_INTERNAL feature(s), prioritizing certain ones over others. Returns error on failure. +/obj/item/bodypart/proc/get_internal_description() + if (biological_state & BIO_BONE) + return "bone" + if (biological_state & BIO_METAL) + return "metal" + + return "error" diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index 22a325f1974a00..5a7343f8a0b3a1 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -5,7 +5,7 @@ return TRUE ///Remove target limb from it's owner, with side effects. -/obj/item/bodypart/proc/dismember(dam_type = BRUTE, silent=TRUE, wound_type) +/obj/item/bodypart/proc/dismember(dam_type = BRUTE, silent=TRUE, wounding_type) if(!owner || (bodypart_flags & BODYPART_UNREMOVABLE)) return FALSE var/mob/living/carbon/limb_owner = owner @@ -23,14 +23,14 @@ limb_owner.add_mood_event("dismembered_[body_zone]", /datum/mood_event/dismembered, src) limb_owner.add_mob_memory(/datum/memory/was_dismembered, lost_limb = src) - if (wound_type) - LAZYSET(limb_owner.body_zone_dismembered_by, body_zone, wound_type) + if (wounding_type) + LAZYSET(limb_owner.body_zone_dismembered_by, body_zone, wounding_type) drop_limb() limb_owner.update_equipment_speed_mods() // Update in case speed affecting item unequipped by dismemberment var/turf/owner_location = limb_owner.loc - if(wound_type != WOUND_BURN && istype(owner_location) && can_bleed()) + if(wounding_type != WOUND_BURN && istype(owner_location) && can_bleed()) limb_owner.add_splatter_floor(owner_location) if(QDELETED(src)) //Could have dropped into lava/explosion/chasm/whatever @@ -55,7 +55,7 @@ return TRUE -/obj/item/bodypart/chest/dismember(dam_type = BRUTE, silent=TRUE, wound_type) +/obj/item/bodypart/chest/dismember(dam_type = BRUTE, silent=TRUE, wounding_type) if(!owner) return FALSE var/mob/living/carbon/chest_owner = owner @@ -64,7 +64,7 @@ if(HAS_TRAIT(chest_owner, TRAIT_NODISMEMBER)) return FALSE . = list() - if(wound_type != WOUND_BURN && isturf(chest_owner.loc) && can_bleed()) + if(wounding_type != WOUND_BURN && isturf(chest_owner.loc) && can_bleed()) chest_owner.add_splatter_floor(chest_owner.loc) playsound(get_turf(chest_owner), 'sound/misc/splort.ogg', 80, TRUE) for(var/obj/item/organ/organ as anything in chest_owner.organs) @@ -158,16 +158,16 @@ * Dismemberment for flesh and bone requires the victim to have the skin on their bodypart destroyed (either a critical cut or piercing wound), and at least a hairline fracture * (severe bone), at which point we can start rolling for dismembering. The attack must also deal at least 10 damage, and must be a brute attack of some kind (sorry for now, cakehat, maybe later) * - * Returns: BODYPART_MANGLED_NONE if we're fine, BODYPART_MANGLED_FLESH if our skin is broken, BODYPART_MANGLED_BONE if our bone is broken, or BODYPART_MANGLED_BOTH if both are broken and we're up for dismembering + * Returns: BODYPART_MANGLED_NONE if we're fine, BODYPART_MANGLED_EXTERIOR if our skin is broken, BODYPART_MANGLED_INTERIOR if our bone is broken, or BODYPART_MANGLED_BOTH if both are broken and we're up for dismembering */ /obj/item/bodypart/proc/get_mangled_state() . = BODYPART_MANGLED_NONE for(var/datum/wound/iter_wound as anything in wounds) - if((iter_wound.wound_flags & MANGLES_BONE)) - . |= BODYPART_MANGLED_BONE - if((iter_wound.wound_flags & MANGLES_FLESH)) - . |= BODYPART_MANGLED_FLESH + if((iter_wound.wound_flags & MANGLES_INTERIOR)) + . |= BODYPART_MANGLED_INTERIOR + if((iter_wound.wound_flags & MANGLES_EXTERIOR)) + . |= BODYPART_MANGLED_EXTERIOR /** * try_dismember() is used, once we've confirmed that a flesh and bone bodypart has both the skin and bone mangled, to actually roll for it @@ -445,8 +445,8 @@ if (LAZYLEN(dismembered_by_copy)) var/datum/scar/scaries = new var/datum/wound/loss/phantom_loss = new // stolen valor, really - phantom_loss.loss_wound_type = dismembered_by_copy?[limb_zone] - if (phantom_loss.loss_wound_type) + phantom_loss.loss_wounding_type = dismembered_by_copy?[limb_zone] + if (phantom_loss.loss_wounding_type) scaries.generate(limb, phantom_loss) LAZYREMOVE(dismembered_by_copy, limb_zone) // in case we're using a passed list else diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index d022e003f2f95c..4207f3541f6415 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -53,7 +53,7 @@ if(cavity_item) cavity_item.forceMove(drop_location()) cavity_item = null - ..() + return ..() /obj/item/bodypart/chest/monkey icon = 'icons/mob/human/species/monkey/bodyparts.dmi' @@ -114,7 +114,7 @@ /// Datum describing how to offset things held in the hands of this arm, the x offset IS functional here var/datum/worn_feature_offset/held_hand_offset - biological_state = (BIO_STANDARD|BIO_JOINTED) + biological_state = BIO_STANDARD_JOINTED /obj/item/bodypart/arm/Destroy() QDEL_NULL(worn_glove_offset) @@ -346,7 +346,7 @@ /// Datum describing how to offset things worn on the foot of this leg, note that an x offset won't do anything here var/datum/worn_feature_offset/worn_foot_offset - biological_state = (BIO_STANDARD|BIO_JOINTED) + biological_state = BIO_STANDARD_JOINTED /obj/item/bodypart/leg/Destroy() QDEL_NULL(worn_foot_offset) diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index 0382f4b048f4f0..37b6cef9897507 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -1,3 +1,4 @@ + #define ROBOTIC_LIGHT_BRUTE_MSG "marred" #define ROBOTIC_MEDIUM_BRUTE_MSG "dented" #define ROBOTIC_HEAVY_BRUTE_MSG "falling apart" @@ -112,10 +113,13 @@ . = ..() if(!.) return - owner.Knockdown(severity == EMP_HEAVY ? 20 SECONDS : 10 SECONDS) + var/knockdown_time = AUGGED_LEG_EMP_KNOCKDOWN_TIME + if (severity == EMP_HEAVY) + knockdown_time *= 2 + owner.Knockdown(knockdown_time) if(owner.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB)) // So the message isn't duplicated. If they were stunned beforehand by something else, then the message not showing makes more sense anyways. return - to_chat(owner, span_danger("As your [src.name] unexpectedly malfunctions, it causes you to fall to the ground!")) + to_chat(owner, span_danger("As your [src] unexpectedly malfunctions, it causes you to fall to the ground!")) /obj/item/bodypart/leg/right/robot name = "cyborg right leg" @@ -154,10 +158,13 @@ . = ..() if(!.) return - owner.Knockdown(severity == EMP_HEAVY ? 20 SECONDS : 10 SECONDS) + var/knockdown_time = AUGGED_LEG_EMP_KNOCKDOWN_TIME + if (severity == EMP_HEAVY) + knockdown_time *= 2 + owner.Knockdown(knockdown_time) if(owner.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB)) // So the message isn't duplicated. If they were stunned beforehand by something else, then the message not showing makes more sense anyways. return - to_chat(owner, span_danger("As your [src.name] unexpectedly malfunctions, it causes you to fall to the ground!")) + to_chat(owner, span_danger("As your [src] unexpectedly malfunctions, it causes you to fall to the ground!")) /obj/item/bodypart/chest/robot name = "cyborg torso" @@ -192,18 +199,29 @@ var/wired = FALSE var/obj/item/stock_parts/cell/cell = null + robotic_emp_paralyze_damage_percent_threshold = 0.6 + /obj/item/bodypart/chest/robot/emp_act(severity) . = ..() if(!.) return - to_chat(owner, span_danger("Your [src.name]'s logic boards temporarily become unresponsive!")) + + var/stun_time = 0 + var/shift_x = 3 + var/shift_y = 0 + var/shake_duration = AUGGED_CHEST_EMP_SHAKE_TIME + if(severity == EMP_HEAVY) - owner.Stun(6 SECONDS) - owner.Shake(pixelshiftx = 5, pixelshifty = 2, duration = 4 SECONDS) - return + stun_time = AUGGED_CHEST_EMP_STUN_TIME + + shift_x = 5 + shift_y = 2 - owner.Stun(3 SECONDS) - owner.Shake(pixelshiftx = 3, pixelshifty = 0, duration = 2.5 SECONDS) + var/damage_percent_to_max = (get_damage() / max_damage) + if (stun_time && (damage_percent_to_max >= robotic_emp_paralyze_damage_percent_threshold)) + to_chat(owner, span_danger("Your [src]'s logic boards temporarily become unresponsive!")) + owner.Stun(stun_time) + owner.Shake(pixelshiftx = shift_x, pixelshifty = shift_y, duration = shake_duration) /obj/item/bodypart/chest/robot/get_cell() return cell @@ -322,9 +340,11 @@ . = ..() if(!.) return - to_chat(owner, span_danger("Your [src.name]'s optical transponders glitch out and malfunction!")) + to_chat(owner, span_danger("Your [src]'s optical transponders glitch out and malfunction!")) - var/glitch_duration = severity == EMP_HEAVY ? 15 SECONDS : 7.5 SECONDS + var/glitch_duration = AUGGED_HEAD_EMP_GLITCH_DURATION + if (severity == EMP_HEAVY) + glitch_duration *= 2 owner.add_client_colour(/datum/client_colour/malfunction) @@ -408,7 +428,7 @@ icon = 'icons/mob/augmentation/surplus_augments.dmi' burn_modifier = 1 brute_modifier = 1 - max_damage = 20 + max_damage = PROSTHESIS_MAX_HP biological_state = (BIO_METAL|BIO_JOINTED) @@ -419,7 +439,7 @@ icon = 'icons/mob/augmentation/surplus_augments.dmi' burn_modifier = 1 brute_modifier = 1 - max_damage = 20 + max_damage = PROSTHESIS_MAX_HP biological_state = (BIO_METAL|BIO_JOINTED) @@ -430,7 +450,7 @@ icon = 'icons/mob/augmentation/surplus_augments.dmi' brute_modifier = 1 burn_modifier = 1 - max_damage = 20 + max_damage = PROSTHESIS_MAX_HP biological_state = (BIO_METAL|BIO_JOINTED) @@ -441,7 +461,7 @@ icon = 'icons/mob/augmentation/surplus_augments.dmi' brute_modifier = 1 burn_modifier = 1 - max_damage = 20 + max_damage = PROSTHESIS_MAX_HP biological_state = (BIO_METAL|BIO_JOINTED) diff --git a/code/modules/surgery/bodyparts/wounds.dm b/code/modules/surgery/bodyparts/wounds.dm index db1407953b656e..1b50dbc8fd1698 100644 --- a/code/modules/surgery/bodyparts/wounds.dm +++ b/code/modules/surgery/bodyparts/wounds.dm @@ -1,81 +1,40 @@ /// Allows us to roll for and apply a wound without actually dealing damage. Used for aggregate wounding power with pellet clouds -/obj/item/bodypart/proc/painless_wound_roll(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus, sharpness=NONE) +/obj/item/bodypart/proc/painless_wound_roll(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus, sharpness=NONE) SHOULD_CALL_PARENT(TRUE) - if(!owner || phantom_wounding_dmg <= WOUND_MINIMUM_DAMAGE || wound_bonus == CANT_WOUND || (owner.status_flags & GODMODE)) + if(!owner || wounding_dmg <= WOUND_MINIMUM_DAMAGE || wound_bonus == CANT_WOUND || (owner.status_flags & GODMODE)) return var/mangled_state = get_mangled_state() var/easy_dismember = HAS_TRAIT(owner, TRAIT_EASYDISMEMBER) // if we have easydismember, we don't reduce damage when redirecting damage to different types (slashing weapons on mangled/skinless limbs attack at 100% instead of 50%) - var/has_exterior = FALSE - var/has_interior = FALSE + var/bio_status = get_bio_state_status() - for (var/state as anything in GLOB.bio_state_states) - var/flag = text2num(state) - if (!(biological_state & flag)) - continue - - var/value = GLOB.bio_state_states[state] - if (value & BIO_EXTERIOR) - has_exterior = TRUE - if (value & BIO_INTERIOR) - has_interior = TRUE - - if (has_exterior && has_interior) - break - - // We put this here so we dont increase init time by doing this all at once on initialization - // Effectively, we "lazy load" - if (isnull(any_existing_wound_can_mangle_our_bone) || isnull(any_existing_wound_can_mangle_our_flesh)) - any_existing_wound_can_mangle_our_bone = FALSE - any_existing_wound_can_mangle_our_flesh = FALSE - for (var/datum/wound/wound_type as anything in GLOB.all_wound_pregen_data) - var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[wound_type] - if (!pregen_data.can_be_applied_to(src, random_roll = TRUE)) // we only consider randoms because non-randoms are usually really specific - continue - if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_FLESH) - any_existing_wound_can_mangle_our_flesh = TRUE - if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_BONE) - any_existing_wound_can_mangle_our_bone = TRUE - - if (any_existing_wound_can_mangle_our_bone && any_existing_wound_can_mangle_our_flesh) - break + var/has_exterior = ((bio_status & ANATOMY_EXTERIOR)) + var/has_interior = ((bio_status & ANATOMY_INTERIOR)) - var/can_theoretically_be_dismembered = (any_existing_wound_can_mangle_our_bone || (any_existing_wound_can_mangle_our_flesh && !has_exterior)) - - var/exterior_ready_to_dismember = (!has_exterior || ((mangled_state & BODYPART_MANGLED_BONE) == BODYPART_MANGLED_BONE)) - var/interior_ready_to_dismember = (!has_interior || ((mangled_state & BODYPART_MANGLED_FLESH) == BODYPART_MANGLED_FLESH)) + var/exterior_ready_to_dismember = (!has_exterior || ((mangled_state & BODYPART_MANGLED_EXTERIOR))) // if we're bone only, all cutting attacks go straight to the bone - if(has_exterior && interior_ready_to_dismember) + if(!has_exterior && has_interior) if(wounding_type == WOUND_SLASH) wounding_type = WOUND_BLUNT - phantom_wounding_dmg *= (easy_dismember ? 1 : 0.6) + wounding_dmg *= (easy_dismember ? 1 : 0.6) else if(wounding_type == WOUND_PIERCE) wounding_type = WOUND_BLUNT - phantom_wounding_dmg *= (easy_dismember ? 1 : 0.75) - if(exterior_ready_to_dismember && try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus)) - return + wounding_dmg *= (easy_dismember ? 1 : 0.75) else // if we've already mangled the skin (critical slash or piercing wound), then the bone is exposed, and we can damage it with sharp weapons at a reduced rate // So a big sharp weapon is still all you need to destroy a limb - if(has_exterior && interior_ready_to_dismember && !(mangled_state & BODYPART_MANGLED_BONE) && sharpness) - playsound(src, "sound/effects/wounds/crackandbleed.ogg", 100) + if(has_interior && exterior_ready_to_dismember && !(mangled_state & BODYPART_MANGLED_INTERIOR) && sharpness) if(wounding_type == WOUND_SLASH && !easy_dismember) - phantom_wounding_dmg *= 0.6 // edged weapons pass along 60% of their wounding damage to the bone since the power is spread out over a larger area + wounding_dmg *= 0.6 // edged weapons pass along 60% of their wounding damage to the bone since the power is spread out over a larger area if(wounding_type == WOUND_PIERCE && !easy_dismember) - phantom_wounding_dmg *= 0.75 // piercing weapons pass along 75% of their wounding damage to the bone since it's more concentrated + wounding_dmg *= 0.75 // piercing weapons pass along 75% of their wounding damage to the bone since it's more concentrated wounding_type = WOUND_BLUNT - else if(interior_ready_to_dismember && exterior_ready_to_dismember && try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus)) + if ((dismemberable_by_wound() || dismemberable_by_total_damage()) && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus)) return - if (use_alternate_dismemberment_calc_even_if_mangleable || !can_theoretically_be_dismembered) - var/percent_to_total_max = (get_damage() / max_damage) - if (percent_to_total_max >= hp_percent_to_dismemberable) - if (try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus)) - return - - return check_wounding(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus) + return check_wounding(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus) /** * check_wounding() is where we handle rolling for, selecting, and applying a wound if we meet the criteria @@ -111,6 +70,8 @@ var/base_roll = rand(1, round(damage ** WOUND_DAMAGE_EXPONENT)) var/injury_roll = base_roll injury_roll += check_woundings_mods(woundtype, damage, wound_bonus, bare_wound_bonus) + var/list/series_wounding_mods = check_series_wounding_mods() + if(injury_roll > WOUND_DISMEMBER_OUTRIGHT_THRESH && prob(get_damage() / max_damage * 100)) var/datum/wound/loss/dismembering = new dismembering.apply_dismember(src, woundtype, outright = TRUE, attack_direction = attack_direction) @@ -119,8 +80,8 @@ var/list/datum/wound/possible_wounds = list() for (var/datum/wound/type as anything in GLOB.all_wound_pregen_data) var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[type] - if (pregen_data.can_be_applied_to(src, woundtype, random_roll = TRUE)) - possible_wounds += type + if (pregen_data.can_be_applied_to(src, list(woundtype), random_roll = TRUE)) + possible_wounds[type] = pregen_data.get_weight(src, woundtype, damage, attack_direction, damage_source) // quick re-check to see if bare_wound_bonus applies, for the benefit of log_wound(), see about getting the check from check_woundings_mods() somehow if(ishuman(owner)) var/mob/living/carbon/human/human_wearer = owner @@ -131,39 +92,137 @@ bare_wound_bonus = 0 break - //cycle through the wounds of the relevant category from the most severe down - for(var/datum/wound/possible_wound as anything in possible_wounds) + for (var/datum/wound/iterated_path as anything in possible_wounds) + for (var/datum/wound/existing_wound as anything in wounds) + if (iterated_path == existing_wound.type) + possible_wounds -= iterated_path + break // breaks out of the nested loop + + var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[iterated_path] + var/specific_injury_roll = (injury_roll + series_wounding_mods[pregen_data.wound_series]) + if (pregen_data.get_threshold_for(src, attack_direction, damage_source) > specific_injury_roll) + possible_wounds -= iterated_path + continue + + if (pregen_data.compete_for_wounding) + for (var/datum/wound/other_path as anything in possible_wounds) + if (other_path == iterated_path) + continue + if (initial(iterated_path.severity) == initial(other_path.severity) && pregen_data.overpower_wounds_of_even_severity) + possible_wounds -= other_path + continue + else if (pregen_data.competition_mode == WOUND_COMPETITION_OVERPOWER_LESSERS) + if (initial(iterated_path.severity) > initial(other_path.severity)) + possible_wounds -= other_path + continue + else if (pregen_data.competition_mode == WOUND_COMPETITION_OVERPOWER_GREATERS) + if (initial(iterated_path.severity) < initial(other_path.severity)) + possible_wounds -= other_path + continue + + while (length(possible_wounds)) + var/datum/wound/possible_wound = pick_weight(possible_wounds) + var/datum/wound_pregen_data/possible_pregen_data = GLOB.all_wound_pregen_data[possible_wound] + possible_wounds -= possible_wound + var/datum/wound/replaced_wound for(var/datum/wound/existing_wound as anything in wounds) - if(existing_wound.wound_series == initial(possible_wound.wound_series)) + var/datum/wound_pregen_data/existing_pregen_data = GLOB.all_wound_pregen_data[existing_wound.type] + if(existing_pregen_data.wound_series == possible_pregen_data.wound_series) if(existing_wound.severity >= initial(possible_wound.severity)) - return + continue else - replaced_wound = existing_wound // if we find something we keep iterating untilw e're done or we find we're outclassed by something in our series - - if(initial(possible_wound.threshold_minimum) < injury_roll) - var/datum/wound/new_wound - if(replaced_wound) - new_wound = replaced_wound.replace_wound(new possible_wound, attack_direction = attack_direction) - else - new_wound = new possible_wound - new_wound.apply_wound(src, attack_direction = attack_direction, wound_source = damage_source) - log_wound(owner, new_wound, damage, wound_bonus, bare_wound_bonus, base_roll) // dismembering wounds are logged in the apply_wound() for loss wounds since they delete themselves immediately, these will be immediately returned - return new_wound + replaced_wound = existing_wound + // if we get through this whole loop without continuing, we found our winner + + var/datum/wound/new_wound = new possible_wound + if(replaced_wound) + new_wound = replaced_wound.replace_wound(new_wound, attack_direction = attack_direction) + else + new_wound.apply_wound(src, attack_direction = attack_direction, wound_source = damage_source) + log_wound(owner, new_wound, damage, wound_bonus, bare_wound_bonus, base_roll) // dismembering wounds are logged in the apply_wound() for loss wounds since they delete themselves immediately, these will be immediately returned + return new_wound // try forcing a specific wound, but only if there isn't already a wound of that severity or greater for that type on this bodypart -/obj/item/bodypart/proc/force_wound_upwards(specific_woundtype, smited = FALSE, wound_source) +/obj/item/bodypart/proc/force_wound_upwards(datum/wound/potential_wound, smited = FALSE, wound_source) SHOULD_NOT_OVERRIDE(TRUE) - var/datum/wound/potential_wound = specific_woundtype + if (isnull(potential_wound)) + return + + var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[potential_wound] for(var/datum/wound/existing_wound as anything in wounds) - if (existing_wound.wound_series == initial(potential_wound.wound_series)) + var/datum/wound_pregen_data/existing_pregen_data = existing_wound.get_pregen_data() + if (existing_pregen_data.wound_series == pregen_data.wound_series) if(existing_wound.severity < initial(potential_wound.severity)) // we only try if the existing one is inferior to the one we're trying to force existing_wound.replace_wound(new potential_wound, smited) return var/datum/wound/new_wound = new potential_wound new_wound.apply_wound(src, smited = smited, wound_source = wound_source) + return new_wound + +/** + * A simple proc to force a type of wound onto this mob. If you just want to force a specific mainline (fractures, bleeding, etc.) wound, you only need to care about the first 3 args. + * + * Args: + * * wounding_type: The wounding_type, e.g. WOUND_BLUNT, WOUND_SLASH to force onto the mob. Can be a list. + * * obj/item/bodypart/limb: The limb we wil be applying the wound to. If null, a random bodypart will be picked. + * * min_severity: The minimum severity that will be considered. + * * max_severity: The maximum severity that will be considered. + * * severity_pick_mode: The "pick mode" to be used. See get_corresponding_wound_type's documentation + * * wound_source: The source of the wound to be applied. Nullable. + * + * For the rest of the args, refer to get_corresponding_wound_type(). + * + * Returns: + * A new wound instance if the application was successful, null otherwise. +*/ +/mob/living/carbon/proc/cause_wound_of_type_and_severity(wounding_type, obj/item/bodypart/limb, min_severity, max_severity = min_severity, severity_pick_mode = WOUND_PICK_HIGHEST_SEVERITY, wound_source) + if (isnull(limb)) + limb = pick(bodyparts) + + var/list/type_list = wounding_type + if (!islist(type_list)) + type_list = list(type_list) + + var/datum/wound/corresponding_typepath = get_corresponding_wound_type(type_list, limb, min_severity, max_severity, severity_pick_mode) + if (corresponding_typepath) + return limb.force_wound_upwards(corresponding_typepath, wound_source = wound_source) + +/// Limb is nullable, but picks a random one. Defers to limb.get_wound_threshold_of_wound_type, see it for documentation. +/mob/living/carbon/proc/get_wound_threshold_of_wound_type(wounding_type, severity, default, obj/item/bodypart/limb, wound_source) + if (isnull(limb)) + limb = pick(bodyparts) + + if (!limb) + return default + + return limb.get_wound_threshold_of_wound_type(wounding_type, severity, default, wound_source) + +/** + * A simple proc that gets the best wound to fit the criteria laid out, then returns its wound threshold. + * + * Args: + * * wounding_type: The wounding_type, e.g. WOUND_BLUNT, WOUND_SLASH to force onto the mob. Can be a list of wounding_types. + * * severity: The severity that will be considered. + * * return_value_if_no_wound: If no wound is found, we will return this instead. (It is reccomended to use named args for this one, as its unclear what it is without) + * * wound_source: The theoretical source of the wound. Nullable. + * + * Returns: + * return_value_if_no_wound if no wound is found - if one IS found, the wound threshold for that wound. + */ +/obj/item/bodypart/proc/get_wound_threshold_of_wound_type(wounding_type, severity, return_value_if_no_wound, wound_source) + var/list/type_list = wounding_type + if (!islist(type_list)) + type_list = list(type_list) + + var/datum/wound/wound_path = get_corresponding_wound_type(type_list, src, severity, duplicates_allowed = TRUE, care_about_existing_wounds = FALSE) + if (wound_path) + var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[wound_path] + return pregen_data.get_threshold_for(src, damage_source = wound_source) + + return return_value_if_no_wound /** * check_wounding_mods() is where we handle the various modifiers of a wound roll @@ -209,7 +268,20 @@ return injury_mod - /// Get whatever wound of the given type is currently attached to this limb, if any +/// Should return an assoc list of (wound_series -> penalty). Will be used in determining series-specific penalties for wounding. +/obj/item/bodypart/proc/check_series_wounding_mods() + RETURN_TYPE(/list) + + var/list/series_mods = list() + + for (var/datum/wound/iterated_wound as anything in wounds) + var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[iterated_wound.type] + + series_mods[pregen_data.wound_series] += iterated_wound.series_threshold_penalty + + return series_mods + +/// Get whatever wound of the given type is currently attached to this limb, if any /obj/item/bodypart/proc/get_wound_type(checking_type) RETURN_TYPE(checking_type) SHOULD_NOT_OVERRIDE(TRUE) @@ -232,11 +304,11 @@ /obj/item/bodypart/proc/update_wounds(replaced = FALSE) SHOULD_CALL_PARENT(TRUE) - var/dam_mul = 1 //initial(wound_damage_multiplier) + var/dam_mul = 1 // we can (normally) only have one wound per type, but remember there's multiple types (smites like :B:loodless can generate multiple cuts on a limb) for(var/datum/wound/iter_wound as anything in wounds) - dam_mul *= iter_wound.damage_mulitplier_penalty + dam_mul *= iter_wound.damage_multiplier_penalty if(!LAZYLEN(wounds) && current_gauze && !replaced) // no more wounds = no need for the gauze anymore owner.visible_message(span_notice("\The [current_gauze.name] on [owner]'s [name] falls away."), span_notice("The [current_gauze.name] on your [parse_zone(body_zone)] falls away.")) diff --git a/code/modules/surgery/organs/autosurgeon.dm b/code/modules/surgery/organs/autosurgeon.dm index d28ffa4062c731..0987df92bd94e1 100644 --- a/code/modules/surgery/organs/autosurgeon.dm +++ b/code/modules/surgery/organs/autosurgeon.dm @@ -157,9 +157,6 @@ /obj/item/autosurgeon/syndicate/anti_stun starting_organ = /obj/item/organ/internal/cyberimp/brain/anti_stun -/obj/item/autosurgeon/syndicate/anti_drop - starting_organ = /obj/item/organ/internal/cyberimp/brain/anti_drop - /obj/item/autosurgeon/syndicate/reviver starting_organ = /obj/item/organ/internal/cyberimp/chest/reviver diff --git a/code/modules/surgery/organs/internal/appendix/_appendix.dm b/code/modules/surgery/organs/internal/appendix/_appendix.dm index 835d7e62bed79a..a52479c10a7321 100644 --- a/code/modules/surgery/organs/internal/appendix/_appendix.dm +++ b/code/modules/surgery/organs/internal/appendix/_appendix.dm @@ -65,7 +65,7 @@ organ_owner.adjustToxLoss(1, updating_health = TRUE, forced = TRUE) if(3) if(SPT_PROB(0.5, seconds_per_tick)) - organ_owner.vomit(95) + organ_owner.vomit(VOMIT_CATEGORY_DEFAULT, lost_nutrition = 95) organ_owner.adjustOrganLoss(ORGAN_SLOT_APPENDIX, 15) diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm b/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm index 55624e88bf1a45..0a7332c0dd893a 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm @@ -172,4 +172,3 @@ new /obj/item/autosurgeon/syndicate/xray_eyes(src) new /obj/item/autosurgeon/syndicate/anti_stun(src) new /obj/item/autosurgeon/syndicate/reviver(src) - new /obj/item/autosurgeon/syndicate/anti_drop(src) diff --git a/code/modules/surgery/organs/internal/ears/_ears.dm b/code/modules/surgery/organs/internal/ears/_ears.dm index 54d35628f85fa4..52f5d7405201c0 100644 --- a/code/modules/surgery/organs/internal/ears/_ears.dm +++ b/code/modules/surgery/organs/internal/ears/_ears.dm @@ -153,4 +153,4 @@ . = ..() if(. & EMP_PROTECT_SELF) return - apply_organ_damage(40/severity) + apply_organ_damage(20 / severity) diff --git a/code/modules/surgery/organs/internal/liver/_liver.dm b/code/modules/surgery/organs/internal/liver/_liver.dm index f871fbd84db588..fe5ca01df4f016 100644 --- a/code/modules/surgery/organs/internal/liver/_liver.dm +++ b/code/modules/surgery/organs/internal/liver/_liver.dm @@ -172,18 +172,18 @@ to_chat(owner, span_userdanger("You feel stabbing pain in your abdomen!")) if(2) to_chat(owner, span_userdanger("You feel a burning sensation in your gut!")) - owner.vomit() + owner.vomit(VOMIT_CATEGORY_DEFAULT) if(3) to_chat(owner, span_userdanger("You feel painful acid in your throat!")) - owner.vomit(blood = TRUE) + owner.vomit(VOMIT_CATEGORY_BLOOD) if(4) to_chat(owner, span_userdanger("Overwhelming pain knocks you out!")) - owner.vomit(blood = TRUE, distance = rand(1,2)) + owner.vomit(VOMIT_CATEGORY_BLOOD, distance = rand(1,2)) owner.emote("Scream") owner.AdjustUnconscious(2.5 SECONDS) if(5) to_chat(owner, span_userdanger("You feel as if your guts are about to melt!")) - owner.vomit(blood = TRUE,distance = rand(1,3)) + owner.vomit(VOMIT_CATEGORY_BLOOD, distance = rand(1,3)) owner.emote("Scream") owner.AdjustUnconscious(5 SECONDS) diff --git a/code/modules/surgery/organs/internal/lungs/_lungs.dm b/code/modules/surgery/organs/internal/lungs/_lungs.dm index ba66721433f44a..5e4e0648067513 100644 --- a/code/modules/surgery/organs/internal/lungs/_lungs.dm +++ b/code/modules/surgery/organs/internal/lungs/_lungs.dm @@ -481,13 +481,13 @@ if(prob(5)) to_chat(breather, span_warning("The stench of rotting carcasses is unbearable!")) breather.add_mood_event("smell", /datum/mood_event/disgust/nauseating_stench) - breather.vomit() + breather.vomit(VOMIT_CATEGORY_DEFAULT) if(30 to INFINITY) //Higher chance to vomit. Let the horror start if(prob(15)) to_chat(breather, span_warning("The stench of rotting carcasses is unbearable!")) breather.add_mood_event("smell", /datum/mood_event/disgust/nauseating_stench) - breather.vomit() + breather.vomit(VOMIT_CATEGORY_DEFAULT) else breather.clear_mood_event("smell") // In a full miasma atmosphere with 101.34 pKa, about 10 disgust per breath, is pretty low compared to threshholds diff --git a/code/modules/surgery/organs/internal/stomach/_stomach.dm b/code/modules/surgery/organs/internal/stomach/_stomach.dm index 4f83b7844a4aea..bebeaacf110a33 100644 --- a/code/modules/surgery/organs/internal/stomach/_stomach.dm +++ b/code/modules/surgery/organs/internal/stomach/_stomach.dm @@ -110,13 +110,13 @@ //The stomach is damage has nutriment but low on theshhold, lo prob of vomit if(SPT_PROB(0.0125 * damage * nutri_vol * nutri_vol, seconds_per_tick)) - body.vomit(damage) + body.vomit(VOMIT_CATEGORY_DEFAULT, lost_nutrition = damage) to_chat(body, span_warning("Your stomach reels in pain as you're incapable of holding down all that food!")) return // the change of vomit is now high if(damage > high_threshold && SPT_PROB(0.05 * damage * nutri_vol * nutri_vol, seconds_per_tick)) - body.vomit(damage) + body.vomit(VOMIT_CATEGORY_DEFAULT, lost_nutrition = damage) to_chat(body, span_warning("Your stomach reels in pain as you're incapable of holding down all that food!")) /obj/item/organ/internal/stomach/proc/handle_hunger(mob/living/carbon/human/human, seconds_per_tick, times_fired) @@ -234,7 +234,7 @@ if(SPT_PROB(pukeprob, seconds_per_tick)) //iT hAndLeS mOrE ThaN PukInG disgusted.adjust_confusion(2.5 SECONDS) disgusted.adjust_stutter(2 SECONDS) - disgusted.vomit(10, distance = 0, vomit_type = NONE) + disgusted.vomit(VOMIT_CATEGORY_DEFAULT, distance = 0) disgusted.set_dizzy_if_lower(10 SECONDS) if(disgust >= DISGUST_LEVEL_DISGUSTED) if(SPT_PROB(13, seconds_per_tick)) @@ -300,7 +300,7 @@ if(. & EMP_PROTECT_SELF) return if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people. - owner.vomit(stun = FALSE) + owner.vomit(vomit_flags = (MOB_VOMIT_MESSAGE | MOB_VOMIT_HARM)) COOLDOWN_START(src, severe_cooldown, 10 SECONDS) if(prob(emp_vulnerability/severity)) //Chance of permanent effects organ_flags |= ORGAN_EMP //Starts organ faliure - gonna need replacing soon. diff --git a/code/modules/surgery/revival.dm b/code/modules/surgery/revival.dm index 1f26a63cc6ac64..e199df0ffd9ec9 100644 --- a/code/modules/surgery/revival.dm +++ b/code/modules/surgery/revival.dm @@ -3,7 +3,8 @@ desc = "An experimental surgical procedure which involves reconstruction and reactivation of the patient's brain even long after death. \ The body must still be able to sustain life." requires_bodypart_type = NONE - possible_locs = list(BODY_ZONE_HEAD) + possible_locs = list(BODY_ZONE_CHEST) + target_mobtypes = list(/mob/living) surgery_flags = SURGERY_REQUIRE_RESTING | SURGERY_REQUIRE_LIMB | SURGERY_MORBID_CURIOSITY steps = list( /datum/surgery_step/incise, @@ -15,15 +16,22 @@ /datum/surgery_step/close, ) -/datum/surgery/revival/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/revival/can_start(mob/user, mob/living/target) if(!..()) return FALSE if(target.stat != DEAD) return FALSE if(HAS_TRAIT(target, TRAIT_SUICIDED) || HAS_TRAIT(target, TRAIT_HUSK) || HAS_TRAIT(target, TRAIT_DEFIB_BLACKLISTED)) return FALSE - var/obj/item/organ/internal/brain/target_brain = target.get_organ_slot(ORGAN_SLOT_BRAIN) - if(!target_brain) + if(!is_valid_target(target)) + return FALSE + return TRUE + +/// Extra checks which can be overridden +/datum/surgery/revival/proc/is_valid_target(mob/living/patient) + if (iscarbon(patient)) + return FALSE + if (!(patient.mob_biotypes & (MOB_ORGANIC|MOB_HUMANOID))) return FALSE return TRUE @@ -59,7 +67,7 @@ to_chat(user, span_warning("You need an electrode for this!")) return FALSE -/datum/surgery_step/revive/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/revive/preop(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery) display_results( user, target, @@ -69,13 +77,13 @@ ) target.notify_ghost_cloning("Someone is trying to zap your brain.", source = target) -/datum/surgery_step/revive/play_preop_sound(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/revive/play_preop_sound(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery) if(istype(tool, /obj/item/shockpaddles)) playsound(tool, 'sound/machines/defib_charge.ogg', 75, 0) else ..() -/datum/surgery_step/revive/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results) +/datum/surgery_step/revive/success(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results) display_results( user, target, @@ -87,24 +95,27 @@ target.adjustOxyLoss(-50, 0) target.updatehealth() if(target.revive()) - target.visible_message(span_notice("...[target] wakes up, alive and aware!")) - target.emote("gasp") - target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 50, 199) //MAD SCIENCE - to_chat(target, "[CONFIG_GET(string/blackoutpolicy)]") //SKYRAT EDIT ADDITION - BLACKOUT POLICY - if(HAS_MIND_TRAIT(user, TRAIT_MORBID) && ishuman(user)) //Contrary to their typical hatred of resurrection, it wouldn't be very thematic if morbid people didn't love playing god - var/mob/living/carbon/human/morbid_weirdo = user - morbid_weirdo.add_mood_event("morbid_revival_success", /datum/mood_event/morbid_revival_success) + on_revived(user, target) return TRUE + + //SKYRAT EDIT CHANGE - DNR TRAIT - need this so that people don't just keep spamming the revival surgery; it runs success just bc the surgery steps are done + if(HAS_TRAIT(target, TRAIT_DNR)) + target.visible_message(span_warning("...[target.p_they()] lie[target.p_s()] still, unaffected. Further attempts are futile, target.p_theyre() gone.")) else - //SKYRAT EDIT ADDITION - DNR TRAIT - need this so that people dont just keep spamming the revival surgery; it runs success just bc the surgery steps are done - if(HAS_TRAIT(target, TRAIT_DNR)) - target.visible_message(span_warning("...[target.p_they()] lies still, unaffected. Further attempts are futile, they're gone.")) - else - target.visible_message(span_warning("...[target.p_they()] convulses, then lies still.")) - //SKYRAT EDIT ADDITION END - DNR TRAIT - ORIGINAL: target.visible_message(span_warning("...[target.p_they()] convulses, then lies still.")) - return FALSE + target.visible_message(span_warning("...[target.p_they()] convulse[target.p_s()], then lie[target.p_s()] still.")) + //SKYRAT EDIT CHANGE END - DNR TRAIT - ORIGINAL: target.visible_message(span_warning("...[target.p_they()] convulse[target.p_s()], then lie[target.p_s()] still.")) + return FALSE -/datum/surgery_step/revive/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/// Called when you have been successfully raised from the dead +/datum/surgery_step/revive/proc/on_revived(mob/surgeon, mob/living/patient) + patient.visible_message(span_notice("...[patient] wakes up, alive and aware!")) + patient.emote("gasp") + to_chat(patient, "[CONFIG_GET(string/blackoutpolicy)]") //SKYRAT EDIT ADDITION - BLACKOUT POLICY + if(HAS_MIND_TRAIT(surgeon, TRAIT_MORBID) && ishuman(surgeon)) // Contrary to their typical hatred of resurrection, it wouldn't be very thematic if morbid people didn't love playing god + var/mob/living/carbon/human/morbid_weirdo = surgeon + morbid_weirdo.add_mood_event("morbid_revival_success", /datum/mood_event/morbid_revival_success) + +/datum/surgery_step/revive/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery) display_results( user, target, @@ -112,5 +123,23 @@ span_notice("[user] send a powerful shock to [target]'s brain with [tool], but [target.p_they()] doesn't react."), span_notice("[user] send a powerful shock to [target]'s brain with [tool], but [target.p_they()] doesn't react."), ) - target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 15, 180) return FALSE + +/// Additional revival effects if the target has a brain +/datum/surgery/revival/carbon + possible_locs = list(BODY_ZONE_HEAD) + target_mobtypes = list(/mob/living/carbon) + +/datum/surgery/revival/carbon/is_valid_target(mob/living/carbon/patient) + var/obj/item/organ/internal/brain/target_brain = patient.get_organ_slot(ORGAN_SLOT_BRAIN) + return !isnull(target_brain) + +/datum/surgery_step/revive/carbon + +/datum/surgery_step/revive/carbon/on_revived(mob/surgeon, mob/living/patient) + . = ..() + patient.adjustOrganLoss(ORGAN_SLOT_BRAIN, 50, 199) // MAD SCIENCE + +/datum/surgery_step/revive/carbon/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + . = ..() + target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 15, 180) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index e469f16740a8b4..a89d4524170d57 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -104,7 +104,6 @@ #include "bloody_footprints.dm" #include "breath.dm" #include "burning.dm" -#include "byond_status.dm" #include "cable_powernets.dm" #include "card_mismatch.dm" #include "cardboard_cutouts.dm" diff --git a/code/modules/unit_tests/byond_status.dm b/code/modules/unit_tests/byond_status.dm deleted file mode 100644 index e27888315565d2..00000000000000 --- a/code/modules/unit_tests/byond_status.dm +++ /dev/null @@ -1,9 +0,0 @@ -/// Tests the SUPPOSED TO BE TEMPORARY byond_status() proc for a useful format -/datum/unit_test/byond_status - -/datum/unit_test/byond_status/Run() - if (world.system_type != UNIX) - return - - var/status = byond_status() - TEST_ASSERT(findtext(status, "Sleeping procs"), "Invalid byond_status: [status]") diff --git a/code/modules/unit_tests/chain_pull_through_space.dm b/code/modules/unit_tests/chain_pull_through_space.dm index 86b0cc69d1cf4e..b767b010495c8c 100644 --- a/code/modules/unit_tests/chain_pull_through_space.dm +++ b/code/modules/unit_tests/chain_pull_through_space.dm @@ -11,15 +11,16 @@ ..() //reserve a tile that is always empty for our z destination - reserved = SSmapping.RequestBlockReservation(5,5) + reserved = SSmapping.request_turf_block_reservation(5, 5, 1) // Create a space tile that goes to another z-level claimed_tile = run_loc_floor_bottom_left.type space_tile = run_loc_floor_bottom_left.ChangeTurf(/turf/open/space) - space_tile.destination_x = round(reserved.bottom_left_coords[1] + (reserved.width-1) / 2) - space_tile.destination_y = round(reserved.bottom_left_coords[2] + (reserved.height-1) / 2) - space_tile.destination_z = reserved.bottom_left_coords[3] + var/turf/bottom_left = reserved.bottom_left_turfs[1] + space_tile.destination_x = round(bottom_left.x + (reserved.width-1) / 2) + space_tile.destination_y = round(bottom_left.y + (reserved.height-1) / 2) + space_tile.destination_z = bottom_left.z // Create our list of humans, all adjacent to one another alice = new(locate(run_loc_floor_bottom_left.x + 2, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z)) diff --git a/code/modules/unit_tests/fish_unit_tests.dm b/code/modules/unit_tests/fish_unit_tests.dm index 6c4a278a39649d..1ef15f8d0f5126 100644 --- a/code/modules/unit_tests/fish_unit_tests.dm +++ b/code/modules/unit_tests/fish_unit_tests.dm @@ -123,5 +123,79 @@ . = ..() probability = 0 //works around the global list initialization skipping abstract/impossible evolutions. +// we want no default spawns in this unit test +/datum/chasm_detritus/restricted/bodies/no_defaults + default_contents_chance = 0 + +/// Checks that we are able to fish people out of chasms with priority and that they end up in the right location +/datum/unit_test/fish_rescue_hook + priority = TEST_LONGER + var/original_turf_type + var/original_turf_baseturfs + var/list/mobs_spawned + +/datum/unit_test/fish_rescue_hook/Run() + // create our human dummies to be dropped into the chasm + var/mob/living/carbon/human/consistent/get_in_the_hole = allocate(/mob/living/carbon/human/consistent) + var/mob/living/basic/mining/lobstrosity/you_too = allocate(/mob/living/basic/mining/lobstrosity) + var/mob/living/carbon/human/consistent/mindless = allocate(/mob/living/carbon/human/consistent) + var/mob/living/carbon/human/consistent/no_brain = allocate(/mob/living/carbon/human/consistent) + var/mob/living/carbon/human/consistent/empty = allocate(/mob/living/carbon/human/consistent) + var/mob/living/carbon/human/consistent/dummy = allocate(/mob/living/carbon/human/consistent) + + mobs_spawned = list( + get_in_the_hole, + you_too, + mindless, + no_brain, + empty, + dummy, + ) + + // create our chasm and remember the previous turf so we can change it back once we're done + original_turf_type = run_loc_floor_bottom_left.type + original_turf_baseturfs = islist(run_loc_floor_bottom_left.baseturfs) ? run_loc_floor_bottom_left.baseturfs.Copy() : run_loc_floor_bottom_left.baseturfs + run_loc_floor_bottom_left.ChangeTurf(/turf/open/chasm) + var/turf/open/chasm/the_hole = run_loc_floor_bottom_left + + // into the hole they go + for(var/mob/mob_spawned in mobs_spawned) + the_hole.drop(mob_spawned) + sleep(0.2 SECONDS) // we have to WAIT because the drop() proc sleeps. + + // our 'fisherman' where we expect the item to be moved to after fishing it up + var/mob/living/carbon/human/consistent/a_fisherman = allocate(/mob/living/carbon/human/consistent, run_loc_floor_top_right) + + // pretend like this mob has a mind. they should be fished up first + no_brain.mind_initialize() + + SEND_SIGNAL(the_hole, COMSIG_PRE_FISHING) // we need to do this for the fishing spot component to be attached + var/datum/component/fishing_spot/the_hole_fishing_spot = the_hole.GetComponent(/datum/component/fishing_spot) + var/datum/fish_source/fishing_source = the_hole_fishing_spot.fish_source + var/obj/item/fishing_hook/rescue/the_hook = allocate(/obj/item/fishing_hook/rescue, run_loc_floor_top_right) + the_hook.chasm_detritus_type = /datum/chasm_detritus/restricted/bodies/no_defaults + + // try to fish up our minded victim + var/atom/movable/reward = fishing_source.dispense_reward(the_hook.chasm_detritus_type, a_fisherman, the_hole) + + // mobs with minds (aka players) should have precedence over any other mobs that are in the chasm + TEST_ASSERT_EQUAL(reward, no_brain, "Fished up [reward] ([REF(reward)]) with a rescue hook; expected to fish up [no_brain]([REF(no_brain)])") + // it should end up on the same turf as the fisherman + TEST_ASSERT_EQUAL(get_turf(reward), get_turf(a_fisherman), "[reward] was fished up with the rescue hook and ended up at [get_turf(reward)]; expected to be at [get_turf(a_fisherman)]") + + // let's further test that by giving a second mob a mind. they should be fished up immediately.. + empty.mind_initialize() + + reward = fishing_source.dispense_reward(the_hook.chasm_detritus_type, a_fisherman, the_hole) + + TEST_ASSERT_EQUAL(reward, empty, "Fished up [reward]([REF(reward)]) with a rescue hook; expected to fish up [empty]([REF(empty)])") + TEST_ASSERT_EQUAL(get_turf(reward), get_turf(a_fisherman), "[reward] was fished up with the rescue hook and ended up at [get_turf(reward)]; expected to be at [get_turf(a_fisherman)]") + +// clean up so we don't mess up subsequent tests +/datum/unit_test/fish_rescue_hook/Destroy() + QDEL_LIST(mobs_spawned) + run_loc_floor_bottom_left.ChangeTurf(original_turf_type, original_turf_baseturfs) + return ..() + #undef TRAIT_FISH_TESTING diff --git a/code/modules/unit_tests/medical_wounds.dm b/code/modules/unit_tests/medical_wounds.dm index 0838b2d18be852..161492a726a923 100644 --- a/code/modules/unit_tests/medical_wounds.dm +++ b/code/modules/unit_tests/medical_wounds.dm @@ -19,10 +19,11 @@ TEST_ASSERT_EQUAL(length(victim.all_wounds), 0, "Patient is somehow wounded before test") var/datum/wound/iter_test_wound + var/datum/wound_pregen_data/iter_pregen_data = GLOB.all_wound_pregen_data[iter_test_wound] var/threshold_penalty = 0 for(iter_test_wound in iter_test_wound_list) - var/threshold = initial(iter_test_wound.threshold_minimum) - threshold_penalty // just enough to guarantee the next tier of wound, given the existing wound threshold penalty + var/threshold = iter_pregen_data.threshold_minimum - threshold_penalty // just enough to guarantee the next tier of wound, given the existing wound threshold penalty if(dam_types[i] == BRUTE) tested_part.receive_damage(WOUND_MINIMUM_DAMAGE, 0, wound_bonus = threshold, sharpness=sharps[i]) else if(dam_types[i] == BURN) @@ -59,10 +60,11 @@ TEST_ASSERT_EQUAL(length(victim.all_wounds), 0, "Patient is somehow wounded before test") var/datum/wound/iter_test_wound + var/datum/wound_pregen_data/iter_pregen_data = GLOB.all_wound_pregen_data[iter_test_wound] var/threshold_penalty = 0 for(iter_test_wound in iter_test_wound_list) - var/threshold = initial(iter_test_wound.threshold_minimum) - threshold_penalty // just enough to guarantee the next tier of wound, given the existing wound threshold penalty + var/threshold = iter_pregen_data.threshold_minimum - threshold_penalty // just enough to guarantee the next tier of wound, given the existing wound threshold penalty if(dam_types[i] == BRUTE) tested_part.receive_damage(WOUND_MINIMUM_DAMAGE, 0, wound_bonus = threshold, sharpness=sharps[i]) else if(dam_types[i] == BURN) diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_assaultoperative.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_assaultoperative.png index 06ef0119d1c558..fefeec4ad1dcd3 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_antag_icons_assaultoperative.png and b/code/modules/unit_tests/screenshots/screenshot_antag_icons_assaultoperative.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodbrother.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodbrother.png index 2bba94849140c9..e53e0a86697708 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodbrother.png and b/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodbrother.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_changeling.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_changeling.png index 38dc445797362e..e1bdbea1058a48 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_antag_icons_changeling.png and b/code/modules/unit_tests/screenshots/screenshot_antag_icons_changeling.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_stowawaychangeling.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_stowawaychangeling.png index 38dc445797362e..e1bdbea1058a48 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_antag_icons_stowawaychangeling.png and b/code/modules/unit_tests/screenshots/screenshot_antag_icons_stowawaychangeling.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard.png index 1bddc8f501137d..766941523231da 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard.png and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard.png differ diff --git a/code/modules/unit_tests/teleporters.dm b/code/modules/unit_tests/teleporters.dm index 2cb047304fbb50..e1af0a71a351d9 100644 --- a/code/modules/unit_tests/teleporters.dm +++ b/code/modules/unit_tests/teleporters.dm @@ -1,10 +1,18 @@ -/datum/unit_test/auto_teleporter_linking/Run() +/datum/unit_test/teleporter/Run() // Put down the teleporter machinery var/obj/machinery/teleport/hub/hub = allocate(/obj/machinery/teleport/hub) var/obj/machinery/teleport/station/station = allocate(/obj/machinery/teleport/station, locate(run_loc_floor_bottom_left.x + 1, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z)) var/obj/machinery/computer/teleporter/computer = allocate(/obj/machinery/computer/teleporter, locate(run_loc_floor_bottom_left.x + 2, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z)) + var/obj/item/beacon/beacon = allocate(/obj/item/beacon) TEST_ASSERT_EQUAL(hub.power_station, station, "Hub didn't link to the station") TEST_ASSERT_EQUAL(station.teleporter_console, computer, "Station didn't link to the teleporter console") TEST_ASSERT_EQUAL(station.teleporter_hub, hub, "Station didn't link to the hub") TEST_ASSERT_EQUAL(computer.power_station, station, "Teleporter console didn't link to the hub") + + computer.set_teleport_target(beacon) + TEST_ASSERT_EQUAL(computer.target_ref, beacon.weak_reference, "Teleporter didn't target beacon correctly") + + computer.set_teleport_target(beacon) + beacon.turn_off() + TEST_ASSERT_NULL(computer.target_ref, "Teleporter beacon isn't properly turned off.") diff --git a/code/modules/uplink/uplink_items/device_tools.dm b/code/modules/uplink/uplink_items/device_tools.dm index 20792cfae708e1..8a83e7450c5563 100644 --- a/code/modules/uplink/uplink_items/device_tools.dm +++ b/code/modules/uplink/uplink_items/device_tools.dm @@ -66,13 +66,14 @@ cost = 1 surplus = 20 -/* /datum/uplink_item/device_tools/briefcase_launchpad // SKYRAT EDIT REMOVAL +/* // SKYRAT EDIT REMOVAL +/datum/uplink_item/device_tools/briefcase_launchpad name = "Briefcase Launchpad" desc = "A briefcase containing a launchpad, a device able to teleport items and people to and from targets up to eight tiles away from the briefcase. \ Also includes a remote control, disguised as an ordinary folder. Touch the briefcase with the remote to link it." surplus = 0 item = /obj/item/storage/briefcase/launchpad - cost = 6 */ + cost = 6 /datum/uplink_item/device_tools/syndicate_teleporter name = "Experimental Syndicate Teleporter" @@ -82,6 +83,7 @@ Comes with 4 charges, recharges randomly. Warranty null and void if exposed to an electromagnetic pulse." item = /obj/item/storage/box/syndie_kit/syndicate_teleporter cost = 8 +*/ //END SKYRAT EDIT /datum/uplink_item/device_tools/camera_app name = "SyndEye Program" @@ -265,3 +267,9 @@ bright lights. Effective, affordable, and nigh undetectable." item = /obj/item/syndicate_contacts cost = 3 + +/datum/uplink_item/device_tools/syndicate_climbing_hook + name = "Syndicate Climbing Hook" + desc = "High-tech rope, a refined hook structure, the peak of climbing technology. Only useful for climbing up holes, provided the operation site has any." + item = /obj/item/climbing_hook/syndicate + cost = 1 diff --git a/code/modules/uplink/uplink_items/nukeops.dm b/code/modules/uplink/uplink_items/nukeops.dm index e25763350a8758..632d4cc2717f44 100644 --- a/code/modules/uplink/uplink_items/nukeops.dm +++ b/code/modules/uplink/uplink_items/nukeops.dm @@ -468,7 +468,7 @@ name = "Cybernetic Implants Bundle" desc = "A box containing x-ray eyes, a CNS Rebooter and Reviver implant. Comes with an autosurgeon for each." item = /obj/item/storage/box/cyber_implants - cost = 25 //worth around 32 TC + cost = 20 //worth 24 TC purchasable_from = UPLINK_NUKE_OPS /datum/uplink_item/bundles_tc/medical @@ -732,13 +732,6 @@ item = /obj/item/autosurgeon/syndicate/anti_stun cost = 8 -/datum/uplink_item/implants/nuclear/antidrop - name = "Anti-Drop Implant" - desc = "This implant will keep you from dropping things from your hands. Be sure to hold onto the item before activating, and \ - activate it again to turn it off. Comes with an autosurgeon." - item = /obj/item/autosurgeon/syndicate/anti_drop - cost = 8 - // Badass (meme items) /datum/uplink_item/badass/costumes diff --git a/code/modules/vehicles/cars/clowncar.dm b/code/modules/vehicles/cars/clowncar.dm index f08e30a7554eac..1fd230bb47a82e 100644 --- a/code/modules/vehicles/cars/clowncar.dm +++ b/code/modules/vehicles/cars/clowncar.dm @@ -121,11 +121,11 @@ if(prob(35)) //Note: The randomstep on dump_mobs throws occupants into each other and often causes wounds regardless. continue for(var/obj/item/bodypart/head/head_to_wound as anything in carbon_occupant.bodyparts) - var/type_wound = pick(list( - /datum/wound/blunt/bone/moderate, - /datum/wound/blunt/bone/severe, - )) - head_to_wound.force_wound_upwards(type_wound, wound_source = src) + var/pick_mode = text2num(pick(list( + "[WOUND_PICK_LOWEST_SEVERITY]", + "[WOUND_PICK_HIGHEST_SEVERITY]" + ))) + carbon_occupant.cause_wound_of_type_and_severity(WOUND_BLUNT, head_to_wound, WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_SEVERE, pick_mode) carbon_occupant.playsound_local(src, 'sound/weapons/flash_ring.ogg', 50) carbon_occupant.set_eye_blur_if_lower(rand(10 SECONDS, 20 SECONDS)) diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index 298af4a7cf9bdb..ab882bf7997924 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -194,8 +194,6 @@ ///Items that the players have loaded into the vendor var/list/vending_machine_input = list() - ///Display header on the input view - var/input_display_header = "Custom Vendor" //The type of refill canisters used by this machine. var/obj/item/vending_refill/refill_canister = null @@ -954,13 +952,9 @@ return FALSE var/mob/living/carbon/carbon_target = atom_target for(var/obj/item/bodypart/squish_part in carbon_target.bodyparts) - var/type_wound - if (squish_part.biological_state & BIO_BONE) - type_wound = pick(list(/datum/wound/blunt/bone/critical, /datum/wound/blunt/bone/severe, /datum/wound/blunt/bone/moderate)) - else - squish_part.receive_damage(brute=30) - if (type_wound) - squish_part.force_wound_upwards(type_wound, wound_source = "crushed by [src]") + var/severity = pick(WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_SEVERE, WOUND_SEVERITY_CRITICAL) + if (!carbon_target.cause_wound_of_type_and_severity(WOUND_BLUNT, squish_part, severity, wound_source = "crushed by [src]")) + squish_part.receive_damage(brute = 30) carbon_target.visible_message(span_danger("[carbon_target]'s body is maimed underneath the mass of [src]!"), span_userdanger("Your body is maimed underneath the mass of [src]!")) return TRUE if(CRUSH_CRIT_HEADGIB) // skull squish! @@ -1042,7 +1036,7 @@ to_chat(user, span_notice("You insert [inserted_item] into [src]'s input compartment.")) for(var/datum/data/vending_product/product_datum in product_records + coin_records + hidden_records) - if(ispath(inserted_item.type, product_datum.product_path)) + if(inserted_item.type == product_datum.product_path) product_datum.amount++ LAZYADD(product_datum.returned_products, inserted_item) return @@ -1536,7 +1530,7 @@ * * user - the user doing the loading */ /obj/machinery/vending/proc/canLoadItem(obj/item/loaded_item, mob/user) - if((loaded_item.type in products) || (loaded_item.type in premium) || (loaded_item.type in contraband)) + if(!length(loaded_item.contents) && ((loaded_item.type in products) || (loaded_item.type in premium) || (loaded_item.type in contraband))) return TRUE to_chat(user, span_warning("[src] does not accept [loaded_item]!")) return FALSE diff --git a/code/modules/vending/snack.dm b/code/modules/vending/snack.dm index ec633084fd8360..23b1bcf2c71e34 100644 --- a/code/modules/vending/snack.dm +++ b/code/modules/vending/snack.dm @@ -44,7 +44,6 @@ default_price = PAYCHECK_CREW * 0.6 extra_price = PAYCHECK_CREW payment_department = ACCOUNT_SRV - input_display_header = "Chef's Food Selection" /obj/item/vending_refill/snack machine_name = "Getmore Chocolate Corp" diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm index d12f43a880d09e..da2c08e04c9ad8 100644 --- a/code/modules/vending/wardrobes.dm +++ b/code/modules/vending/wardrobes.dm @@ -5,7 +5,6 @@ default_price = PAYCHECK_CREW extra_price = PAYCHECK_COMMAND payment_department = NO_FREEBIES - input_display_header = "Returned Clothing" panel_type = "panel19" light_mask = "wardrobe-light-mask" diff --git a/config/config.txt b/config/config.txt index d714caf92c32d6..8d28b656c30c1b 100644 --- a/config/config.txt +++ b/config/config.txt @@ -395,7 +395,7 @@ CLIENT_ERROR_BUILD 1421 ## Set to 0 or comment out to disable. SECOND_TOPIC_LIMIT 10 -MINUTE_TOPIC_LIMIT 100 +MINUTE_TOPIC_LIMIT 200 ## CLICK RATE LIMITING diff --git a/config/spaceruinblacklist.txt b/config/spaceruinblacklist.txt index 7b951c28e467bc..6ac8f8f08c266c 100644 --- a/config/spaceruinblacklist.txt +++ b/config/spaceruinblacklist.txt @@ -35,6 +35,7 @@ #_maps/RandomRuins/SpaceRuins/derelict6.dmm #_maps/RandomRuins/SpaceRuins/derelict7.dmm #_maps/RandomRuins/SpaceRuins/derelict8.dmm +#_maps/RandomRuins/SpaceRuins/derelict9.dmm #_maps/RandomRuins/SpaceRuins/dj_station.dmm #_maps/RandomRuins/SpaceRuins/emptyshell.dmm #_maps/RandomRuins/SpaceRuins/fasttravel.dmm diff --git a/html/changelogs/AutoChangeLog-pr-23528.yml b/html/changelogs/AutoChangeLog-pr-23528.yml new file mode 100644 index 00000000000000..2b0c89d8c7f7e6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-23528.yml @@ -0,0 +1,6 @@ +author: "jjpark-kb" +delete-after: True +changes: + - qol: "you can now construct, deconstruct, and anchor/unanchor the millstone" + - rscadd: "rough stones will now occasionally drop from mineral walls (the mining kind)" + - bugfix: "you can now cut/process rough stones" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-23560.yml b/html/changelogs/AutoChangeLog-pr-23560.yml deleted file mode 100644 index d5bef4bd17620a..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-23560.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "LT3" -delete-after: True -changes: - - bugfix: "Votes play an alert sound again" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-23595.yml b/html/changelogs/AutoChangeLog-pr-23595.yml deleted file mode 100644 index 45cc56938222dd..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-23595.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "SkyratBot" -delete-after: True -changes: - - qol: "adds some more traitor objective brainwashing default objectives." - - spellcheck: "fixes the double-punctuation on traitor objective brainwashing broadcasts." - - spellcheck: "brainwashing deadchat broadcasts will now auto-punctuate." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-23596.yml b/html/changelogs/AutoChangeLog-pr-23596.yml deleted file mode 100644 index 04863e880946ac..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-23596.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "SkyratBot" -delete-after: True -changes: - - bugfix: "Golems can eat" - - bugfix: "Cooked and crafted food should be edible" - - bugfix: "Medborgs can now spawn vanilla ice cream instead of nothing ice cream" - - bugfix: "Ghosts can examine food" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-23597.yml b/html/changelogs/AutoChangeLog-pr-23597.yml deleted file mode 100644 index ee4a97c4445ea9..00000000000000 --- a/html/changelogs/AutoChangeLog-pr-23597.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SkyratBot" -delete-after: True -changes: - - bugfix: "Exploration drones can't be used to reach Centcom anymore." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-23824.yml b/html/changelogs/AutoChangeLog-pr-23824.yml new file mode 100644 index 00000000000000..63758f49096d51 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-23824.yml @@ -0,0 +1,5 @@ +author: "SkyratBot" +delete-after: True +changes: + - bugfix: "Projectiles no longer cause a blood graphic or blood splatters if they hit a limb that cant bleed" + - rscadd: "Prosthetics/Augments now spark when shot" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-23833.yml b/html/changelogs/AutoChangeLog-pr-23833.yml new file mode 100644 index 00000000000000..04f0b925c93e96 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-23833.yml @@ -0,0 +1,4 @@ +author: "SkyratBot" +delete-after: True +changes: + - image: "resprites t-ray scanner." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-23834.yml b/html/changelogs/AutoChangeLog-pr-23834.yml new file mode 100644 index 00000000000000..43c91f27ba9874 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-23834.yml @@ -0,0 +1,4 @@ +author: "GoldenAlpharex" +delete-after: True +changes: + - bugfix: "The green pin is no longer unremovable for those that had it on before they hit the 100 hours threshold. It will now be automatically disabled for them." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-23835.yml b/html/changelogs/AutoChangeLog-pr-23835.yml new file mode 100644 index 00000000000000..9c26357d5173d3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-23835.yml @@ -0,0 +1,4 @@ +author: "SkyratBot" +delete-after: True +changes: + - admin: "Admins can transform misbehaving players into arbitrary objects at will." \ No newline at end of file diff --git a/html/changelogs/archive/2023-09.yml b/html/changelogs/archive/2023-09.yml index 5d9abd2c928b3e..7fc3abe8ebc66a 100644 --- a/html/changelogs/archive/2023-09.yml +++ b/html/changelogs/archive/2023-09.yml @@ -321,3 +321,559 @@ shuttle will begin with more reputation and likely be able to immediately access most of the uplink catalogue. - image: updates medigel sprites +2023-09-10: + A.C.M.O.: + - bugfix: Fixed Poly's voice commands. Poly will now perch on the Chief Engineer's + shoulder when expected. + LT3: + - image: Delam emergency procedure wall biscuit replaced with SAFETY MOTH + - code_imp: Delam panic button works when APC is dead + - code_imp: Removed extra calls to nightshift subsystem during delam + - bugfix: Votes play an alert sound again + SkyratBot: + - bugfix: Golems can eat + - bugfix: Cooked and crafted food should be edible + - bugfix: Medborgs can now spawn vanilla ice cream instead of nothing ice cream + - bugfix: Ghosts can examine food + - bugfix: Exploration drones can't be used to reach Centcom anymore. + - admin: Admins can add/remove the spawner component from arbitrary items again. + - qol: adds some more traitor objective brainwashing default objectives. + - spellcheck: fixes the double-punctuation on traitor objective brainwashing broadcasts. + - spellcheck: brainwashing deadchat broadcasts will now auto-punctuate. + - admin: The "Create Command Report" verb now has the option to not print report + papers at communications consoles. + - bugfix: It is now possible to smoke cigarettes even if you aren't wearing a safety + helmet + StrangeWeirdKitten: + - bugfix: Fixes Interdyne mining reward boards making golem reward vendors + vinylspiders: + - bugfix: fixed a bug that was preventing large mortar from getting any of the extra + reagents from grinding/juicing certain items +2023-09-11: + Hatterhat: + - rscdel: Thanks to lobbying from other factions within the Syndicate, the black + markets accessible by telecrystal-based uplinks are no longer stocking modified + hand teleporters, citing a new "stand and deliver" doctrine established by more + violent, militant arms of the organization. + Melbert: + - qol: Haunted 8-ball no longer requires the ghost orbit the petitioner to submit + votes + - qol: Haunted 8-ball ghosts can now change their vote after submitting it + - bugfix: Haunted 8-ball no longer always reports "yes" + - bugfix: Haunted 8-ball no longer always reports default "yes", "no", or "maybe" + and now gives a proper eight ball response + - bugfix: Haunted 8-ball can be picked up via the stat panel + RatFromTheJungle: + - rscdel: Guns, collectively, can no longer right-click holdup people + SkyratBot: + - rscadd: 'Added the service borg "drink apparatus" upgrade, which adds an extra + drinking apparatus to the borg, up to a maximum of 5 extra. + + :cl:' + - bugfix: Changeling tentacle and bloodchiller from xenobio will no longer stop + working if you have antimagic + - qol: Rice Dough may be made in beaker instead of being crafted, but the rice and + flour must be added first + - rscadd: humpback emergency shuttle + - image: Hivelords have a new sprite. + - image: Hivelord and Legion brood have a death animation. + - bugfix: Mortar and pestle can grind stuff again + Wallem, MTandi: + - image: Updates chem factory tank sprites + jjpark-kb: + - bugfix: revive mob ritual works on basic mobs now + - bugfix: ashwalkers have the ashwalker faction + softcerv: + - bugfix: ghost cafe NIFs no longer have access to hivemind +2023-09-12: + Adelphon: + - rscadd: new underwear + GoldenAlpharex: + - bugfix: All potted plants should now be visible again. + - admin: Player ranks are now displayed in the Player Panel of each user. + - code_imp: Player ranks can now be checked without taking into account the admin + bypass while in-game. + - bugfix: Fixed the rounding errors that caused decimals to wrongly appear when + hitting the Shift Layer Upwards or the Shift Layer Downwards verbs. + - bugfix: The message sent to admins when a new admin has been added via the Permissions + Panel will now properly show the new admin's ckey. + - qol: Character Previews are now always displayed in the Examine panel, rather + than disappearing when the flavor text would otherwise be hidden. + LT3: + - code_imp: Status display shuttle timer no longer scrolls + - bugfix: Fixed Void Raptor cargo door labels and IDs + - bugfix: Singularities are no longer invisible. You can again see your impending + doom + Melbert: + - rscdel: Spacers are slightly shorter. They're still taller than other people, + just not as much. + OrionTheFox: + - bugfix: fixed being unable to re-select the "Quartermaster" title in job prefs + after selecting an alt-title + - image: updated the greyscale Cattleman Hat to be not-bad. It now isn't 1px too + low, and actually looks like a cattleman rather than a lump of butter on a plate! + SkyratBot: + - bugfix: The vorpal scythe is no longer as greedy about you murdering people, and + will once again accept striking any living creature to be sated. + - bugfix: Fix capture devices allowing mob actions while inside + - bugfix: Your clothes and such should correctly reposition themselves if a black + charged slime extract turns you into a monkey. + - bugfix: Ninjas should be correctly credited for using their spider bombs + - balance: Supermatter zap power generation scales with the delta time between its + last zaps, preventing faster zapping from scaling power generation to extreme + levels. + - bugfix: Fixes supermatter zap rate not scaling properly. It should zap much faster + at higher energy levels as intended. + - qol: Changeling chemical generation scales with the world's delta time, making + its rate independent of subsystem lag. + - qol: Revenant essence generation scales with the world's delta time, making its + rate independent of subsystem lag. + - qol: Xenomorph plasma generation and resin healing scales with the world's delta + time, making their rates independent of subsystem lag. + - balance: polymorph belt now blacklists mobs that are undead, humanoid, robotic + or spiritual (in nature, not religiously), as well as megafauna + - balance: however, this means that it works with more mobs that it should logically + work with, like slimes/bugs/lightgeists etc + - bugfix: fixed headslug shenanigans with the polymorph belt hopefully for good + this time + - bugfix: fixed headslug description mentioning its movement despite the slug being + dead + sergeirocks100: + - bugfix: Briefs now make use of their digitigrade sprite. +2023-09-13: + CoiledLamb, Time-Green: + - image: resprites the radioactive nebula shielding + Ghommie (Based on an old PR by Trilbyspaceclone from Citadel): + - qol: The notepad app now includes basic nautical directions in its default message. + - qol: A tip about nautical directions, too. + LT3: + - bugfix: All missing surgery trays have been found. Don't ask where. + Literallynotpickles: + - qol: Adjusted medical tongue bounties to mention that cybernetic ones _do_ work + for them. + Melbert: + - bugfix: Birdboat's Augment Theater is named less odd now + Rhials: + - bugfix: The psyker headset is no longer a syndicate headset subtype, and no longer + has syndie comms. + SkyratBot: + - rscadd: The SC/FISHER disruptor pistol, a very compact, permanently silenced energy + gun, is now stocked in Nanotrasen-accessible black markets with a price generally + somewhere between 400 and 800 credits. Aspiring users are warned that it's really + bad for trying to actually kill people. Caveat emptor. + - rscadd: Guns now have a dry_fire_sound_volume variable, allowing for guns to be + less loud when trying to fire while empty. + - bugfix: Closets and crates now properly count as structures for pass flags again. + - balance: Add hypnosis vulnerability for drugged victims + - rscadd: Operative MODsuits now have an attached "jump jet" which sends you upwards + and allows you to use your jetpack under gravity for a few seconds, perfect + for navigating the pits and valleys of Icebox Station. + - qol: Shuttle engines now tell you how to install them in their screentips and + their examine text. + - image: resprites pestkiller, weedkiller, and nolabel sprays + - image: updates shading on medigels + - image: resprites all spray bottles + - bugfix: Medicine allergy can no longer roll quantum medicine + - bugfix: fixed grown food items not getting the right seed type passed to them + upon creation + - bugfix: The holographic pufferfish from the holographic beach from the holodeck + no longer looks like a goldfish. + - bugfix: the ablative coat's hood now hides the wearer's hair and ear + - bugfix: Soup recipes, that make items, spawn the correct number of items per reaction + instead of just one item + - bugfix: Soup recipes, that make items, consumes the correct number of reagents + instead of the largest multiple of the reagents + - balance: removed anti-drop implants from the nuclear operative uplink + - balance: removed anti-drop implant from the nukie implants bundle and changed + its cost to 20 TC + SuicidalPickles: + - qol: Cargo Coats/Jackets can now equip universal scanners on their suit-slots. + burgerenergy: + - balance: Buffed MCR damage in line with an upstream generic laser buff + vinylspiders: + - bugfix: Headsets now have their old worn sprites back, did you ever notice it? +2023-09-14: + LT3: + - bugfix: Emergency shuttle should correctly scale timer up/down when changing security + levels + OrionTheFox: + - rscdel: Removed the now-obsolete Skyrat Cargo Gorka-Jacket; TG now has one! + - image: updated all of the cargo sprites to match TG's, including digitigrade sprites! + - bugfix: the QM's Formal Skirt now actually uses the Skirt icon rather than the + Suit + Rhials: + - rscadd: Shuttle Firesale positive station trait. Some emergency shuttle options + have been put on sale! + - rscadd: Misplaced Wallet positive station trait. You wouldn't steal from a missing + wallet, would you?? + - rscadd: Wisdom Cow Invasion positive station trait. + - rscadd: Advanced Medbots positive station trait. Better roundstart medbots! + - rscadd: Loaner Shuttle positive station trait. More shuttle loan offers and more + payout! + - qol: Station Trait titles are now italicized for easier reading. + - spellcheck: Fixes a "prerequisites" typo in the shuttle purchase menu. + Seven: + - balance: The supermatter delamination countdown has been lowered from 30 to 13 + seconds + - balance: Removing a sliver from the supermatter further lowers that down to 3 + seconds + - balance: Supermatter panic button warning reduced from 5 to 3 seconds + - balance: Supermatter suppression system healing runtime reduced from 9 to 7 seconds + - balance: The supermatter crystal uses bigger text on its final countdown + - spellcheck: Some supermatter delamination related mood descriptions have been + edited to explain the mood effect better + SkyratBot: + - bugfix: You can no longer teleport to disabled beacon if the teleporter was previously + locked-on to it. + - bugfix: Dynamic now biases less heavily towards the exact average. + - bugfix: Nightmares can no longer receive wounds + - bugfix: Nightmares can no longer have limbs dismembered + - qol: Conveyor belts now have screentips and a better examine tip to teach you + how to set one up properly. + - qol: Using a conveyor belt stack on a placed conveyor belt will extend the conveyor + belt to the output of that conveyor belt.. You can use this to place fully integrated + conveyor belts much easier now. + - image: When you throw up nanites, your vomit should now be appropriately nanite-colored. + - bugfix: Fix poor dynamic threat distribution at lower population levels, causing + dynamic to generate better threat curves at lower population levels than it + did before. + - bugfix: Roundstart medbots and cleanbots are now more likely to be able to be + possessed by observers. + - admin: It's easier to modify the properties of bots to stop them from being possessed + or depossessed. + Wallem: + - qol: Examine a Dish Drive to see all the items inside of it, as well as the item + you'll pull out when you interact with it. + - qol: Dish Drive servo tier increases suction range + honkpocket: + - bugfix: Players who run the DNR quirk no longer appear as revivable when examined + nikothedude: + - qol: 'Temporary flavor text preview character limit: From 37 to 110' + tf-4: + - rscadd: You can now craft ammo pouches from four leather. + - spellcheck: Fixed typo in cocaine snorting message. +2023-09-15: + LovliestPlant: + - rscadd: '[Void Raptor] Adds an exam room and charting office to medbay, just opposite + of the escape pod.' + - rscadd: '[Void Raptor] Adds a refrigeration system to medbay''s cold storage room.' + - qol: '[Void Raptor] Removes some clutter from medbay (storage plants, extra anesthetic + closets), adds blankets to TC beds.' + - qol: '[Void Raptor] Access to the Southern entrance to the Security office now + matches that of the North entrance.' + - qol: '[Void Raptor] Overhauls medbay''s cold storage room. Adds a coldroom freezer + system; adds a handful of emergency oxygen tanks, emergency nitrogen tanks, + and masks to the internals crate; replaces the empty medical crate with a spare + robotics limbs crate; and replaces the Oxygen canisters with anesthetic mix + canisters.' + - qol: '[Void Raptor] Adds towel bin to perma, replaces the linen bin in the public + pool with a towel bin.' + - bugfix: '[Void Raptor] Replaces flooring with bare plating in sections of maints, + should fix mouse spawning.' + - bugfix: '[Void Raptor] Fixes the back entrance to the medbay''s treatment center + requiring morgue access.' + - bugfix: '[Void Raptor] CO''s can now open the brig officer locker in their office.' + - bugfix: '[Void Raptor] Fixes a minor clipping issue with the records console in + the CO office.' + Lunar248: + - qol: Gave Freighter a few things to reduce some tediousness, such as a welding + tank in engineering, water tank in botany, and a proper sink in the kitchen. + - bugfix: Added missing lights, and light switches to Freighter. + SkyratBot: + - bugfix: you can no longer bypass html sanitization using the table element. >:( +2023-09-16: + LT3: + - code_imp: Engaging in Role Play on the Interlink should no longer lead to heart + attack and death + LT3, unit0016: + - qol: You can now choose between limb, prosthetic, or no limb at all + Literallynotpickles: + - balance: Changeling Horror-Form no longer has reduced click-delay. + RatFromTheJungle: + - balance: The captains sabre now does five more damage totaling to 20 (while losing + a bit of wound chance!), while the shamshir does the same with equally less + wound chance, less armor pen, and worse block. + SkyratBot: + - bugfix: fixes a bug that would cause grown inedible plant seeds (like tower cap) + to vanish from existence upon being added to the seed extractor + - bugfix: fixes a issue that would cause fruit wine to bug out when trying to blend + its reagent color + - bugfix: The nuclear operative MODsuit intellicard now actually downloads an AI + rather than simply kicking candidates from the game. + - bugfix: Fixed a race condition that made fishing yield no reward way too often. + - bugfix: The legendary fisher achievement is awarded even if you don't win the + minigame. + - bugfix: Fixed a fish hook exploit. + - bugfix: Baits are now properly consumed by caught fish and (alive) mobs. + - bugfix: Fixes tesla coils duplicating the power of >7GeV supermatter zaps. + - bugfix: Space ruin Anomaly Research - Fixes stacked windows and underplating + - rscadd: There's a new space ruin in town, be on the lookout for a hidden supply + cache. + - rscadd: Added a new type of wall which can only be destroyed by blowing it up. + - balance: Pulling embedded items e.g. shrapnel with hemostats is now a lot faster, + and scales appropriately with toolspeed. + - balance: You can now pull embedded items with wirecutters, at a speed penalty. + - bugfix: Unary vents & Injectors now link properly with air sensors via multitool + both ways + - balance: Watchers will no longer put you at gunpoint. + - balance: The spontaneous brain trauma event will no longer occur if there are + fewer than 13 players. + - bugfix: Flares and candles no longer sound like flashlights when being turned + on. + - bugfix: Getting shot by an SC/FISHER now disables PDA lights for consistency's + sake. + - spellcheck: Replaced an irrelevant tip of the round about scars with a better + one + - balance: You will be knocked down again on certain vomits. Don't worry, you'll + deserve it when it happens. + - qol: The supply beacon will no longer delete itself due to explosions, and you + can now anchor it with a wrench. + - spellcheck: Express console now correctly states that it needs cargo access instead + of QM access. + - bugfix: returning items to vendors works correctly + - bugfix: you can't return items that has stuff in it for e.g. a serving tray with + food in it + - bugfix: fixed fishing. + - bugfix: the bank machine cannot print holochips worth 0 credits now + - bugfix: adds the bolted and welded helper to the bar backroom/kitchen coldroom + airlock on birdshot, as to prevent chefs from being able to access armor and + sunglasses roundstart with barely any work involved + nikothedude: + - rscadd: 2 Bonesetters, 4 stacks of gauze, 2 health analyzers that cant be used + for medibots, all in the robodrobe +2023-09-17: + SkyratBot: + - refactor: Refactored wounds yet again + - bugfix: Wounds are now picked from the most severe down again, meaning eswords + can jump to avulsions + - bugfix: Scar descs are now properly applied + honkpocket: + - rscadd: The bullet-drive machine can once again be bought from the cargo-imports + menu + nikothedude: + - bugfix: Msucle scars no longer cause general disfigurement +2023-09-18: + Majkl-J: + - bugfix: laser magazines can now be reloaded correctly + SkyratBot: + - bugfix: Monkeys have their tails back. + - bugfix: Fixed a resource dupe in the ORM. + - rscadd: added the inspectors hat to the detectives cabinet, a special hat that + allows the wearer to say a phrase to dispense a stored item + - rscadd: climbing hooks that allow you to go up holes for multiz, found in internals + boxes (on planetary maps), the uplink, cargo and nukie personal lockers + - rscadd: A new ruin has appeared on lavaland, featuring the site of an ancient + battle. + - qol: '[Deltastation, Icebox, Metastation, Tramstation] Adds cell timers to isolation + cells. (they do not auto-open the doors)' + - qol: '[Birdshot, Deltastation, Icebox, Metastation, Northstar, Tramstation] Adds + translator glove modules to the stacks of "accessibility" (e.g. plasma fixation + / thermal regulator) modules found in security, medical, and engineering storage + rooms.' + - qol: '[Birdshot] Adds a roll of packaging paper to the cargo office.' + - qol: '[Icebox] Adds a hand labeler to security''s gear room.' + - qol: '[Northstar] Nudges the set of binoculars covering the mass driver controls + in ordnance over a few inches.' + - bugfix: '[Birdshot] Remaps the janitor''s closet such that the recycling machine + will now work.' + - bugfix: '[Icebox] Removes a duplicated hand labeler from the rack near security''s + brig cells.' + - bugfix: '[Metastation] Patches a broken corpse disposal pipe running from aux + surgery to the morgue.' + - bugfix: '[Northstar] Fixes the SM being hotwired at round-start (partially rewires + the SM room, moves the APC to the North wall).' + - code_imp: added some null checks for general juicing & grinding items + - bugfix: grinding stacks now grinds as many pieces/sheets from the stack as possible + that can fit in a beaker/container without wasting the whole stack + - bugfix: plumbing chemical grinder now actually works again + - bugfix: the plumbing chemical grinder allows stuff to enter from any direction + but not mobs and also accepts items put inside it via hand including bags + - bugfix: You can remove the beaker from the all in 1 grinder when power is off + via right click + - bugfix: All in 1 grinder now mixes faster with upgraded parts + - refactor: you can no longer walk into a plumbing chemical grinder + - bugfix: adds a few firelocks and alarms around IceBox + - bugfix: the nukie medibot (oppenheimer) has access to the doors of the infiltrator + and is not shot at by the turrets + - refactor: heretic sacrifice room is now lazyloaded + - bugfix: Lipolicide and other chems now puts you in crit, even if it is the only + source of damage + - bugfix: made the radiation protection crate's contents match it's description + - rscadd: Ghosts (observers) can eat ghost burgers and booberry muffins. + - balance: Ghost burgers will not decay or pick up germs due to the fact that they + moved themselves off a table. + - rscadd: NanoTrasen improved the quality of the local durathread strain; resulting + in it now being twice as filling! + - image: Hercuri spray now uses the same sprite as the yellow medical spray + - spellcheck: Added a missing space to hercuri spray's description + - bugfix: Manually constructed windoors have correct unrestricted accesses applied + to them + - bugfix: Windoors created via RCD now actually have electronics inside them + - bugfix: Airlocks constructed via RCD have the shell component correctly installed + inside them and have no other missing variables + - rscadd: Wall mounted objects (Things like APCs, Air Alarms, Light switches, Signs, + Posters, Newscasters, you name it) will now fall to the ground and break or + deconstruct when their attaching wall is changed or broken. + - spellcheck: Fixed some typos on QM's Overcoat + - bugfix: Forgetting to take dough out of the oven no longer progresses the server + to a crash-worthy state with infinite bread and ash and burned food products + for all. + - bugfix: Recipe paper in the ruins now shows a normal recipe for Metalgen and Secret + sauce. + - code_imp: Cleans up some unnecessary code left over from caseless ammo. + - qol: the recycler can now be rotated + - qol: Machines now transfer their local materials to silo during linking with multitool + SpaceLove: + - balance: Bluespace Miners have been made cheaper by Nanotrasen as they have found + a huge mine of materials recently! + TheOneAndOnlyCreeperJoe: + - bugfix: Hydra quirk now properly works instead of making you British. + Thebleh: + - bugfix: Bluespace RPEDs can now be rigged again + nikothedude: + - rscadd: Several common 'household' reagents can be used as improvised medicine + treatment. + - rscadd: Drinking tea will help mend (non-bone) wounds over time. + - rscadd: Flour and corn starch may be splashed onto wounds to help dry them up, + though they'll have a negative effect on burn wounds. + - rscadd: Added a new reagent, saltwater, made by combining table salt with water. + - rscadd: Table salt and saltwater can be splashed onto wounds as well, reducing + bleeding and improving sanitization and disinfection significantly. However, + the coarse undiluted salt will irritate the wounds, reducing clot rate and flesh + healing, and both of the reagents will increase a burn wound's infestation rate. + - rscadd: Altered Table Salt's recipe to just need sodium and chloride. Changed + the recipe of Pentetic Acid and Heparin to need table salt (sodium x chloride) + and thus slightly altered the total output of those reagents (pentacid went + from 5u per reaction to 4u, heparin 4u->3u) + - rscadd: Saline-Glucose Solution now needs 2u of saltwater and 1u of sugar, meaning + the overall recipe should be completely unchanged in practice. Contact me on + discord if any issues arise from these chemical changes! + - qol: First aid analyzers now give easy-to-understand direct information, with + the specific recommended treatments bolded in the analysis text. They also have + a 'unique' extra bit of info, telling you about improvised ways to remedy your + wound. + tf-4: + - bugfix: fixes being able to eat, use pills etc through gas masks and such +2023-09-19: + Ghommie (Thanks Sealed101): + - refactor: Reworked the fishing minigame into a game screen object from a TGUI + interface + Melbert: + - balance: Humanoids without tongues cannot cast spells with vocal components + - balance: Humanoids without arms cannot cast spells with emotive components + SkyratBot: + - bugfix: Makes sure pump-up properly grants the baton resistance trait. + - bugfix: The Nightmare's Light Eater can no longer suck the light out of space + tiles. + - bugfix: Fix wooden barricade description "This looks like it can be barricaded + with planks of wood" being spammed on objects. + - bugfix: basic mobs retaliate targetting now selects targets they can attack + - bugfix: Makes ethanol and sugar pure by default. + - balance: Player-controlled basic mobs attack as fast as those mobs can when controlled + by the AI + - balance: Player-controlled Faithless can paralyse people they attack, like the + AI does + - balance: Player-controlled Star Gazers (if an admin felt like making one) apply + the star mark on attack and deal damage to everything around them, like the + AI does + - rscadd: Many kinds of mobs can now be brought back to life through revival surgery. + - rscadd: Dogs can wear eyepatches. + - code_imp: Scars now stack trace if they fail to get a valid description + - rscdel: Removes the computer vendor. + - bugfix: pancake stack layering + - bugfix: pizzabox stack layering + - bugfix: pizzabox bombs that spawn unarmed now label their pizza correctly and + cannot spawn a spriteless pizza + - bugfix: Fixes a misplaced status display in Meta's medical storage. + - rscadd: mass drivers are now buildable, you activate them by attaching a signaler + to their launch wire, and can increase their power by pulsing the safeties wire, + and reset it back to normal by cutting the safeties wire. + - server: Default-configuration MINUTE_TOPIC_LIMIT has been increased + - bugfix: Fix a runtime when trying to cycle move intents with a hotkey as a dead + mob. + - bugfix: Nanotrasen has finally recalled their faulty multitools and replaced them + with working ones! The multitool's buffer now properly clears itself. + - qol: Moved multitool link messages to balloon alerts + - bugfix: added some missing firealarms on icebox in the hall towards departures + and the upper section of chapel + - bugfix: normal ethereal blood now works for electrolysis, the hydrogen and oxygen + output of the electrolysis recipe has been increased. + - balance: Only traitor, changeling, heretic, blood brother, headrev, wizard, obsessed, + magic/gun survivalists and greentext book holders can now double their hardcore + random score + - qol: Redtexting as antag with hardcore random score will pay you default points, + instead of none (normal survival rules) + - bugfix: End report screen will properly report hardcore random survival in case + of station destruction +2023-09-20: + LT3: + - rscadd: 'New random event: Supermatter Surge' + - refactor: It's different than the Supermatter Surge you're used to + - refactor: 'The scale is now 1: low severity to 4: most severe. Keep that in mind!' + - rscdel: Removed Skyrat version of Supermatter Surge + - code_imp: Individual supermatter crystals can have custom gas properties + SkyratBot: + - image: resprites t-ray scanner, gas analyzer, geiger counter and hand drill. + - qol: Surgery trays can now be crafted via the crafting menu (two rods, one silver), + and deconstructed via secondary click with a screwdriver! + - spellcheck: Unreverted and improved resonance cascade message. + - qol: Crafting R&D guns from gun kits no longer requires tools or cable coil. The + decloner and energy crossbow still need reagents. + - qol: Halved R&D gun crafting time. 20->10 seconds. + - bugfix: Fixed Mafia achievements + - balance: Unholy and Eldritch water are self-consuming like holy water! They don't + need a liver to be processed. + - bugfix: Fixes a selection window in the game rock-paper-scissors with death. + - bugfix: fixes inedible grown items (such as tower caps) becoming unclickable when + harvested, fixes their seeds disappearing when inserted into the seed machine + - refactor: Refactors the camera console UI. + - rscadd: heretic knock path and its respective items and award + - bugfix: Lava can no longer occasionally generate inside of previously loaded templates + and breach and/or destroy shit + - qol: mice and rats now are visually spaced out from eachother for visual clarity + - balance: Supermatter now takes 15 seconds to delaminate normally and 5 if a sliver + has been taken from it. Gives a little more time to escape in the case of the + sliver and also evens out the times to please perfectionists. + - bugfix: Supermatter now accurately reports it's detonation time. + - spellcheck: Supermatter mood descriptions have been reverted back to their old, + more flavorful selves. + Zergspower: + - qol: reworks the verb panel to be less of a CVS receipt + vinylspiders: + - bugfix: removed a deprecated loadout item 'Black Two-Piece Suit' which had an + invalid item path. The old item has been replaced with 'Black Suit'. +2023-09-21: + LT3: + - bugfix: Interdyne scientists get their Interdyne labcoat + Rhials: + - qol: Restores holiday hats for drones. + - qol: Extends holiday hat behavior to assistants. Get festive! + SkyratBot: + - bugfix: RCD Construction effects will no longer fall into chasms. + - bugfix: Gauze no longer falls off if a wound is demoted or promoted + - bugfix: The caller in a holopad call should now be able to hear people on the + other end. + - bugfix: wall mounted objects air alarms, fire alarms etc now actually falls off/gets + destroyed when their attached wall is deconstructed + - bugfix: wall mounts crafted in game also properly falls off/gets destroyed when + their attached wall is deconstructed + - bugfix: Fixes a bug allowing holopara injectors to be refundable when used. + - balance: Improvised shotgun shells now deal half as much damage to humans and + cause less wounds, but do 50% more damage to structures and machines. They also + require a glass shard for crafting. + - balance: 'EMP damage on augs: 2/1.5 from 3/2' + - balance: Augs now only get paralyzed by EMP for 3/6 seconds if they are damaged + below 70% HP, + - balance: Aug EMP knockdown reduced to 3 seconds + - balance: Synthetic ears now take far less EMP damage + - bugfix: rescue hooks will once again drop the mob next to the fisherman instead + of just displaying a balloon alert and doing nothing + - bugfix: Recipe that converts Vegetable Oil into Olive Oil works properly + - rscadd: Splashing antihol on a patient before surgery will make it to go slower. + honkpocket: + - rscadd: Adds garment bags to the blueshield and NTC lockers + - rscadd: Adds turtlenecks and the intern outfit to the NTC garment bag + vinylspiders: + - bugfix: spiritual quirk is no longer missing from the game + zydras: + - bugfix: properly paths NT Consultant and Blueshield areas diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index f7615fc045bf4b..29e59dc6c7148d 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/effects/eldritch.dmi b/icons/effects/eldritch.dmi index 40d4ea80df2d66..8b7738f3b46a0d 100644 Binary files a/icons/effects/eldritch.dmi and b/icons/effects/eldritch.dmi differ diff --git a/icons/hud/fishing_hud.dmi b/icons/hud/fishing_hud.dmi new file mode 100644 index 00000000000000..b68acee09b76af Binary files /dev/null and b/icons/hud/fishing_hud.dmi differ diff --git a/icons/hud/screen_alert.dmi b/icons/hud/screen_alert.dmi index 944337b18e552b..a1fc01434e4564 100755 Binary files a/icons/hud/screen_alert.dmi and b/icons/hud/screen_alert.dmi differ diff --git a/icons/mob/actions/actions_ecult.dmi b/icons/mob/actions/actions_ecult.dmi index a684dd1fbe6274..747b57949be822 100644 Binary files a/icons/mob/actions/actions_ecult.dmi and b/icons/mob/actions/actions_ecult.dmi differ diff --git a/icons/mob/inhands/64x64_lefthand.dmi b/icons/mob/inhands/64x64_lefthand.dmi index 26c177f7293ab7..8a6bab69776678 100644 Binary files a/icons/mob/inhands/64x64_lefthand.dmi and b/icons/mob/inhands/64x64_lefthand.dmi differ diff --git a/icons/mob/inhands/64x64_righthand.dmi b/icons/mob/inhands/64x64_righthand.dmi index 79c30f5cb19787..251458590bdd48 100644 Binary files a/icons/mob/inhands/64x64_righthand.dmi and b/icons/mob/inhands/64x64_righthand.dmi differ diff --git a/icons/mob/simple/corgi_head.dmi b/icons/mob/simple/corgi_head.dmi index b582d0406f99d8..2e14a3ed0bb5dd 100644 Binary files a/icons/mob/simple/corgi_head.dmi and b/icons/mob/simple/corgi_head.dmi differ diff --git a/icons/mob/simple/lavaland/lavaland_monsters.dmi b/icons/mob/simple/lavaland/lavaland_monsters.dmi index 1d546bd17d45d6..13c37dca594f0c 100644 Binary files a/icons/mob/simple/lavaland/lavaland_monsters.dmi and b/icons/mob/simple/lavaland/lavaland_monsters.dmi differ diff --git a/icons/obj/clothing/modsuit/mod_modules.dmi b/icons/obj/clothing/modsuit/mod_modules.dmi index d548f615c44286..f1d19c29da119e 100644 Binary files a/icons/obj/clothing/modsuit/mod_modules.dmi and b/icons/obj/clothing/modsuit/mod_modules.dmi differ diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index b6ccf1b8c41697..d89ee6e5d6408f 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/icons/obj/machines/floor.dmi b/icons/obj/machines/floor.dmi index 38ea510f37bb34..6f858465dcdcb1 100644 Binary files a/icons/obj/machines/floor.dmi and b/icons/obj/machines/floor.dmi differ diff --git a/icons/obj/machines/nebula_shielding.dmi b/icons/obj/machines/nebula_shielding.dmi index 32aedcc1b7af5c..1da2b5f2a9b2a1 100644 Binary files a/icons/obj/machines/nebula_shielding.dmi and b/icons/obj/machines/nebula_shielding.dmi differ diff --git a/icons/obj/machines/recycling.dmi b/icons/obj/machines/recycling.dmi index de419374151e60..9a6dffaaee2d5b 100644 Binary files a/icons/obj/machines/recycling.dmi and b/icons/obj/machines/recycling.dmi differ diff --git a/icons/obj/medical/chemical.dmi b/icons/obj/medical/chemical.dmi index d41fc3b167ae7e..b4b26e4f848c62 100644 Binary files a/icons/obj/medical/chemical.dmi and b/icons/obj/medical/chemical.dmi differ diff --git a/icons/obj/mining.dmi b/icons/obj/mining.dmi index 6c5560438c60c3..54b19553b84028 100644 Binary files a/icons/obj/mining.dmi and b/icons/obj/mining.dmi differ diff --git a/icons/obj/pipes_n_cables/hydrochem/plumbers.dmi b/icons/obj/pipes_n_cables/hydrochem/plumbers.dmi index 792868a8ae3445..19775b6eff8a22 100644 Binary files a/icons/obj/pipes_n_cables/hydrochem/plumbers.dmi and b/icons/obj/pipes_n_cables/hydrochem/plumbers.dmi differ diff --git a/icons/obj/service/hydroponics/equipment.dmi b/icons/obj/service/hydroponics/equipment.dmi index dc164c5b1c9431..afcc4de523512a 100644 Binary files a/icons/obj/service/hydroponics/equipment.dmi and b/icons/obj/service/hydroponics/equipment.dmi differ diff --git a/icons/obj/service/janitor.dmi b/icons/obj/service/janitor.dmi index 8c73a99b416424..0e814ca4545899 100644 Binary files a/icons/obj/service/janitor.dmi and b/icons/obj/service/janitor.dmi differ diff --git a/icons/obj/service/library.dmi b/icons/obj/service/library.dmi index dfd8aca6b89fa9..8229c1fc3947e7 100644 Binary files a/icons/obj/service/library.dmi and b/icons/obj/service/library.dmi differ diff --git a/icons/obj/tools.dmi b/icons/obj/tools.dmi index a04a34edd319a0..e6679c8c51848a 100644 Binary files a/icons/obj/tools.dmi and b/icons/obj/tools.dmi differ diff --git a/icons/obj/weapons/guns/energy.dmi b/icons/obj/weapons/guns/energy.dmi index 07ac342a36d76c..97b75335b91a0e 100644 Binary files a/icons/obj/weapons/guns/energy.dmi and b/icons/obj/weapons/guns/energy.dmi differ diff --git a/icons/obj/weapons/khopesh.dmi b/icons/obj/weapons/khopesh.dmi index 4bbd4d5f0f9c92..ab7a0c252cbf77 100644 Binary files a/icons/obj/weapons/khopesh.dmi and b/icons/obj/weapons/khopesh.dmi differ diff --git a/icons/turf/overlays.dmi b/icons/turf/overlays.dmi index 83309e4d18ebbb..c9decbc5a3af30 100644 Binary files a/icons/turf/overlays.dmi and b/icons/turf/overlays.dmi differ diff --git a/icons/ui_icons/achievements/achievements.dmi b/icons/ui_icons/achievements/achievements.dmi index ad34dfd16f0ce1..b3e64c9d09f835 100644 Binary files a/icons/ui_icons/achievements/achievements.dmi and b/icons/ui_icons/achievements/achievements.dmi differ diff --git a/icons/ui_icons/fishing/default.png b/icons/ui_icons/fishing/default.png deleted file mode 100644 index 20dabae9210ed9..00000000000000 Binary files a/icons/ui_icons/fishing/default.png and /dev/null differ diff --git a/icons/ui_icons/fishing/lavaland.png b/icons/ui_icons/fishing/lavaland.png deleted file mode 100644 index b6e2487bdc4b8f..00000000000000 Binary files a/icons/ui_icons/fishing/lavaland.png and /dev/null differ diff --git a/libbyond_sleeping_procs.so b/libbyond_sleeping_procs.so deleted file mode 100644 index 8596115fd9624a..00000000000000 Binary files a/libbyond_sleeping_procs.so and /dev/null differ diff --git a/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm b/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm index 620317122b22e9..b74721c63ae260 100644 --- a/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -102,6 +102,7 @@ GLOBAL_LIST_INIT(skyrat_leather_belt_recipes, list( new/datum/stack_recipe("xenoarch belt", /obj/item/storage/belt/utility/xenoarch, 4, check_density = FALSE, category = CAT_CONTAINERS), new/datum/stack_recipe("medical bandolier", /obj/item/storage/belt/medbandolier, 5, check_density = FALSE, category = CAT_CONTAINERS), new/datum/stack_recipe("gear harness", /obj/item/clothing/under/misc/skyrat/gear_harness, 6, check_density = FALSE, category = CAT_CLOTHING), + new/datum/stack_recipe("ammo pouch", /obj/item/storage/pouch/ammo, 4, check_density = FALSE, category = CAT_CONTAINERS), )) /obj/item/stack/sheet/leather/get_main_recipes() diff --git a/modular_skyrat/master_files/code/modules/cargo/bounties/medical.dm b/modular_skyrat/master_files/code/modules/cargo/bounties/medical.dm new file mode 100644 index 00000000000000..e1b032bbc332fa --- /dev/null +++ b/modular_skyrat/master_files/code/modules/cargo/bounties/medical.dm @@ -0,0 +1,2 @@ +/datum/bounty/item/medical/tongue + description = "A recent attack by Mime extremists has left staff at Station 23 speechless. Ship some spare tongues. We'll accept cybernetic variants if need be." \ No newline at end of file diff --git a/modular_skyrat/master_files/code/modules/client/playtime.dm b/modular_skyrat/master_files/code/modules/client/playtime.dm index c640b4b95d7cee..b1d301120e777f 100644 --- a/modular_skyrat/master_files/code/modules/client/playtime.dm +++ b/modular_skyrat/master_files/code/modules/client/playtime.dm @@ -20,6 +20,10 @@ return preferences?.parent?.is_green() /datum/preference/toggle/green_pin/apply_to_human(mob/living/carbon/human/wearer, value) + if(value && wearer.client && !wearer.client?.is_green()) + // This way, it doesn't stick for those that had it set to TRUE before they got their 100 hours in. + wearer.client?.prefs?.write_preference(GLOB.preference_entries[/datum/preference/toggle/green_pin], FALSE) + return /client/proc/is_green() diff --git a/modular_skyrat/master_files/code/modules/clothing/under/jobs/cargo.dm b/modular_skyrat/master_files/code/modules/clothing/under/jobs/cargo.dm index adbbbd0dc5b0d6..8fe26c3b34260f 100644 --- a/modular_skyrat/master_files/code/modules/clothing/under/jobs/cargo.dm +++ b/modular_skyrat/master_files/code/modules/clothing/under/jobs/cargo.dm @@ -103,7 +103,7 @@ /obj/item/clothing/under/rank/cargo/qm/skyrat/formal/skirt name = "quartermaster's formal jumpskirt" desc = "A western-like alternate uniform for the old fashioned QM. Skirt included!" - icon_state = "supply_chief" + icon_state = "supply_chief_skirt" can_adjust = FALSE body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT diff --git a/modular_skyrat/master_files/code/modules/mob/living/carbon/human_helpers.dm b/modular_skyrat/master_files/code/modules/mob/living/carbon/human_helpers.dm index 4cffb1a204590f..b13a1ec0e3eeed 100644 --- a/modular_skyrat/master_files/code/modules/mob/living/carbon/human_helpers.dm +++ b/modular_skyrat/master_files/code/modules/mob/living/carbon/human_helpers.dm @@ -4,7 +4,7 @@ var/t_He = p_They() var/t_is = p_are() //This checks to see if the body is revivable - if(key || !get_organ_by_type(/obj/item/organ/internal/brain) || ghost?.can_reenter_corpse) + if((key || !get_organ_by_type(/obj/item/organ/internal/brain) || ghost?.can_reenter_corpse) && (!HAS_TRAIT(src, TRAIT_DNR))) return span_deadsay("[t_He] [t_is] limp and unresponsive; they're still twitching on occasion, perhaps [p_they()] can still be saved..!") else return span_deadsay("[t_He] [t_is] limp and unresponsive; there are no signs of life and they've degraded beyond revival...") diff --git a/modular_skyrat/master_files/code/modules/surgery/organs/internal/appendix/_appendix.dm b/modular_skyrat/master_files/code/modules/surgery/organs/internal/appendix/_appendix.dm new file mode 100644 index 00000000000000..296696d559f94f --- /dev/null +++ b/modular_skyrat/master_files/code/modules/surgery/organs/internal/appendix/_appendix.dm @@ -0,0 +1,8 @@ +/obj/item/organ/internal/appendix/become_inflamed() + if(engaged_role_play_check(owner, station = TRUE, dorms = TRUE)) + return + + if(!(owner.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) + return + + ..() diff --git a/modular_skyrat/master_files/icons/mob/clothing/head/cowboy.dmi b/modular_skyrat/master_files/icons/mob/clothing/head/cowboy.dmi index 835a46c9d16b15..94d19052982a55 100644 Binary files a/modular_skyrat/master_files/icons/mob/clothing/head/cowboy.dmi and b/modular_skyrat/master_files/icons/mob/clothing/head/cowboy.dmi differ diff --git a/modular_skyrat/master_files/icons/mob/clothing/suit.dmi b/modular_skyrat/master_files/icons/mob/clothing/suit.dmi index cf43274be0564b..c00b68f50cfac0 100644 Binary files a/modular_skyrat/master_files/icons/mob/clothing/suit.dmi and b/modular_skyrat/master_files/icons/mob/clothing/suit.dmi differ diff --git a/modular_skyrat/master_files/icons/mob/clothing/under/cargo.dmi b/modular_skyrat/master_files/icons/mob/clothing/under/cargo.dmi index 6f988460699695..9a8042cf0a0f6e 100644 Binary files a/modular_skyrat/master_files/icons/mob/clothing/under/cargo.dmi and b/modular_skyrat/master_files/icons/mob/clothing/under/cargo.dmi differ diff --git a/modular_skyrat/master_files/icons/mob/clothing/under/cargo_digi.dmi b/modular_skyrat/master_files/icons/mob/clothing/under/cargo_digi.dmi index b975af5de8c257..c4ecb9e4f81203 100644 Binary files a/modular_skyrat/master_files/icons/mob/clothing/under/cargo_digi.dmi and b/modular_skyrat/master_files/icons/mob/clothing/under/cargo_digi.dmi differ diff --git a/modular_skyrat/master_files/icons/mob/clothing/underwear.dmi b/modular_skyrat/master_files/icons/mob/clothing/underwear.dmi index bb41c5562b69c5..09b9161fadec48 100644 Binary files a/modular_skyrat/master_files/icons/mob/clothing/underwear.dmi and b/modular_skyrat/master_files/icons/mob/clothing/underwear.dmi differ diff --git a/modular_skyrat/master_files/icons/obj/clothing/head/cowboy.dmi b/modular_skyrat/master_files/icons/obj/clothing/head/cowboy.dmi index bd26b776ee56b2..fb582bf495ce59 100644 Binary files a/modular_skyrat/master_files/icons/obj/clothing/head/cowboy.dmi and b/modular_skyrat/master_files/icons/obj/clothing/head/cowboy.dmi differ diff --git a/modular_skyrat/master_files/icons/obj/clothing/suits.dmi b/modular_skyrat/master_files/icons/obj/clothing/suits.dmi index e2a568e2c918f0..45b23619f8976e 100644 Binary files a/modular_skyrat/master_files/icons/obj/clothing/suits.dmi and b/modular_skyrat/master_files/icons/obj/clothing/suits.dmi differ diff --git a/modular_skyrat/master_files/icons/obj/clothing/under/cargo.dmi b/modular_skyrat/master_files/icons/obj/clothing/under/cargo.dmi index bc6d0043e132fe..fccbf88fbc9e86 100644 Binary files a/modular_skyrat/master_files/icons/obj/clothing/under/cargo.dmi and b/modular_skyrat/master_files/icons/obj/clothing/under/cargo.dmi differ diff --git a/modular_skyrat/modules/alternative_job_titles/code/alt_job_titles.dm b/modular_skyrat/modules/alternative_job_titles/code/alt_job_titles.dm index e62c81552d59cc..d7abb4e00f0116 100644 --- a/modular_skyrat/modules/alternative_job_titles/code/alt_job_titles.dm +++ b/modular_skyrat/modules/alternative_job_titles/code/alt_job_titles.dm @@ -300,6 +300,7 @@ /datum/job/quartermaster alt_titles = list( + "Quartermaster", "Union Requisitions Officer", "Deck Chief", "Warehouse Supervisor", diff --git a/modular_skyrat/modules/ashwalkers/code/effects/ash_rituals.dm b/modular_skyrat/modules/ashwalkers/code/effects/ash_rituals.dm index b49156bd0a13f4..ae8176bffb5908 100644 --- a/modular_skyrat/modules/ashwalkers/code/effects/ash_rituals.dm +++ b/modular_skyrat/modules/ashwalkers/code/effects/ash_rituals.dm @@ -331,23 +331,47 @@ /datum/ash_ritual/revive_animal/ritual_success(obj/effect/ash_rune/success_rune) . = ..() + if(!revive_simple(success_rune)) + revive_basic(success_rune) + +/datum/ash_ritual/revive_animal/proc/revive_simple(obj/effect/ash_rune/success_rune) var/turf/src_turf = get_turf(success_rune) var/mob/living/simple_animal/find_animal = locate() in src_turf if(!find_animal) - return + return FALSE if(find_animal.stat != DEAD) - return + return FALSE if(find_animal.sentience_type != SENTIENCE_ORGANIC) - return + return FALSE - find_animal.faction = list(FACTION_NEUTRAL) + find_animal.faction = list(FACTION_ASHWALKER) if(ishostile(find_animal)) var/mob/living/simple_animal/hostile/hostile_animal = find_animal hostile_animal.attack_same = FALSE find_animal.revive(HEAL_ALL) + return TRUE + +/datum/ash_ritual/revive_animal/proc/revive_basic(obj/effect/ash_rune/success_rune) + var/turf/src_turf = get_turf(success_rune) + + var/mob/living/basic/find_animal = locate() in src_turf + + if(!find_animal) + return FALSE + + if(find_animal.health > 0) + return FALSE + + if(find_animal.sentience_type != SENTIENCE_ORGANIC) + return FALSE + + find_animal.faction = list(FACTION_ASHWALKER) + + find_animal.revive() + return TRUE diff --git a/modular_skyrat/modules/ashwalkers/code/species/Ashwalkers.dm b/modular_skyrat/modules/ashwalkers/code/species/Ashwalkers.dm index d24aa290ec0686..0e60d2ed7e90ce 100644 --- a/modular_skyrat/modules/ashwalkers/code/species/Ashwalkers.dm +++ b/modular_skyrat/modules/ashwalkers/code/species/Ashwalkers.dm @@ -13,10 +13,12 @@ . = ..() RegisterSignal(carbon_target, COMSIG_MOB_ITEM_ATTACK, PROC_REF(mob_attack)) carbon_target.AddComponent(/datum/component/ash_age) + carbon_target.faction |= FACTION_ASHWALKER /datum/species/lizard/ashwalker/on_species_loss(mob/living/carbon/carbon_target) . = ..() UnregisterSignal(carbon_target, COMSIG_MOB_ITEM_ATTACK) + carbon_target.faction &= FACTION_ASHWALKER /datum/species/lizard/ashwalker/proc/mob_attack(datum/source, mob/mob_target, mob/user) SIGNAL_HANDLER diff --git a/modular_skyrat/modules/blueshield/code/closet.dm b/modular_skyrat/modules/blueshield/code/closet.dm index 54e5665135eeac..1ceaf37325b6f2 100644 --- a/modular_skyrat/modules/blueshield/code/closet.dm +++ b/modular_skyrat/modules/blueshield/code/closet.dm @@ -1,3 +1,19 @@ +/obj/item/storage/bag/garment/blueshield + name = "Blueshield's garment bag" + desc = "A bag for storing extra clothes and shoes. This one belongs to the blueshield." + +/obj/item/storage/bag/garment/blueshield/PopulateContents() + new /obj/item/clothing/suit/hooded/wintercoat/skyrat/blueshield(src) + new /obj/item/clothing/head/beret/blueshield(src) + new /obj/item/clothing/head/beret/blueshield/navy(src) + new /obj/item/clothing/under/rank/blueshield(src) + new /obj/item/clothing/under/rank/blueshield/skirt(src) + new /obj/item/clothing/under/rank/blueshield/turtleneck(src) + new /obj/item/clothing/under/rank/blueshield/turtleneck/skirt(src) + new /obj/item/clothing/suit/armor/vest/blueshield(src) + new /obj/item/clothing/suit/armor/vest/blueshield/jacket(src) + new /obj/item/clothing/neck/mantle/bsmantle(src) + /obj/structure/closet/secure_closet/blueshield name = "\the blueshield's locker" icon_state = "bs" @@ -12,5 +28,5 @@ new /obj/item/assembly/flash/handheld(src) new /obj/item/restraints/handcuffs(src) new /obj/item/clothing/glasses/hud/security/sunglasses(src) - new /obj/item/clothing/suit/hooded/wintercoat/skyrat/blueshield(src) new /obj/item/storage/medkit/tactical/blueshield(src) + new /obj/item/storage/bag/garment/blueshield(src) diff --git a/modular_skyrat/modules/bluespace_miner/code/bluespace_miner.dm b/modular_skyrat/modules/bluespace_miner/code/bluespace_miner.dm index 6b45258c05108d..e082ddabb42ae7 100644 --- a/modular_skyrat/modules/bluespace_miner/code/bluespace_miner.dm +++ b/modular_skyrat/modules/bluespace_miner/code/bluespace_miner.dm @@ -151,7 +151,7 @@ /datum/supply_pack/misc/bluespace_miner name = "Bluespace Miner" desc = "Nanotrasen has revolutionized the procuring of materials with bluespace-- featuring the Bluespace Miner!" - cost = CARGO_CRATE_VALUE * 150 // 30,000 + cost = CARGO_CRATE_VALUE * 50 // 10,000 contains = list(/obj/item/circuitboard/machine/bluespace_miner) crate_name = "Bluespace Miner Circuitboard Crate" crate_type = /obj/structure/closet/crate diff --git a/modular_skyrat/modules/cell_component/code/flashlight.dm b/modular_skyrat/modules/cell_component/code/flashlight.dm index 01de50266e3e57..6e585781a838ee 100644 --- a/modular_skyrat/modules/cell_component/code/flashlight.dm +++ b/modular_skyrat/modules/cell_component/code/flashlight.dm @@ -18,13 +18,10 @@ /obj/item/flashlight/Initialize(mapload) . = ..() - if(icon_state == "[initial(icon_state)]-on") - turn_on(FALSE) - update_brightness() - register_context() + update_item_action_buttons() if(uses_battery) - AddComponent(/datum/component/cell, cell_override, CALLBACK(src, PROC_REF(turn_off)), _has_cell_overlays = FALSE) + AddComponent(/datum/component/cell, cell_override, CALLBACK(src, PROC_REF(quietly_turn_off)), _has_cell_overlays = FALSE) /obj/item/flashlight/examine(mob/user) . = ..() @@ -55,46 +52,37 @@ set_light_power(initial(light_power)) to_chat(user, span_notice("You set [src] to low.")) -/obj/item/flashlight/proc/toggle_light() +/obj/item/flashlight/toggle_light(noisy = TRUE) + . = ..() if(on) - turn_off() - else + after_turn_on() if(uses_battery && !(item_use_power(power_use_amount, TRUE) & COMPONENT_POWER_SUCCESS)) return - turn_on(makes_noise_when_lit) - playsound(src, on ? sound_on : sound_off, 40, TRUE) - return TRUE - -/obj/item/flashlight/attack_self(mob/user) - . = ..() - toggle_light() + if(noisy) + playsound(src, on ? sound_on : sound_off, 40, TRUE) /** * Handles turning on the flashlight. * Parameters: * * noisy - Boolean on whether the flashlight should make an additional noise from being turned on or not. Defaults to TRUE. */ -/obj/item/flashlight/proc/turn_on(noisy = TRUE) - on = TRUE - if (uses_battery) +/obj/item/flashlight/proc/after_turn_on(noisy = TRUE) + if(uses_battery) START_PROCESSING(SSobj, src) - update_brightness() if(noisy) playsound(src, 'modular_skyrat/master_files/sound/effects/flashlight.ogg', 40, TRUE) //Credits to ERIS for the sound - update_item_action_buttons() -/// Handles turning off the flashlight. -/obj/item/flashlight/proc/turn_off() - on = FALSE - update_brightness() - update_item_action_buttons() +/// Quietly turns the flashlight off if it was on (called by the battery running out of charge). +/obj/item/flashlight/proc/quietly_turn_off() + if(on) + toggle_light(noisy = FALSE) /obj/item/flashlight/process(seconds_per_tick) if(!on) STOP_PROCESSING(SSobj, src) return if(uses_battery && !(item_use_power(power_use_amount) & COMPONENT_POWER_SUCCESS)) - turn_off() + quietly_turn_off() /obj/item/flashlight/update_icon_state() . = ..() diff --git a/modular_skyrat/modules/company_imports/code/armament_datums/vitezstvi_ammo.dm b/modular_skyrat/modules/company_imports/code/armament_datums/vitezstvi_ammo.dm index 27a3a48920fb23..3e6df12d1246e8 100644 --- a/modular_skyrat/modules/company_imports/code/armament_datums/vitezstvi_ammo.dm +++ b/modular_skyrat/modules/company_imports/code/armament_datums/vitezstvi_ammo.dm @@ -15,6 +15,10 @@ item_type = /obj/item/disk/ammo_workbench/advanced cost = PAYCHECK_COMMAND * 5 +/datum/armament_entry/company_import/vitezstvi/ammo_bench/bullet_drive + item_type = /obj/item/circuitboard/machine/dish_drive/bullet + cost = PAYCHECK_COMMAND * 2 + // Boxes of non-shotgun ammo /datum/armament_entry/company_import/vitezstvi/ammo_boxes diff --git a/modular_skyrat/modules/contractor/code/datums/contract.dm b/modular_skyrat/modules/contractor/code/datums/contract.dm index 47e7906254d1ba..7d57f029f844e5 100644 --- a/modular_skyrat/modules/contractor/code/datums/contract.dm +++ b/modular_skyrat/modules/contractor/code/datums/contract.dm @@ -213,9 +213,9 @@ for(var/i in 1 to 2) var/obj/item/bodypart/limb = target.get_bodypart(pick_n_take(parts_to_fuck_up)) - var/datum/wound/blunt/bone/severe/severe_wound_type = /datum/wound/blunt/bone/severe - var/datum/wound/blunt/bone/critical/critical_wound_type = /datum/wound/blunt/bone/critical - limb.receive_damage(brute = WOUND_MINIMUM_DAMAGE, wound_bonus = rand(initial(severe_wound_type.threshold_minimum), initial(critical_wound_type.threshold_minimum) + 10)) + var/min_wound = limb.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_SEVERE, return_value_if_no_wound = 40) + var/max_wound = limb.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_CRITICAL, return_value_if_no_wound = 60) + limb.receive_damage(brute = WOUND_MINIMUM_DAMAGE, wound_bonus = rand(min_wound, max_wound)) target.update_damage_overlays() addtimer(CALLBACK(src, PROC_REF(victim_stage_three), target), 6 SECONDS) diff --git a/modular_skyrat/modules/customization/modules/client/augment/limbs.dm b/modular_skyrat/modules/customization/modules/client/augment/limbs.dm index e1bc30db944485..e5f8f4f14e7beb 100644 --- a/modular_skyrat/modules/customization/modules/client/augment/limbs.dm +++ b/modular_skyrat/modules/customization/modules/client/augment/limbs.dm @@ -67,6 +67,12 @@ path = /obj/item/bodypart/arm/left/plasmaman uses_robotic_styles = FALSE +/datum/augment_item/limb/l_arm/self_destruct + name = "No Left Arm" + path = /obj/item/bodypart/arm/left/self_destruct + cost = -3 + uses_robotic_styles = FALSE + //RIGHT ARMS /datum/augment_item/limb/r_arm slot = AUGMENT_SLOT_R_ARM @@ -85,6 +91,12 @@ path = /obj/item/bodypart/arm/right/plasmaman uses_robotic_styles = FALSE +/datum/augment_item/limb/r_arm/self_destruct + name = "No Right Arm" + path = /obj/item/bodypart/arm/right/self_destruct + cost = -3 + uses_robotic_styles = FALSE + //LEFT LEGS /datum/augment_item/limb/l_leg slot = AUGMENT_SLOT_L_LEG @@ -103,6 +115,12 @@ path = /obj/item/bodypart/leg/left/plasmaman uses_robotic_styles = FALSE +/datum/augment_item/limb/l_leg/self_destruct + name = "No Left Leg" + path = /obj/item/bodypart/leg/left/self_destruct + cost = -3 + uses_robotic_styles = FALSE + //RIGHT LEGS /datum/augment_item/limb/r_leg slot = AUGMENT_SLOT_R_LEG @@ -120,3 +138,9 @@ name = "Plasmaman right leg" path = /obj/item/bodypart/leg/right/plasmaman uses_robotic_styles = FALSE + +/datum/augment_item/limb/r_leg/self_destruct + name = "No Right Leg" + path = /obj/item/bodypart/leg/right/self_destruct + cost = -3 + uses_robotic_styles = FALSE diff --git a/modular_skyrat/modules/customization/modules/clothing/under/utility_port/suits_port.dm b/modular_skyrat/modules/customization/modules/clothing/under/utility_port/suits_port.dm index 07ce022f2a4602..bb88ca325dbf63 100644 --- a/modular_skyrat/modules/customization/modules/clothing/under/utility_port/suits_port.dm +++ b/modular_skyrat/modules/customization/modules/clothing/under/utility_port/suits_port.dm @@ -53,16 +53,6 @@ desc = "A comfortable jacket in a neutral black" icon_state = "off_dep_jacket" -/obj/item/clothing/suit/gorka //THIS WILL BE MOVED IN THE NEXT PR ADDING PROPER GORKAS (not cargo related so not in this PR), BUT FOR NOW ITS HERE FOR THE SUBTYPE'S FILE LINKS - icon = 'modular_skyrat/master_files/icons/obj/clothing/suits.dmi' - worn_icon = 'modular_skyrat/master_files/icons/mob/clothing/suit.dmi' - supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON - -/obj/item/clothing/suit/gorka/supply //Put here for sorting purposes, considering the cargo gorkas are in the utility file too. The base Gorka and Jacket (to be added later) will most likely be elsewhere - name = "supply gorka jacket" - desc = "A snug jacket to wear over your gorka. This one matches with supply's colors." - icon_state = "gorka_jacket_supply" - /obj/item/clothing/suit/toggle/jacket/supply/head name = "quartermaster's jacket" desc = "Even if people refuse to recognize you as a head, they can recognize you as a badass." diff --git a/modular_skyrat/modules/customization/modules/jobs/_job.dm b/modular_skyrat/modules/customization/modules/jobs/_job.dm index af223cbc67cc68..e6be489f524f51 100644 --- a/modular_skyrat/modules/customization/modules/jobs/_job.dm +++ b/modular_skyrat/modules/customization/modules/jobs/_job.dm @@ -5,6 +5,8 @@ var/loadout = TRUE //List of banned quirks in their names(dont blame me, that's how they're stored), players can't join as the job if they have the quirk. Associative for the purposes of performance var/list/banned_quirks + /// List of banned augments + var/list/banned_augments ///A list of slots that can't have loadout items assigned to them if no_dresscode is applied, used for important items such as ID, PDA, backpack and headset var/list/blacklist_dresscode_slots //Whitelist of allowed species for this job. If not specified then all roundstart races can be used. Associative with TRUE @@ -41,6 +43,20 @@ return TRUE return FALSE +/datum/job/proc/has_banned_augment(datum/preferences/pref) + if(!pref) + return FALSE + + if(!banned_augments) + return FALSE + + var/list/player_augments = pref.augments + for(var/key in player_augments) + if(player_augments[key] in banned_augments) + return TRUE + + return FALSE + // Misc /datum/job/assistant no_dresscode = TRUE @@ -53,43 +69,56 @@ //Security /datum/job/security_officer banned_quirks = list(SEC_RESTRICTED_QUIRKS) + banned_augments = list(SEC_RESTRICTED_AUGMENTS) /datum/job/detective banned_quirks = list(SEC_RESTRICTED_QUIRKS) + banned_augments = list(SEC_RESTRICTED_AUGMENTS) /datum/job/warden banned_quirks = list(SEC_RESTRICTED_QUIRKS) + banned_augments = list(SEC_RESTRICTED_AUGMENTS) /datum/job/blueshield banned_quirks = list(SEC_RESTRICTED_QUIRKS) + banned_augments = list(SEC_RESTRICTED_AUGMENTS) /datum/job/corrections_officer banned_quirks = list(SEC_RESTRICTED_QUIRKS) + banned_augments = list(SEC_RESTRICTED_AUGMENTS) // Command /datum/job/captain banned_quirks = list(HEAD_RESTRICTED_QUIRKS) + banned_augments = list(HEAD_RESTRICTED_AUGMENTS) /datum/job/nanotrasen_consultant banned_quirks = list(HEAD_RESTRICTED_QUIRKS) + banned_augments = list(HEAD_RESTRICTED_AUGMENTS) /datum/job/head_of_security banned_quirks = list(SEC_RESTRICTED_QUIRKS, HEAD_RESTRICTED_QUIRKS) + banned_augments = list(SEC_RESTRICTED_AUGMENTS) /datum/job/chief_medical_officer banned_quirks = list(HEAD_RESTRICTED_QUIRKS) + banned_augments = list(HEAD_RESTRICTED_AUGMENTS) /datum/job/chief_engineer banned_quirks = list(HEAD_RESTRICTED_QUIRKS, "Paraplegic" = TRUE) + banned_augments = list(HEAD_RESTRICTED_AUGMENTS) /datum/job/research_director banned_quirks = list(HEAD_RESTRICTED_QUIRKS) + banned_augments = list(HEAD_RESTRICTED_AUGMENTS) /datum/job/head_of_personnel banned_quirks = list(HEAD_RESTRICTED_QUIRKS) + banned_augments = list(HEAD_RESTRICTED_AUGMENTS) /datum/job/quartermaster banned_quirks = list(HEAD_RESTRICTED_QUIRKS) + banned_augments = list(HEAD_RESTRICTED_AUGMENTS) //Silicon /datum/job/ai @@ -147,12 +176,16 @@ // Nanotrasen Fleet /datum/job/fleetmaster banned_quirks = list(HEAD_RESTRICTED_QUIRKS) + banned_augments = list(HEAD_RESTRICTED_AUGMENTS) /datum/job/operations_inspector banned_quirks = list(HEAD_RESTRICTED_QUIRKS) + banned_augments = list(HEAD_RESTRICTED_AUGMENTS) /datum/job/deck_crew banned_quirks = list(HEAD_RESTRICTED_QUIRKS) + banned_augments = list(HEAD_RESTRICTED_AUGMENTS) /datum/job/bridge_officer banned_quirks = list(HEAD_RESTRICTED_QUIRKS) + banned_augments = list(HEAD_RESTRICTED_AUGMENTS) diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories.dm index cd22694da794c6..33a5ba2487f30b 100644 --- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories.dm +++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories.dm @@ -579,6 +579,9 @@ GLOBAL_LIST_EMPTY(cached_mutant_icon_files) /* End of adding hides_breasts to TG stuff, start of adding has_digitigrade to TG stuff */ +/datum/sprite_accessory/underwear/male_briefs + has_digitigrade = TRUE + /datum/sprite_accessory/underwear/male_boxers has_digitigrade = TRUE @@ -655,6 +658,12 @@ GLOBAL_LIST_EMPTY(cached_mutant_icon_files) gender = FEMALE use_static = null +/datum/sprite_accessory/undershirt/hi_vis_bra + name = "Safekini" + icon_state = "hi_vis_bra" + gender = FEMALE + use_static = TRUE + /datum/sprite_accessory/undershirt/bra_alt name = "Bra - Alt" icon_state = "bra_alt" diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/_hemophage_defines.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/_hemophage_defines.dm index 50fcc84f3f7346..7471839e1dbfae 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/_hemophage_defines.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/_hemophage_defines.dm @@ -10,6 +10,8 @@ /// Minimum amount of blood that you can reach via blood regeneration, regeneration will stop below this. #define MINIMUM_VOLUME_FOR_REGEN (BLOOD_VOLUME_BAD + 1) // We do this to avoid any jankiness, and because we want to ensure that they don't fall into a state where they're constantly passing out in a locker. +/// Vomit flags for hemophages who eat food +#define HEMOPHAGE_VOMIT_FLAGS (MOB_VOMIT_MESSAGE | MOB_VOMIT_HARM | MOB_VOMIT_FORCE) /// The ratio of reagents that get purged while a Hemophage vomits from trying to eat/drink something that their tumor doesn't like. #define HEMOPHAGE_VOMIT_PURGE_RATIO 0.95 /// How much disgust we're at after eating/drinking something the tumor doesn't like. diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/corrupted_liver.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/corrupted_liver.dm index 5210b20977539f..bf731c941aae7b 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/corrupted_liver.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/corrupted_liver.dm @@ -49,7 +49,7 @@ to_chat(body, span_warning("That tasted awful...")) // We don't lose nutrition because we don't even use nutrition as Hemopahges. It WILL however purge nearly all of what's in their stomach. - body.vomit(lost_nutrition = 0, stun = FALSE, distance = 1, force = TRUE, purge_ratio = HEMOPHAGE_VOMIT_PURGE_RATIO) + body.vomit(vomit_flags = HEMOPHAGE_VOMIT_FLAGS, lost_nutrition = 0, distance = 1, purge_ratio = HEMOPHAGE_VOMIT_PURGE_RATIO) #undef MINIMUM_BLOOD_REGENING_REAGENT_RATIO diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/corrupted_stomach.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/corrupted_stomach.dm index 801f65fb7e02aa..3af433695a9af8 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/corrupted_stomach.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/corrupted_stomach.dm @@ -1,4 +1,3 @@ - /datum/component/organ_corruption/stomach corruptable_organ_type = /obj/item/organ/internal/stomach corrupted_icon_state = "stomach" @@ -43,4 +42,4 @@ to_chat(body, span_warning("That tasted awful...")) // We don't lose nutrition because we don't even use nutrition as hemopahges. It WILL however purge nearly all of what's in their stomach. - body.vomit(lost_nutrition = 0, stun = FALSE, distance = 1, force = TRUE, purge_ratio = HEMOPHAGE_VOMIT_PURGE_RATIO) + body.vomit(vomit_flags = HEMOPHAGE_VOMIT_FLAGS, lost_nutrition = 0, distance = 1, purge_ratio = HEMOPHAGE_VOMIT_PURGE_RATIO) diff --git a/modular_skyrat/modules/customization/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/modular_skyrat/modules/customization/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 25af43017e76aa..32391bd465e3c0 100644 --- a/modular_skyrat/modules/customization/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/modular_skyrat/modules/customization/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -31,7 +31,7 @@ if(!(C.mob_biotypes & MOB_ROBOTIC)) C.reagents.remove_reagent(type, 3.6) //gets removed from organics very fast if(prob(25)) - C.vomit(5, FALSE, FALSE) + C.vomit(VOMIT_CATEGORY_DEFAULT, lost_nutrition = 5) return ..() /datum/reagent/consumable/ethanol/synthanol/expose_mob(mob/living/carbon/C, method=TOUCH, volume) diff --git a/modular_skyrat/modules/customization/modules/surgery/bodyparts/parts.dm b/modular_skyrat/modules/customization/modules/surgery/bodyparts/parts.dm new file mode 100644 index 00000000000000..85b251c08b6a1e --- /dev/null +++ b/modular_skyrat/modules/customization/modules/surgery/bodyparts/parts.dm @@ -0,0 +1,32 @@ +/// Self Destructing Bodyparts, For Augmentation. I'm leaving out heads + chests as, while it would be cool for synths, I also don't want people to start the round unrevivable sans botany because they're dumb as heck. You know who and what you are. +/obj/item/bodypart/arm/left/self_destruct/try_attach_limb(mob/living/carbon/limb_owner, special) + . = ..() + drop_limb() + qdel(src) + +/obj/item/bodypart/arm/left/self_destruct/set_icon_static(new_icon) + return + +/obj/item/bodypart/arm/right/self_destruct/try_attach_limb(mob/living/carbon/limb_owner, special) + . = ..() + drop_limb() + qdel(src) + +/obj/item/bodypart/arm/right/self_destruct/set_icon_static(new_icon) + return + +/obj/item/bodypart/leg/left/self_destruct/try_attach_limb(mob/living/carbon/limb_owner, special) + . = ..() + drop_limb() + qdel(src) + +/obj/item/bodypart/leg/left/self_destruct/set_icon_static(new_icon) + return + +/obj/item/bodypart/leg/right/self_destruct/try_attach_limb(mob/living/carbon/limb_owner, special) + . = ..() + drop_limb() + qdel(src) + +/obj/item/bodypart/leg/right/self_destruct/set_icon_static(new_icon) + return diff --git a/modular_skyrat/modules/delam_emergency_stop/code/scram.dm b/modular_skyrat/modules/delam_emergency_stop/code/scram.dm index 1cc11c47ef9ef2..5e6fefa8b1f5e7 100644 --- a/modular_skyrat/modules/delam_emergency_stop/code/scram.dm +++ b/modular_skyrat/modules/delam_emergency_stop/code/scram.dm @@ -1,4 +1,3 @@ -#define DELAM_MACHINE_POWER_CONSUMPTION 375 #define SM_PREVENT_EXPLOSION_THRESHOLD 100 #define SM_COOLING_MIXTURE_MOLES 64000 #define SM_COOLING_MIXTURE_TEMP 120 @@ -18,8 +17,9 @@ #define SHATTER_FLASH_RANGE 5 #define SHATTER_MIN_TIME 13 SECONDS #define SHATTER_MAX_TIME 15 SECONDS -#define POWER_CUT_MIN_DURATION 19 SECONDS -#define POWER_CUT_MAX_DURATION 21 SECONDS +#define EVAC_WARNING_TIMER 3 SECONDS +#define POWER_CUT_MIN_DURATION_SECONDS 19 +#define POWER_CUT_MAX_DURATION_SECONDS 21 #define AIR_INJECT_RATE 33 #define BUTTON_SOUND_RANGE 7 #define BUTTON_SOUND_FALLOFF_DISTANCE 7 @@ -176,11 +176,12 @@ notify_volume = 75, ) - radio.talk_into(src, "DELAMINATION SUPPRESSION SYSTEM FIRING IN 5 SECONDS. EVACUATE THE SUPERMATTER ENGINE ROOM!", emergency_channel) + radio.talk_into(src, "DELAMINATION SUPPRESSION SYSTEM FIRING. EVACUATE THE SUPERMATTER ENGINE ROOM!", emergency_channel) // fight power with power - addtimer(CALLBACK(src, PROC_REF(put_on_a_show)), 5 SECONDS) - INVOKE_ASYNC(SSnightshift, TYPE_PROC_REF(/datum/controller/subsystem/nightshift, suck_light_power)) + addtimer(CALLBACK(src, PROC_REF(put_on_a_show)), EVAC_WARNING_TIMER) + playsound(src, 'sound/misc/bloblarm.ogg', 100, FALSE, MACHINE_RUMBLE_SOUND_RANGE, ignore_walls = TRUE, use_reverb = TRUE, falloff_distance = MACHINE_SOUND_FALLOFF_DISTANCE) + power_fail((EVAC_WARNING_TIMER / 10) + POWER_CUT_MAX_DURATION_SECONDS, (EVAC_WARNING_TIMER / 10) + POWER_CUT_MAX_DURATION_SECONDS) /// Stop the delamination. Let the fireworks begin /obj/machinery/atmospherics/components/unary/delam_scram/proc/put_on_a_show() @@ -190,7 +191,6 @@ // Fire bell close, that nice 'are we gonna die?' rumble out far on = TRUE - playsound(src, 'sound/machines/hypertorus/HFR_critical_explosion.ogg', 100, FALSE, MACHINE_RUMBLE_SOUND_RANGE, ignore_walls = TRUE, use_reverb = TRUE, falloff_distance = MACHINE_SOUND_FALLOFF_DISTANCE) alert_sound_to_playing('sound/misc/earth_rumble_distant3.ogg', override_volume = TRUE) update_appearance() @@ -217,10 +217,7 @@ addtimer(CALLBACK(fucked_window, TYPE_PROC_REF(/obj/structure/window/reinforced/plasma, shatter_window)), rand(SHATTER_MIN_TIME, SHATTER_MAX_TIME)) // Let the gas work for a few seconds to cool the crystal. If it has damage beyond repair, heal it a bit - addtimer(CALLBACK(src, PROC_REF(prevent_explosion)), 9 SECONDS) - - // Restore the power that we were 'channelling' to the SM - addtimer(CALLBACK(SSnightshift, TYPE_PROC_REF(/datum/controller/subsystem/nightshift, restore_light_power)), rand(POWER_CUT_MIN_DURATION, POWER_CUT_MAX_DURATION)) + addtimer(CALLBACK(src, PROC_REF(prevent_explosion)), 7 SECONDS) /// Shatter the supermatter chamber windows /obj/structure/window/reinforced/plasma/proc/shatter_window() @@ -261,24 +258,6 @@ delam_juice.temperature = SM_COOLING_MIXTURE_TEMP airs[1] = delam_juice -/// Dims the lights and consumes a bit of APC power, summoning that electricity to stop the delam... somehow -/datum/controller/subsystem/nightshift/proc/suck_light_power() - SSnightshift.can_fire = FALSE - for(var/obj/machinery/power/apc/light_to_suck as anything in SSmachines.get_machines_by_type(/obj/machinery/power/apc)) - light_to_suck.cell.charge -= DELAM_MACHINE_POWER_CONSUMPTION - light_to_suck.lighting = APC_CHANNEL_OFF - light_to_suck.nightshift_lights = TRUE - light_to_suck.update_appearance() - light_to_suck.update() - -/// Restores the lighting after the delam suppression -/datum/controller/subsystem/nightshift/proc/restore_light_power() - SSnightshift.can_fire = TRUE - for(var/obj/machinery/power/apc/light_to_restore as anything in SSmachines.get_machines_by_type(/obj/machinery/power/apc)) - light_to_restore.lighting = APC_CHANNEL_AUTO_ON - light_to_restore.update_appearance() - light_to_restore.update() - /// A big red button you can smash to stop the supermatter engine, oh how tempting! /obj/machinery/button/delam_scram name = "\improper supermatter emergency stop button" @@ -289,6 +268,7 @@ can_alter_skin = FALSE silicon_access_disabled = TRUE resistance_flags = FREEZE_PROOF | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + use_power = NO_POWER_USE light_color = LIGHT_COLOR_INTENSE_RED light_power = 0.7 ///one use only! @@ -319,7 +299,6 @@ /// Proc for arming the red button, it hasn't been pushed yet /obj/machinery/button/delam_scram/attack_hand(mob/user, list/modifiers) . = ..() - if((machine_stat & BROKEN)) return @@ -338,8 +317,8 @@ // Give them a cheeky instructions card. But only one! If you lost it, question your engineering prowess in this moment if(button_stage == BUTTON_IDLE) - visible_message(span_danger("A biscuit card falls out of [src]!")) - user.put_in_hands(new /obj/item/folder/biscuit/confidential/delam(get_turf(user))) + visible_message(span_danger("A plastic card falls out of [src]!")) + user.put_in_hands(new /obj/item/paper/paperslip/corporate/fluff/delam_procedure(get_turf(user))) button_stage = BUTTON_AWAKE return @@ -424,32 +403,69 @@ active = FALSE update_appearance() -/obj/item/folder/biscuit/confidential/delam - name = "NT-approved delam emergency procedure" - contained_slip = /obj/item/paper/paperslip/corporate/fluff/delam_procedure - layer = SIGN_LAYER - /obj/item/paper/paperslip/corporate/fluff/delam_procedure/Initialize(mapload) - name = "delam emergency procedure" + name = "NT-approved delam emergency procedure" desc = "Now you're a REAL engineer!" - default_raw_text = "EMERGENCY PROCEDURE: SUPERMATTER DELAMINATION

\ - So you've found yourself in a bit of a pickle with a delamination of a supermatter reactor.
Don't worry, saving the day is just a few steps away!


\ - - Locate the ever-elusive red emergency stop button. It's probably hiding in plain sight, so take your time, have a laugh, and enjoy the anticipation. Remember, it's like a treasure hunt, only with the added bonus of preventing a nuclear disaster.

\ - - Once you've uncovered the button, muster all your courage and push it like there's no tomorrow. Well, actually, you're pushing it to ensure there is a tomorrow. But hey, who doesn't love a little paradoxical button-pushing?

\ - - Prepare for the impending suppression of the supermatter engine room, because things are about to get real quiet. Just make sure everyone has evacuated, or else they'll be in for a surprise. The system needs its space, and it's not known for being the friendliest neighbour.

\ - - After the delamination is successfully suppressed, take a moment to appreciate the delicate beauty of crystal-based electricity. Take a look around and fix any damage to those fragile glass components. Feel free to put on your finest overalls and channel your inner engiborg while doing so.

\ - - Keep an eye out for fires and the infamous air mix. It's always an adventure trying to strike the perfect balance between breathable air and potential suffocation. Remember, oxygen plus a spark equals fireworks – the kind you definitely don't want inside a reactor.

\ - - To avoid singeing your eyebrows off, consider enlisting the help of a synth or a trusty borg. After all, nothing says \"safety first\" like outsourcing your firefighting to non-living, non-breathing assistants.

\ - - Clear out any lightly radioactive debris (The cargo department will probably love to dispose it for you.)

\ - - Finally, revel in the satisfaction of knowing that you've single-handedly prevented a delamination. But, of course, don't forget to feel guilty because SAFETY MOTH Knows. SAFETY MOTH knows everything. It's always watching, judging, and probably taking notes for its next safety briefing. So bask in the glory of your heroism, but know that the all-knowing Moff is onto you.

\ - (Optional step, for the true daredevils out there)

\ - - When it comes time for your second attempt at starting the SM: Fold these instructions into a paper plane, give it a good toss towards the crystal, and watch it soar through the air. Because nothing says \"I'm dealing with a potentially catastrophic situation\" like engaging in some whimsical paper airplane shenanigans.

\ - Hopefully you'll never need to use this. However, good luck!" + return ..() + +/obj/item/paper/paperslip/corporate/fluff/delam_procedure/examine(mob/user) + . = ..() + ui_interact(user) + +/obj/item/paper/paperslip/corporate/fluff/delam_procedure/attackby(obj/item/attacking_item, mob/living/user, params) + if(burn_paper_product_attackby_check(attacking_item, user)) + SStgui.close_uis(src) + return + + // Enable picking paper up by clicking on it with the clipboard or folder + if(istype(attacking_item, /obj/item/clipboard) || istype(attacking_item, /obj/item/folder) || istype(attacking_item, /obj/item/paper_bin)) + attacking_item.attackby(src, user) + return + + ui_interact(user) + return ..() + +/obj/item/paper/paperslip/corporate/fluff/delam_procedure/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "DelamProcedure") + ui.autoupdate = FALSE + ui.open() + +/obj/structure/sign/delam_procedure + name = "Safety Moth - Delamination Emergency Procedure" + desc = "This informational sign uses Safety Moth™ to tell the viewer how to use the emergency stop button if the Supermatter Crystal is delaminating." + icon = 'modular_skyrat/modules/delam_emergency_stop/icons/scram.dmi' + icon_state = "moff-poster" + pixel_y = 4 + armor_type = /datum/armor/sign_delam + anchored = TRUE + +/datum/armor/sign_delam + melee = 60 + acid = 70 + fire = 90 + +/obj/structure/sign/delam_procedure/examine(mob/user) + . = ..() + ui_interact(user) + +/obj/structure/sign/delam_procedure/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "DelamProcedure") + ui.autoupdate = FALSE + ui.open() + +/obj/structure/sign/delam_procedure/ui_status(mob/user) + if(user.is_blind()) + return UI_CLOSE + return ..() MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/atmospherics/components/unary/delam_scram, 0) +MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/delam_procedure, 32) -#undef DELAM_MACHINE_POWER_CONSUMPTION #undef DAMAGED_SUPERMATTER_COLOR #undef SM_PREVENT_EXPLOSION_THRESHOLD #undef SM_COOLING_MIXTURE_MOLES @@ -469,8 +485,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/atmospherics/components/unary/delam_s #undef SHATTER_FLASH_RANGE #undef SHATTER_MIN_TIME #undef SHATTER_MAX_TIME -#undef POWER_CUT_MIN_DURATION -#undef POWER_CUT_MAX_DURATION +#undef EVAC_WARNING_TIMER +#undef POWER_CUT_MIN_DURATION_SECONDS +#undef POWER_CUT_MAX_DURATION_SECONDS #undef AIR_INJECT_RATE #undef BUTTON_SOUND_RANGE #undef BUTTON_SOUND_FALLOFF_DISTANCE diff --git a/modular_skyrat/modules/delam_emergency_stop/icons/scram.dmi b/modular_skyrat/modules/delam_emergency_stop/icons/scram.dmi index 8828ba8410b0a2..b654175abd4852 100644 Binary files a/modular_skyrat/modules/delam_emergency_stop/icons/scram.dmi and b/modular_skyrat/modules/delam_emergency_stop/icons/scram.dmi differ diff --git a/modular_skyrat/modules/gunsgalore/code/projectile.dm b/modular_skyrat/modules/gunsgalore/code/projectile.dm deleted file mode 100644 index 9de14ea56075f3..00000000000000 --- a/modular_skyrat/modules/gunsgalore/code/projectile.dm +++ /dev/null @@ -1,94 +0,0 @@ - -/** - * Called when the projectile hits something - * - * @params - * target - thing hit - * blocked - percentage of hit blocked - * pierce_hit - are we piercing through or regular hitting - */ -/obj/projectile/proc/on_hit(atom/target, blocked = FALSE, pierce_hit) - if(fired_from) - SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle) - // i know that this is probably more with wands and gun mods in mind, but it's a bit silly that the projectile on_hit signal doesn't ping the projectile itself. - // maybe we care what the projectile thinks! See about combining these via args some time when it's not 5AM - var/obj/item/bodypart/hit_limb - if(isliving(target)) - var/mob/living/L = target - hit_limb = L.check_limb_hit(def_zone) - SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle, hit_limb) - - if(QDELETED(src)) // in case one of the above signals deleted the projectile for whatever reason - return - var/turf/target_loca = get_turf(target) - - var/hitx - var/hity - if(target == original) - hitx = target.pixel_x + p_x - 16 - hity = target.pixel_y + p_y - 16 - else - hitx = target.pixel_x + rand(-8, 8) - hity = target.pixel_y + rand(-8, 8) - - var/impact_sound - if(hitsound) - impact_sound = hitsound - else - impact_sound = target.impact_sound - get_sfx() - playsound(src, get_sfx_skyrat(impact_sound), vol_by_damage(), TRUE, -1) - - if(damage > 0 && (damage_type == BRUTE || damage_type == BURN) && iswallturf(target_loca) && prob(75)) - var/turf/closed/wall/W = target_loca - if(impact_effect_type && !hitscan) - new impact_effect_type(target_loca, hitx, hity) - - W.add_dent(WALL_DENT_SHOT, hitx, hity) - - return BULLET_ACT_HIT - - if(!isliving(target)) - if(impact_effect_type && !hitscan) - new impact_effect_type(target_loca, hitx, hity) - return BULLET_ACT_HIT - - var/mob/living/L = target - - if(blocked != 100) // not completely blocked - if(damage && L.blood_volume && damage_type == BRUTE) - var/splatter_dir = dir - if(starting) - splatter_dir = get_dir(starting, target_loca) - if(isalien(L)) - new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target_loca, splatter_dir) - else - new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir) - if(prob(33)) - L.add_splatter_floor(target_loca) - else if(impact_effect_type && !hitscan) - new impact_effect_type(target_loca, hitx, hity) - - var/organ_hit_text = "" - var/limb_hit = hit_limb - if(limb_hit) - organ_hit_text = " in \the [parse_zone(limb_hit)]" - else if(suppressed && suppressed != SUPPRESSED_VERY) - to_chat(L, span_userdanger("You're shot by \a [src][organ_hit_text]!")) - else - L.visible_message(span_danger("[L] is hit by \a [src][organ_hit_text]!"), \ - span_userdanger("You're hit by \a [src][organ_hit_text]!"), null, COMBAT_MESSAGE_RANGE) - L.on_hit(src) - - var/reagent_note - if(reagents?.reagent_list) - reagent_note = " REAGENTS:" - for(var/datum/reagent/R in reagents.reagent_list) - reagent_note += "[R.name] ([num2text(R.volume)])" - - if(ismob(firer)) - log_combat(firer, L, "shot", src, reagent_note) - else - L.log_message("has been shot by [firer] with [src]", LOG_ATTACK, color="orange") - - return BULLET_ACT_HIT diff --git a/modular_skyrat/modules/hev_suit/code/hev_suit.dm b/modular_skyrat/modules/hev_suit/code/hev_suit.dm index 081b4a0853fa5c..fd8e5462a6dd90 100644 --- a/modular_skyrat/modules/hev_suit/code/hev_suit.dm +++ b/modular_skyrat/modules/hev_suit/code/hev_suit.dm @@ -621,16 +621,18 @@ var/sound_to_play - var/wound_series = new_wound.wound_series - var/wound_type = new_wound.wound_type + var/datum/wound_pregen_data/pregen_data = new_wound.get_pregen_data() var/wound_severity = new_wound.severity - if (wound_type == WOUND_SLASH || wound_type == WOUND_PIERCE) + var/is_laceration = pregen_data.wounding_types_valid(list(WOUND_SLASH, WOUND_PIERCE)) + var/is_fracture = pregen_data.wounding_types_valid(list(WOUND_BLUNT)) + + if (is_laceration) if (wound_severity >= WOUND_SEVERITY_SEVERE) sound_to_play = major_lacerations_sound else sound_to_play = minor_lacerations_sound - else if (wound_type == WOUND_BLUNT || wound_series == WOUND_SERIES_MUSCLE_DAMAGE) + else if (is_fracture) if (wound_severity >= WOUND_SEVERITY_SEVERE) sound_to_play = major_fracture_sound else diff --git a/modular_skyrat/modules/horrorform/code/true_changeling.dm b/modular_skyrat/modules/horrorform/code/true_changeling.dm index bc51c730b7df63..4765f9f9df6ebb 100644 --- a/modular_skyrat/modules/horrorform/code/true_changeling.dm +++ b/modular_skyrat/modules/horrorform/code/true_changeling.dm @@ -32,7 +32,6 @@ attack_verb_continuous = "rips into" attack_verb_simple = "rip into" attack_sound = 'sound/effects/blobattack.ogg' - next_move_modifier = 0.5 //Faster attacks butcher_results = list(/obj/item/food/meat/slab/human = 15) //It's a pretty big dude. Actually killing one is a feat. gold_core_spawnable = FALSE //Should stay exclusive to changelings tbh, otherwise makes it much less significant to sight one var/datum/action/innate/turn_to_human diff --git a/modular_skyrat/modules/hydra/code/neutral.dm b/modular_skyrat/modules/hydra/code/neutral.dm index e87de1a4bf25bc..aea55dcc14736e 100644 --- a/modular_skyrat/modules/hydra/code/neutral.dm +++ b/modular_skyrat/modules/hydra/code/neutral.dm @@ -16,8 +16,6 @@ spell.owner = hydra resetspell.Grant(hydra) resetspell.owner = hydra - hydra.name_archive = hydra.real_name - /datum/action/innate/hydra name = "Switch head" @@ -33,12 +31,16 @@ /datum/action/innate/hydrareset/Activate() var/mob/living/carbon/human/hydra = owner + if(!hydra.name_archive) // sets the archived 'real' name if not set. + hydra.name_archive = hydra.real_name hydra.real_name = hydra.name_archive hydra.visible_message(span_notice("[hydra.name] pushes all three heads forwards; they seem to be talking as a collective."), \ span_notice("You are now talking as [hydra.name_archive]!"), ignored_mobs=owner) /datum/action/innate/hydra/Activate() //Oops, all hydra! var/mob/living/carbon/human/hydra = owner + if(!hydra.name_archive) // sets the archived 'real' name if not set. + hydra.name_archive = hydra.real_name var/list/names = splittext(hydra.name_archive,"-") var/selhead = input("Who would you like to speak as?","Heads:") in names hydra.real_name = selhead diff --git a/modular_skyrat/modules/ices_events/code/ICES_event_config.dm b/modular_skyrat/modules/ices_events/code/ICES_event_config.dm index 7f4e2bfde6797f..bd49fc1de1753e 100644 --- a/modular_skyrat/modules/ices_events/code/ICES_event_config.dm +++ b/modular_skyrat/modules/ices_events/code/ICES_event_config.dm @@ -576,7 +576,7 @@ * Supermatter Surge */ /datum/round_event_control/supermatter_surge - max_occurrences = 2 + max_occurrences = 1 weight = MED_EVENT_FREQ /** diff --git a/modular_skyrat/modules/ices_events/code/events/ev_roleplay_check.dm b/modular_skyrat/modules/ices_events/code/events/ev_roleplay_check.dm new file mode 100644 index 00000000000000..d55fd75aeb3967 --- /dev/null +++ b/modular_skyrat/modules/ices_events/code/events/ev_roleplay_check.dm @@ -0,0 +1,13 @@ +/** + * Checks if a player meets certain conditions to exclude them from event selection. + */ +/proc/engaged_role_play_check(mob/living/carbon/human/player, station = TRUE, dorms = TRUE) + var/turf/player_turf = get_turf(player) + var/area/player_area = get_area(player_turf) + if(!is_station_level(player_turf.z) && station) + return TRUE + + if(istype(player_area, /area/station/commons/dorms) && dorms) + return TRUE + + return FALSE diff --git a/modular_skyrat/modules/interaction_menu/code/interaction_component.dm b/modular_skyrat/modules/interaction_menu/code/interaction_component.dm index fe3b6fea50d507..b6122decd070ee 100644 --- a/modular_skyrat/modules/interaction_menu/code/interaction_component.dm +++ b/modular_skyrat/modules/interaction_menu/code/interaction_component.dm @@ -77,6 +77,7 @@ var/list/data = list() var/list/descriptions = list() var/list/categories = list() + var/list/display_categories = list() var/list/colors = list() for(var/datum/interaction/interaction in interactions) if(!can_interact(interaction, user)) @@ -85,13 +86,15 @@ categories[interaction.category] = list(interaction.name) else categories[interaction.category] += interaction.name + var/list/sorted_category = sort_list(categories[interaction.category]) + categories[interaction.category] = sorted_category descriptions[interaction.name] = interaction.description colors[interaction.name] = interaction.color - data["categories"] = list() data["descriptions"] = descriptions data["colors"] = colors for(var/category in categories) - data["categories"] += category + display_categories += category + data["categories"] = sort_list(display_categories) data["ref_user"] = REF(user) data["ref_self"] = REF(self) data["self"] = self.name diff --git a/modular_skyrat/modules/layer_shift/code/mob_movement.dm b/modular_skyrat/modules/layer_shift/code/mob_movement.dm index 5725a349e52e08..2bc2ed4cdee594 100644 --- a/modular_skyrat/modules/layer_shift/code/mob_movement.dm +++ b/modular_skyrat/modules/layer_shift/code/mob_movement.dm @@ -1,7 +1,10 @@ -#define MOB_LAYER_SHIFT_INCREMENT 0.01 -#define MOB_LAYER_SHIFT_MIN 3.95 -//#define MOB_LAYER 4 // This is a byond standard define -#define MOB_LAYER_SHIFT_MAX 4.05 +#define MOB_LAYER_SHIFT_INCREMENT 1 +/// The amount by which layers are multiplied before being modified. +/// Helps avoiding floating point errors. +#define MOB_LAYER_MULTIPLIER 100 +#define MOB_LAYER_SHIFT_MIN 3.95 +//#define MOB_LAYER 4 // This is a byond standard define +#define MOB_LAYER_SHIFT_MAX 4.05 /mob/living/verb/layershift_up() set name = "Shift Layer Upwards" @@ -15,8 +18,8 @@ to_chat(src, span_warning("You cannot increase your layer priority any further.")) return - layer += MOB_LAYER_SHIFT_INCREMENT - var/layer_priority = (layer - MOB_LAYER) * 100 // Just for text feedback + layer = min(((layer * MOB_LAYER_MULTIPLIER) + MOB_LAYER_SHIFT_INCREMENT) / MOB_LAYER_MULTIPLIER, MOB_LAYER_SHIFT_MAX) + var/layer_priority = round(layer * MOB_LAYER_MULTIPLIER - MOB_LAYER * MOB_LAYER_MULTIPLIER, MOB_LAYER_SHIFT_INCREMENT) // Just for text feedback to_chat(src, span_notice("Your layer priority is now [layer_priority].")) /mob/living/verb/layershift_down() @@ -31,6 +34,6 @@ to_chat(src, span_warning("You cannot decrease your layer priority any further.")) return - layer -= MOB_LAYER_SHIFT_INCREMENT - var/layer_priority = (layer - MOB_LAYER) * 100 // Just for text feedback + layer = max(((layer * MOB_LAYER_MULTIPLIER) - MOB_LAYER_SHIFT_INCREMENT) / MOB_LAYER_MULTIPLIER, MOB_LAYER_SHIFT_MIN) + var/layer_priority = round(layer * MOB_LAYER_MULTIPLIER - MOB_LAYER * MOB_LAYER_MULTIPLIER, MOB_LAYER_SHIFT_INCREMENT) // Just for text feedback to_chat(src, span_notice("Your layer priority is now [layer_priority].")) diff --git a/modular_skyrat/modules/liquids/code/ocean_turfs.dm b/modular_skyrat/modules/liquids/code/ocean_turfs.dm index dc25e69d7dd48a..35066f098574b3 100644 --- a/modular_skyrat/modules/liquids/code/ocean_turfs.dm +++ b/modular_skyrat/modules/liquids/code/ocean_turfs.dm @@ -9,7 +9,7 @@ for(var/obj/structure/flora/plant in contents) qdel(plant) - var/turf/T = below() + var/turf/T = GET_TURF_BELOW(src) if(T) if(T.turf_flags & NO_RUINS) ChangeTurf(replacement_turf, null, CHANGETURF_IGNORE_AIR) diff --git a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_suit.dm b/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_suit.dm index 8f788249efc2be..27bad2580397ab 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_suit.dm +++ b/modular_skyrat/modules/loadouts/loadout_items/loadout_datum_suit.dm @@ -640,11 +640,6 @@ GLOBAL_LIST_INIT(loadout_exosuits, generate_loadout_items(/datum/loadout_item/su item_path = /obj/item/clothing/suit/toggle/jacket/supply restricted_roles = list(JOB_QUARTERMASTER, JOB_CARGO_TECHNICIAN, JOB_SHAFT_MINER, JOB_CUSTOMS_AGENT) -/datum/loadout_item/suit/supply_gorka_jacket - name = "Supply Gorka Jacket" - item_path = /obj/item/clothing/suit/gorka/supply - restricted_roles = list(JOB_QUARTERMASTER, JOB_CARGO_TECHNICIAN, JOB_SHAFT_MINER, JOB_CUSTOMS_AGENT) - /datum/loadout_item/suit/cargo_gorka_jacket name = "Cargo Gorka Jacket" item_path = /obj/item/clothing/suit/toggle/cargo_tech diff --git a/modular_skyrat/modules/loadouts/loadout_items/under/loadout_datum_under.dm b/modular_skyrat/modules/loadouts/loadout_items/under/loadout_datum_under.dm index 21ef8c9a2906ad..ad748c17e57d5a 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/under/loadout_datum_under.dm +++ b/modular_skyrat/modules/loadouts/loadout_items/under/loadout_datum_under.dm @@ -672,10 +672,6 @@ GLOBAL_LIST_INIT(loadout_miscunders, generate_loadout_items(/datum/loadout_item/ name = "Black Suitskirt" item_path = /obj/item/clothing/under/suit/black/skirt -/datum/loadout_item/under/formal/black_twopiece - name = "Black Two-Piece Suit" - item_path = /obj/item/clothing/under/suit/blacktwopiece - /datum/loadout_item/under/formal/black_lawyer_suit name = "Black Lawyer Suit" item_path = /obj/item/clothing/under/rank/civilian/lawyer/black diff --git a/modular_skyrat/modules/mapping/code/areas/station.dm b/modular_skyrat/modules/mapping/code/areas/station.dm index 8a310ece882613..8c24b2dcbec2e7 100644 --- a/modular_skyrat/modules/mapping/code/areas/station.dm +++ b/modular_skyrat/modules/mapping/code/areas/station.dm @@ -26,13 +26,13 @@ icon_state = "secure_bunker" // NT Consultant area -/area/command/heads_quarters/captain/private/nt_rep +/area/station/command/heads_quarters/nt_rep name = "Nanotrasen Consultant's Office" icon = 'modular_skyrat/modules/mapping/icons/areas/areas_station.dmi' icon_state = "nt_rep" -// BlueShield area -/area/blueshield +// Blueshield area +/area/station/command/heads_quarters/blueshield name = "Blueshield's Office" icon = 'modular_skyrat/modules/mapping/icons/areas/areas_station.dmi' icon_state = "blueshield" diff --git a/modular_skyrat/modules/mapping/code/interdyne_mining.dm b/modular_skyrat/modules/mapping/code/interdyne_mining.dm index 522b5cabe5bb73..860d17d104bde1 100644 --- a/modular_skyrat/modules/mapping/code/interdyne_mining.dm +++ b/modular_skyrat/modules/mapping/code/interdyne_mining.dm @@ -1,6 +1,6 @@ /obj/item/circuitboard/computer/order_console/mining/interdyne name = "Interdyne Mining Equipment Vendor Console" - build_path = /obj/machinery/computer/order_console/mining/golem + build_path = /obj/machinery/computer/order_console/mining/interdyne // Interdyne/DS-2 mining equipment vendor that doesn't need a cargo shuttle to work diff --git a/modular_skyrat/modules/mapping/code/lavaland_ruin_code.dm b/modular_skyrat/modules/mapping/code/lavaland_ruin_code.dm index 24b1c9abd96d71..c66faed0810c45 100644 --- a/modular_skyrat/modules/mapping/code/lavaland_ruin_code.dm +++ b/modular_skyrat/modules/mapping/code/lavaland_ruin_code.dm @@ -23,6 +23,7 @@ /datum/outfit/lavaland_syndicate name = "Interdyne Bioweapon Scientist" uniform = /obj/item/clothing/under/rank/rnd/scientist/skyrat/utility/syndicate + suit = /obj/item/clothing/suit/toggle/labcoat/interdyne ears = /obj/item/radio/headset/interdyne /datum/outfit/lavaland_syndicate/post_equip(mob/living/carbon/human/syndicate, visualsOnly = FALSE) diff --git a/modular_skyrat/modules/mapping/code/wardrobes.dm b/modular_skyrat/modules/mapping/code/wardrobes.dm index 81a1d86f681c42..bfb7e2621d3757 100644 --- a/modular_skyrat/modules/mapping/code/wardrobes.dm +++ b/modular_skyrat/modules/mapping/code/wardrobes.dm @@ -37,12 +37,17 @@ /obj/item/clothing/under/syndicate/skyrat/maid = 5, /obj/item/clothing/gloves/combat/maid = 5, /obj/item/clothing/head/costume/maidheadband/syndicate = 5, - /obj/item/storage/box/nif_ghost_box = 10, + /obj/item/storage/box/nif_ghost_box/ghost_role = 10, ) refill_canister = /obj/item/vending_refill/wardrobe/syndie_wardrobe light_color = COLOR_MOSTLY_PURE_RED +/obj/machinery/vending/wardrobe/syndie_wardrobe/ghost_cafe + excluded_products = list( + /obj/item/storage/box/nif_ghost_box/ghost_role, + ) + /obj/item/vending_refill/wardrobe/syndie_wardrobe machine_name = "SynDrobe" diff --git a/modular_skyrat/modules/marines/code/smartgun.dm b/modular_skyrat/modules/marines/code/smartgun.dm index a31cf1a6bc0292..1927413f51b018 100644 --- a/modular_skyrat/modules/marines/code/smartgun.dm +++ b/modular_skyrat/modules/marines/code/smartgun.dm @@ -118,7 +118,6 @@ /obj/item/ammo_casing/smart firing_effect_type = null - is_cased_ammo = FALSE /obj/item/ammo_casing/smart/Initialize(mapload) . = ..() diff --git a/modular_skyrat/modules/medical/code/grasp.dm b/modular_skyrat/modules/medical/code/grasp.dm index 8fbc3c407bed23..808732c5572aa8 100644 --- a/modular_skyrat/modules/medical/code/grasp.dm +++ b/modular_skyrat/modules/medical/code/grasp.dm @@ -1,5 +1,5 @@ /mob/living/carbon/proc/self_grasp_bleeding_limb(obj/item/bodypart/grasped_part, supress_message = FALSE) - if(!grasped_part?.get_modified_bleed_rate()) + if(!grasped_part?.can_be_grasped()) return var/starting_hand_index = active_hand_index if(starting_hand_index == grasped_part.held_index) diff --git a/modular_skyrat/modules/medical/code/health_analyzer.dm b/modular_skyrat/modules/medical/code/health_analyzer.dm new file mode 100644 index 00000000000000..1d7eba6198f3e7 --- /dev/null +++ b/modular_skyrat/modules/medical/code/health_analyzer.dm @@ -0,0 +1,11 @@ +/// If TRUE, this analyzer can be used for medibot construction. If FALSE, it cannot. Returns TRUE by default. +/obj/item/healthanalyzer/proc/can_be_used_in_medibot() + return TRUE + +/obj/item/healthanalyzer/no_medibot + name = "surplus health analyzer" + desc = "A hand-held body scanner capable of distinguishing vital signs of the subject. Has a side button to scan for chemicals, and can be toggled to scan wounds. \ + This one seems to lack the mounting braces usually found on medibot-compatable analyzers..." + +/obj/item/healthanalyzer/no_medibot/can_be_used_in_medibot() + return FALSE diff --git a/modular_skyrat/modules/medical/code/wounds/muscle.dm b/modular_skyrat/modules/medical/code/wounds/muscle.dm index 7c6b0e11b3b42a..c1f9c3fc4c3515 100644 --- a/modular_skyrat/modules/medical/code/wounds/muscle.dm +++ b/modular_skyrat/modules/medical/code/wounds/muscle.dm @@ -6,66 +6,33 @@ /datum/wound/muscle name = "Muscle Wound" sound_effect = 'sound/effects/wounds/blood1.ogg' - wound_type = WOUND_BLUNT wound_flags = (ACCEPTS_GAUZE | SPLINT_OVERLAY) - wound_series = WOUND_SERIES_MUSCLE_DAMAGE - processes = TRUE /// How much do we need to regen. Will regen faster if we're splinted and or laying down var/regen_ticks_needed /// Our current counter for healing var/regen_ticks_current = 0 + can_scar = FALSE + /datum/wound_pregen_data/muscle abstract = TRUE viable_zones = list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) required_limb_biostate = BIO_FLESH -/datum/wound_pregen_data/muscle/can_be_applied_to(obj/item/bodypart/limb, wound_type, datum/wound/old_wound, random_roll) - if (!istype(limb) || !limb.owner) - return FALSE - - if (random_roll && !can_be_randomly_generated) - return FALSE - - if (HAS_TRAIT(limb.owner, TRAIT_NEVER_WOUNDED) || (limb.owner.status_flags & GODMODE)) - return FALSE - // THIS IS HIGHLY TEMPORARY A PROC WILL COME FROM UPSTREAM THAT SHOULD REPLACE THIS!! REPLACE IT!!!!!!!!!!!! REMOVE THE OVERRIDE 8/31/23 ~Niko - if (wound_type != (WOUND_BLUNT) && wound_type != (WOUND_SLASH) && wound_type != (WOUND_PIERCE)) - return FALSE - else - for (var/datum/wound/preexisting_wound as anything in limb.wounds) - if (preexisting_wound.wound_series == initial(wound_path_to_generate.wound_series)) - if (preexisting_wound.severity >= initial(wound_path_to_generate.severity)) - return FALSE + required_wounding_types = list(WOUND_BLUNT, WOUND_SLASH, WOUND_PIERCE) + match_all_wounding_types = FALSE - if (!ignore_cannot_bleed && ((required_limb_biostate & BIO_BLOODED) && !limb.can_bleed())) - return FALSE - - if (!biostate_valid(limb.biological_state)) - return FALSE - - if (!(limb.body_zone in viable_zones)) - return FALSE + wound_series = WOUND_SERIES_MUSCLE_DAMAGE - // we accept promotions and demotions, but no point in redundancy. This should have already been checked wherever the wound was rolled and applied for (see: bodypart damage code), but we do an extra check - // in case we ever directly add wounds - if (!duplicates_allowed) - for (var/datum/wound/preexisting_wound as anything in limb.wounds) - if (preexisting_wound.type == wound_path_to_generate && (preexisting_wound != old_wound)) - return FALSE - return TRUE + weight = 3 // very low chance to replace a normal wound. this is about 4.5% /* Overwriting of base procs */ /datum/wound/muscle/wound_injury(datum/wound/old_wound = null, attack_direction) - // hook into gaining/losing gauze so crit muscle wounds can re-enable/disable depending if they're slung or not - RegisterSignals(limb, list(COMSIG_BODYPART_SPLINTED, COMSIG_BODYPART_SPLINT_DESTROYED), PROC_REF(update_inefficiencies)) - - RegisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(attack_with_hurt_hand)) if(limb.held_index && victim.get_item_for_held_index(limb.held_index) && (disabling || prob(30 * severity))) var/obj/item/I = victim.get_item_for_held_index(limb.held_index) if(istype(I, /obj/item/offhand)) @@ -74,14 +41,19 @@ if(I && victim.dropItemToGround(I)) victim.visible_message(span_danger("[victim] drops [I] in shock!"), span_warning("The force on your [parse_zone(limb.body_zone)] causes you to drop [I]!"), vision_distance=COMBAT_MESSAGE_RANGE) - update_inefficiencies() + return ..() + +/datum/wound/muscle/set_victim(new_victim) + if (victim) + UnregisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK) + + if (new_victim) + RegisterSignal(new_victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(attack_with_hurt_hand)) + + return ..() /datum/wound/muscle/remove_wound(ignore_limb, replaced) limp_slowdown = 0 - if(limb) - UnregisterSignal(limb, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED)) - if(victim) - UnregisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK) return ..() /datum/wound/muscle/handle_process() @@ -149,43 +121,17 @@ return "[msg.Join()]" -/* - Common procs mostly copied from bone wounds, as their behaviour is very similar -*/ - -/datum/wound/muscle/proc/update_inefficiencies() - SIGNAL_HANDLER - if(limb.body_zone in list(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) - if(limb.current_gauze) - limp_slowdown = initial(limp_slowdown) * limb.current_gauze.splint_factor - else - limp_slowdown = initial(limp_slowdown) - victim.apply_status_effect(/datum/status_effect/limp) - else if(limb.body_zone in list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) - if(limb.current_gauze) - interaction_efficiency_penalty = 1 + ((interaction_efficiency_penalty - 1) * limb.current_gauze.splint_factor) - else - interaction_efficiency_penalty = interaction_efficiency_penalty - - if(initial(disabling)) - if(limb.current_gauze) - set_disabling(FALSE) - else - set_disabling(TRUE) - - limb.update_wounds() - /// Moderate (Muscle Tear) /datum/wound/muscle/moderate name = "Muscle Tear" desc = "Patient's muscle has torn, causing serious pain and reduced limb functionality." - treat_text = "Recommended rest and sleep, or splinting the limb." + treat_text = "A tight splint on the affected limb, as well as plenty of rest and sleep." examine_desc = "appears unnaturallly red and swollen" occur_text = "swells up, it's skin turning red" severity = WOUND_SEVERITY_MODERATE interaction_efficiency_penalty = 1.5 limp_slowdown = 2 - threshold_minimum = 35 + limp_chance = 30 threshold_penalty = 15 status_effect_type = /datum/status_effect/wound/muscle/moderate regen_ticks_needed = 90 @@ -194,6 +140,7 @@ abstract = FALSE wound_path_to_generate = /datum/wound/muscle/moderate + threshold_minimum = 35 /* Severe (Ruptured Tendon) @@ -203,13 +150,13 @@ name = "Ruptured Tendon" sound_effect = 'sound/effects/wounds/blood2.ogg' desc = "Patient's tendon has been severed, causing significant pain and near uselessness of limb." - treat_text = "Recommended rest and sleep aswell as splinting the limb." + treat_text = "A tight splint on the affected limb, as well as plenty of rest and sleep." examine_desc = "is limp and awkwardly twitching, skin swollen and red" occur_text = "twists in pain and goes limp, it's tendon ruptured" severity = WOUND_SEVERITY_SEVERE interaction_efficiency_penalty = 2 limp_slowdown = 5 - threshold_minimum = 80 + limp_chance = 40 threshold_penalty = 35 disabling = TRUE status_effect_type = /datum/status_effect/wound/muscle/severe @@ -219,42 +166,10 @@ abstract = FALSE wound_path_to_generate = /datum/wound/muscle/severe - -/datum/status_effect/wound/muscle - -/datum/status_effect/wound/muscle/on_apply() - . = ..() - RegisterSignal(owner, COMSIG_MOB_SWAP_HANDS, PROC_REF(on_swap_hands)) - on_swap_hands() - -/datum/status_effect/wound/muscle/on_remove() - . = ..() - UnregisterSignal(owner, COMSIG_MOB_SWAP_HANDS) - var/mob/living/carbon/wound_owner = owner - wound_owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/muscle_wound) - -/datum/status_effect/wound/muscle/proc/on_swap_hands() - SIGNAL_HANDLER - - var/mob/living/carbon/wound_owner = owner - if(wound_owner.get_active_hand() == linked_limb) - wound_owner.add_actionspeed_modifier(/datum/actionspeed_modifier/muscle_wound, (linked_wound.interaction_efficiency_penalty - 1)) - else - wound_owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/muscle_wound) - -/datum/status_effect/wound/muscle/nextmove_modifier() - var/mob/living/carbon/C = owner - - if(C.get_active_hand() == linked_limb) - return linked_wound.interaction_efficiency_penalty - - return 1 + threshold_minimum = 80 // muscle /datum/status_effect/wound/muscle/moderate id = "torn muscle" /datum/status_effect/wound/muscle/severe id = "ruptured tendon" - -/datum/actionspeed_modifier/muscle_wound - variable = TRUE diff --git a/modular_skyrat/modules/mentor/code/client_procs.dm b/modular_skyrat/modules/mentor/code/client_procs.dm index af6ecae38e4a6d..8c83b8c615ef8d 100644 --- a/modular_skyrat/modules/mentor/code/client_procs.dm +++ b/modular_skyrat/modules/mentor/code/client_procs.dm @@ -44,6 +44,13 @@ cmd_mentor_dementor() -/client/proc/is_mentor() // admins are mentors too. - if(mentor_datum || check_rights_for(src, R_ADMIN)) +/** + * Returns whether or not the user is qualified as a mentor. + * + * Arguments: + * * admin_bypass - Whether or not admins can succeed this check, even if they + * do not actually possess the role. Defaults to `TRUE`. + */ +/client/proc/is_mentor(admin_bypass = TRUE) + if(mentor_datum || (admin_bypass && check_rights_for(src, R_ADMIN))) return TRUE diff --git a/modular_skyrat/modules/microfusion/code/projectiles.dm b/modular_skyrat/modules/microfusion/code/projectiles.dm index c1f0a5f908ea99..6e90ebfda46888 100644 --- a/modular_skyrat/modules/microfusion/code/projectiles.dm +++ b/modular_skyrat/modules/microfusion/code/projectiles.dm @@ -16,7 +16,7 @@ /obj/projectile/beam/laser/microfusion name = "microfusion laser" icon = 'modular_skyrat/modules/microfusion/icons/projectiles.dmi' - damage = 20 + damage = 25 /obj/projectile/beam/microfusion_disabler name = "microfusion disabler laser" @@ -36,7 +36,7 @@ /obj/projectile/beam/laser/microfusion/superheated name = "superheated microfusion laser" icon_state = "laser_greyscale" - damage = 15 //Trading damage for fire stacks + damage = 20 //Trading damage for fire stacks color = LIGHT_COLOR_FIRE light_color = LIGHT_COLOR_FIRE @@ -51,7 +51,7 @@ name = "hellfire microfusion laser" icon_state = "laser_greyscale" wound_bonus = 0 - damage = 15 // You are trading damage for a significant wound bonus and speed increase + damage = 20 // You are trading damage for a significant wound bonus and speed increase speed = 0.6 color = LIGHT_COLOR_FLARE light_color = LIGHT_COLOR_FLARE @@ -63,16 +63,16 @@ name = "scatter microfusion laser" /obj/projectile/beam/laser/microfusion/repeater - damage = 10 + damage = 12.5 /obj/projectile/beam/laser/microfusion/penetrator name = "focused microfusion laser" - damage = 15 + damage = 20 armour_penetration = 50 /obj/projectile/beam/laser/microfusion/lance name = "lance microfusion laser" - damage = 40 // We're turning the gun into a heavylaser + damage = 50 // We're turning the gun into a heavylaser tracer_type = /obj/effect/projectile/tracer/heavy_laser muzzle_type = /obj/effect/projectile/muzzle/heavy_laser impact_type = /obj/effect/projectile/impact/heavy_laser @@ -91,7 +91,7 @@ color = COLOR_VIVID_YELLOW light_color = COLOR_VIVID_YELLOW damage_type = STAMINA - damage = 20 + damage = 25 armor_flag = ENERGY hitsound = 'sound/misc/slip.ogg' impact_type = /obj/effect/projectile/impact/disabler diff --git a/modular_skyrat/modules/modular_implants/code/nifs.dm b/modular_skyrat/modules/modular_implants/code/nifs.dm index 18944df55f70b5..69c0a581c3594c 100644 --- a/modular_skyrat/modules/modular_implants/code/nifs.dm +++ b/modular_skyrat/modules/modular_implants/code/nifs.dm @@ -497,13 +497,16 @@ /obj/item/storage/box/nif_ghost_box/PopulateContents() new /obj/item/autosurgeon/organ/nif/ghost_role(src) - new /obj/item/disk/nifsoft_uploader/hivemind(src) new /obj/item/disk/nifsoft_uploader/shapeshifter(src) new /obj/item/disk/nifsoft_uploader/summoner(src) new /obj/item/disk/nifsoft_uploader/money_sense(src) new /obj/item/disk/nifsoft_uploader/dorms(src) new /obj/item/disk/nifsoft_uploader/soulcatcher(src) +/obj/item/storage/box/nif_ghost_box/ghost_role/PopulateContents() + . = ..() + new /obj/item/disk/nifsoft_uploader/hivemind(src) + #undef NIF_CALIBRATION_STAGE_1 #undef NIF_CALIBRATION_STAGE_1_END #undef NIF_CALIBRATION_STAGE_2 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/human.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/human.dm index ce6aa14dfb2290..c861b924d6f3f6 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/human.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/human.dm @@ -209,6 +209,21 @@ else return TRUE +/// Returns true if the human has accessible tail for the parameter. Accepts any of the `REQUIRE_GENITAL_` defines. +/mob/living/carbon/human/proc/has_tail(required_state = REQUIRE_GENITAL_ANY) + var/obj/item/organ/genital = get_organ_slot(ORGAN_SLOT_TAIL) + if(!genital) + return FALSE + + switch(required_state) + if(REQUIRE_GENITAL_ANY) + return TRUE + if(REQUIRE_GENITAL_EXPOSED) + return !get_item_by_slot(ORGAN_SLOT_TAIL) + if(REQUIRE_GENITAL_UNEXPOSED) + return get_item_by_slot(ORGAN_SLOT_TAIL) + else + return TRUE /* * This code needed for changing character's gender by chems @@ -363,3 +378,7 @@ if(wear_suit && istype(wear_suit, /obj/item/clothing/suit/straight_jacket/kinky_sleepbag)) return FALSE ..() + +/// Checks if the tail is exposed. +/obj/item/organ/external/tail/proc/is_exposed() + return TRUE // your tail is always exposed, dummy! why are you checking this diff --git a/modular_skyrat/modules/modular_vending/code/wardrobes.dm b/modular_skyrat/modules/modular_vending/code/wardrobes.dm index 8cf3fb0f6da247..e5f3e0210e7c9d 100644 --- a/modular_skyrat/modules/modular_vending/code/wardrobes.dm +++ b/modular_skyrat/modules/modular_vending/code/wardrobes.dm @@ -43,7 +43,6 @@ /obj/item/clothing/under/rank/cargo/tech/skyrat/turtleneck/skirt = 3, /obj/item/clothing/under/rank/cargo/tech/skyrat/utility = 3, /obj/item/clothing/under/rank/cargo/tech/skyrat/casualman = 3, - /obj/item/clothing/suit/gorka/supply = 3, /obj/item/clothing/suit/toggle/jacket/supply = 3, /obj/item/clothing/glasses/hud/gun_permit = 5, //from company imports module /obj/item/storage/backpack/messenger = 3, @@ -62,6 +61,9 @@ /obj/item/clothing/mask/breath = 2, /obj/item/reagent_containers/cup/bottle/morphine = 2, /obj/item/reagent_containers/syringe = 2, + /obj/item/bonesetter = 2, // for dislocations + /obj/item/stack/medical/gauze = 4, // for ALL wounds + /obj/item/healthanalyzer/no_medibot = 2, // disallows medibot use so its not wasted immediately on medibots /obj/item/storage/backpack/science/robo = 2, /obj/item/storage/backpack/satchel/science/robo = 2, /obj/item/storage/backpack/duffelbag/science/robo = 2, diff --git a/modular_skyrat/modules/modular_weapons/code/energy.dm b/modular_skyrat/modules/modular_weapons/code/energy.dm index 247a9a82ba5e86..550af2c130eff8 100644 --- a/modular_skyrat/modules/modular_weapons/code/energy.dm +++ b/modular_skyrat/modules/modular_weapons/code/energy.dm @@ -219,7 +219,7 @@ icon = 'modular_skyrat/modules/modular_weapons/icons/obj/ammo.dmi' icon_state = "plasma_shell" worn_icon_state = "shell" - caliber = "Beam Shell" + caliber = CALIBER_LASER custom_materials = list(/datum/material/iron=SHEET_MATERIAL_AMOUNT * 2,/datum/material/plasma=HALF_SHEET_MATERIAL_AMOUNT) projectile_type = /obj/projectile/beam/laser/single @@ -228,7 +228,6 @@ desc = "A chemical mixture that once triggered, creates a deadly projectile, melting it's own casing in the process." icon_state = "plasma_shell2" worn_icon_state = "shell" - caliber = "Beam Shell" custom_materials = list(/datum/material/iron=SHEET_MATERIAL_AMOUNT * 2,/datum/material/plasma=HALF_SHEET_MATERIAL_AMOUNT) projectile_type = /obj/projectile/beam/laser/double @@ -237,7 +236,6 @@ desc = "A chemical mixture that once triggered, creates a deadly bouncing projectile, melting it's own casing in the process." icon_state = "bounce_shell" worn_icon_state = "shell" - caliber = "Beam Shell" custom_materials = list(/datum/material/iron=SHEET_MATERIAL_AMOUNT * 2,/datum/material/plasma=HALF_SHEET_MATERIAL_AMOUNT) projectile_type = /obj/projectile/beam/laser/bounce diff --git a/modular_skyrat/modules/modular_weapons/code/melee.dm b/modular_skyrat/modules/modular_weapons/code/melee.dm index e2b633a9c1eacb..8165a798a6fd79 100644 --- a/modular_skyrat/modules/modular_weapons/code/melee.dm +++ b/modular_skyrat/modules/modular_weapons/code/melee.dm @@ -1,4 +1,5 @@ -// Cargo Sabres +// Sabres, including the cargo variety + /obj/item/storage/belt/sabre/cargo name = "authentic shamshir leather sheath" desc = "A good-looking sheath that is advertised as being made of real Venusian black leather. It feels rather plastic-like to the touch, and it looks like it's made to fit a British cavalry sabre." @@ -9,6 +10,11 @@ new /obj/item/melee/sabre/cargo(src) update_appearance() +/obj/item/melee/sabre + force = 20 // Original: 15 + wound_bonus = 5 // Original: 10 + bare_wound_bonus = 20 // Original: 25 Both down slightly, to make up for the damage buff, since it'd get a bit wacky ontop of the armor pen. + /obj/item/melee/sabre/cargo name = "authentic shamshir sabre" desc = "An expertly crafted historical human sword once used by the Persians which has recently gained traction due to Venusian historal recreation sports. One small flaw, the Taj-based company who produces these has mistaken them for British cavalry sabres akin to those used by high ranking Nanotrasen officials. Atleast it cuts the same way!" @@ -18,6 +24,7 @@ block_chance = 20 armour_penetration = 25 + // This is here so that people can't buy the Sabres and craft them into powercrepes /datum/crafting_recipe/food/powercrepe blacklist = list(/obj/item/melee/sabre/cargo) diff --git a/modular_skyrat/modules/mold/code/mold_disease.dm b/modular_skyrat/modules/mold/code/mold_disease.dm index 4e008aa3a54930..8778e469becbd0 100644 --- a/modular_skyrat/modules/mold/code/mold_disease.dm +++ b/modular_skyrat/modules/mold/code/mold_disease.dm @@ -63,7 +63,7 @@ to_chat(affected_mob, span_danger("[pick("You feel uncomfortably hot...", "You feel like unzipping your jumpsuit", "You feel like taking off some clothes...")]")) affected_mob.adjust_bodytemperature(30) if(SPT_PROB(5, seconds_per_tick)) - affected_mob.vomit(20) + affected_mob.vomit(vomit_flags = VOMIT_CATEGORY_DEFAULT, lost_nutrition = 20) /datum/reagent/cryptococcus_spores name = "Cryptococcus gattii microbes" diff --git a/modular_skyrat/modules/morenarcotics/code/cocaine_item.dm b/modular_skyrat/modules/morenarcotics/code/cocaine_item.dm index 4673264c92db24..2a4da011635738 100644 --- a/modular_skyrat/modules/morenarcotics/code/cocaine_item.dm +++ b/modular_skyrat/modules/morenarcotics/code/cocaine_item.dm @@ -52,7 +52,7 @@ if(covered) to_chat(user, span_warning("You have to remove your [covered] first!")) return - user.visible_message(span_notice("'[user] starts snorting the [src].")) + user.visible_message(span_notice("[user] starts snorting the [src].")) if(do_after(user, 30)) to_chat(user, span_notice("You finish snorting the [src].")) if(reagents.total_volume) diff --git a/modular_skyrat/modules/moretraitoritems/code/mafioso.dm b/modular_skyrat/modules/moretraitoritems/code/mafioso.dm index bc58e789153099..e07039ded74b84 100644 --- a/modular_skyrat/modules/moretraitoritems/code/mafioso.dm +++ b/modular_skyrat/modules/moretraitoritems/code/mafioso.dm @@ -13,10 +13,10 @@ acid = 30 wound = 20 -/obj/item/clothing/under/suit/blacktwopiece/armoured - armor_type = /datum/armor/clothing_under/blacktwopiece_armoured +/obj/item/clothing/under/suit/black/armoured + armor_type = /datum/armor/clothing_under/black_armoured -/datum/armor/clothing_under/blacktwopiece_armoured +/datum/armor/clothing_under/black_armoured melee = 10 bullet = 10 laser = 10 diff --git a/modular_skyrat/modules/moretraitoritems/code/syndicate_loadout.dm b/modular_skyrat/modules/moretraitoritems/code/syndicate_loadout.dm index 8a49d1b6cf582d..2df1919fbbffe8 100644 --- a/modular_skyrat/modules/moretraitoritems/code/syndicate_loadout.dm +++ b/modular_skyrat/modules/moretraitoritems/code/syndicate_loadout.dm @@ -188,7 +188,7 @@ new /obj/item/gun/ballistic/automatic/tommygun(src) new /obj/item/ammo_box/magazine/tommygunm45(src) new /obj/item/clothing/suit/jacket/det_suit/noir/mafioso(src) - new /obj/item/clothing/under/suit/blacktwopiece/armoured(src) + new /obj/item/clothing/under/suit/black/armoured(src) new /obj/item/clothing/mask/fakemoustache/italian(src) new /obj/item/switchblade(src) new /obj/item/clothing/shoes/laceup(src) diff --git a/modular_skyrat/modules/nanotrasen_rep/code/nanotrasen_consultant.dm b/modular_skyrat/modules/nanotrasen_rep/code/nanotrasen_consultant.dm index 12d2406d0b7d22..b9126f3a3a5940 100644 --- a/modular_skyrat/modules/nanotrasen_rep/code/nanotrasen_consultant.dm +++ b/modular_skyrat/modules/nanotrasen_rep/code/nanotrasen_consultant.dm @@ -73,14 +73,14 @@ id_trim = /datum/id_trim/job/nanotrasen_consultant /obj/item/radio/headset/heads/nanotrasen_consultant - name = "\proper the nanotrasen consultant's headset" + name = "\proper the Nanotrasen consultant's headset" desc = "An official Central Command headset." icon_state = "cent_headset" keyslot = new /obj/item/encryptionkey/headset_com keyslot2 = new /obj/item/encryptionkey/headset_cent /obj/item/radio/headset/heads/nanotrasen_consultant/alt - name = "\proper the nanotrasen consultant's bowman headset" + name = "\proper the Nanotrasen consultant's bowman headset" desc = "An official Central Command headset. Protects ears from flashbangs." icon_state = "cent_headset_alt" @@ -126,6 +126,27 @@ new /obj/item/ammo_box/magazine/m45a5(src) new /obj/item/ammo_box/magazine/m45a5(src) +/obj/item/storage/bag/garment/nanotrasen_consultant + name = "Nanotrasen consultant's garment bag" + desc = "A bag for storing extra clothes and shoes. This one belongs to the Nanotrasen consultant." + +/obj/item/storage/bag/garment/nanotrasen_consultant/PopulateContents() + new /obj/item/clothing/shoes/sneakers/brown(src) + new /obj/item/clothing/glasses/sunglasses/gar/giga(src) + new /obj/item/clothing/gloves/combat(src) + new /obj/item/clothing/gloves/combat/naval/nanotrasen_consultant(src) + new /obj/item/clothing/suit/hooded/wintercoat/centcom/nt_consultant(src) + new /obj/item/clothing/under/rank/nanotrasen_consultant(src) + new /obj/item/clothing/under/rank/nanotrasen_consultant/skirt(src) + new /obj/item/clothing/under/rank/centcom/officer(src) + new /obj/item/clothing/under/rank/centcom/officer_skirt(src) + new /obj/item/clothing/head/nanotrasen_consultant(src) + new /obj/item/clothing/head/nanotrasen_consultant/beret(src) + new /obj/item/clothing/head/beret/centcom_formal/nt_consultant(src) + new /obj/item/clothing/head/hats/centhat(src) + new /obj/item/clothing/suit/armor/centcom_formal/nt_consultant(src) + new /obj/item/clothing/under/rank/centcom/intern(src) + new /obj/item/clothing/head/hats/intern(src) /obj/structure/closet/secure_closet/nanotrasen_consultant/station name = "\proper nanotrasen consultant's locker" @@ -139,14 +160,10 @@ new /obj/item/storage/backpack/satchel/leather(src) new /obj/item/clothing/neck/petcollar(src) new /obj/item/pet_carrier(src) - new /obj/item/clothing/shoes/sneakers/brown(src) new /obj/item/clothing/suit/armor/vest(src) new /obj/item/computer_disk/command/captain(src) new /obj/item/radio/headset/heads/nanotrasen_consultant/alt(src) new /obj/item/radio/headset/heads/nanotrasen_consultant(src) - new /obj/item/clothing/glasses/sunglasses/gar/giga(src) - new /obj/item/clothing/gloves/combat(src) - new /obj/item/clothing/gloves/combat/naval/nanotrasen_consultant(src) new /obj/item/storage/photo_album/personal(src) new /obj/item/bedsheet/centcom(src) - new /obj/item/clothing/suit/hooded/wintercoat/centcom/nt_consultant(src) + new /obj/item/storage/bag/garment/nanotrasen_consultant(src) diff --git a/modular_skyrat/modules/player_ranks/code/subsystem/player_ranks.dm b/modular_skyrat/modules/player_ranks/code/subsystem/player_ranks.dm index 8e20fcda771360..264d9f8bedce84 100644 --- a/modular_skyrat/modules/player_ranks/code/subsystem/player_ranks.dm +++ b/modular_skyrat/modules/player_ranks/code/subsystem/player_ranks.dm @@ -46,15 +46,17 @@ SUBSYSTEM_DEF(player_ranks) * * Arguments: * * user - The client to verify the donator status of. + * * admin_bypass - Whether or not admins can succeed this check, even if they + * do not actually possess the role. Defaults to `TRUE`. */ -/datum/controller/subsystem/player_ranks/proc/is_donator(client/user) +/datum/controller/subsystem/player_ranks/proc/is_donator(client/user, admin_bypass = TRUE) if(!istype(user)) CRASH("Invalid user type provided to is_donator(), expected 'client' and obtained '[user ? user.type : "null"]'.") if(GLOB.donator_list[user.ckey]) return TRUE - if(is_admin(user)) + if(admin_bypass && is_admin(user)) return TRUE return FALSE @@ -66,12 +68,14 @@ SUBSYSTEM_DEF(player_ranks) * * Arguments: * * user - The client to verify the mentor status of. + * * admin_bypass - Whether or not admins can succeed this check, even if they + * do not actually possess the role. Defaults to `TRUE`. */ -/datum/controller/subsystem/player_ranks/proc/is_mentor(client/user) +/datum/controller/subsystem/player_ranks/proc/is_mentor(client/user, admin_bypass = TRUE) if(!istype(user)) CRASH("Invalid user type provided to is_mentor(), expected 'client' and obtained '[user ? user.type : "null"]'.") - return user.is_mentor() + return user.is_mentor(admin_bypass) /** @@ -79,15 +83,17 @@ SUBSYSTEM_DEF(player_ranks) * * Arguments: * * user - The client to verify the veteran status of. + * * admin_bypass - Whether or not admins can succeed this check, even if they + * do not actually possess the role. Defaults to `TRUE`. */ -/datum/controller/subsystem/player_ranks/proc/is_veteran(client/user) +/datum/controller/subsystem/player_ranks/proc/is_veteran(client/user, admin_bypass = TRUE) if(!istype(user)) CRASH("Invalid user type provided to is_veteran(), expected 'client' and obtained '[user ? user.type : "null"]'.") if(GLOB.veteran_list[user.ckey]) return TRUE - if(is_admin(user)) + if(admin_bypass && is_admin(user)) return TRUE return FALSE diff --git a/modular_skyrat/modules/poly_commands/parrot.dm b/modular_skyrat/modules/poly_commands/parrot.dm index df8c73ef882634..f522edf7da11bf 100644 --- a/modular_skyrat/modules/poly_commands/parrot.dm +++ b/modular_skyrat/modules/poly_commands/parrot.dm @@ -12,7 +12,7 @@ /mob/living/simple_animal/parrot/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, list/message_mods = list(), message_range) . = ..() - if(check_command(message, speaker)) + if(check_command(raw_message, speaker)) return if(speaker != src && prob(50)) //Dont imitate ourselves if(!radio_freq || prob(10)) @@ -20,7 +20,7 @@ speech_buffer -= pick(speech_buffer) speech_buffer |= html_decode(raw_message) if(speaker == src && !client) //If a parrot squawks in the woods and no one is around to hear it, does it make a sound? This code says yes! - return message + return raw_message /mob/living/simple_animal/parrot/proc/perch_on_human(mob/living/carbon/human/human_target) if(!human_target) @@ -61,30 +61,30 @@ /mob/living/simple_animal/parrot/poly/proc/command_perch(mob/living/carbon/human/human_target) if (!buckled) buckled_to_human = FALSE - if(human_target.buckled_mobs?.len >= human_target.max_buckled_mobs) + if(LAZYLEN(human_target.buckled_mobs) >= human_target.max_buckled_mobs) return if(buckled_to_human) - emote("me", EMOTE_VISIBLE, "gives [human_target] a confused look, squawking softly.") + manual_emote("gives [human_target] a confused look, squawking softly.") return if(get_dist(src, human_target) > 1 || buckled) // Only adjacent - emote("me", EMOTE_VISIBLE, "tilts their head at [human_target], before bawking loudly and staying put.") + manual_emote("tilts their head at [human_target], before bawking loudly and staying put.") return - emote("me", EMOTE_VISIBLE, "obediently hops up onto [human_target]'s shoulder, spreading their wings for a moment before settling down.") + manual_emote("obediently hops up onto [human_target]'s shoulder, spreading their wings for a moment before settling down.") perch_on_human(human_target) /mob/living/simple_animal/parrot/poly/proc/command_hop_off(mob/living/carbon/human/human_target) if (!buckled) buckled_to_human = FALSE if(!buckled_to_human || !buckled) - emote("me", EMOTE_VISIBLE, "gives [human_target] a confused look, squawking softly.") + manual_emote("gives [human_target] a confused look, squawking softly.") return icon_state = icon_living parrot_state = PARROT_WANDER if(buckled) - to_chat(src, span_notice("You are no longer sitting on [buckled].")) + to_chat(src, span_notice("You are no longer sitting on [human_target].")) buckled.unbuckle_mob(src, TRUE) - emote("me", EMOTE_VISIBLE, "squawks and hops off of [buckled], flying away.") + manual_emote("squawks and hops off of [human_target], flying away.") buckled = null buckled_to_human = FALSE pixel_x = initial(pixel_x) diff --git a/modular_skyrat/modules/primitive_cooking_additions/code/big_mortar.dm b/modular_skyrat/modules/primitive_cooking_additions/code/big_mortar.dm index 3639e7005db5b5..3c2fc629a79619 100644 --- a/modular_skyrat/modules/primitive_cooking_additions/code/big_mortar.dm +++ b/modular_skyrat/modules/primitive_cooking_additions/code/big_mortar.dm @@ -138,14 +138,14 @@ ///Juices the passed target item, and transfers any contained chems to the mortar as well /obj/structure/large_mortar/proc/juice_target_item(obj/item/to_be_juiced, mob/living/carbon/human/user) - to_be_juiced.juice(src, user) + to_be_juiced.juice(src.reagents, user) to_chat(user, span_notice("You juice [to_be_juiced] into a liquid.")) QDEL_NULL(to_be_juiced) ///Grinds the passed target item, and transfers any contained chems to the mortar as well /obj/structure/large_mortar/proc/grind_target_item(obj/item/to_be_ground, mob/living/carbon/human/user) - to_be_ground.grind(src, user) + to_be_ground.grind(src.reagents, user) to_chat(user, span_notice("You break [to_be_ground] into a fine powder.")) QDEL_NULL(to_be_ground) diff --git a/modular_skyrat/modules/primitive_cooking_additions/code/millstone.dm b/modular_skyrat/modules/primitive_cooking_additions/code/millstone.dm index d477528acd47ec..314390a7f54e22 100644 --- a/modular_skyrat/modules/primitive_cooking_additions/code/millstone.dm +++ b/modular_skyrat/modules/primitive_cooking_additions/code/millstone.dm @@ -88,6 +88,22 @@ return TRUE + if(attacking_item.tool_behaviour == TOOL_WRENCH) + attacking_item.play_tool_sound(src) + anchored = !anchored + balloon_alert(user, "[src] [anchored ? "anchored" : "unanchored"]") + return TRUE + + if(attacking_item.tool_behaviour == TOOL_SCREWDRIVER) + attacking_item.play_tool_sound(src) + + for(var/i in 1 to 6) + var/obj/item/stack/sheet/mineral/stone = new (get_turf(src)) + transfer_fingerprints_to(stone) + + qdel(src) + return TRUE + if(!((istype(attacking_item, /obj/item/food/grown/)) || (istype(attacking_item, /obj/item/grown)))) balloon_alert(user, "can only mill plants") return ..() diff --git a/modular_skyrat/modules/sec_haul/code/misc/bullet_drive.dm b/modular_skyrat/modules/sec_haul/code/misc/bullet_drive.dm index 747601cb1f1a7f..7abf5585e086b3 100644 --- a/modular_skyrat/modules/sec_haul/code/misc/bullet_drive.dm +++ b/modular_skyrat/modules/sec_haul/code/misc/bullet_drive.dm @@ -6,7 +6,7 @@ density = TRUE circuit = /obj/item/circuitboard/machine/dish_drive/bullet collectable_items = list(/obj/item/ammo_casing) - succrange = 10 + suck_distance = 8 binrange = 10 /obj/item/circuitboard/machine/dish_drive/bullet @@ -52,7 +52,7 @@ do_the_dishes() if(!suction_enabled) return - for(var/obj/item/I in view(succrange, src)) + for(var/obj/item/I in view(2 + suck_distance, src)) if(istype(I, /obj/machinery/dish_drive/bullet)) visible_message(span_userdanger("[src] has detected another bullet drive nearby, and is sad!")) break diff --git a/modular_skyrat/modules/stone/code/stone.dm b/modular_skyrat/modules/stone/code/stone.dm index fb7ecd3f43a093..e41ac38f34448a 100644 --- a/modular_skyrat/modules/stone/code/stone.dm +++ b/modular_skyrat/modules/stone/code/stone.dm @@ -20,6 +20,7 @@ GLOBAL_LIST_INIT(stone_recipes, list ( \ new/datum/stack_recipe("stone brick wall", /turf/closed/wall/mineral/stone, 5, one_per_turf = 1, on_solid_ground = 1, applies_mats = TRUE, category = CAT_STRUCTURE), \ new/datum/stack_recipe("stone brick tile", /obj/item/stack/tile/mineral/stone, 1, 4, 20, check_density = FALSE, category = CAT_TILES), + new/datum/stack_recipe("millstone", /obj/structure/millstone, 6, one_per_turf = 1, on_solid_ground = 1, category = CAT_STRUCTURE), )) /obj/item/stack/sheet/mineral/stone/get_main_recipes() @@ -54,7 +55,7 @@ GLOBAL_LIST_INIT(stone_recipes, list ( \ . += span_notice("With a chisel or even a pickaxe of some kind, you could cut this into blocks.") /obj/item/stack/stone/attackby(obj/item/attacking_item, mob/user, params) - if((attacking_item.tool_behaviour != TOOL_MINING) || !(istype(attacking_item, /obj/item/chisel))) + if((attacking_item.tool_behaviour != TOOL_MINING) && !(istype(attacking_item, /obj/item/chisel))) return ..() playsound(src, 'sound/effects/picaxe1.ogg', 50, TRUE) balloon_alert_to_viewers("cutting...") @@ -127,3 +128,9 @@ GLOBAL_LIST_INIT(stone_recipes, list ( \ smoothing_flags = SMOOTH_BITMASK smoothing_groups = SMOOTH_GROUP_STONE_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS canSmoothWith = SMOOTH_GROUP_STONE_WALLS + +/turf/closed/mineral/gets_drilled(mob/user, give_exp = FALSE) + if(prob(5)) + new /obj/item/stack/stone(src) + + return ..() diff --git a/modular_skyrat/modules/supermatter_surge/code/supermatter_surge.dm b/modular_skyrat/modules/supermatter_surge/code/supermatter_surge.dm deleted file mode 100644 index 351903a3e49cd9..00000000000000 --- a/modular_skyrat/modules/supermatter_surge/code/supermatter_surge.dm +++ /dev/null @@ -1,70 +0,0 @@ -#define SUPERMATTER_SURGE_BULLET_ENERGY_FACTOR_UPPER 300 -#define SUPERMATTER_SURGE_BULLET_ENERGY_FACTOR_LOWER 100 -#define SUPERMATTER_SURGE_TIME_UPPER 360 * 0.5 -#define SUPERMATTER_SURGE_TIME_LOWER 180 * 0.5 -#define SUPERMATTER_SURGE_ANNOUNCE_THRESHOLD 25 -#define LOWER_SURGE_LIMIT 100 to 150 -#define MIDDLE_SURGE_LIMIT 151 to 200 -#define UPPER_SURGE_LIMIT 201 to 250 -/** - * Supermatter Surge - * - * A very simple event designed to give engineering a challenge. It simply increases the supermatters power by a set amount, and announces it. - * - * This should be entirely fine for a powerful setup, but will require intervention on a lower power setup. - */ - -/datum/round_event_control/supermatter_surge - name = "Supermatter Surge" - typepath = /datum/round_event/supermatter_surge - category = EVENT_CATEGORY_ENGINEERING - max_occurrences = 4 - earliest_start = 30 MINUTES - description = "The supermatter will increase in power by a random amount, and announce it." - -/datum/round_event/supermatter_surge - announce_when = 1 - end_when = SUPERMATTER_SURGE_TIME_LOWER - /// How powerful is the supermatter surge going to be? Set in setup. - var/surge_power = SUPERMATTER_SURGE_BULLET_ENERGY_FACTOR_LOWER - var/starting_surge_power = 0 - /// Typecasted reference to the supermatter chosen at the events start. Prevents the engine from going AWOL if it changes for some reason. - var/obj/machinery/power/supermatter_crystal/our_main_engine - -/datum/round_event/supermatter_surge/setup() - our_main_engine = GLOB.main_supermatter_engine - surge_power = rand(SUPERMATTER_SURGE_BULLET_ENERGY_FACTOR_LOWER, SUPERMATTER_SURGE_BULLET_ENERGY_FACTOR_UPPER) - starting_surge_power = our_main_engine.bullet_energy - end_when = rand(SUPERMATTER_SURGE_TIME_LOWER, SUPERMATTER_SURGE_TIME_UPPER) - -/datum/round_event/supermatter_surge/announce() - if(surge_power > SUPERMATTER_SURGE_ANNOUNCE_THRESHOLD || prob(round(surge_power))) - priority_announce("Class [get_surge_level()] supermatter surge detected. Intervention may be required.", "Anomaly Alert", ANNOUNCER_KLAXON) - -/datum/round_event/supermatter_surge/proc/get_surge_level() - switch(surge_power) - if(LOWER_SURGE_LIMIT) - return 4 - if(MIDDLE_SURGE_LIMIT) - return 3 - if(UPPER_SURGE_LIMIT) - return 2 - else - return 1 - -/datum/round_event/supermatter_surge/start() - our_main_engine?.bullet_energy *= surge_power - -/datum/round_event/supermatter_surge/end() - our_main_engine?.bullet_energy = starting_surge_power - priority_announce("The supermatter surge has dissipated.", "Anomaly Cleared") - our_main_engine = null - -#undef SUPERMATTER_SURGE_BULLET_ENERGY_FACTOR_UPPER -#undef SUPERMATTER_SURGE_BULLET_ENERGY_FACTOR_LOWER -#undef SUPERMATTER_SURGE_TIME_UPPER -#undef SUPERMATTER_SURGE_TIME_LOWER -#undef SUPERMATTER_SURGE_ANNOUNCE_THRESHOLD -#undef LOWER_SURGE_LIMIT -#undef MIDDLE_SURGE_LIMIT -#undef UPPER_SURGE_LIMIT diff --git a/modular_skyrat/modules/synths/code/reagents/reagents.dm b/modular_skyrat/modules/synths/code/reagents/reagents.dm index b99291084f24d9..ef48f0bf9479ae 100644 --- a/modular_skyrat/modules/synths/code/reagents/reagents.dm +++ b/modular_skyrat/modules/synths/code/reagents/reagents.dm @@ -78,7 +78,7 @@ return ..() affected_mob.reagents.remove_reagent(type, NANITE_SLURRY_ORGANIC_PURGE_RATE) //gets removed from organics very fast if(prob(NANITE_SLURRY_ORGANIC_VOMIT_CHANCE)) - affected_mob.vomit(vomit_type = VOMIT_NANITE) + affected_mob.vomit(vomit_flags = (MOB_VOMIT_MESSAGE | MOB_VOMIT_HARM), vomit_type = /obj/effect/decal/cleanable/vomit/nanites) return TRUE #undef NANITE_SLURRY_ORGANIC_PURGE_RATE diff --git a/sound/machines/engine_alert3.ogg b/sound/machines/engine_alert3.ogg new file mode 100644 index 00000000000000..394bfed2a138de Binary files /dev/null and b/sound/machines/engine_alert3.ogg differ diff --git a/sound/magic/hereticknock.ogg b/sound/magic/hereticknock.ogg new file mode 100644 index 00000000000000..87ca57302a285f Binary files /dev/null and b/sound/magic/hereticknock.ogg differ diff --git a/strings/tips.txt b/strings/tips.txt index 514a9dada7a50b..12248bb4124355 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -13,9 +13,9 @@ As a Botanist, you should look into increasing the potency of your plants. This As a Cargo Technician, you can earn more cargo points by shipping back crates from maintenance, liquid containers, plasma sheets, rare seeds from hydroponics, and more! As a Cargo Technician, you can hack MULEbots to make them faster, run over people in their way, and even let you ride them! As a Cargo Technician, you can order contraband items from the supply shuttle console by de-constructing it and using a multitool on the circuit board, the re-assembling it. +As a Changeling, taking on someone else's appearance will also give you all of their scars. You can use Fleshmend to get rid of all scars. As a Changeling, the Extract DNA sting counts for your genome absorb objective, but does not let you respec your powers. As a Changeling, you can absorb someone by strangling them and using the Absorb verb; this gives you the ability to rechoose your powers, the DNA of whoever you absorbed, the memory of the absorbed, and some samples of things the absorbed said. -As a Changeling, your Regenerate Limbs power will quickly heal all of your wounds, but they'll still leave scars. Changelings can use Fleshmend to get rid of scars, or you can ingest Carpotoxin to get rid of them like a normal person. As a Chemist, some chemicals can only be synthesized by heating up the contents with a chemical heater or manually with lighters and similar tools. As a Chemist, there are dozens of chemicals that can heal, and even more that can cause harm. Experiment! As a Chemist, Water and Potassium mixed together will create an explosion, with power scaling by amount used. Don't do it. @@ -267,3 +267,4 @@ You can spray a fire extinguisher, throw items or fire a gun while floating thro You can swap floor tiles by holding a crowbar in one hand and a stack of tiles in the other. You can use a machine in the vault to deposit cash or rob Cargo's department funds. You'll quickly lose your interest in the game if you play to win and kill. If you find yourself doing this, take a step back and talk to people - it's a much better experience! +Some areas of the station use simple nautical directions to indicate their respective locations, like Fore (Front of the ship), Aft (Back), Port (Left side), Starboard (Right), Quarter and Bow (Either sides of Aft and Fore, respectively). You can review these terms on the Notepad App of your PDA. \ No newline at end of file diff --git a/strings/wounds/bone_scar_desc.json b/strings/wounds/bone_scar_desc.json index b1eb84bb8b79b0..2a89f0220021f0 100644 --- a/strings/wounds/bone_scar_desc.json +++ b/strings/wounds/bone_scar_desc.json @@ -1,6 +1,11 @@ { "generic": ["general disfigurement"], + "dislocate": [ + "the bone equivalent of a faded bruise", + "a series of tiny chip marks" + ], + "bluntmoderate": [ "the bone equivalent of a faded bruise", "a series of tiny chip marks" diff --git a/strings/wounds/flesh_scar_desc.json b/strings/wounds/flesh_scar_desc.json index d8c253873cc38a..0fd78bec8e4f18 100644 --- a/strings/wounds/flesh_scar_desc.json +++ b/strings/wounds/flesh_scar_desc.json @@ -1,6 +1,12 @@ { "generic": ["general disfigurement"], + "dislocate": [ + "light discoloring", + "a slight blue tint", + "a slightly deadened tint" + ], + "bluntmoderate": [ "light discoloring", "a slight blue tint", diff --git a/tgstation.dme b/tgstation.dme index 17bda6dc3eabce..40c8f89ab3abcb 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -104,6 +104,7 @@ #include "code\__DEFINES\ghost.dm" #include "code\__DEFINES\gravity.dm" #include "code\__DEFINES\guardian_defines.dm" +#include "code\__DEFINES\holiday.dm" #include "code\__DEFINES\holopads.dm" #include "code\__DEFINES\hud.dm" #include "code\__DEFINES\icon_smoothing.dm" @@ -300,6 +301,7 @@ #include "code\__DEFINES\dcs\signals\signals_janitor.dm" #include "code\__DEFINES\dcs\signals\signals_key.dm" #include "code\__DEFINES\dcs\signals\signals_ladder.dm" +#include "code\__DEFINES\dcs\signals\signals_lazy_templates.dm" #include "code\__DEFINES\dcs\signals\signals_leash.dm" #include "code\__DEFINES\dcs\signals\signals_lift.dm" #include "code\__DEFINES\dcs\signals\signals_light_eater.dm" @@ -319,6 +321,7 @@ #include "code\__DEFINES\dcs\signals\signals_radiation.dm" #include "code\__DEFINES\dcs\signals\signals_reagent.dm" #include "code\__DEFINES\dcs\signals\signals_restaurant.dm" +#include "code\__DEFINES\dcs\signals\signals_saboteur.dm" #include "code\__DEFINES\dcs\signals\signals_scangate.dm" #include "code\__DEFINES\dcs\signals\signals_screentips.dm" #include "code\__DEFINES\dcs\signals\signals_spatial_grid.dm" @@ -453,7 +456,6 @@ #include "code\__HELPERS\atoms.dm" #include "code\__HELPERS\auxtools.dm" #include "code\__HELPERS\bitflag_lists.dm" -#include "code\__HELPERS\byond_status.dm" #include "code\__HELPERS\cameras.dm" #include "code\__HELPERS\chat.dm" #include "code\__HELPERS\chat_filter.dm" @@ -761,6 +763,7 @@ #include "code\controllers\subsystem\processing\digital_clock.dm" #include "code\controllers\subsystem\processing\fastprocess.dm" #include "code\controllers\subsystem\processing\fire_burning.dm" +#include "code\controllers\subsystem\processing\fishing.dm" #include "code\controllers\subsystem\processing\greyscale.dm" #include "code\controllers\subsystem\processing\instruments.dm" #include "code\controllers\subsystem\processing\obj.dm" @@ -1193,6 +1196,7 @@ #include "code\datums\components\uplink.dm" #include "code\datums\components\usb_port.dm" #include "code\datums\components\vacuum.dm" +#include "code\datums\components\wall_mounted.dm" #include "code\datums\components\wearertargeting.dm" #include "code\datums\components\weatherannouncer.dm" #include "code\datums\components\wet_floor.dm" @@ -1224,6 +1228,7 @@ #include "code\datums\components\food\decomposition.dm" #include "code\datums\components\food\edible.dm" #include "code\datums\components\food\germ_sensitive.dm" +#include "code\datums\components\food\ghost_edible.dm" #include "code\datums\components\food\golem_food.dm" #include "code\datums\components\food\ice_cream_holder.dm" #include "code\datums\components\material\material_container.dm" @@ -1325,6 +1330,7 @@ #include "code\datums\elements\bed_tucking.dm" #include "code\datums\elements\befriend_petting.dm" #include "code\datums\elements\blocks_explosives.dm" +#include "code\datums\elements\bombable_turf.dm" #include "code\datums\elements\bonus_damage.dm" #include "code\datums\elements\bsa_blocker.dm" #include "code\datums\elements\bugkiller_reagent.dm" @@ -1388,6 +1394,7 @@ #include "code\datums\elements\light_eater.dm" #include "code\datums\elements\loomable.dm" #include "code\datums\elements\mirage_border.dm" +#include "code\datums\elements\mob_grabber.dm" #include "code\datums\elements\mob_killed_tally.dm" #include "code\datums\elements\movement_turf_changer.dm" #include "code\datums\elements\movetype_handler.dm" @@ -1576,10 +1583,89 @@ #include "code\datums\proximity_monitor\fields\projectile_dampener.dm" #include "code\datums\proximity_monitor\fields\timestop.dm" #include "code\datums\quirks\_quirk.dm" -#include "code\datums\quirks\negative_quirks\negative_quirks.dm" -#include "code\datums\quirks\neutral_quirks\neutral_quirks.dm" -#include "code\datums\quirks\positive_quirks\positive_quirks.dm" +#include "code\datums\quirks\negative_quirks\allergic.dm" +#include "code\datums\quirks\negative_quirks\bad_back.dm" +#include "code\datums\quirks\negative_quirks\bad_touch.dm" +#include "code\datums\quirks\negative_quirks\big_hands.dm" +#include "code\datums\quirks\negative_quirks\blindness.dm" +#include "code\datums\quirks\negative_quirks\blood_deficiency.dm" +#include "code\datums\quirks\negative_quirks\body_purist.dm" +#include "code\datums\quirks\negative_quirks\brain_problems.dm" +#include "code\datums\quirks\negative_quirks\chronic_illness.dm" +#include "code\datums\quirks\negative_quirks\claustrophobia.dm" +#include "code\datums\quirks\negative_quirks\clumsy.dm" +#include "code\datums\quirks\negative_quirks\cursed.dm" +#include "code\datums\quirks\negative_quirks\deafness.dm" +#include "code\datums\quirks\negative_quirks\depression.dm" +#include "code\datums\quirks\negative_quirks\family_heirloom.dm" +#include "code\datums\quirks\negative_quirks\frail.dm" +#include "code\datums\quirks\negative_quirks\glass_jaw.dm" +#include "code\datums\quirks\negative_quirks\heavy_sleeper.dm" +#include "code\datums\quirks\negative_quirks\hemiplegic.dm" +#include "code\datums\quirks\negative_quirks\hypersensitive.dm" +#include "code\datums\quirks\negative_quirks\illiterate.dm" +#include "code\datums\quirks\negative_quirks\indebted.dm" +#include "code\datums\quirks\negative_quirks\insanity.dm" +#include "code\datums\quirks\negative_quirks\junkie.dm" +#include "code\datums\quirks\negative_quirks\light_drinker.dm" +#include "code\datums\quirks\negative_quirks\mute.dm" +#include "code\datums\quirks\negative_quirks\nearsighted.dm" +#include "code\datums\quirks\negative_quirks\non_violent.dm" +#include "code\datums\quirks\negative_quirks\numb.dm" +#include "code\datums\quirks\negative_quirks\nyctophobia.dm" +#include "code\datums\quirks\negative_quirks\paraplegic.dm" +#include "code\datums\quirks\negative_quirks\photophobia.dm" +#include "code\datums\quirks\negative_quirks\poor_aim.dm" +#include "code\datums\quirks\negative_quirks\prosopagnosia.dm" +#include "code\datums\quirks\negative_quirks\prosthetic_limb.dm" +#include "code\datums\quirks\negative_quirks\prosthetic_organ.dm" +#include "code\datums\quirks\negative_quirks\pushover.dm" +#include "code\datums\quirks\negative_quirks\quadruple_amputee.dm" +#include "code\datums\quirks\negative_quirks\social_anxiety.dm" +#include "code\datums\quirks\negative_quirks\softspoken.dm" +#include "code\datums\quirks\negative_quirks\tin_man.dm" +#include "code\datums\quirks\negative_quirks\unstable.dm" +#include "code\datums\quirks\neutral_quirks\bald.dm" +#include "code\datums\quirks\neutral_quirks\colorist.dm" +#include "code\datums\quirks\neutral_quirks\deviant_tastes.dm" +#include "code\datums\quirks\neutral_quirks\extrovert.dm" +#include "code\datums\quirks\neutral_quirks\foreigner.dm" +#include "code\datums\quirks\neutral_quirks\gamer.dm" +#include "code\datums\quirks\neutral_quirks\heretochromatic.dm" +#include "code\datums\quirks\neutral_quirks\introvert.dm" +#include "code\datums\quirks\neutral_quirks\monochromatic.dm" +#include "code\datums\quirks\neutral_quirks\no_taste.dm" +#include "code\datums\quirks\neutral_quirks\phobia.dm" +#include "code\datums\quirks\neutral_quirks\photographer.dm" +#include "code\datums\quirks\neutral_quirks\pineapple_hater.dm" +#include "code\datums\quirks\neutral_quirks\pineapple_liker.dm" +#include "code\datums\quirks\neutral_quirks\pride_pin.dm" +#include "code\datums\quirks\neutral_quirks\shifty_eyes.dm" +#include "code\datums\quirks\neutral_quirks\snob.dm" +#include "code\datums\quirks\neutral_quirks\vegetarian.dm" +#include "code\datums\quirks\positive_quirks\alcohol_tolerance.dm" +#include "code\datums\quirks\positive_quirks\apathetic.dm" +#include "code\datums\quirks\positive_quirks\bilingual.dm" +#include "code\datums\quirks\positive_quirks\clown_enjoyer.dm" +#include "code\datums\quirks\positive_quirks\drunk_healing.dm" +#include "code\datums\quirks\positive_quirks\empath.dm" +#include "code\datums\quirks\positive_quirks\freerunning.dm" +#include "code\datums\quirks\positive_quirks\friendly.dm" +#include "code\datums\quirks\positive_quirks\jolly.dm" +#include "code\datums\quirks\positive_quirks\light_step.dm" +#include "code\datums\quirks\positive_quirks\mime_fan.dm" +#include "code\datums\quirks\positive_quirks\musician.dm" +#include "code\datums\quirks\positive_quirks\night_vision.dm" +#include "code\datums\quirks\positive_quirks\poster_boy.dm" +#include "code\datums\quirks\positive_quirks\self_aware.dm" +#include "code\datums\quirks\positive_quirks\settler.dm" +#include "code\datums\quirks\positive_quirks\signer.dm" +#include "code\datums\quirks\positive_quirks\skittish.dm" #include "code\datums\quirks\positive_quirks\spacer.dm" +#include "code\datums\quirks\positive_quirks\spiritual.dm" +#include "code\datums\quirks\positive_quirks\tagger.dm" +#include "code\datums\quirks\positive_quirks\throwing_arm.dm" +#include "code\datums\quirks\positive_quirks\voracious.dm" #include "code\datums\records\crime.dm" #include "code\datums\records\data.dm" #include "code\datums\records\manifest.dm" @@ -1692,6 +1778,7 @@ #include "code\datums\wires\emitter.dm" #include "code\datums\wires\explosive.dm" #include "code\datums\wires\fax.dm" +#include "code\datums\wires\mass_driver.dm" #include "code\datums\wires\mecha.dm" #include "code\datums\wires\microwave.dm" #include "code\datums\wires\mod.dm" @@ -2070,6 +2157,7 @@ #include "code\game\objects\items\choice_beacon.dm" #include "code\game\objects\items\chromosome.dm" #include "code\game\objects\items\cigs_lighters.dm" +#include "code\game\objects\items\climbingrope.dm" #include "code\game\objects\items\clown_items.dm" #include "code\game\objects\items\control_wand.dm" #include "code\game\objects\items\cosmetics.dm" @@ -2524,6 +2612,7 @@ #include "code\game\turfs\change_turf.dm" #include "code\game\turfs\turf.dm" #include "code\game\turfs\closed\_closed.dm" +#include "code\game\turfs\closed\indestructible.dm" #include "code\game\turfs\closed\minerals.dm" #include "code\game\turfs\closed\walls.dm" #include "code\game\turfs\closed\wall\material_walls.dm" @@ -2568,6 +2657,7 @@ #include "code\modules\actionspeed\modifiers\drugs.dm" #include "code\modules\actionspeed\modifiers\mood.dm" #include "code\modules\actionspeed\modifiers\status_effects.dm" +#include "code\modules\actionspeed\modifiers\wound.dm" #include "code\modules\admin\admin.dm" #include "code\modules\admin\admin_fax_panel.dm" #include "code\modules\admin\admin_investigate.dm" @@ -2607,11 +2697,11 @@ #include "code\modules\admin\whitelist.dm" #include "code\modules\admin\callproc\callproc.dm" #include "code\modules\admin\smites\bad_luck.dm" +#include "code\modules\admin\smites\become_object.dm" #include "code\modules\admin\smites\berforate.dm" #include "code\modules\admin\smites\bloodless.dm" #include "code\modules\admin\smites\boneless.dm" #include "code\modules\admin\smites\brain_damage.dm" -#include "code\modules\admin\smites\bread.dm" #include "code\modules\admin\smites\bsa.dm" #include "code\modules\admin\smites\curse_of_babel.dm" #include "code\modules\admin\smites\dock_pay.dm" @@ -2853,17 +2943,21 @@ #include "code\modules\antagonists\heretic\items\heretic_blades.dm" #include "code\modules\antagonists\heretic\items\heretic_necks.dm" #include "code\modules\antagonists\heretic\items\hunter_rifle.dm" +#include "code\modules\antagonists\heretic\items\keyring.dm" +#include "code\modules\antagonists\heretic\items\lintel.dm" #include "code\modules\antagonists\heretic\items\madness_mask.dm" #include "code\modules\antagonists\heretic\knowledge\ash_lore.dm" #include "code\modules\antagonists\heretic\knowledge\blade_lore.dm" #include "code\modules\antagonists\heretic\knowledge\cosmic_lore.dm" #include "code\modules\antagonists\heretic\knowledge\flesh_lore.dm" #include "code\modules\antagonists\heretic\knowledge\general_side.dm" +#include "code\modules\antagonists\heretic\knowledge\knock_lore.dm" #include "code\modules\antagonists\heretic\knowledge\rust_lore.dm" #include "code\modules\antagonists\heretic\knowledge\side_ash_flesh.dm" #include "code\modules\antagonists\heretic\knowledge\side_blade_rust.dm" #include "code\modules\antagonists\heretic\knowledge\side_cosmos_ash.dm" #include "code\modules\antagonists\heretic\knowledge\side_flesh_void.dm" +#include "code\modules\antagonists\heretic\knowledge\side_knock_flesh.dm" #include "code\modules\antagonists\heretic\knowledge\side_rust_cosmos.dm" #include "code\modules\antagonists\heretic\knowledge\side_void_blade.dm" #include "code\modules\antagonists\heretic\knowledge\starting_lore.dm" @@ -2873,10 +2967,14 @@ #include "code\modules\antagonists\heretic\knowledge\sacrifice_knowledge\sacrifice_map.dm" #include "code\modules\antagonists\heretic\knowledge\sacrifice_knowledge\sacrifice_moodlets.dm" #include "code\modules\antagonists\heretic\magic\aggressive_spread.dm" +#include "code\modules\antagonists\heretic\magic\apetravulnera.dm" +#include "code\modules\antagonists\heretic\magic\ascended_shapeshift.dm" #include "code\modules\antagonists\heretic\magic\ash_ascension.dm" #include "code\modules\antagonists\heretic\magic\ash_jaunt.dm" #include "code\modules\antagonists\heretic\magic\blood_cleave.dm" #include "code\modules\antagonists\heretic\magic\blood_siphon.dm" +#include "code\modules\antagonists\heretic\magic\burglar_finesse.dm" +#include "code\modules\antagonists\heretic\magic\caretaker.dm" #include "code\modules\antagonists\heretic\magic\cosmic_expansion.dm" #include "code\modules\antagonists\heretic\magic\cosmic_runes.dm" #include "code\modules\antagonists\heretic\magic\eldritch_blind.dm" @@ -2904,12 +3002,14 @@ #include "code\modules\antagonists\heretic\magic\void_cold_cone.dm" #include "code\modules\antagonists\heretic\magic\void_phase.dm" #include "code\modules\antagonists\heretic\magic\void_pull.dm" +#include "code\modules\antagonists\heretic\magic\wave_of_desperation.dm" #include "code\modules\antagonists\heretic\mobs\maid_in_mirror.dm" #include "code\modules\antagonists\heretic\status_effects\buffs.dm" #include "code\modules\antagonists\heretic\status_effects\debuffs.dm" #include "code\modules\antagonists\heretic\status_effects\ghoul.dm" #include "code\modules\antagonists\heretic\status_effects\mark_effects.dm" #include "code\modules\antagonists\heretic\structures\carving_knife.dm" +#include "code\modules\antagonists\heretic\structures\knock_final.dm" #include "code\modules\antagonists\heretic\structures\mawed_crucible.dm" #include "code\modules\antagonists\highlander\highlander.dm" #include "code\modules\antagonists\hypnotized\hypnotized.dm" @@ -3596,6 +3696,7 @@ #include "code\modules\events\shuttle_insurance.dm" #include "code\modules\events\spider_infestation.dm" #include "code\modules\events\stray_cargo.dm" +#include "code\modules\events\supermatter_surge.dm" #include "code\modules\events\tram_malfunction.dm" #include "code\modules\events\vent_clog.dm" #include "code\modules\events\wisdomcow.dm" @@ -4682,7 +4783,6 @@ #include "code\modules\mod\modules\modules_supply.dm" #include "code\modules\mod\modules\modules_timeline.dm" #include "code\modules\mod\modules\modules_visor.dm" -#include "code\modules\modular_computers\laptop_vendor.dm" #include "code\modules\modular_computers\computers\item\computer.dm" #include "code\modules\modular_computers\computers\item\computer_files.dm" #include "code\modules\modular_computers\computers\item\computer_power.dm" @@ -4992,6 +5092,7 @@ #include "code\modules\projectiles\projectile\special\floral.dm" #include "code\modules\projectiles\projectile\special\gravity.dm" #include "code\modules\projectiles\projectile\special\ion.dm" +#include "code\modules\projectiles\projectile\special\lightbreaker.dm" #include "code\modules\projectiles\projectile\special\meteor.dm" #include "code\modules\projectiles\projectile\special\mindflayer.dm" #include "code\modules\projectiles\projectile\special\neurotoxin.dm" @@ -5794,6 +5895,7 @@ #include "modular_skyrat\master_files\code\modules\buildmode\submodes\offercontrol.dm" #include "modular_skyrat\master_files\code\modules\cargo\goodies.dm" #include "modular_skyrat\master_files\code\modules\cargo\orderconsole.dm" +#include "modular_skyrat\master_files\code\modules\cargo\bounties\medical.dm" #include "modular_skyrat\master_files\code\modules\cargo\exports\tools.dm" #include "modular_skyrat\master_files\code\modules\cargo\exports\traitor.dm" #include "modular_skyrat\master_files\code\modules\cargo\markets\market_items\weapons.dm" @@ -5997,6 +6099,7 @@ #include "modular_skyrat\master_files\code\modules\surgery\surgery.dm" #include "modular_skyrat\master_files\code\modules\surgery\bodyparts\_bodyparts.dm" #include "modular_skyrat\master_files\code\modules\surgery\organs\tongue.dm" +#include "modular_skyrat\master_files\code\modules\surgery\organs\internal\appendix\_appendix.dm" #include "modular_skyrat\master_files\code\modules\vehicles\sealed.dm" #include "modular_skyrat\master_files\code\modules\vehicles\snowmobile.dm" #include "modular_skyrat\modules\additional_circuit\code\_designs.dm" @@ -6610,6 +6713,7 @@ #include "modular_skyrat\modules\customization\modules\reagents\chemistry\reagents\toxin_reagents.dm" #include "modular_skyrat\modules\customization\modules\reagents\chemistry\recipes\medicine.dm" #include "modular_skyrat\modules\customization\modules\surgery\bodyparts\_bodyparts.dm" +#include "modular_skyrat\modules\customization\modules\surgery\bodyparts\parts.dm" #include "modular_skyrat\modules\customization\modules\surgery\bodyparts\robot_bodyparts.dm" #include "modular_skyrat\modules\customization\modules\surgery\organs\cap.dm" #include "modular_skyrat\modules\customization\modules\surgery\organs\ears.dm" @@ -6717,7 +6821,6 @@ #include "modular_skyrat\modules\gunhud\code\gun_hud_component.dm" #include "modular_skyrat\modules\gunpoint\code\gunpoint.dm" #include "modular_skyrat\modules\gunpoint\code\gunpoint_datum.dm" -#include "modular_skyrat\modules\gunsgalore\code\projectile.dm" #include "modular_skyrat\modules\gunsgalore\code\ammo\ammo.dm" #include "modular_skyrat\modules\gunsgalore\code\guns\akm.dm" #include "modular_skyrat\modules\gunsgalore\code\guns\ballistic_master.dm" @@ -6761,6 +6864,7 @@ #include "modular_skyrat\modules\ices_events\code\ICES_tgui.dm" #include "modular_skyrat\modules\ices_events\code\effects\ef_foam.dm" #include "modular_skyrat\modules\ices_events\code\events\ev_meteors.dm" +#include "modular_skyrat\modules\ices_events\code\events\ev_roleplay_check.dm" #include "modular_skyrat\modules\ices_events\code\events\ev_scrubbers.dm" #include "modular_skyrat\modules\icspawning\code\cards_ids.dm" #include "modular_skyrat\modules\icspawning\code\observer.dm" @@ -6901,6 +7005,7 @@ #include "modular_skyrat\modules\medical\code\carbon_examine.dm" #include "modular_skyrat\modules\medical\code\carbon_update_icons.dm" #include "modular_skyrat\modules\medical\code\grasp.dm" +#include "modular_skyrat\modules\medical\code\health_analyzer.dm" #include "modular_skyrat\modules\medical\code\smartdarts.dm" #include "modular_skyrat\modules\medical\code\wounds\_wounds.dm" #include "modular_skyrat\modules\medical\code\wounds\bleed.dm" @@ -7386,7 +7491,6 @@ #include "modular_skyrat\modules\subsystems\code\ticket_ping\adminhelp.dm" #include "modular_skyrat\modules\subsystems\code\ticket_ping\preference.dm" #include "modular_skyrat\modules\subsystems\code\ticket_ping\ticket_ss.dm" -#include "modular_skyrat\modules\supermatter_surge\code\supermatter_surge.dm" #include "modular_skyrat\modules\Syndie_edits\code\area.dm" #include "modular_skyrat\modules\Syndie_edits\code\syndie_edits.dm" #include "modular_skyrat\modules\synths\code\bodyparts\brain.dm" diff --git a/tgui/packages/tgui/interfaces/CameraConsole.js b/tgui/packages/tgui/interfaces/CameraConsole.js deleted file mode 100644 index 57cc34e77e18c7..00000000000000 --- a/tgui/packages/tgui/interfaces/CameraConsole.js +++ /dev/null @@ -1,137 +0,0 @@ -import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; -import { classes } from 'common/react'; -import { createSearch } from 'common/string'; -import { useBackend, useLocalState } from '../backend'; -import { Button, ByondUi, Flex, Input, Section } from '../components'; -import { Window } from '../layouts'; - -/** - * Returns previous and next camera names relative to the currently - * active camera. - */ -export const prevNextCamera = (cameras, activeCamera) => { - if (!activeCamera) { - return []; - } - const index = cameras.findIndex( - (camera) => camera.name === activeCamera.name - ); - return [cameras[index - 1]?.name, cameras[index + 1]?.name]; -}; - -/** - * Camera selector. - * - * Filters cameras, applies search terms and sorts the alphabetically. - */ -export const selectCameras = (cameras, searchText = '') => { - const testSearch = createSearch(searchText, (camera) => camera.name); - return flow([ - // Null camera filter - filter((camera) => camera?.name), - // Optional search term - searchText && filter(testSearch), - // Slightly expensive, but way better than sorting in BYOND - sortBy((camera) => camera.name), - ])(cameras); -}; - -export const CameraConsole = (props, context) => { - const { act, data } = useBackend(context); - const { mapRef, activeCamera } = data; - const cameras = selectCameras(data.cameras); - const [prevCameraName, nextCameraName] = prevNextCamera( - cameras, - activeCamera - ); - return ( - -
- - - -
-
-
- Camera: - {(activeCamera && activeCamera.name) || '—'} -
-
-
- -
-
- ); -}; - -export const CameraConsoleContent = (props, context) => { - const { act, data } = useBackend(context); - const [searchText, setSearchText] = useLocalState(context, 'searchText', ''); - const { activeCamera } = data; - const cameras = selectCameras(data.cameras, searchText); - return ( - - - setSearchText(value)} - /> - - -
- {cameras.map((camera) => ( - // We're not using the component here because performance - // would be absolutely abysmal (50+ ms for each re-render). -
- act('switch_camera', { - name: camera.name, - }) - }> - {camera.name} -
- ))} -
-
-
- ); -}; diff --git a/tgui/packages/tgui/interfaces/CameraConsole.tsx b/tgui/packages/tgui/interfaces/CameraConsole.tsx new file mode 100644 index 00000000000000..b1077f6bdcb599 --- /dev/null +++ b/tgui/packages/tgui/interfaces/CameraConsole.tsx @@ -0,0 +1,199 @@ +import { filter, sortBy } from 'common/collections'; +import { flow } from 'common/fp'; +import { BooleanLike, classes } from 'common/react'; +import { createSearch } from 'common/string'; +import { useBackend, useLocalState } from '../backend'; +import { Button, ByondUi, Input, NoticeBox, Section, Stack } from '../components'; +import { Window } from '../layouts'; + +type Data = { + can_spy: BooleanLike; + mapRef: string; + cameras: Camera[]; + activeCamera: Camera & { status: BooleanLike }; + network: string[]; +}; + +type Camera = { + name: string; +}; + +/** + * Returns previous and next camera names relative to the currently + * active camera. + */ +const prevNextCamera = ( + cameras: Camera[], + activeCamera: Camera & { status: BooleanLike } +) => { + if (!activeCamera) { + return []; + } + const index = cameras.findIndex( + (camera) => camera?.name === activeCamera.name + ); + return [cameras[index - 1]?.name, cameras[index + 1]?.name]; +}; + +/** + * Camera selector. + * + * Filters cameras, applies search terms and sorts the alphabetically. + */ +const selectCameras = (cameras: Camera[], searchText = ''): Camera[] => { + const testSearch = createSearch(searchText, (camera: Camera) => camera.name); + + return flow([ + // Null camera filter + filter((camera: Camera) => !!camera?.name), + // Optional search term + searchText && filter(testSearch), + // Slightly expensive, but way better than sorting in BYOND + sortBy((camera: Camera) => camera.name), + ])(cameras); +}; + +export const CameraConsole = (props, context) => { + return ( + + + + + + ); +}; + +export const CameraContent = (props, context) => { + return ( + + + + + + + + + ); +}; + +const CameraSelector = (props, context) => { + const { act, data } = useBackend(context); + const [searchText, setSearchText] = useLocalState(context, 'searchText', ''); + const { activeCamera } = data; + const cameras = selectCameras(data.cameras, searchText); + + return ( + + + setSearchText(value)} + /> + + +
+ {cameras.map((camera) => ( + // We're not using the component here because performance + // would be absolutely abysmal (50+ ms for each re-render). +
+ act('switch_camera', { + name: camera.name, + }) + }> + {camera.name} +
+ ))} +
+
+
+ ); +}; + +const CameraControls = (props, context) => { + const { act, data } = useBackend(context); + const { activeCamera, can_spy, mapRef } = data; + const cameras = selectCameras(data.cameras); + + const [prevCameraName, nextCameraName] = prevNextCamera( + cameras, + activeCamera + ); + + return ( +
+ + + + + {activeCamera?.name ? ( + {activeCamera.name} + ) : ( + No input signal + )} + + + + {!!can_spy && ( +
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/CargoExpress.tsx b/tgui/packages/tgui/interfaces/CargoExpress.tsx index 904cf38e6f1c86..a4fb35edebccfe 100644 --- a/tgui/packages/tgui/interfaces/CargoExpress.tsx +++ b/tgui/packages/tgui/interfaces/CargoExpress.tsx @@ -24,7 +24,7 @@ export const CargoExpress = (props, context) => { return ( - + {!locked && } diff --git a/tgui/packages/tgui/interfaces/CommandReport.tsx b/tgui/packages/tgui/interfaces/CommandReport.tsx index 8ec0a6f8949a10..f299e25a70981d 100644 --- a/tgui/packages/tgui/interfaces/CommandReport.tsx +++ b/tgui/packages/tgui/interfaces/CommandReport.tsx @@ -10,6 +10,7 @@ type Data = { command_report_content: string; custom_name: string; played_sound: string; + print_report: string; }; export const CommandReport = () => { @@ -94,7 +95,7 @@ const AnnouncementSound = (props, context) => { /** Creates the report textarea with a submit button. */ const ReportText = (props, context) => { const { act, data } = useBackend(context); - const { announce_contents, command_report_content } = data; + const { announce_contents, print_report, command_report_content } = data; const [commandReport, setCommandReport] = useLocalState( context, 'textArea', @@ -117,6 +118,18 @@ const ReportText = (props, context) => { onClick={() => act('toggle_announce')}> Announce Contents + act('toggle_printing')} + tooltip={ + !announce_contents && + "Printing the report is required since we aren't announcing its contents." + } + tooltipPosition="top"> + Print Report + !shuttle.emagOnly, - (shuttle) => shuttle.creditCost + (shuttle) => shuttle.initial_cost ); const AlertButton = (props, context) => { @@ -198,7 +198,7 @@ const PageBuyingShuttle = (props, context) => { {shuttle.prerequisites ? ( - Prerequisitces: {shuttle.prerequisites} + Prerequisites: {shuttle.prerequisites} ) : null} diff --git a/tgui/packages/tgui/interfaces/ComputerFabricator.js b/tgui/packages/tgui/interfaces/ComputerFabricator.js deleted file mode 100644 index 8f27f59a984511..00000000000000 --- a/tgui/packages/tgui/interfaces/ComputerFabricator.js +++ /dev/null @@ -1,202 +0,0 @@ -import { multiline } from 'common/string'; -import { useBackend } from '../backend'; -import { Box, Button, Grid, Section, Table, Tooltip } from '../components'; -import { Window } from '../layouts'; - -export const ComputerFabricator = (props, context) => { - const { act, data } = useBackend(context); - return ( - - -
- Your perfect device, only three steps away... -
- {data.state !== 0 && ( -