diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml index 160bdf9bd2c..6e2c037c58b 100644 --- a/.github/workflows/ci_suite.yml +++ b/.github/workflows/ci_suite.yml @@ -69,12 +69,7 @@ jobs: tools/bootstrap/python -m define_sanity.check tools/bootstrap/python -m dmi.test tools/bootstrap/python -m mapmerge2.dmm_test - ~/dreamchecker > ${GITHUB_WORKSPACE}/output-annotations.txt 2>&1 - - name: Annotate Lints - uses: yogstation13/DreamAnnotate@v2 - if: always() - with: - outputFile: output-annotations.txt + ~/dreamchecker 2>&1 | bash tools/ci/annotate_dm.sh compile_all_maps: if: "!contains(github.event.head_commit.message, '[ci skip]')" diff --git a/.github/workflows/run_integration_tests.yml b/.github/workflows/run_integration_tests.yml index 22cec5d48bb..0c4ba61a8a4 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 f8688c913d8..1c74dfcdf37 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 00000000000..7dbc17d40f9 --- /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/LavaRuins/lavaland_biodome_clown_planet.dmm b/_maps/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm index 7ab354935c3..ef650913f14 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm @@ -671,7 +671,7 @@ /area/ruin/powered/clownplanet) "RW" = ( /obj/effect/mapping_helpers/no_lava, -/mob/living/simple_animal/hostile/retaliate/clown, +/mob/living/basic/clown, /turf/open/floor/noslip, /area/ruin/powered/clownplanet) "Tj" = ( @@ -714,7 +714,7 @@ "YI" = ( /obj/machinery/light/small/directional/south, /obj/effect/mapping_helpers/no_lava, -/mob/living/simple_animal/hostile/retaliate/clown, +/mob/living/basic/clown, /turf/open/floor/noslip, /area/ruin/powered/clownplanet) "Zg" = ( diff --git a/_maps/RandomRuins/SpaceRuins/anomaly_research.dmm b/_maps/RandomRuins/SpaceRuins/anomaly_research.dmm index 50a3ba98cba..e3015469bce 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/clownplanet.dmm b/_maps/RandomRuins/SpaceRuins/clownplanet.dmm index b0cc8cc29e2..fa0b50cc443 100644 --- a/_maps/RandomRuins/SpaceRuins/clownplanet.dmm +++ b/_maps/RandomRuins/SpaceRuins/clownplanet.dmm @@ -26,7 +26,7 @@ /turf/open/floor/engine, /area/ruin/space/has_grav/powered/clownplanet) "ah" = ( -/mob/living/simple_animal/hostile/retaliate/clown/clownhulk/destroyer, +/mob/living/basic/clown/clownhulk/destroyer, /turf/open/floor/engine, /area/ruin/space/has_grav/powered/clownplanet) "ai" = ( diff --git a/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm b/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm index bae9001b061..a1b7d571679 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 00000000000..2fa948a60fa --- /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 e2a49a71d1a..bd0ba4cc2ff 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 79a80371d07..57d2cafa4df 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/standard, +/obj/item/mod/core/standard, /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/storage/backpack/duffelbag/med/surgery, +/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 769f3ff42b2..1897f962201 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/storage/backpack/duffelbag/med/surgery, +/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/storage/backpack/duffelbag/med/surgery, +/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 88666dfae1b..ae5484c9891 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/storage/backpack/duffelbag/med/surgery, +/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/storage/backpack/duffelbag/med/surgery, +/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 b2132a30bad..6e42ed738cd 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/storage/backpack/duffelbag/med/surgery, +/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/storage/backpack/duffelbag/med/surgery, +/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 9d672426b7b..eef26fbf6d9 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/storage/backpack/duffelbag/med/surgery, +/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/storage/backpack/duffelbag/med/surgery, +/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 30195414409..3f65766b5af 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/storage/backpack/duffelbag/med/surgery, +/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 8bc3f3fed9b..3524b7a08a3 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/storage/backpack/duffelbag/med/surgery, +/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 aeb3fef36c2..e5b1e49530f 100644 --- a/_maps/RandomRuins/SpaceRuins/spacehotel_skyrat.dmm +++ b/_maps/RandomRuins/SpaceRuins/spacehotel_skyrat.dmm @@ -6960,7 +6960,7 @@ /area/ruin/space/has_grav/hotel) "Ps" = ( /obj/structure/table, -/obj/item/storage/backpack/duffelbag/med/surgery, +/obj/item/surgery_tray/full, /turf/open/floor/iron/showroomfloor, /area/ruin/space/has_grav/hotel) "Pw" = ( @@ -7839,7 +7839,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 8f91cc3fee2..6b0f009dcc6 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 90eff043bb5..b9887279a16 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/storage/backpack/duffelbag/med/surgery, +/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 01ecb68c703..21b1cddf818 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" = ( @@ -5495,6 +5497,14 @@ }, /turf/open/floor/iron, /area/station/maintenance/port/fore) +"ciL" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/structure/extinguisher_cabinet/directional/north, +/turf/open/floor/iron, +/area/station/cargo/storage) "ciR" = ( /obj/structure/table, /obj/effect/spawner/random/techstorage/command_all, @@ -5933,6 +5943,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 +7696,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" = ( @@ -8362,6 +8386,10 @@ }, /turf/open/floor/plating, /area/station/maintenance/disposal/incinerator) +"dmz" = ( +/obj/effect/spawner/random/structure/closet_maintenance, +/turf/open/floor/plating, +/area/station/maintenance/port/fore) "dmT" = ( /obj/machinery/camera/directional/north{ c_tag = "Xenobiology - Cell 2"; @@ -9534,14 +9562,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 +10305,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 +12278,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 +13560,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 +13808,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 +16685,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 +19701,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" = ( @@ -20201,18 +20241,21 @@ /obj/effect/turf_decal/stripes/white/line, /turf/open/floor/plating, /area/station/cargo/miningoffice) +"hsK" = ( +/obj/machinery/recycler{ + dir = 8 + }, +/obj/machinery/conveyor{ + dir = 4; + id = "garbage" + }, +/turf/open/floor/plating, +/area/station/service/janitor) "hsO" = ( /obj/structure/cable, /obj/effect/spawner/structure/window, /turf/open/floor/plating, /area/station/hallway/secondary/command) -"hsX" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/sink/directional/south, -/obj/item/reagent_containers/cup/bucket, -/obj/item/mop, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) "hsZ" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -20223,11 +20266,6 @@ /obj/structure/barricade/wooden, /turf/open/floor/plating, /area/station/security/tram) -"htt" = ( -/obj/structure/rack, -/obj/effect/spawner/random/maintenance/two, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) "htI" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -20276,12 +20314,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/department/science/xenobiology) -"huc" = ( -/obj/effect/turf_decal/bot_white, -/obj/structure/rack, -/obj/item/electronics/apc, -/turf/open/floor/iron/smooth_large, -/area/station/cargo/warehouse) "huh" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -20657,6 +20689,16 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) +"hzN" = ( +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/item/radio/intercom/directional/north, +/turf/open/floor/iron, +/area/station/cargo/storage) "hzV" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable, @@ -20981,6 +21023,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/smooth, /area/station/hallway/secondary/command) +"hFm" = ( +/obj/effect/turf_decal/bot_white, +/obj/structure/rack, +/obj/item/electronics/apc, +/turf/open/floor/iron/smooth_large, +/area/station/cargo/warehouse) "hFx" = ( /turf/open/floor/iron/chapel{ dir = 1 @@ -21655,19 +21703,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 +23387,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" = ( @@ -24514,13 +24558,6 @@ /obj/effect/decal/cleanable/cobweb/cobweb2, /turf/open/floor/plating, /area/station/service/abandoned_gambling_den) -"iUG" = ( -/obj/machinery/door/airlock/maintenance{ - name = "Maintenance" - }, -/obj/effect/mapping_helpers/airlock/access/all/supply/general, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) "iUH" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/table/reinforced/titaniumglass, @@ -24774,7 +24811,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 +25898,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 +27172,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, @@ -27490,6 +27531,15 @@ /obj/effect/turf_decal/siding/wideplating/dark/corner, /turf/open/floor/iron, /area/station/security) +"jXE" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/light/cold/directional/north, +/obj/structure/sign/poster/official/random/directional/north, +/turf/open/floor/iron, +/area/station/cargo/storage) "jXQ" = ( /obj/structure/flora/bush/large/style_random{ pixel_x = -18; @@ -27606,10 +27656,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 +27683,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 +27733,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 +27767,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, @@ -27915,11 +27943,6 @@ dir = 8 }, /area/station/hallway/secondary/dock) -"kfA" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/spawner/random/structure/crate, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) "kfC" = ( /obj/effect/spawner/random/engineering/atmospherics_portable, /turf/open/floor/plating, @@ -28106,10 +28129,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 +28238,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" = ( @@ -29043,15 +29063,6 @@ }, /turf/open/floor/iron/small, /area/station/hallway/primary/central/fore) -"kzF" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/cable, -/obj/machinery/light/cold/directional/north, -/obj/structure/sign/poster/official/random/directional/north, -/turf/open/floor/iron, -/area/station/cargo/storage) "kzI" = ( /obj/effect/turf_decal/bot_white, /obj/effect/spawner/random/structure/crate_empty, @@ -29162,16 +29173,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" = ( @@ -29818,10 +29837,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/textured_half, /area/station/cargo/miningoffice) -"kOA" = ( -/obj/effect/spawner/random/structure/closet_maintenance, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) "kOG" = ( /obj/structure/cable, /obj/machinery/door/airlock/external{ @@ -30554,27 +30569,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{ @@ -31340,6 +31353,10 @@ /obj/structure/ore_box, /turf/open/floor/plating, /area/station/maintenance/starboard/greater) +"lnT" = ( +/obj/machinery/rnd/bepis, +/turf/open/floor/iron, +/area/station/cargo/storage) "lnZ" = ( /obj/effect/turf_decal/tile/dark_red, /obj/effect/decal/cleanable/dirt, @@ -31881,6 +31898,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" = ( @@ -31905,16 +31923,6 @@ /obj/item/wrench, /turf/open/floor/iron, /area/station/security/tram) -"lzn" = ( -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/item/radio/intercom/directional/north, -/turf/open/floor/iron, -/area/station/cargo/storage) "lzp" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -32943,10 +32951,6 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/plating, /area/station/maintenance/starboard/central) -"lQq" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/plating, -/area/station/maintenance/port/fore) "lQu" = ( /obj/machinery/light/broken/directional/south, /obj/effect/spawner/random/trash/bin, @@ -33940,14 +33944,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 +35115,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, @@ -35547,6 +35543,11 @@ }, /turf/open/floor/iron, /area/station/security/processing) +"mLx" = ( +/obj/structure/rack, +/obj/effect/spawner/random/maintenance/two, +/turf/open/floor/plating, +/area/station/maintenance/port/fore) "mLA" = ( /obj/structure/cable, /obj/machinery/power/apc/auto_name/directional/west, @@ -36374,11 +36375,6 @@ /obj/structure/alien/weeds, /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, -/area/station/service/janitor) "ncl" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -37895,20 +37891,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 +37939,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 +38211,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" = ( @@ -39112,10 +39104,6 @@ /obj/structure/steam_vent, /turf/open/floor/plating/rust, /area/station/maintenance/fore/greater) -"odN" = ( -/obj/machinery/rnd/bepis, -/turf/open/floor/iron, -/area/station/cargo/storage) "odP" = ( /obj/machinery/firealarm/directional/west, /obj/effect/landmark/generic_maintenance_landmark, @@ -39660,14 +39648,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 +41408,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 +41917,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 +42041,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 +42163,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 +42907,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 +44331,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 +44582,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 +48816,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 +51179,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 +55534,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 +55603,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, @@ -55863,6 +55851,13 @@ /obj/machinery/shower/directional/west, /turf/open/floor/iron/dark, /area/station/medical/pharmacy) +"tDm" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Maintenance" + }, +/obj/effect/mapping_helpers/airlock/access/all/supply/general, +/turf/open/floor/plating, +/area/station/maintenance/port/fore) "tDn" = ( /turf/closed/wall/r_wall, /area/station/maintenance/department/prison) @@ -57793,13 +57788,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 +57876,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 +57914,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) @@ -57994,14 +57976,6 @@ /obj/machinery/firealarm/directional/west, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) -"unz" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/cable, -/obj/structure/extinguisher_cabinet/directional/north, -/turf/open/floor/iron, -/area/station/cargo/storage) "unK" = ( /obj/structure/rack, /obj/effect/spawner/random/maintenance, @@ -60667,6 +60641,13 @@ /obj/structure/closet/emcloset, /turf/open/floor/iron/small, /area/station/maintenance/starboard/central) +"viR" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/sink/directional/south, +/obj/item/reagent_containers/cup/bucket, +/obj/item/mop, +/turf/open/floor/plating, +/area/station/maintenance/port/fore) "viT" = ( /obj/machinery/light/cold/directional/east, /turf/open/floor/iron, @@ -63936,6 +63917,10 @@ /obj/effect/spawner/structure/window, /turf/open/floor/plating, /area/station/hallway/secondary/exit/departure_lounge) +"whS" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plating, +/area/station/maintenance/port/fore) "whX" = ( /obj/structure/disposalpipe/segment, /obj/machinery/door/airlock{ @@ -64051,8 +64036,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" = ( @@ -66301,6 +66292,11 @@ /obj/machinery/door/firedoor, /turf/open/floor/iron/textured_half, /area/station/security/prison/work) +"wTn" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/spawner/random/structure/crate, +/turf/open/floor/plating, +/area/station/maintenance/port/fore) "wTs" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/sign/poster/official/random/directional/north, @@ -69214,16 +69210,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 +70716,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" = ( @@ -83017,7 +83003,7 @@ uzJ mQh nJU ppk -odN +lnT ovQ oRr poM @@ -83518,14 +83504,14 @@ gOK slY hfc slY -hsX +viR jBb kPW kwY -lQq -kOA +whS +dmz slY -lzn +hzN lRc moz kee @@ -83775,14 +83761,14 @@ gPN gZk iNE ueX -htt +mLx kwY slY slY kwY slY slY -kzF +jXE lTv oem oem @@ -84035,10 +84021,10 @@ jCo hff jCo slY -kfA -lQq +wTn +whS kPW -iUG +tDm jkS lTN mRD @@ -84296,7 +84282,7 @@ slY slY slY slY -unz +ciL lUz ohj ohj @@ -84546,7 +84532,7 @@ sNz hyO roi slY -huc +hFm hAN jMb kzI @@ -98165,7 +98151,7 @@ qjy vPP otX hei -xHm +hei vPP hxJ jVe @@ -103830,9 +103816,9 @@ sOs xmO lKn nFW +dXO sRL sRL -nEJ nVX sRL sRL @@ -104089,10 +104075,10 @@ sHe nFW kam boX -kBH +asZ ukW cZL -xVV +sRL dCH ixP sRL @@ -104343,9 +104329,9 @@ kCW xID xmO sHs -nFW +pke tzD -ukW +cqS kCN wjM lcW @@ -104600,11 +104586,11 @@ rIJ rAG xmO sHe -mhW +nFW mEy -ncf +hsK nFA -ujl +kBH onR xVV lOt @@ -104859,9 +104845,9 @@ xmO qzO nFW ghW -ulM +boX kCP -kbc +kBH saD sRL sRL @@ -105116,7 +105102,7 @@ sJR sIA jPq kaF -roB +ffD hTW roB lde @@ -105372,10 +105358,10 @@ xmO jsn sIS nFW +sRL +sRL xVV -xVV -xVV -xVV +sRL xVV sRL bFg @@ -111823,7 +111809,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 b3ab8ca3b8e..15c9aae2b71 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 5e1a887d167..f3ff89fcc80 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/KiloStation2/KiloStation2.dmm b/_maps/map_files/KiloStation2/KiloStation2.dmm index d055aa13ef9..8e20d8b305b 100644 --- a/_maps/map_files/KiloStation2/KiloStation2.dmm +++ b/_maps/map_files/KiloStation2/KiloStation2.dmm @@ -2540,7 +2540,7 @@ pixel_x = -2 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "aNp" = ( /obj/effect/turf_decal/bot, /obj/structure/closet/emcloset, @@ -3941,7 +3941,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) "bpz" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -5261,7 +5261,7 @@ "bPf" = ( /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) "bPK" = ( /obj/machinery/status_display/shuttle/directional/east{ shuttle_id = "arrivals_shuttle" @@ -9328,7 +9328,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) "deZ" = ( /obj/structure/chair, /obj/effect/turf_decal/tile/neutral/half/contrasted, @@ -11797,7 +11797,7 @@ pixel_x = -4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "dSn" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/cobweb/cobweb2, @@ -12912,7 +12912,7 @@ }, /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) "emx" = ( /obj/effect/turf_decal/stripes/white/line{ dir = 8 @@ -12956,7 +12956,7 @@ /area/station/maintenance/disposal/incinerator) "enj" = ( /turf/closed/wall/r_wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "enr" = ( /obj/structure/table, /obj/item/storage/box/lights/mixed{ @@ -13532,7 +13532,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) "exN" = ( /obj/effect/turf_decal/box/corners, /obj/effect/decal/cleanable/dirt, @@ -18684,7 +18684,7 @@ }, /obj/structure/filingcabinet/chestdrawer, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "gbY" = ( /obj/effect/turf_decal/bot/left, /obj/effect/decal/cleanable/ash, @@ -19416,7 +19416,7 @@ /turf/open/floor/iron/dark/corner{ dir = 4 }, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "goY" = ( /obj/structure/chair/pew/right{ dir = 4 @@ -20500,7 +20500,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) "gGs" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -22043,7 +22043,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) "hiQ" = ( /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -23388,7 +23388,7 @@ }, /obj/machinery/holopad, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "hCK" = ( /obj/structure/table, /obj/item/clothing/gloves/color/orange, @@ -23810,7 +23810,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) "hIS" = ( /obj/structure/rack, /obj/effect/spawner/random/techstorage/rnd_all, @@ -30785,7 +30785,7 @@ /area/station/science/server) "jPe" = ( /turf/closed/wall/r_wall/rust, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "jPq" = ( /obj/structure/table/wood, /obj/effect/decal/cleanable/cobweb, @@ -31087,7 +31087,7 @@ pixel_x = -32 }, /obj/machinery/light/directional/north, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/machinery/status_display/evac/directional/north, /obj/effect/turf_decal/tile/neutral/half/contrasted{ dir = 4 @@ -33858,7 +33858,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, -/obj/machinery/recycler, +/obj/machinery/recycler{ + dir = 8 + }, /turf/open/floor/iron/dark, /area/station/service/janitor) "kSs" = ( @@ -34524,7 +34526,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) "lby" = ( /turf/closed/wall, /area/station/science/robotics/mechbay) @@ -35280,7 +35282,7 @@ "loy" = ( /obj/structure/filingcabinet/employment, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "loI" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -37205,7 +37207,7 @@ "lVe" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/table/reinforced, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /turf/open/floor/iron/dark, /area/station/medical/morgue) "lVf" = ( @@ -42175,7 +42177,7 @@ "nBZ" = ( /obj/machinery/newscaster/directional/west, /obj/structure/table, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/effect/turf_decal/bot, /obj/effect/turf_decal/tile/neutral/half/contrasted, /turf/open/floor/iron/dark, @@ -43402,7 +43404,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) "nZE" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /obj/effect/turf_decal/stripes/line{ @@ -43799,7 +43801,7 @@ /area/space/nearstation) "ogL" = ( /turf/closed/wall/rust, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "ogM" = ( /obj/structure/table/wood/fancy, /obj/effect/turf_decal/siding/wideplating/dark/corner, @@ -44914,7 +44916,6 @@ /area/station/hallway/primary/fore) "oAO" = ( /obj/effect/turf_decal/stripes/corner, -/obj/machinery/lapvend, /obj/effect/turf_decal/tile/neutral/anticorner/contrasted{ dir = 8 }, @@ -47948,7 +47949,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) "pzC" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -53027,7 +53028,7 @@ /area/station/cargo/office) "riT" = ( /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "riW" = ( /obj/effect/turf_decal/siding/wood{ dir = 6 @@ -53066,7 +53067,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) "rjR" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/bot, @@ -55465,7 +55466,7 @@ dir = 1 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "rUj" = ( /obj/effect/turf_decal/tile/neutral, /turf/open/floor/iron/dark/corner, @@ -55905,7 +55906,7 @@ dir = 4 }, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "scE" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -56029,7 +56030,7 @@ "sdT" = ( /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) "sdX" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark, @@ -56435,7 +56436,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) "slo" = ( /obj/structure/cable, /obj/effect/spawner/structure/window/reinforced/tinted, @@ -60504,7 +60505,7 @@ }, /obj/item/camera_film, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "twu" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, @@ -61855,7 +61856,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) "tUO" = ( /obj/structure/railing{ dir = 1 @@ -62880,7 +62881,7 @@ "ukd" = ( /obj/structure/table/wood, /turf/open/floor/carpet/executive, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "uke" = ( /obj/structure/chair/sofa/bench/right{ dir = 1 @@ -63495,7 +63496,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) "usV" = ( /obj/structure/table/wood, /obj/item/pai_card, @@ -63732,7 +63733,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) "uwX" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/decal/cleanable/dirt, @@ -66496,7 +66497,7 @@ id = "nt_rep_priv" }, /turf/open/floor/plating, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "vtv" = ( /obj/structure/table/bronze, /obj/item/clothing/suit/costume/bronze, @@ -71274,7 +71275,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) "wNs" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -71945,7 +71946,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) "wZW" = ( /obj/machinery/door/firedoor, /turf/open/floor/iron/dark, @@ -75780,7 +75781,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) "ykK" = ( /obj/structure/frame/computer{ anchored = 1; diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index f112651342b..cfa13aef72e 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 e96bc43b16b..5f7a19198bb 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/NSSJourney/NSSJourney.dmm b/_maps/map_files/NSSJourney/NSSJourney.dmm index acde1370c4d..19299f10006 100644 --- a/_maps/map_files/NSSJourney/NSSJourney.dmm +++ b/_maps/map_files/NSSJourney/NSSJourney.dmm @@ -1123,7 +1123,7 @@ }, /obj/machinery/holopad, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "aio" = ( /turf/open/floor/iron/dark, /area/station/ai_monitored/command/storage/eva) @@ -1141,7 +1141,7 @@ /obj/machinery/photocopier, /obj/machinery/airalarm/directional/east, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "aiA" = ( /obj/machinery/door/airlock/maintenance{ name = "Recharge Dock" @@ -2227,7 +2227,7 @@ pixel_y = -2 }, /turf/open/floor/carpet/executive, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "aph" = ( /turf/closed/wall/r_wall, /area/station/maintenance/fore) @@ -2257,7 +2257,7 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "apt" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -3083,7 +3083,7 @@ /obj/structure/cable, /obj/effect/landmark/navigate_destination, /turf/open/floor/wood, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "ate" = ( /obj/effect/landmark/generic_maintenance_landmark, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2{ @@ -5998,12 +5998,12 @@ "aDi" = ( /obj/structure/sign/poster/official/no_erp/directional/north, /turf/open/floor/carpet/executive, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "aDj" = ( /obj/machinery/photocopier, /obj/machinery/airalarm/directional/west, /turf/open/floor/carpet/executive, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "aDo" = ( /turf/open/floor/iron, /area/station/commons/storage/primary) @@ -6054,7 +6054,7 @@ /obj/machinery/light/directional/north, /obj/machinery/newscaster/directional/north, /turf/open/floor/carpet/executive, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "aDz" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 1 @@ -6642,13 +6642,13 @@ fax_name = "Blueshield's Office" }, /turf/open/floor/carpet/executive, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "aFX" = ( /obj/structure/table/wood, /obj/item/paper_bin, /obj/item/pen/fountain, /turf/open/floor/carpet/executive, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "aFY" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2{ dir = 4 @@ -7043,7 +7043,7 @@ dir = 1 }, /turf/open/floor/wood, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "aHk" = ( /obj/machinery/holopad, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -7079,7 +7079,7 @@ }, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/wood, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "aHw" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -7561,7 +7561,7 @@ /area/station/commons/storage/primary) "aJa" = ( /turf/open/floor/wood, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "aJb" = ( /obj/effect/turf_decal/delivery, /turf/open/floor/iron, @@ -7595,7 +7595,7 @@ }, /obj/machinery/light/directional/east, /turf/open/floor/iron/dark/textured, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "aJj" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2{ dir = 10 @@ -7728,7 +7728,7 @@ }, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /turf/open/floor/wood, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "aJC" = ( /turf/closed/wall, /area/station/service/bar) @@ -7985,7 +7985,7 @@ "aKA" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "aKD" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -11618,7 +11618,6 @@ /area/station/commons/locker) "aXt" = ( /obj/effect/turf_decal/stripes/corner, -/obj/machinery/lapvend, /turf/open/floor/iron, /area/station/commons/locker) "aXu" = ( @@ -13927,7 +13926,9 @@ dir = 4; id = "garbage" }, -/obj/machinery/recycler, +/obj/machinery/recycler{ + dir = 8 + }, /obj/structure/sign/warning/secure_area/directional/north{ name = "\improper STAY CLEAR HEAVY MACHINERY" }, @@ -14260,7 +14261,6 @@ /obj/effect/turf_decal/tile/purple{ dir = 8 }, -/obj/machinery/lapvend, /obj/item/radio/intercom/directional/south, /turf/open/floor/iron, /area/station/hallway/primary/starboard) @@ -14652,7 +14652,7 @@ "bhp" = ( /obj/effect/decal/cleanable/cobweb, /obj/structure/table/reinforced, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /turf/open/floor/iron/dark, /area/station/medical/morgue) "bhq" = ( @@ -15083,7 +15083,7 @@ /area/station/medical/morgue) "biC" = ( /obj/structure/cable, -/obj/structure/bodycontainer/morgue/beeper_off{ +/obj/structure/bodycontainer/morgue{ dir = 2 }, /turf/open/floor/iron/dark, @@ -15095,7 +15095,7 @@ pixel_x = -5; pixel_y = 30 }, -/obj/structure/bodycontainer/morgue/beeper_off{ +/obj/structure/bodycontainer/morgue{ dir = 2 }, /turf/open/floor/iron/dark, @@ -15331,7 +15331,7 @@ dir = 4 }, /turf/open/floor/carpet/executive, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "bjl" = ( /obj/structure/disposalpipe/segment{ dir = 9 @@ -15349,7 +15349,7 @@ /obj/structure/chair/comfy/brown, /obj/effect/landmark/start/blueshield, /turf/open/floor/carpet/executive, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "bjo" = ( /obj/machinery/camera/directional/north{ c_tag = "Cargo Bay North" @@ -15580,10 +15580,10 @@ /turf/open/floor/iron/smooth_large, /area/station/engineering/main) "bkd" = ( -/obj/structure/bodycontainer/morgue/beeper_off{ +/obj/structure/window/reinforced/spawner/directional/south, +/obj/structure/bodycontainer/morgue{ dir = 1 }, -/obj/structure/window/reinforced/spawner/directional/south, /turf/open/floor/iron/dark, /area/station/medical/morgue) "bkf" = ( @@ -18785,6 +18785,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/mapping_helpers/mail_sorting/science/research, +/obj/structure/cable, /turf/open/floor/iron/white, /area/station/science/research) "bto" = ( @@ -21330,7 +21331,7 @@ dir = 1 }, /turf/open/floor/wood, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "bCA" = ( /obj/machinery/vending/cigarette, /turf/open/floor/iron/dark, @@ -23043,13 +23044,6 @@ /turf/open/floor/plating, /area/station/maintenance/aft) "bHY" = ( -/obj/machinery/door_buttons/access_button{ - idDoor = "virology_airlock_exterior"; - idSelf = "virology_airlock_control"; - name = "Virology Access Button"; - pixel_x = -24; - req_access = list("virology") - }, /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/locked, /obj/machinery/door/airlock/virology{ @@ -24550,11 +24544,11 @@ /turf/open/floor/iron, /area/station/science/xenobiology) "bNq" = ( -/obj/structure/bodycontainer/morgue/beeper_off{ - dir = 1 - }, /obj/structure/window/reinforced/spawner/directional/south, /obj/structure/window/reinforced/spawner/directional/west, +/obj/structure/bodycontainer/morgue{ + dir = 1 + }, /turf/open/floor/iron/dark, /area/station/medical/morgue) "bNr" = ( @@ -25548,15 +25542,6 @@ /turf/open/floor/iron/dark, /area/station/medical/virology) "bRP" = ( -/obj/machinery/door_buttons/airlock_controller{ - idExterior = "virology_airlock_exterior"; - idInterior = "virology_airlock_interior"; - idSelf = "virology_airlock_control"; - name = "Virology Access Console"; - pixel_x = 8; - pixel_y = 22; - req_access = list("virology") - }, /obj/machinery/light_switch{ pixel_x = -4; pixel_y = 24 @@ -25564,6 +25549,14 @@ /obj/effect/turf_decal/trimline/green/filled/line{ dir = 9 }, +/obj/machinery/door_buttons/access_button{ + idDoor = "virology_airlock_interior"; + idSelf = "virology_airlock_control"; + name = "Virology Access Button"; + pixel_x = 8; + req_access = list("virology"); + pixel_y = 24 + }, /turf/open/floor/iron/white, /area/station/medical/virology) "bRQ" = ( @@ -25605,7 +25598,7 @@ dir = 8 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "bSh" = ( /obj/machinery/power/apc/auto_name/directional/east, /obj/structure/cable, @@ -29180,10 +29173,10 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/blood/old, /obj/structure/cable, -/obj/structure/bodycontainer/morgue/beeper_off{ +/obj/structure/window/reinforced/spawner/directional/south, +/obj/structure/bodycontainer/morgue{ dir = 1 }, -/obj/structure/window/reinforced/spawner/directional/south, /turf/open/floor/iron/dark, /area/station/medical/morgue) "chN" = ( @@ -34643,7 +34636,7 @@ /obj/effect/landmark/navigate_destination, /obj/effect/mapping_helpers/airlock/access/any/cent_com/rep_door, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "dbg" = ( /obj/machinery/door/airlock/security/glass{ name = "Solitary Cell" @@ -35510,9 +35503,7 @@ /turf/open/floor/wood, /area/station/service/library/abandoned) "dSj" = ( -/obj/machinery/dish_drive/bullet{ - succrange = 4 - }, +/obj/machinery/dish_drive/bullet, /turf/open/floor/iron/dark, /area/station/security/office) "dSm" = ( @@ -35987,13 +35978,13 @@ /turf/open/floor/iron/freezer, /area/station/commons/toilet) "eml" = ( -/obj/structure/bodycontainer/morgue/beeper_off{ - dir = 1 - }, /obj/structure/window/reinforced/spawner/directional/south, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2{ dir = 8 }, +/obj/structure/bodycontainer/morgue{ + dir = 1 + }, /turf/open/floor/iron/dark, /area/station/medical/morgue) "emn" = ( @@ -36182,7 +36173,7 @@ /obj/structure/table/wood, /obj/item/storage/fancy/donut_box, /turf/open/floor/carpet/executive, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "ewk" = ( /obj/machinery/atmospherics/pipe/smart/simple/dark/visible, /obj/machinery/atmospherics/pipe/smart/manifold4w/brown/visible/layer2, @@ -36595,7 +36586,7 @@ "eRD" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "eRH" = ( /obj/structure/table/wood, /obj/item/flashlight/lamp/green{ @@ -36806,7 +36797,7 @@ dir = 8 }, /turf/open/floor/iron/dark/textured, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "fdf" = ( /obj/machinery/power/apc/auto_name/directional/west, /obj/machinery/camera/directional/south{ @@ -37581,7 +37572,7 @@ }, /obj/effect/mapping_helpers/airlock/access/any/cent_com/rep_door, /turf/open/floor/plating, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "fJu" = ( /obj/item/radio/intercom/directional/west, /obj/structure/table/reinforced/rglass, @@ -37722,7 +37713,7 @@ pixel_y = 8 }, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "fPh" = ( /obj/effect/turf_decal/stripes/white/line{ dir = 4 @@ -37831,14 +37822,6 @@ /area/station/security/prison/safe) "fRG" = ( /obj/structure/sink/directional/east, -/obj/machinery/door_buttons/access_button{ - idDoor = "virology_airlock_interior"; - idSelf = "virology_airlock_control"; - name = "Virology Access Button"; - pixel_x = 8; - pixel_y = -28; - req_access = list("virology") - }, /obj/effect/turf_decal/stripes/line{ dir = 10 }, @@ -37846,6 +37829,15 @@ dir = 10 }, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/door_buttons/airlock_controller{ + idExterior = "virology_airlock_exterior"; + idInterior = "virology_airlock_interior"; + idSelf = "virology_airlock_control"; + name = "Virology Access Console"; + pixel_x = 7; + pixel_y = -26; + req_access = list("virology") + }, /turf/open/floor/iron/white, /area/station/medical/virology) "fSb" = ( @@ -38058,7 +38050,7 @@ }, /obj/effect/turf_decal/tile/blue, /obj/structure/table/glass, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/machinery/vending/wallmed{ pixel_x = 32 }, @@ -38449,7 +38441,7 @@ fax_name = "Nanotrasen Consultant's Office" }, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "guf" = ( /obj/structure/closet/secure_closet/warden, /obj/structure/cable, @@ -40876,7 +40868,7 @@ dir = 8 }, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "iFN" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/general/hidden, @@ -41408,7 +41400,7 @@ dir = 4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "jei" = ( /obj/effect/turf_decal/trimline/blue/filled/line, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -41553,7 +41545,7 @@ "jiY" = ( /obj/structure/filingcabinet/medical, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "jjr" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2{ @@ -41929,7 +41921,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) "jzb" = ( /obj/machinery/door/airlock/research/glass{ name = "Ordnance Lab" @@ -42176,7 +42168,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/structure/cable, -/obj/structure/bodycontainer/morgue/beeper_off{ +/obj/structure/bodycontainer/morgue{ dir = 2 }, /turf/open/floor/iron/dark, @@ -42227,7 +42219,7 @@ /obj/structure/filingcabinet/employment, /obj/machinery/firealarm/directional/west, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "jMm" = ( /obj/effect/turf_decal/bot_white, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -43092,7 +43084,7 @@ dir = 8 }, /obj/structure/table/glass, -/obj/item/surgery_tray, +/obj/item/surgery_tray/full, /obj/machinery/vending/wallmed{ pixel_x = -32 }, @@ -43150,7 +43142,7 @@ dir = 8 }, /turf/open/floor/wood, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "kwa" = ( /obj/structure/tank_dispenser, /turf/open/floor/iron, @@ -49536,7 +49528,7 @@ /area/station/commons/dorms) "qcW" = ( /turf/closed/wall/r_wall, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "qde" = ( /obj/item/crowbar, /obj/item/wrench, @@ -49795,7 +49787,7 @@ name = "Premium Cozy Chair" }, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "qpr" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, @@ -50465,7 +50457,7 @@ dir = 4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "qRt" = ( /obj/effect/turf_decal/stripes/red/line{ dir = 5 @@ -50797,7 +50789,7 @@ dir = 6 }, /turf/open/floor/wood, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "reQ" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -50807,7 +50799,7 @@ dir = 4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "rfj" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/public/glass{ @@ -51377,7 +51369,7 @@ /area/station/hallway/primary/starboard) "rGG" = ( /turf/closed/wall/r_wall, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "rGH" = ( /obj/effect/turf_decal/tile/blue{ dir = 1 @@ -51445,7 +51437,7 @@ /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "rJl" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4{ @@ -52630,7 +52622,7 @@ /obj/machinery/light/directional/north, /obj/machinery/newscaster/directional/north, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "sLX" = ( /obj/effect/turf_decal/tile/yellow, /obj/effect/turf_decal/tile/yellow{ @@ -53843,13 +53835,9 @@ pixel_x = -5; pixel_y = -1 }, -/obj/item/folder/documents{ - pixel_y = 2; - pixel_x = -5 - }, /obj/item/folder/yellow{ pixel_x = -5; - pixel_y = 5 + pixel_y = 3 }, /obj/item/folder/red{ pixel_y = 7; @@ -53857,7 +53845,7 @@ }, /obj/item/pen/fountain, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "tNv" = ( /obj/structure/disposalpipe/segment{ dir = 5 @@ -54602,7 +54590,7 @@ /area/station/medical/medbay/aft) "uyx" = ( /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "uyD" = ( /turf/open/floor/iron/chapel, /area/station/service/chapel) @@ -54886,7 +54874,7 @@ dir = 8 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "uOx" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/window/reinforced/spawner/directional/west, @@ -55478,7 +55466,7 @@ }, /obj/machinery/firealarm/directional/east, /turf/open/floor/iron/dark/textured, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "vmV" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden{ dir = 4 @@ -55721,7 +55709,7 @@ /obj/structure/filingcabinet/security, /obj/machinery/light/directional/west, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "vAk" = ( /obj/machinery/door/window/left/directional/west{ dir = 1; @@ -55764,7 +55752,7 @@ dir = 4 }, /turf/open/floor/wood, -/area/blueshield) +/area/station/command/heads_quarters/blueshield) "vBc" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, @@ -56260,7 +56248,7 @@ /obj/machinery/power/apc/auto_name/directional/south, /obj/structure/cable, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "vTE" = ( /obj/effect/turf_decal/tile/red{ dir = 4 @@ -56612,7 +56600,7 @@ dir = 4 }, /turf/open/floor/wood, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "whr" = ( /obj/item/stack/tile/iron/white/smooth_large, /obj/effect/mapping_helpers/burnt_floor, @@ -58188,7 +58176,7 @@ pixel_y = -2 }, /turf/open/floor/carpet/green, -/area/command/heads_quarters/captain/private/nt_rep) +/area/station/command/heads_quarters/nt_rep) "xwv" = ( /obj/structure/rack, /obj/item/tank/internals/oxygen/red, @@ -58933,6 +58921,14 @@ dir = 10 }, /obj/item/kirbyplants/random, +/obj/machinery/door_buttons/access_button{ + idDoor = "virology_airlock_exterior"; + idSelf = "virology_airlock_control"; + name = "Virology Access Button"; + req_access = list("virology"); + pixel_y = -24; + pixel_x = 8 + }, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) "yck" = ( diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index f701e36239c..d9fff1d8af0 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/VoidRaptor/VoidRaptor.dmm b/_maps/map_files/VoidRaptor/VoidRaptor.dmm index d5c9a9c1586..c3918c21108 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) @@ -18728,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 @@ -19518,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{ @@ -19677,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, @@ -20005,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" = ( @@ -20109,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" = ( @@ -20649,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, @@ -20857,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 @@ -21049,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" = ( @@ -21262,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) @@ -21470,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, @@ -22053,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" = ( @@ -22827,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 @@ -22849,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."; @@ -23720,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 @@ -23771,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{ @@ -24225,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{ @@ -24254,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" = ( @@ -24587,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, @@ -24727,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, @@ -25081,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, @@ -25184,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{ @@ -25202,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, @@ -25458,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, @@ -25930,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, @@ -26220,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{ @@ -26347,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{ @@ -26966,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{ @@ -27577,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, @@ -27687,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, @@ -27727,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 @@ -27819,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, @@ -27828,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 @@ -28118,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, @@ -28158,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{ @@ -28289,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, @@ -28305,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 @@ -28373,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{ @@ -28767,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" = ( @@ -28819,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 @@ -28845,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, @@ -28859,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, @@ -29085,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 @@ -29647,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 @@ -29711,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{ @@ -29880,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"; @@ -30059,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{ @@ -30111,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{ @@ -30876,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 @@ -31060,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, @@ -31137,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, @@ -31202,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, @@ -32022,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, @@ -32326,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{ @@ -32523,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, @@ -33206,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 @@ -33864,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{ @@ -33952,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{ @@ -34552,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, @@ -34566,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 @@ -34640,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 @@ -35474,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, @@ -35722,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 @@ -35927,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{ @@ -36187,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, @@ -36234,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, @@ -36636,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, @@ -36655,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, @@ -36690,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, @@ -37085,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, @@ -37152,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{ @@ -37599,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) @@ -37705,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" = ( @@ -37966,7 +38247,7 @@ /area/station/command/heads_quarters/captain/private) "kRg" = ( /obj/structure/table/reinforced, -/obj/item/storage/backpack/duffelbag/med/surgery, +/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, @@ -38048,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, @@ -38747,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" = ( @@ -39099,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{ @@ -39203,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) @@ -39210,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) @@ -39269,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, @@ -39284,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 @@ -39617,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 @@ -39759,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; @@ -39794,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 @@ -40308,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{ @@ -40771,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, @@ -40873,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, @@ -40893,7 +41194,7 @@ dir = 6 }, /obj/effect/turf_decal/tile/blue/full, -/obj/item/storage/backpack/duffelbag/med/surgery, +/obj/item/surgery_tray/full, /obj/structure/sign/poster/official/random/directional/south, /obj/structure/sign/nanotrasen{ pixel_x = 32 @@ -41307,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" = ( @@ -41428,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{ @@ -41536,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, @@ -43153,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 @@ -44642,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, @@ -44764,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, @@ -44983,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 @@ -45340,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, @@ -45395,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, @@ -45756,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, @@ -45787,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 @@ -45928,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, @@ -46177,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{ @@ -46205,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, @@ -46865,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 @@ -47071,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) @@ -47187,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" = ( @@ -47399,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, @@ -47533,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{ @@ -47576,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{ @@ -47653,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, @@ -47826,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 @@ -47922,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, @@ -47995,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, @@ -48712,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, @@ -49478,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, @@ -49497,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" = ( @@ -49780,7 +50126,7 @@ dir = 5 }, /obj/effect/turf_decal/tile/blue/full, -/obj/item/storage/backpack/duffelbag/med/surgery, +/obj/item/surgery_tray/full, /obj/structure/sign/nanotrasen{ pixel_x = 32 }, @@ -49795,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, @@ -49813,6 +50172,7 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, +/obj/machinery/light/cold/directional/south, /turf/open/floor/iron/white/smooth_edge{ dir = 1 }, @@ -49913,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, @@ -50402,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 @@ -50848,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 @@ -50877,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, @@ -51009,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, @@ -51318,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, @@ -51420,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, @@ -51769,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"; @@ -51984,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" = ( @@ -52830,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, @@ -52868,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, @@ -52992,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, @@ -53242,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, @@ -53685,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, @@ -53929,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, @@ -54138,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{ @@ -54499,7 +54925,7 @@ id = "cargounload" }, /obj/machinery/door/poddoor{ - id = "cargounload"; + id = 68; name = "Supply Dock Unloading Door" }, /turf/open/floor/iron/smooth_large, @@ -54897,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, @@ -55006,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, @@ -55049,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 @@ -55162,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, @@ -55263,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{ @@ -55440,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, @@ -55714,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, @@ -56121,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, @@ -57346,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" = ( @@ -57367,7 +57822,6 @@ }, /area/station/science/xenobiology) "qgT" = ( -/obj/machinery/lapvend, /turf/open/floor/iron/white, /area/station/hallway/primary/fore) "qha" = ( @@ -57463,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"; @@ -57585,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{ @@ -57718,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, @@ -57942,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 @@ -58047,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, @@ -58702,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{ @@ -58713,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, @@ -58755,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, @@ -59557,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{ @@ -59741,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, @@ -60083,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 @@ -60267,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, @@ -60989,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, @@ -61379,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, @@ -61392,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{ @@ -61406,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, @@ -61587,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{ @@ -62050,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, @@ -62092,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, @@ -62439,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; @@ -62454,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, @@ -62756,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, @@ -63340,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, @@ -63735,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, @@ -63792,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, @@ -64098,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, @@ -64143,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 @@ -64215,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, @@ -64339,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, @@ -64798,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{ @@ -64901,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 @@ -65064,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, @@ -65626,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, @@ -65649,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, @@ -65797,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, @@ -66458,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{ @@ -66728,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" = ( @@ -67703,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, @@ -67912,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, @@ -68140,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{ @@ -68539,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, @@ -69188,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, @@ -69616,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, @@ -69817,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, @@ -71189,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 @@ -71333,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 @@ -71552,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{ @@ -71950,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 @@ -71971,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, @@ -72294,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, @@ -72712,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 @@ -72902,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 @@ -72929,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, @@ -74179,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{ @@ -74654,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, @@ -74814,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, @@ -75182,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" @@ -75381,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{ @@ -75499,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, @@ -76618,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, @@ -76729,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 @@ -76810,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, @@ -77006,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, @@ -77168,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, @@ -77340,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 @@ -77374,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, @@ -77776,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, @@ -78499,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{ @@ -78894,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, @@ -78956,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, @@ -79274,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" = ( @@ -79373,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" = ( @@ -79415,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, @@ -79652,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{ @@ -79664,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) @@ -79944,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" = ( @@ -80247,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{ @@ -80626,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, @@ -80800,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, @@ -80854,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{ @@ -80932,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, @@ -81398,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{ @@ -81524,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) @@ -81737,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, @@ -82349,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 @@ -82459,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, @@ -82477,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, @@ -82510,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, @@ -82540,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, @@ -82759,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, @@ -82819,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, @@ -82920,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{ @@ -82944,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{ @@ -83256,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, @@ -83488,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, @@ -83558,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{ @@ -83568,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, @@ -83736,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{ @@ -83781,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" = ( @@ -83815,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, @@ -84067,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{ @@ -84214,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{ @@ -84501,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, @@ -85087,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 @@ -85715,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, @@ -105649,7 +106355,7 @@ ttw ttw ttw sAM -fDA +jVE cvH knY xhU @@ -105662,10 +106368,10 @@ cvH grR mUM rcl -rcl -rcl -rcl -rcl +pxe +pxe +pxe +pxe oQo pxe ttw @@ -105906,7 +106612,7 @@ ttw ttw ttw sAM -fDA +jVE cvH cvH cvH @@ -105922,10 +106628,10 @@ rcl liB qgv dGj -rcl -oQo pxe -ttw +wFc +pxe +pxe ttw ttw ttw @@ -106163,7 +106869,7 @@ ttw ttw sAM sAM -nvM +vik qFH sAM oXc @@ -106179,10 +106885,10 @@ pcx gjT wtc sNq -rcl -oQo pxe -ttw +wFc +mJA +pxe ttw ttw ttw @@ -106232,7 +106938,7 @@ ydA sWI ron lQt -pZH +oxA ipJ dwi vPk @@ -106436,10 +107142,10 @@ flH mdK oLS hbE -rcl -oQo pxe -ttw +wGg +gHM +pxe ttw ttw ttw @@ -106487,9 +107193,9 @@ xtV dUO lQt eMd -pZH -pZH -pZH +oxA +oxA +oxA uUU ptY voU @@ -106694,9 +107400,9 @@ fUy bMN wNJ lMx -xNL +xim +pxe pxe -ttw ttw ttw ttw @@ -106744,7 +107450,7 @@ xtV aDC qQC qMB -spp +xwf yaE oNW uUU @@ -106950,8 +107656,8 @@ rcl rcl rcl rcl -rcl -xNL +pxe +xmF pxe ttw ttw @@ -106973,7 +107679,7 @@ nhU vAk qbS xiD -vAk +rSG vAk ryX kMf @@ -106985,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 @@ -107203,12 +107909,12 @@ hIh abQ aCm xZk -abQ -ttw -ttw -ttw -hxT -xNL +asX +tme +vAC +xwC +pxe +xmF hxT ttw ttw @@ -107227,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 @@ -107409,7 +108115,7 @@ paS eyy rcr nFs -bQF +mYn oKR oBd uvj @@ -107460,10 +108166,10 @@ bxX rFD jzo xry -rFD -ttw -ttw -ttw +asX +cEB +tzN +eKs pxe xNL pxe @@ -107483,9 +108189,9 @@ kZJ kZJ kRE pkR -nhU -nhU -nhU +imc +imc +imc nMv nhU nhU @@ -107498,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 @@ -107515,8 +108221,8 @@ gEq eLz eLz qAt -eLz -eLz +wpK +wpK qBl eLz eLz @@ -107666,8 +108372,8 @@ xyX eyy kJq nFs -oKR -hAA +lyJ +vzg rcf mbJ odJ @@ -107717,11 +108423,11 @@ abQ rFD icP icP -rFD -ttw -ttw -ttw -hxT +wfk +cGu +jqH +vIY +xrG oQo fUk ttw @@ -107732,7 +108438,7 @@ lvJ cJm xWK hbp -vGO +cgH cgZ wxn qlA @@ -107740,7 +108446,7 @@ qFA qFA rDm pkR -nhU +imc vAk lMS alm @@ -107923,7 +108629,7 @@ wlV eyy qtl nFs -oKR +lyJ oKR ixT uvj @@ -107974,10 +108680,10 @@ abQ ybI icP icP -rFD -ttw -ttw -ttw +asX +asX +asX +asX pxe oQo pxe @@ -107989,7 +108695,7 @@ rol rol sgk kIm -vGO +cgH cgZ wNh qlA @@ -107997,7 +108703,7 @@ qFA krh fZT pkR -nhU +imc eVW lMS ipg @@ -108231,11 +108937,11 @@ dMY icP rBo icP -rFD -ttw -ttw -ttw -hxT +wxG +tvc +plo +pcS +pxe oQo hxT ttw @@ -108254,8 +108960,8 @@ qFA krh oJG pkR -pXE -vAk +ijj +rSG lMS ipg fSa @@ -108488,10 +109194,10 @@ abQ wsZ icP icP -rFD -ttw -ttw -pxe +ooU +ngZ +efn +kzV pxe wSR pxe @@ -108503,7 +109209,7 @@ cgZ qHg xMk cgZ -sYt +lnU cgZ wNh oMd @@ -108512,7 +109218,7 @@ krh xOz pkR nhU -vAk +rSG lMS ipg fSa @@ -108745,12 +109451,12 @@ abQ rFD icP icP -rFD -ttw -ttw +wxG +ofG +mTl +icH pxe -wpU -oQo +idg lgX lgX lgX @@ -108760,7 +109466,7 @@ sud iii jom wKf -sYt +lnU cgZ wNh oMd @@ -108949,7 +109655,7 @@ aFO mSI enW dUw -oKR +lyJ uss wqg wqg @@ -109002,14 +109708,14 @@ xMq rFD pyQ pyQ -rFD -ttw -ttw -hxT +wxG +pAE +qkb +irU bgo ikc jwV -eak +utq lgX gMx wKf @@ -109017,7 +109723,7 @@ ryt olf rLZ wKf -sYt +lnU cgZ wxn oMd @@ -109259,10 +109965,10 @@ sAM sAM rNH hEf -abQ -lAB -lAB -lAB +nwW +vOX +vOX +vOX lAB mDL lAB @@ -109274,7 +109980,7 @@ gQi qaN kEw wKf -vGO +cgH cgZ wNh qFA @@ -109464,7 +110170,7 @@ btZ enW lpz qwH -oKR +lyJ bao uvj uvj @@ -109523,7 +110229,7 @@ erF gzy xWN lpZ -bwm +lAB duU eak ukV @@ -109531,7 +110237,7 @@ iSK bDF coR cgZ -vGO +cgH cgZ wNh qFA @@ -109796,7 +110502,7 @@ oON krh xZo pkR -nhU +imc nQG lMS deE @@ -110053,8 +110759,8 @@ qFA hzD kXW pkR -nhU -vAk +imc +rSG lMS wMb jmT @@ -110747,7 +111453,7 @@ eFQ fLX eFQ qwH -ljL +eFQ uRe ekX uvj @@ -111080,7 +111786,7 @@ fia jNA tAw pkR -vAk +rSG nhU hCL twe @@ -111256,7 +111962,7 @@ xsF xMq uvj lKX -iJJ +oBd uvj uvj iIq @@ -111517,8 +112223,8 @@ rcf uvj ioI nGH -nGH -eWu +lQf +mlv kIf wjI ffz @@ -111594,7 +112300,7 @@ kbV vco wLc pkR -lGH +cEL xvp lMS nXs @@ -111773,9 +112479,9 @@ rWs uvj uvj xmH -nGH +lQf rXL -nGH +lQf nRd wjI nSU @@ -112027,12 +112733,12 @@ ttw ttw rpk aUu -gGT +aiq wjI gwZ nGH ayc -eWu +mlv lsn wjI vSj @@ -112147,7 +112853,7 @@ tBC luV toq jKu -fpk +nES xVm iHL eJf @@ -112284,7 +112990,7 @@ wjI wjI wjI dTz -nGH +lQf wjI wjI wjI @@ -112404,7 +113110,7 @@ rOM vIt toq jKu -fpk +nES xVm eRt izg @@ -112548,9 +113254,9 @@ pKM oqF pKM pKM -pKM +dqM pDx -see +qUt see wjI mhe @@ -112762,10 +113468,10 @@ oQh veh veh hpq -gQh +knn eSD gQh -aXD +pnU xsZ gQh lrY @@ -112778,11 +113484,11 @@ lrY hml vHV dQq -gQh +knn gbM jYe mPw -aXD +pnU bcf vtD wPO @@ -112804,8 +113510,8 @@ vew clk gAG bnJ -nGH -nGH +lQf +lQf vWf nGH lbi @@ -112847,7 +113553,7 @@ etW rMu ups ufc -wen +ufc jRj rnF kUZ @@ -112875,7 +113581,7 @@ aFU sHv wiz rol -bXt +jtq sHv mjM biU @@ -112918,7 +113624,7 @@ dYh xtF toq nFg -wme +hYA xVm tXe kth @@ -113017,8 +113723,8 @@ veh vlt tTQ aXD -gQh -gQh +knn +knn tTQ pCm pCm @@ -113132,7 +113838,7 @@ sea sHv naG rol -bXt +jtq sHv dWt eUH @@ -113320,7 +114026,7 @@ lov jFt ydK wjI -vWf +lGy eWu nPV wjI @@ -113388,7 +114094,7 @@ jpF uUS sHv pRv -pIN +vij bXt sHv thY @@ -113577,8 +114283,8 @@ gNh rUo wQg wjI -vWf -nGH +lGy +lQf omw wjI mhe @@ -113645,7 +114351,7 @@ ads vxT sHv jLS -bXt +jtq sHv sHv fXP @@ -113834,8 +114540,8 @@ iVy jQM moF wjI -vWf -eWu +lGy +mlv jFH wjI nqC @@ -114192,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 @@ -114450,9 +115156,9 @@ pLI fwB fwB fwB -fwB -fwB -fwB +ssU +ssU +ssU fwB fwB brI @@ -114606,7 +115312,7 @@ cgx rIQ wjI vWf -eWu +mlv xOR wjI wjI @@ -114704,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 @@ -114864,10 +115570,10 @@ xWf wjI uZo oqF -pKM -ucl -pKM -pKM +dqM +oZB +dqM +dqM pVu vmf dPm @@ -114961,7 +115667,7 @@ crK ubZ tFt pLI -svC +rJa gjs brI brI @@ -114972,8 +115678,8 @@ fwB iUL brI dVe -cwa -rOQ +uvB +jte hUR brI xMq @@ -115230,7 +115936,7 @@ rOQ svC frl cwa -rOQ +jte brI brI brI @@ -115482,10 +116188,10 @@ eYM brI iJi svC -cwa -cwa -cwa -cwa +uvB +uvB +uvB +uvB cwa xRu gls @@ -115640,7 +116346,7 @@ rWc poX leB uZo -oqF +gTk kZX pKM nvZ @@ -117024,7 +117730,7 @@ rin lFE pEt rgE -eUp +kux owF puj kCR @@ -117281,7 +117987,7 @@ rin lFE pEt veD -eUp +kux cGZ kzc vQS @@ -117538,7 +118244,7 @@ kmZ lFE pEt evE -eUp +kux qbp qbp gmz @@ -117794,7 +118500,7 @@ tZZ xMq lFE pEt -awv +isr xhr lhE qbp @@ -118052,7 +118758,7 @@ xMq lFE pEt awv -eUp +kux jfq qbp nIl @@ -118824,7 +119530,7 @@ vVU egH hAk ulH -gXR +xgK qbp nIl pkp @@ -120109,7 +120815,7 @@ hUc aEC pEt eUp -gXR +xgK vau qbp rTG @@ -121136,7 +121842,7 @@ oCl oCl pEt pEt -eUp +kux koQ qbp nIl @@ -121393,7 +122099,7 @@ xMq xMq pEt eRP -ycu +taC rfk qbp nIl @@ -121650,8 +122356,8 @@ svT xMq dXU awv -ycu -gXR +taC +xgK qbp nIl pkp @@ -121907,8 +122613,8 @@ xMq xMq pEt qXm -eUp -gXR +kux +xgK qbp rTG pkp @@ -122136,11 +122842,11 @@ tpL dAD kGP phK -cCJ +duy tTt agW mto -cCJ +duy vlh dZH kbf @@ -122164,7 +122870,7 @@ oCl oCl pEt gug -eUp +kux wHN qbp qbp @@ -122421,7 +123127,7 @@ fzm nUU pEt nMu -eUp +kux eUp eUp dyl @@ -122651,9 +123357,9 @@ fAJ fAJ hgW hOj -cCJ -cCJ -cCJ +duy +duy +duy jnT vlh bSV @@ -122678,8 +123384,8 @@ ldR bru sAx xck -gXR -gXR +xgK +xgK eUp evE qbp @@ -122910,7 +123616,7 @@ fAJ fAJ aGq iyw -cCJ +duy jnT vlh mWF @@ -123452,7 +124158,7 @@ iBF iBF fer fqz -jnZ +aXG xGA gdu pkp @@ -123709,7 +124415,7 @@ avf iBF clM sLc -jnZ +aXG xGA myC pkp @@ -124224,7 +124930,7 @@ iBF bxt sLc kVU -tER +bgz tER iPh vPx @@ -124479,9 +125185,9 @@ jDY vWd iBF ygc -jnZ -sLc -jnZ +aXG +udp +aXG sJd sJd sJd @@ -124647,10 +125353,10 @@ vLO dUD ecR ecR -ssV -ssV -ecR -ecR +aXl +aXl +lqL +lqL nRG ssV ecR @@ -125147,8 +125853,8 @@ kit xQj iNV iNV -rIe -qGT +ofF +pMG vLe rne egh @@ -125404,8 +126110,8 @@ pAD cuF iNV dzp -gYP -qGT +beq +pMG vLe hlD dnq @@ -125508,7 +126214,7 @@ hNu uAD iPZ obh -nnm +nGb fPm sJd jOm @@ -125765,7 +126471,7 @@ jwq pRr iPZ hhQ -nnm +nGb mUp sJd xmL @@ -125919,7 +126625,7 @@ hRp iFc qXe iNV -qGT +pMG bSp aoD gYP @@ -126023,7 +126729,7 @@ weW iPZ rzT cUA -nnm +nGb ptO jKW sPT @@ -126180,10 +126886,10 @@ sJy ssV ssV xLQ -ssV -ssV -ssV -ssV +aXl +aXl +aXl +aXl nRG uEF ykh @@ -126517,7 +127223,7 @@ qeS fKq fKq gcc -kAL +kpB sID kAL uXM @@ -126930,9 +127636,9 @@ afj ndR fTi fTi -hmN -fTi -oUo +ouX +tYr +fpE hmN hmN pWC @@ -127293,7 +127999,7 @@ pEn scP mpm fuK -jya +ish ktu pEn sDL @@ -127469,7 +128175,7 @@ pzh pzh vRf pzh -pzh +mLy ykh irO bcY @@ -127548,9 +128254,9 @@ tKV tKV pEn oec -hyV -tJj -jya +gfv +dcL +ish aVb yiU dJY @@ -127564,7 +128270,7 @@ sak sak sak sak -aEH +uVV qaO kLc unI @@ -127726,7 +128432,7 @@ wqd ePH ePH wqd -pzh +mLy ykh ykh ykh @@ -127806,7 +128512,7 @@ tKV pEn pEn jya -tJj +dcL aPu yiU yiU @@ -127814,7 +128520,7 @@ pEn xlM oIw pEn -jya +ish noI sak hCA @@ -127823,7 +128529,7 @@ kcW sak kFT eWs -aEH +uVV djs hMy olE @@ -127983,7 +128689,7 @@ wcb sEc jhT gap -pzh +mLy eTo iNV tzI @@ -128063,15 +128769,15 @@ tKV pEn ipp jya -tJj -jya +dcL +ish hnn pEn fXG lUm pit jya -jya +ish noI vmX wLt @@ -128240,7 +128946,7 @@ qRv hrZ idl ePH -pzh +mLy pzh wgI hyf @@ -128337,7 +129043,7 @@ bWt sak kFh eWs -aEH +uVV djs ltn olE @@ -128577,7 +129283,7 @@ tKV pEn xOh jya -spf +nrb iay iay iay @@ -128593,8 +129299,8 @@ aLU oVX sak tuk -qaO -aEH +jCq +uVV unI uXf xnu @@ -129090,14 +129796,14 @@ tKV tKV pEn frV -jya -tJj +ish +dcL vBb bjg kAN -vty -vty -vty +kLl +kLl +kLl pSJ vty rgH @@ -129107,7 +129813,7 @@ ufe ntn gLb lAi -eWs +xof aEH unI dNL @@ -129347,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 @@ -129613,12 +130319,12 @@ oSa dDq dsL pSJ -vty +kLl eQi iay tnp -aEH -aEH +uVV +uVV shE lAi dsg @@ -130272,10 +130978,10 @@ mrZ fTi oUo fTi -hbc -fTi +sCN +tYr xnR -fTi +tYr fTi iwq rCm @@ -130390,8 +131096,8 @@ aBh mqd iiO qqg -aEH -aEH +uVV +uVV qaO hmY unI @@ -130633,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 @@ -130891,10 +131597,10 @@ gNu pEn bKE jya -jya -jya -jya -jya +ish +ish +ish +ish rtr pEn dFG @@ -130906,7 +131612,7 @@ lAi lAi kLc tyt -aEH +uVV ajL lAi uLA @@ -131150,8 +131856,8 @@ bKE wrR emd nub -jya -hyV +ish +gfv pEn pEn pIm @@ -131415,7 +132121,7 @@ cDs lOz lAi sdb -tCp +uVV jDi lAi lAi @@ -134383,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 4072ee21a70..a475bd64013 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 704c4629463..9b6c1b6d5d5 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 af288c2920d..d187e5f5dac 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/storage/backpack/duffelbag/med/surgery, +/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/storage/backpack/duffelbag/med/surgery, +/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 aea13abc6e3..4ef52187a09 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 d861d6af348..20ffeb679d7 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 be456bdb4f4..67dc9f62da7 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 69bf06c0fa3..99e9848a0b0 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 00000000000..f4c50bf6b84 --- /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 81eaec94c61..c6c0d9d9c18 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 29f973398d3..73c5f42b38f 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 4570d643bee..95eada06cfb 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 d51346fb179..20795c72317 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 a62e21c6ddb..6d8a0e5e8fb 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 a1c4cd7acc7..15593e7e956 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 f76c9aa787e..5ec40d242d6 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 5b66424a623..a8a933b5b70 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 15f1a5f0806..ac61c9b98df 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 967a2e09c53..7c210566e08 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/storage/backpack/duffelbag/med/surgery, +/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 a6eacf1dd4b..fee55c936e9 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/storage/backpack/duffelbag/med/surgery{ +/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 51db46c9b8c..25dc64ed0fc 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 72c843587f7..48d47820df2 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 36df707a668..2ee3a6e691e 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/templates/birdshot/birdshot_ntrep_office.dmm b/_maps/skyrat/automapper/templates/birdshot/birdshot_ntrep_office.dmm index b815c467669..41608333fd3 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/deltastation/deltastation_ntrep_office.dmm b/_maps/skyrat/automapper/templates/deltastation/deltastation_ntrep_office.dmm index 65763878a52..2ce018e9314 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/icebox/icebox_ntrep_office.dmm b/_maps/skyrat/automapper/templates/icebox/icebox_ntrep_office.dmm index 3bcb075cc9d..cbfaddfb20c 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/kilostation/kilostation_ert_bay.dmm b/_maps/skyrat/automapper/templates/kilostation/kilostation_ert_bay.dmm index 7e94976b7cc..34e0fbcad74 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 9bee58a4be2..d123d8de9bc 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 11fb07a577f..c18d33363e6 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/northstar/northstar_ntrep_office.dmm b/_maps/skyrat/automapper/templates/northstar/northstar_ntrep_office.dmm index abbfb683347..f797c7905a7 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/tramstation/tramstation_ntrep_office.dmm b/_maps/skyrat/automapper/templates/tramstation/tramstation_ntrep_office.dmm index 9cc955b7652..bd1e3e8870c 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/lazy_templates/reebe.dmm b/_maps/skyrat/lazy_templates/reebe.dmm index 05c0f545f8b..852d14d41c5 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 0e33b8d3922..4c7d2e172ff 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 d0277a1e712..cbabb4c6485 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 a364024c345..40efeb77e7f 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 6a1115b432b..68913efe70d 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 b5efdb76f1a..4a0299d835a 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.dm b/code/__DEFINES/ai/ai.dm index 1a6829946a1..467fc9d7c0f 100644 --- a/code/__DEFINES/ai/ai.dm +++ b/code/__DEFINES/ai/ai.dm @@ -29,7 +29,9 @@ /// Don't move if being pulled #define STOP_MOVING_WHEN_PULLED (1<<0) /// Continue processing even if dead -#define CAN_ACT_WHILE_DEAD (1<<1) +#define CAN_ACT_WHILE_DEAD (1<<1) +/// Stop processing while in a progress bar +#define PAUSE_DURING_DO_AFTER (1<<2) //Base Subtree defines diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index 289f7586222..443a51a7eb7 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,14 @@ #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" + +///currently only used by clowns, a list of what can the mob speak randomly +#define BB_BASIC_MOB_SPEAK_LINES "BB_speech_lines" +#define BB_EMOTE_SAY "emote_say" +#define BB_EMOTE_HEAR "emote_hear" +#define BB_EMOTE_SEE "emote_see" +#define BB_EMOTE_SOUND "emote_sound" +#define BB_EMOTE_CHANCE "emote_chance" diff --git a/code/__DEFINES/ai/monsters.dm b/code/__DEFINES/ai/monsters.dm index 4040bdb23a8..927f3736832 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" @@ -135,3 +130,19 @@ #define BB_AUTOMATED_MINING "automated_mining" /// key that stores the nearest dead human #define BB_NEARBY_DEAD_MINER "nearby_dead_miner" + +//seedling keys +/// the water can we will pick up +#define BB_WATERCAN_TARGET "watercan_target" +/// the hydrotray we will heal +#define BB_HYDROPLANT_TARGET "hydroplant_target" +/// minimum weed levels for us to cure +#define BB_WEEDLEVEL_THRESHOLD "weedlevel_threshold" +/// minimum water levels for us to refill +#define BB_WATERLEVEL_THRESHOLD "waterlevel_threshold" +/// key holds our solarbeam ability +#define BB_SOLARBEAM_ABILITY "solarbeam_ability" +/// key holds our rapid seeds ability +#define BB_RAPIDSEEDS_ABILITY "rapidseeds_ability" +/// key holds the tray we will beam +#define BB_BEAMABLE_HYDROPLANT_TARGET "beamable_hydroplant_target" diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 7c530b3970e..e74cd6a58bd 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 5c575184273..87995d46abb 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/combat.dm b/code/__DEFINES/combat.dm index 4c8e407e8f4..92e7749860b 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -99,10 +99,12 @@ DEFINE_BITFIELD(status_flags, list( //click cooldowns, in tenths of a second, used for various combat actions #define CLICK_CD_MELEE 8 -#define CLICK_CD_THROW 8 -#define CLICK_CD_RANGE 4 #define CLICK_CD_RAPID 2 #define CLICK_CD_HYPER_RAPID 1 +#define CLICK_CD_SLOW 10 + +#define CLICK_CD_THROW 8 +#define CLICK_CD_RANGE 4 #define CLICK_CD_CLICK_ABILITY 6 #define CLICK_CD_BREAKOUT 100 #define CLICK_CD_HANDCUFFED 10 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 d47833f84c0..a2198cfb63c 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_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm index 9b6960e2730..c75b169b90d 100644 --- a/code/__DEFINES/dcs/signals/signals_global.dm +++ b/code/__DEFINES/dcs/signals/signals_global.dm @@ -89,3 +89,8 @@ /// Global signal when light debugging is canceled #define COMSIG_LIGHT_DEBUG_DISABLED "!light_debug_disabled" + +/// Global signal sent when a religious sect is chosen +#define COMSIG_RELIGIOUS_SECT_CHANGED "!religious_sect_changed" +/// Global signal sent when a religious sect is reset +#define COMSIG_RELIGIOUS_SECT_RESET "!religious_sect_reset" 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 00000000000..1c6ce7926ea --- /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 dd5b38113d3..677a65a7be1 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 2533b698528..c4007d12969 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 fee0ca52781..19286859e9e 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 00000000000..5b0fef52aee --- /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/events.dm b/code/__DEFINES/events.dm index ac86e77a4e0..2b1755b22c4 100644 --- a/code/__DEFINES/events.dm +++ b/code/__DEFINES/events.dm @@ -36,6 +36,8 @@ /// Return from admin setup to stop the event from triggering entirely. #define ADMIN_CANCEL_EVENT "cancel event" +/// Event can never be triggered by wizards +#define NEVER_TRIGGERED_BY_WIZARDS -1 /// Event can only run on a map set in space #define EVENT_SPACE_ONLY (1 << 0) /// Event can only run on a map which is a planet diff --git a/code/__DEFINES/fishing.dm b/code/__DEFINES/fishing.dm index 2481f0ae3e7..dc73623f27c 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 f509b740d26..849b3a28b9c 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/food.dm b/code/__DEFINES/food.dm index 73e8e31fe09..aa7833711eb 100644 --- a/code/__DEFINES/food.dm +++ b/code/__DEFINES/food.dm @@ -165,9 +165,10 @@ GLOBAL_LIST_INIT(food_buffs, list( )) /// Food quality change according to species diet -#define TOXIC_FOOD_QUALITY_CHANGE -4 #define DISLIKED_FOOD_QUALITY_CHANGE -2 #define LIKED_FOOD_QUALITY_CHANGE 2 +/// Threshold for food to give a toxic reaction +#define TOXIC_FOOD_QUALITY_THRESHOLD -8 /// Food is "in a container", not in a code sense, but in a literal sense (canned foods) #define FOOD_IN_CONTAINER (1<<0) diff --git a/code/__DEFINES/holiday.dm b/code/__DEFINES/holiday.dm new file mode 100644 index 00000000000..1c35940e718 --- /dev/null +++ b/code/__DEFINES/holiday.dm @@ -0,0 +1 @@ +#define HOLIDAY_HAT_CHANCE 20 diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 3c4ebd9d124..a52d2d809e6 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -176,7 +176,7 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( #define ismegafauna(A) (istype(A, /mob/living/simple_animal/hostile/megafauna)) -#define isclown(A) (istype(A, /mob/living/simple_animal/hostile/retaliate/clown)) +#define isclown(A) (istype(A, /mob/living/basic/clown)) #define isspider(A) (istype(A, /mob/living/basic/spider/giant)) diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index 71fc835d25e..44e67226604 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 0f05c0fe12b..33178bc7c8b 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 d075b1e681a..1e8fab8d92c 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 c40f3c4f59c..eb1b2ecce51 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 8ef3f2809e5..f3ae254e6b8 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 @@ -392,6 +403,14 @@ #define SHOCK_NOSTUN (1 << 3) /// No default message is sent from the shock #define SHOCK_SUPPRESS_MESSAGE (1 << 4) +/// No skeleton animation if a human was shocked +#define SHOCK_NO_HUMAN_ANIM (1 << 5) +/// Ignores TRAIT_STUNIMMUNE +#define SHOCK_IGNORE_IMMUNITY (1 << 6) +/// Prevents the immediate stun, instead only gives the delay +#define SHOCK_DELAY_STUN (1 << 7) +/// Makes the paralyze into a knockdown +#define SHOCK_KNOCKDOWN (1 << 8) #define INCORPOREAL_MOVE_BASIC 1 /// normal movement, see: [/mob/living/var/incorporeal_move] #define INCORPOREAL_MOVE_SHADOW 2 /// leaves a trail of shadows @@ -878,12 +897,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 9d167495fa8..370eaa8ba45 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 eec9472c2bf..3bc745756aa 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 e874b68f02b..a6ba5c0ed38 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 3649bc4a6b0..6f15ea65216 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 4262472475a..50b33eb4c75 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 da2a1dfadc6..2f452345ef9 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 ac7a1f67b29..bac35207fb5 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 c24252a394d..a416a081cb8 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 d4f0cb748e1..6f618ac8240 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 5529ee1f0c6..19ccd843dd4 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 4571ca57af2..78bed9213e3 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 ccc055f0da0..c7804a0d956 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 92af0760c94..f00d0a72a66 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 098c801a101..c32d18bbd4f 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 dc32d8e3b66..71f8c21e894 100644 --- a/code/__DEFINES/~skyrat_defines/mobs.dm +++ b/code/__DEFINES/~skyrat_defines/mobs.dm @@ -6,12 +6,10 @@ #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) +#define UNDERWEAR_HIDE_BRA (1<<3) //Appends to the bottom of Defib fails - DNR TRAIT #define DEFIB_FAIL_DNR (1<<11) diff --git a/code/__DEFINES/~skyrat_defines/wounds.dm b/code/__DEFINES/~skyrat_defines/wounds.dm index 4c29cd6a642..f6a9275db8e 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 4a4bc828cf8..34512b95952 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 1985080418c..00000000000 --- 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/dynamic_human_icon_gen.dm b/code/__HELPERS/dynamic_human_icon_gen.dm index 9f9dd9f1aa1..31957a27600 100644 --- a/code/__HELPERS/dynamic_human_icon_gen.dm +++ b/code/__HELPERS/dynamic_human_icon_gen.dm @@ -14,6 +14,7 @@ GLOBAL_LIST_EMPTY(dynamic_human_appearances) dummy.underwear = "Nude" dummy.undershirt = "Nude" dummy.socks = "Nude" + dummy.bra = "Nude" // SKYRAT EDIT ADDITION - Underwear and bra split if(outfit_path) var/datum/outfit/outfit = new outfit_path() if(r_hand != NO_REPLACE) //we can still override to be null, no replace means just use outfit's diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 659c2c0144e..994aa6cfa81 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -34,6 +34,9 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_antennae, GLOB.moth_antennae_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_markings, GLOB.moth_markings_list) */ //SKYRAT EDIT REMOVAL END + //bras + init_sprite_accessory_subtypes(/datum/sprite_accessory/bra, GLOB.bra_list, GLOB.bra_m, GLOB.bra_f) // SKYRAT EDIT ADDITION + init_sprite_accessory_subtypes(/datum/sprite_accessory/wings/moth, GLOB.moth_wings_list) // SKYRAT EDIT ADDITION - Customization init_sprite_accessory_subtypes(/datum/sprite_accessory/pod_hair, GLOB.pod_hair_list, add_blank = TRUE) // SKYRAT EDIT - Customization - ORIGINAL: init_sprite_accessory_subtypes(/datum/sprite_accessory/pod_hair, GLOB.pod_hair_list) diff --git a/code/__HELPERS/hallucinations.dm b/code/__HELPERS/hallucinations.dm index 9deb27b9040..525114cea28 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 6bb147721fd..de9ed493b62 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), )) */ @@ -363,7 +363,7 @@ GLOBAL_LIST_EMPTY(species_list) X.flags_1 |= ADMIN_SPAWNED_1 return X //return the last mob spawned -/proc/spawn_and_random_walk(spawn_type, target, amount, walk_chance=100, max_walk=3, always_max_walk=FALSE, admin_spawn=FALSE) +/proc/spawn_and_random_walk(spawn_type, target, amount, walk_chance=100, max_walk=3, always_max_walk=FALSE, admin_spawn=FALSE, cardinals_only = TRUE) var/turf/T = get_turf(target) var/step_count = 0 if(!T) @@ -392,7 +392,7 @@ GLOBAL_LIST_EMPTY(species_list) step_count = rand(1, max_walk) for(var/i in 1 to step_count) - step(X, pick(NORTH, SOUTH, EAST, WEST)) + step(X, cardinals_only ? pick(GLOB.cardinals) : pick(GLOB.alldirs)) return spawned_mobs diff --git a/code/__HELPERS/mouse_control.dm b/code/__HELPERS/mouse_control.dm index 8896afb3ec6..0c99e53e7a0 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 0d61a7efb13..7c8fb23f4c3 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 80d9d3e9b09..fad0deb0bd8 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 be439d8217f..8ac2f0d3ddf 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 309b31ceb37..a6cb2dedb32 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/_globalvars/religion.dm b/code/_globalvars/religion.dm index 164491a0a3a..063ff0e8642 100644 --- a/code/_globalvars/religion.dm +++ b/code/_globalvars/religion.dm @@ -14,3 +14,37 @@ GLOBAL_LIST_EMPTY(chaplain_altars) //gear GLOBAL_VAR(holy_weapon_type) GLOBAL_VAR(holy_armor_type) + +/// Sets a new religious sect used by all chaplains int he round +/proc/set_new_religious_sect(path, reset_existing = FALSE) + if(!ispath(path, /datum/religion_sect)) + message_admins("[ADMIN_LOOKUPFLW(usr)] has tried to spawn an item when selecting a sect.") + return + + if(!isnull(GLOB.religious_sect)) + if (!reset_existing) + return + reset_religious_sect() + + GLOB.religious_sect = new path() + for(var/i in GLOB.player_list) + if(!isliving(i)) + continue + var/mob/living/am_i_holy_living = i + if(!am_i_holy_living.mind?.holy_role) + continue + GLOB.religious_sect.on_conversion(am_i_holy_living) + SEND_GLOBAL_SIGNAL(COMSIG_RELIGIOUS_SECT_CHANGED) + +/// Removes any existing religious sect from chaplains, allowing another to be selected +/proc/reset_religious_sect() + for(var/i in GLOB.player_list) + if(!isliving(i)) + continue + var/mob/living/am_i_holy_living = i + if(!am_i_holy_living.mind?.holy_role) + continue + GLOB.religious_sect.on_deconversion(am_i_holy_living) + + GLOB.religious_sect = null + SEND_GLOBAL_SIGNAL(COMSIG_RELIGIOUS_SECT_RESET) diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm index c4f8de8e63b..edecd0ba78f 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 9b85f6e464c..5c957445526 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -24,6 +24,9 @@ SUBSYSTEM_DEF(job) var/list/unassigned = list() //Players who need jobs var/initial_players_to_assign = 0 //used for checking against population caps + // Whether to run DivideOccupations pure so that there are no side-effects from calling it other than + // a player's assigned_role being set to some value. + var/run_divide_occupation_pure = FALSE var/list/prioritized_jobs = list() var/list/latejoin_trackers = list() @@ -369,11 +372,11 @@ SUBSYSTEM_DEF(job) * fills var "assigned_role" for all ready players. * This proc must not have any side effect besides of modifying "assigned_role". **/ -/datum/controller/subsystem/job/proc/DivideOccupations() +/datum/controller/subsystem/job/proc/DivideOccupations(pure = FALSE, allow_all = FALSE) //Setup new player list and get the jobs list - JobDebug("Running DO") - - SEND_SIGNAL(src, COMSIG_OCCUPATIONS_DIVIDED) + JobDebug("Running DO, allow_all = [allow_all], pure = [pure]") + run_divide_occupation_pure = pure + SEND_SIGNAL(src, COMSIG_OCCUPATIONS_DIVIDED, pure, allow_all) //Get the players who are ready for(var/i in GLOB.new_player_list) @@ -441,8 +444,9 @@ SUBSYSTEM_DEF(job) // Loop through all unassigned players for(var/mob/dead/new_player/player in unassigned) - if(PopcapReached()) - RejectPlayer(player) + if(!allow_all) + if(PopcapReached()) + RejectPlayer(player) // Loop through all jobs for(var/datum/job/job in shuffledoccupations) // SHUFFLE ME BABY @@ -480,7 +484,7 @@ SUBSYSTEM_DEF(job) // Hand out random jobs to the people who didn't get any in the last check // Also makes sure that they got their preference correct for(var/mob/dead/new_player/player in unassigned) - HandleUnassigned(player) + HandleUnassigned(player, allow_all) JobDebug("DO, Ending handle unassigned.") JobDebug("DO, Handle unrejectable unassigned") @@ -490,21 +494,23 @@ SUBSYSTEM_DEF(job) if(!AssignRole(player, GetJobType(overflow_role))) //If everything is already filled, make them an assistant JobDebug("DO, Forced antagonist could not be assigned any random job or the overflow role. DivideOccupations failed.") JobDebug("---------------------------------------------------") + run_divide_occupation_pure = FALSE return FALSE //Living on the edge, the forced antagonist couldn't be assigned to overflow role (bans, client age) - just reroll JobDebug("DO, Ending handle unrejectable unassigned") JobDebug("All divide occupations tasks completed.") JobDebug("---------------------------------------------------") - + run_divide_occupation_pure = FALSE return TRUE //We couldn't find a job from prefs for this guy. -/datum/controller/subsystem/job/proc/HandleUnassigned(mob/dead/new_player/player) +/datum/controller/subsystem/job/proc/HandleUnassigned(mob/dead/new_player/player, allow_all = FALSE) var/jobless_role = player.client.prefs.read_preference(/datum/preference/choiced/jobless_role) - if(PopcapReached()) - RejectPlayer(player) - return + if(!allow_all) + if(PopcapReached()) + RejectPlayer(player) + return switch (jobless_role) if (BEOVERFLOW) @@ -698,10 +704,11 @@ SUBSYSTEM_DEF(job) if(PopcapReached()) JobDebug("Popcap overflow Check observer located, Player: [player]") JobDebug("Player rejected :[player]") - to_chat(player, "You have failed to qualify for any job you desired.") unassigned -= player - player.ready = PLAYER_NOT_READY - player.client << output(player.ready, "lobby_browser:imgsrc") //SKYRAT EDIT ADDITION + if(!run_divide_occupation_pure) + to_chat(player, "You have failed to qualify for any job you desired.") + player.ready = PLAYER_NOT_READY + player.client << output(player.ready, "lobby_browser:imgsrc") //SKYRAT EDIT ADDITION /datum/controller/subsystem/job/Recover() @@ -961,6 +968,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 +984,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 396d736ac3f..681658caa3b 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 00000000000..da10d3d631a --- /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 9bd803602df..d4fb13d9988 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 661c1de2574..0e5ed6ca685 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 8240ebbf62e..f83f2cde7b0 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/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index c396771a033..9ce83becc17 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -349,6 +349,11 @@ multiple modular subtrees with behaviors minimum_distance = iter_behavior.required_distance return minimum_distance +/// Returns true if we have a blackboard key with the provided key and it is not qdeleting +/datum/ai_controller/proc/blackboard_key_exists(key) + var/datum/key_value = blackboard[key] + return !QDELETED(key_value) + /** * Used to manage references to datum by AI controllers * diff --git a/code/datums/ai/babies/babies_subtrees.dm b/code/datums/ai/babies/babies_subtrees.dm index 0c71b6d757b..aad92f8422e 100644 --- a/code/datums/ai/babies/babies_subtrees.dm +++ b/code/datums/ai/babies/babies_subtrees.dm @@ -20,13 +20,8 @@ if(is_type_in_list(controller.pawn, baby_types)) return - var/atom/target = controller.blackboard[BB_BABIES_TARGET] - // Find target - if(QDELETED(target)) - controller.queue_behavior(/datum/ai_behavior/find_partner, BB_BABIES_TARGET, BB_BABIES_PARTNER_TYPES, BB_BABIES_CHILD_TYPES) - return - - // Do target - controller.queue_behavior(/datum/ai_behavior/make_babies, BB_BABIES_TARGET, BB_BABIES_CHILD_TYPES) - return SUBTREE_RETURN_FINISH_PLANNING + if(controller.blackboard_key_exists(BB_BABIES_TARGET)) + controller.queue_behavior(/datum/ai_behavior/make_babies, BB_BABIES_TARGET, BB_BABIES_CHILD_TYPES) + return SUBTREE_RETURN_FINISH_PLANNING + controller.queue_behavior(/datum/ai_behavior/find_partner, BB_BABIES_TARGET, BB_BABIES_PARTNER_TYPES, BB_BABIES_CHILD_TYPES) diff --git a/code/datums/ai/basic_mobs/base_basic_controller.dm b/code/datums/ai/basic_mobs/base_basic_controller.dm index b4f7c27c2f9..3eb79a815ad 100644 --- a/code/datums/ai/basic_mobs/base_basic_controller.dm +++ b/code/datums/ai/basic_mobs/base_basic_controller.dm @@ -15,10 +15,13 @@ /datum/ai_controller/basic_controller/able_to_run() . = ..() - if(isliving(pawn)) - var/mob/living/living_pawn = pawn - if(IS_DEAD_OR_INCAP(living_pawn)) - return FALSE + if(!isliving(pawn)) + return + var/mob/living/living_pawn = pawn + if(!(ai_traits & CAN_ACT_WHILE_DEAD) && IS_DEAD_OR_INCAP(living_pawn)) + return FALSE + if(ai_traits & PAUSE_DURING_DO_AFTER && LAZYLEN(living_pawn.do_afters)) + return FALSE /datum/ai_controller/basic_controller/proc/update_speed(mob/living/basic/basic_mob) SIGNAL_HANDLER 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 480aa68984d..6683fb02f93 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,11 +1,10 @@ /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) . = ..() - var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key] - if(isnull(targetting_datum)) + if(!controller.blackboard_key_exists(targetting_datum_key)) CRASH("No target datum was supplied in the blackboard for [controller.pawn]") //Hiding location is priority @@ -16,6 +15,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 +45,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_ai_behaviors/targeted_mob_ability.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeted_mob_ability.dm index c0bd9d1323b..04cb9b171dd 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeted_mob_ability.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeted_mob_ability.dm @@ -19,12 +19,6 @@ var/atom/target = controller.blackboard[target_key] if (QDELETED(target)) controller.clear_blackboard_key(target_key) - return - if (!isliving(target)) - return - var/mob/living/living_target = target - if(living_target.stat >= UNCONSCIOUS) - controller.clear_blackboard_key(target_key) /datum/ai_behavior/targeted_mob_ability/proc/get_ability_to_use(datum/ai_controller/controller, ability_key) return controller.blackboard[ability_key] diff --git a/code/datums/ai/basic_mobs/basic_subtrees/attack_adjacent_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/attack_adjacent_target.dm new file mode 100644 index 00000000000..c3d334165d9 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/attack_adjacent_target.dm @@ -0,0 +1,33 @@ +/// Attack something which is already adjacent to us, without ending planning +/datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic + melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/opportunistic + end_planning = FALSE + +/datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + . = ..() + var/atom/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] + if(QDELETED(target) || !controller.pawn.Adjacent(target)) + return + if (isliving(controller.pawn)) + var/mob/living/pawn = controller.pawn + if (LAZYLEN(pawn.do_afters)) + return + controller.queue_behavior(melee_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + +/// Attack something which is already adjacent to us without moving +/datum/ai_behavior/basic_melee_attack/opportunistic + action_cooldown = 0.2 SECONDS // We gotta check unfortunately often because we're in a race condition with nextmove + behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + +/datum/ai_behavior/basic_melee_attack/opportunistic/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) + if (!controller.blackboard_key_exists(targetting_datum_key)) + CRASH("No target datum was supplied in the blackboard for [controller.pawn]") + return controller.blackboard_key_exists(target_key) + +/datum/ai_behavior/basic_melee_attack/opportunistic/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) + var/atom/movable/atom_pawn = controller.pawn + if(!atom_pawn.CanReach(controller.blackboard[target_key])) + finish_action(controller, TRUE, target_key) // Don't clear target + return FALSE + . = ..() + finish_action(controller, TRUE, target_key) // Try doing something else diff --git a/code/datums/ai/basic_mobs/basic_subtrees/climb_tree.dm b/code/datums/ai/basic_mobs/basic_subtrees/climb_tree.dm index 6827f3eee99..1beab6ec907 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/climb_tree.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/climb_tree.dm @@ -7,11 +7,8 @@ if(!SPT_PROB(climb_chance, seconds_per_tick)) return - var/obj/structure/flora/tree/target = controller.blackboard[BB_CLIMBED_TREE] + if(controller.blackboard_key_exists(BB_CLIMBED_TREE)) + controller.queue_behavior(/datum/ai_behavior/climb_tree, BB_CLIMBED_TREE) + return SUBTREE_RETURN_FINISH_PLANNING - if(QDELETED(target)) - controller.queue_behavior(/datum/ai_behavior/find_and_set/valid_tree, BB_CLIMBED_TREE, /obj/structure/flora/tree) - return - - controller.queue_behavior(/datum/ai_behavior/climb_tree, BB_CLIMBED_TREE) - return SUBTREE_RETURN_FINISH_PLANNING + controller.queue_behavior(/datum/ai_behavior/find_and_set/valid_tree, BB_CLIMBED_TREE, /obj/structure/flora/tree) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/find_food.dm b/code/datums/ai/basic_mobs/basic_subtrees/find_food.dm index 8d20df7b9c7..b02ec8eaa85 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/find_food.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/find_food.dm @@ -3,8 +3,7 @@ /datum/ai_planning_subtree/find_food/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() - var/atom/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] - if(!QDELETED(target)) + if(controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)) // Busy with something return diff --git a/code/datums/ai/basic_mobs/basic_subtrees/find_paper_and_write.dm b/code/datums/ai/basic_mobs/basic_subtrees/find_paper_and_write.dm index 900d13e0a04..0d2d0c3e3b4 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/find_paper_and_write.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/find_paper_and_write.dm @@ -1,10 +1,9 @@ /datum/ai_planning_subtree/find_paper_and_write /datum/ai_planning_subtree/find_paper_and_write/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - var/obj/item/inhand_paper = controller.blackboard[BB_SIMPLE_CARRY_ITEM] var/mob/living/basic/wizard = controller.pawn - if(!QDELETED(inhand_paper)) + if(controller.blackboard_key_exists(BB_SIMPLE_CARRY_ITEM)) controller.queue_behavior(/datum/ai_behavior/write_on_paper, BB_SIMPLE_CARRY_ITEM, BB_WRITING_LIST) return SUBTREE_RETURN_FINISH_PLANNING diff --git a/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm index 6ae7885618b..a4982fa660e 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm @@ -9,10 +9,7 @@ /datum/ai_planning_subtree/flee_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() - if (!controller.blackboard[BB_BASIC_MOB_FLEEING]) - return - var/atom/target = controller.blackboard[target_key] - if(QDELETED(target)) + if (!controller.blackboard[BB_BASIC_MOB_FLEEING] || !controller.blackboard_key_exists(target_key)) return controller.queue_behavior(flee_behaviour, target_key, hiding_place_key) return SUBTREE_RETURN_FINISH_PLANNING //we gotta get out of here. diff --git a/code/datums/ai/basic_mobs/basic_subtrees/move_to_cardinal.dm b/code/datums/ai/basic_mobs/basic_subtrees/move_to_cardinal.dm new file mode 100644 index 00000000000..c98878e0fd7 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/move_to_cardinal.dm @@ -0,0 +1,71 @@ +/// Try to line up with a cardinal direction of your target +/datum/ai_planning_subtree/move_to_cardinal + /// Behaviour to execute to line ourselves up + var/move_behaviour = /datum/ai_behavior/move_to_cardinal + /// Blackboard key in which to store selected target + var/target_key = BB_BASIC_MOB_CURRENT_TARGET + +/datum/ai_planning_subtree/move_to_cardinal/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + . = ..() + if(!controller.blackboard_key_exists(target_key)) + return + controller.queue_behavior(move_behaviour, target_key) + +/// Try to line up with a cardinal direction of your target +/datum/ai_behavior/move_to_cardinal + required_distance = 0 + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_MOVE_AND_PERFORM | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + /// How close to our target is too close? + var/minimum_distance = 1 + /// How far away is too far? + var/maximum_distance = 9 + +/datum/ai_behavior/move_to_cardinal/setup(datum/ai_controller/controller, target_key) + var/atom/target = controller.blackboard[target_key] + if(QDELETED(target)) + return FALSE + target_nearest_cardinal(controller, target) + return TRUE + +/// Set our movement target to the closest cardinal space to our target +/datum/ai_behavior/move_to_cardinal/proc/target_nearest_cardinal(datum/ai_controller/controller, atom/target) + var/atom/move_target + var/closest = INFINITY + + for (var/dir in GLOB.cardinals) + var/turf/cardinal_turf = get_ranged_target_turf(target, dir, minimum_distance) + if (cardinal_turf.is_blocked_turf()) + continue + var/distance_to = get_dist(controller.pawn, cardinal_turf) + if (distance_to >= closest) + continue + closest = distance_to + move_target = cardinal_turf + + if (isnull(move_target)) + move_target = target + if (controller.current_movement_target == move_target) + return + set_movement_target(controller, move_target) + +/datum/ai_behavior/move_to_cardinal/perform(seconds_per_tick, datum/ai_controller/controller, target_key) + var/atom/target = controller.blackboard[target_key] + if (QDELETED(target)) + finish_action(controller = controller, succeeded = FALSE, target_key = target_key) + return + if (!(get_dir(controller.pawn, target) in GLOB.cardinals)) + target_nearest_cardinal(controller, target) + return + var/distance_to_target = get_dist(controller.pawn, target) + if (distance_to_target < minimum_distance) + target_nearest_cardinal(controller, target) + return + if (distance_to_target > maximum_distance) + return + finish_action(controller = controller, succeeded = TRUE, target_key = target_key) + return + +/datum/ai_behavior/move_to_cardinal/finish_action(datum/ai_controller/controller, succeeded, target_key) + if (!succeeded) + controller.clear_blackboard_key(target_key) + return ..() diff --git a/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm b/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm index 07fb6f8b0dc..1ff752d925f 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm @@ -8,8 +8,7 @@ /datum/ai_planning_subtree/ranged_skirmish/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() - var/atom/target = controller.blackboard[target_key] - if(QDELETED(target)) + if(!controller.blackboard_key_exists(target_key)) return controller.queue_behavior(attack_behavior, target_key, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) 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 90379fcac0a..210aaf0aa8b 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 @@ -1,16 +1,16 @@ /datum/ai_planning_subtree/basic_melee_attack_subtree + /// What do we do in order to attack someone? var/datum/ai_behavior/basic_melee_attack/melee_attack_behavior = /datum/ai_behavior/basic_melee_attack + /// Is this the last thing we do? (if we set a movement target, this will usually be yes) + var/end_planning = TRUE /datum/ai_planning_subtree/basic_melee_attack_subtree/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() - var/atom/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] - if(QDELETED(target)) + if(!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)) return 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 + if (end_planning) + return SUBTREE_RETURN_FINISH_PLANNING //we are going into battle...no distractions. /datum/ai_planning_subtree/basic_ranged_attack_subtree operational_datums = list(/datum/component/ranged_attacks) @@ -18,8 +18,7 @@ /datum/ai_planning_subtree/basic_ranged_attack_subtree/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() - var/atom/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] - if(QDELETED(target)) + if(!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)) return controller.queue_behavior(ranged_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. diff --git a/code/datums/ai/basic_mobs/basic_subtrees/sleep_with_no_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/sleep_with_no_target.dm index ccd67d6d1e7..93499cf673c 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/sleep_with_no_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/sleep_with_no_target.dm @@ -16,7 +16,7 @@ /datum/ai_behavior/sleep_after_targetless_time/perform(seconds_per_tick, datum/ai_controller/controller, target_key) var/atom/target = controller.blackboard[target_key] - finish_action(controller, succeeded = !target, seconds_per_tick = seconds_per_tick) + finish_action(controller, succeeded = QDELETED(target), seconds_per_tick = seconds_per_tick) /datum/ai_behavior/sleep_after_targetless_time/finish_action(datum/ai_controller/controller, succeeded, seconds_per_tick) . = ..() diff --git a/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm b/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm index a04765b1a88..005a9ee835d 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm @@ -199,3 +199,19 @@ speech_chance = 5 emote_hear = list("rawrs.","grumbles.","grawls.", "stomps!") emote_see = list("stares ferociously.") + +/datum/ai_planning_subtree/random_speech/blackboard //literal tower of babel, subtree form + speech_chance = 1 + +/datum/ai_planning_subtree/random_speech/blackboard/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/list/speech_lines = controller.blackboard[BB_BASIC_MOB_SPEAK_LINES] + if(isnull(speech_lines)) + return ..() + + speak = speech_lines[BB_EMOTE_SAY] ? speech_lines[BB_EMOTE_SAY] : initial(speak) + emote_see = speech_lines[BB_EMOTE_SEE] ? speech_lines[BB_EMOTE_SEE] : initial(emote_see) + emote_hear = speech_lines[BB_EMOTE_HEAR] ? speech_lines[BB_EMOTE_HEAR] : initial(emote_hear) + sound = speech_lines[BB_EMOTE_SOUND] ? speech_lines[BB_EMOTE_SOUND] : initial(sound) + speech_chance = speech_lines[BB_EMOTE_CHANCE] ? speech_lines[BB_EMOTE_CHANCE] : initial(speech_chance) + + return ..() 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 2d553fe4b2f..6133759183d 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/targeted_mob_ability.dm b/code/datums/ai/basic_mobs/basic_subtrees/targeted_mob_ability.dm index b6b4d286df1..8d75f797163 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/targeted_mob_ability.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/targeted_mob_ability.dm @@ -13,9 +13,11 @@ if (!ability_key) CRASH("You forgot to tell this mob where to find its ability") - var/mob/living/target = controller.blackboard[target_key] + if (!controller.blackboard_key_exists(target_key)) + return + var/datum/action/cooldown/using_action = controller.blackboard[ability_key] - if (QDELETED(target) || QDELETED(using_action) || !using_action.IsAvailable()) + if (!using_action?.IsAvailable()) return controller.queue_behavior(use_ability_behaviour, ability_key, target_key) 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 2c618e98e72..fb83b8f8684 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. @@ -15,7 +15,7 @@ CRASH("You forgot to tell this mob where to find its ability") var/datum/action/cooldown/using_action = controller.blackboard[ability_key] - if (QDELETED(using_action) || !using_action.IsAvailable()) + if (!using_action?.IsAvailable()) return controller.queue_behavior(use_ability_behaviour, ability_key) 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 643089bb5ea..570088ce4d6 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 @@ -115,3 +124,9 @@ /datum/targetting_datum/basic/of_size/larger find_smaller = FALSE inclusive = FALSE + +/datum/targetting_datum/basic/attack_until_dead + stat_attack = HARD_CRIT + +/datum/targetting_datum/basic/attack_even_if_dead + stat_attack = DEAD diff --git a/code/datums/ai/dog/dog_behaviors.dm b/code/datums/ai/dog/dog_behaviors.dm index 7bd0d5824a1..6c9cb779bb3 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/ai/generic/find_and_set.dm b/code/datums/ai/generic/find_and_set.dm index 443febae2a0..eb09506a282 100644 --- a/code/datums/ai/generic/find_and_set.dm +++ b/code/datums/ai/generic/find_and_set.dm @@ -8,8 +8,7 @@ /datum/ai_behavior/find_and_set/perform(seconds_per_tick, datum/ai_controller/controller, set_key, locate_path, search_range) . = ..() - var/atom/current_target = controller.blackboard[set_key] - if (!QDELETED(current_target)) + if (controller.blackboard_key_exists(set_key)) return var/find_this_thing = search_tactic(controller, locate_path, search_range) if(find_this_thing) diff --git a/code/datums/ai/hunting_behavior/hunting_behaviors.dm b/code/datums/ai/hunting_behavior/hunting_behaviors.dm index 777cb851ee4..036176dc85e 100644 --- a/code/datums/ai/hunting_behavior/hunting_behaviors.dm +++ b/code/datums/ai/hunting_behavior/hunting_behaviors.dm @@ -16,6 +16,8 @@ var/hunt_range = 2 /// What are the chances we hunt something at any given moment var/hunt_chance = 100 + ///do we finish planning subtree + var/finish_planning = TRUE /datum/ai_planning_subtree/find_and_hunt_target/New() . = ..() @@ -35,13 +37,15 @@ // We're not hunting anything, look around for something if(isnull(hunted)) controller.queue_behavior(finding_behavior, target_key, hunt_targets, hunt_range) + return // We ARE hunting something, execute the hunt. // Note that if our AI controller has multiple hunting subtrees set, // we may accidentally be executing another tree's hunt - not ideal, // try to set a unique target key if you have multiple - else - controller.queue_behavior(hunting_behavior, target_key, BB_HUNTING_COOLDOWN) + + controller.queue_behavior(hunting_behavior, target_key, BB_HUNTING_COOLDOWN) + if(finish_planning) return SUBTREE_RETURN_FINISH_PLANNING //If we're hunting we're too busy for anything else /// Finds a specific atom type to hunt. @@ -124,3 +128,19 @@ /datum/ai_behavior/hunt_target/unarmed_attack_target/target_caught(mob/living/hunter, obj/structure/cable/hunted) hunter.UnarmedAttack(hunted, TRUE) + +/datum/ai_behavior/hunt_target/use_ability_on_target + always_reset_target = TRUE + ///the ability we will use + var/ability_key + +/datum/ai_behavior/hunt_target/use_ability_on_target/perform(seconds_per_tick, datum/ai_controller/controller, hunting_target_key, hunting_cooldown_key) + var/datum/action/cooldown/ability = controller.blackboard[ability_key] + if(QDELETED(ability) || !ability.IsAvailable()) + finish_action(controller, FALSE, hunting_target_key) + return ..() + +/datum/ai_behavior/hunt_target/use_ability_on_target/target_caught(mob/living/hunter, atom/hunted) + var/datum/action/cooldown/ability = hunter.ai_controller.blackboard[ability_key] + ability.InterceptClickOn(hunter, null, hunted) + diff --git a/code/datums/ai/idle_behaviors/idle_random_walk.dm b/code/datums/ai/idle_behaviors/idle_random_walk.dm index b25f983f313..d5a3972a3d0 100644 --- a/code/datums/ai/idle_behaviors/idle_random_walk.dm +++ b/code/datums/ai/idle_behaviors/idle_random_walk.dm @@ -14,3 +14,13 @@ /datum/idle_behavior/idle_random_walk/less_walking walk_chance = 10 + +/// Only walk if we don't have a target +/datum/idle_behavior/idle_random_walk/no_target + /// Where do we look for a target? + var/target_key = BB_BASIC_MOB_CURRENT_TARGET + +/datum/idle_behavior/idle_random_walk/no_target/perform_idle_behavior(seconds_per_tick, datum/ai_controller/controller) + if (!controller.blackboard_key_exists(target_key)) + return + return ..() diff --git a/code/datums/beam.dm b/code/datums/beam.dm index a2542afcdb4..6b138387290 100644 --- a/code/datums/beam.dm +++ b/code/datums/beam.dm @@ -41,7 +41,21 @@ /// If set will be used instead of targets's pixel_y in offset calculations var/override_target_pixel_y = null -/datum/beam/New(origin, target, icon = 'icons/effects/beam.dmi', icon_state = "b_beam", time = INFINITY, max_distance = INFINITY, beam_type = /obj/effect/ebeam, beam_color = null, emissive = TRUE, override_origin_pixel_x = null, override_origin_pixel_y = null, override_target_pixel_x = null, override_target_pixel_y = null) +/datum/beam/New( + origin, + target, + icon = 'icons/effects/beam.dmi', + icon_state = "b_beam", + time = INFINITY, + max_distance = INFINITY, + beam_type = /obj/effect/ebeam, + beam_color = null, + emissive = TRUE, + override_origin_pixel_x = null, + override_origin_pixel_y = null, + override_target_pixel_x = null, + override_target_pixel_y = null, +) src.origin = origin src.target = target src.icon = icon @@ -65,8 +79,7 @@ visuals.icon = icon visuals.icon_state = icon_state visuals.color = beam_color - visuals.layer = ABOVE_ALL_MOB_LAYER - visuals.vis_flags = VIS_INHERIT_PLANE + visuals.vis_flags = VIS_INHERIT_PLANE|VIS_INHERIT_LAYER visuals.emissive = emissive visuals.update_appearance() Draw() @@ -166,6 +179,8 @@ /obj/effect/ebeam mouse_opacity = MOUSE_OPACITY_TRANSPARENT + plane = GAME_PLANE_UPPER_FOV_HIDDEN + layer = ABOVE_ALL_MOB_LAYER anchored = TRUE var/emissive = TRUE var/datum/beam/owner diff --git a/code/datums/brain_damage/mild.dm b/code/datums/brain_damage/mild.dm index 5275ff97150..52731852c11 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 d3d53237777..059bc2f787d 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 1088205d357..5aa60cd89a7 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 6467fbd7bbc..5473dbd0fa0 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 3a360c012f6..0ed00e7dd94 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 12dff2b6aa9..fc93123921c 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 1c46052140d..9f17b3d1d7e 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 bdd7372f170..6cfe215a4b7 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 ac7b6eb39af..a8d631c6266 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 fd6993220ec..206adbaefb1 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 433784e845e..f4d7b5d7369 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/edible.dm b/code/datums/components/food/edible.dm index 505dc610b73..7c86ddc2243 100644 --- a/code/datums/components/food/edible.dm +++ b/code/datums/components/food/edible.dm @@ -223,6 +223,8 @@ Behavior that's still missing from this component that original food items had t examine_list += span_green("You find this meal [quality_label].") else if (quality == 0) examine_list += span_notice("You find this meal edible.") + else if (quality <= TOXIC_FOOD_QUALITY_THRESHOLD) + examine_list += span_warning("You find this meal disgusting!") else examine_list += span_warning("You find this meal inedible.") @@ -529,25 +531,12 @@ Behavior that's still missing from this component that original food items had t gourmand.add_mood_event("breakfast", /datum/mood_event/breakfast) last_check_time = world.time - var/food_taste_reaction - - if(HAS_TRAIT(parent, TRAIT_FOOD_SILVER) && !isjellyperson(gourmand)) // it's not real food - food_taste_reaction = FOOD_TOXIC - - if(check_liked) //Callback handling; use this as an override for special food like donuts - food_taste_reaction = check_liked.Invoke(fraction, gourmand) - - if(!food_taste_reaction) - food_taste_reaction = gourmand.get_food_taste_reaction(parent, foodtypes) - - if(food_taste_reaction == FOOD_TOXIC) + var/food_quality = get_perceived_food_quality(gourmand, parent) + if(food_quality <= TOXIC_FOOD_QUALITY_THRESHOLD) to_chat(gourmand,span_warning("What the hell was that thing?!")) gourmand.adjust_disgust(25 + 30 * fraction) gourmand.add_mood_event("toxic_food", /datum/mood_event/disgusting_food) - return - - var/food_quality = get_perceived_food_quality(gourmand, parent) - if(food_quality < 0) + else if(food_quality < 0) to_chat(gourmand,span_notice("That didn't taste very good...")) gourmand.adjust_disgust(11 + 15 * fraction) gourmand.add_mood_event("gross_food", /datum/mood_event/gross_food) @@ -578,10 +567,25 @@ Behavior that's still missing from this component that original food items had t var/food_quality = get_recipe_complexity() if(HAS_TRAIT(parent, TRAIT_FOOD_SILVER)) // it's not real food - food_quality += isjellyperson(eater) ? 2 : -4 + if(!isjellyperson(eater)) //if you aren't a jellyperson, it makes you sick no matter how nice it looks + return TOXIC_FOOD_QUALITY_THRESHOLD + food_quality += LIKED_FOOD_QUALITY_CHANGE - if (ishuman(eater)) - food_quality += TOXIC_FOOD_QUALITY_CHANGE * count_matching_foodtypes(foodtypes, eater.get_toxic_foodtypes()) + if(check_liked) //Callback handling; use this as an override for special food like donuts + var/special_reaction = check_liked.Invoke(eater) + switch(special_reaction) //return early for special foods + if(FOOD_LIKED) + return LIKED_FOOD_QUALITY_CHANGE + if(FOOD_DISLIKED) + return DISLIKED_FOOD_QUALITY_CHANGE + if(FOOD_TOXIC) + return TOXIC_FOOD_QUALITY_THRESHOLD + + if(ishuman(eater)) + if(count_matching_foodtypes(foodtypes, eater.get_toxic_foodtypes())) //if the food is toxic, we don't care about anything else + return TOXIC_FOOD_QUALITY_THRESHOLD + if(HAS_TRAIT(eater, TRAIT_AGEUSIA)) //if you can't taste it, it doesn't taste good + return 0 food_quality += DISLIKED_FOOD_QUALITY_CHANGE * count_matching_foodtypes(foodtypes, eater.get_disliked_foodtypes()) food_quality += LIKED_FOOD_QUALITY_CHANGE * count_matching_foodtypes(foodtypes, eater.get_liked_foodtypes()) diff --git a/code/datums/components/food/ghost_edible.dm b/code/datums/components/food/ghost_edible.dm new file mode 100644 index 00000000000..25207800a74 --- /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 d79fcabb11a..c2540f54cc1 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 b43d45f7c70..f1fe80fe9fb 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 ae29949961b..f742c1233fd 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/ling_decoy_brain.dm b/code/datums/components/ling_decoy_brain.dm new file mode 100644 index 00000000000..7bcb4e38c8f --- /dev/null +++ b/code/datums/components/ling_decoy_brain.dm @@ -0,0 +1,68 @@ +/// Component applied to ling brains to make them into decoy brains, as ling brains are vestigial and don't do anything +/datum/component/ling_decoy_brain + /// The ling this brain is linked to + VAR_FINAL/datum/antagonist/changeling/parent_ling + /// A talk action that is granted to the ling when this decoy enters an MMI + VAR_FINAL/datum/action/changeling/mmi_talk/talk_action + +/datum/component/ling_decoy_brain/Initialize(datum/antagonist/changeling/ling) + if(!istype(parent, /obj/item/organ/internal/brain)) + return COMPONENT_INCOMPATIBLE + if(isnull(ling)) + stack_trace("[type] instantiated without a changeling to link to.") + return COMPONENT_INCOMPATIBLE + + parent_ling = ling + RegisterSignal(parent_ling, COMSIG_QDELETING, PROC_REF(clear_decoy)) + +/datum/component/ling_decoy_brain/Destroy() + UnregisterSignal(parent_ling, COMSIG_QDELETING) + parent_ling = null + QDEL_NULL(talk_action) + return ..() + +/datum/component/ling_decoy_brain/RegisterWithParent() + var/obj/item/organ/internal/brain/ling_brain = parent + ling_brain.organ_flags &= ~ORGAN_VITAL + ling_brain.decoy_override = TRUE + RegisterSignal(ling_brain, COMSIG_ATOM_ENTERING, PROC_REF(entered_mmi)) + +/datum/component/ling_decoy_brain/UnregisterFromParent() + var/obj/item/organ/internal/brain/ling_brain = parent + ling_brain.organ_flags |= ORGAN_VITAL + ling_brain.decoy_override = FALSE + UnregisterSignal(ling_brain, COMSIG_ATOM_ENTERING, PROC_REF(entered_mmi)) + +/** + * Signal proc for [COMSIG_ATOM_ENTERING], when the brain enters an MMI grant the MMI talk action to the ling + * + * Unfortunately this is hooked on Entering rather than its own dedicated MMI signal becuase MMI code is a fuck + */ +/datum/component/ling_decoy_brain/proc/entered_mmi(obj/item/organ/internal/brain/source, atom/entering, atom/old_loc, ...) + SIGNAL_HANDLER + + var/mob/living/the_real_ling = parent_ling.owner.current + if(!istype(the_real_ling)) + return + + if(istype(source.loc, /obj/item/mmi) && talk_action?.owner != the_real_ling) + if(isnull(talk_action)) + talk_action = new() // Not linked to anything, we manage the reference (and don't want it disappearing on us) + talk_action.brain_ref = source + + if(the_real_ling.key) + to_chat(the_real_ling, span_ghostalert("We detect our decoy brain has been placed within a Man-Machine Interface. \ + We can use the \"MMI Talk\" action to command it to speak.")) + else + the_real_ling.notify_ghost_cloning("Your decoy brain has been placed in an MMI, re-enter your body to talk via it!", source = the_real_ling, flashwindow = TRUE) + talk_action.Grant(the_real_ling) + + else if(talk_action?.owner == the_real_ling) + to_chat(the_real_ling, span_ghostalert("We can no longer detect our decoy brain.")) + talk_action.Remove(the_real_ling) + +/// Clear up the decoy if the ling is de-linged +/datum/component/ling_decoy_brain/proc/clear_decoy(datum/source) + SIGNAL_HANDLER + + qdel(src) diff --git a/code/datums/components/material/remote_materials.dm b/code/datums/components/material/remote_materials.dm index c9677ecec44..17561581083 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 40381df8e86..fbd32fe5e4f 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 a07a94fff3f..ff29b8f37d2 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 aecaa2c1808..f75d29a10f4 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/religious_tool.dm b/code/datums/components/religious_tool.dm index fabed36595c..e64e28f83a3 100644 --- a/code/datums/components/religious_tool.dm +++ b/code/datums/components/religious_tool.dm @@ -27,6 +27,8 @@ after_sect_select_cb = _after_sect_select_cb if(override_catalyst_type) catalyst_type = override_catalyst_type + RegisterSignal(SSdcs, COMSIG_RELIGIOUS_SECT_CHANGED, PROC_REF(SetGlobalToLocal)) + RegisterSignal(SSdcs, COMSIG_RELIGIOUS_SECT_RESET, PROC_REF(on_sect_reset)) /datum/component/religious_tool/Destroy(force, silent) easy_access_sect = null @@ -46,15 +48,21 @@ * Sets the easy access variable to the global if it exists. */ /datum/component/religious_tool/proc/SetGlobalToLocal() + SIGNAL_HANDLER if(easy_access_sect) return TRUE if(!GLOB.religious_sect) return FALSE easy_access_sect = GLOB.religious_sect - if(after_sect_select_cb) - after_sect_select_cb.Invoke() + after_sect_select_cb?.Invoke() return TRUE +/// Sets the easy access variable to null in case an admin needed to change it +/datum/component/religious_tool/proc/on_sect_reset() + SIGNAL_HANDLER + easy_access_sect = null + after_sect_select_cb?.Invoke() + /** * Since all of these involve attackby, we require mega proc. Handles Invocation, Sacrificing, And Selection of Sects. */ @@ -66,7 +74,7 @@ /**********Sacrificing**********/ else if(operation_flags & RELIGION_TOOL_SACRIFICE) - if(!easy_access_sect?.can_sacrifice(the_item,user)) + if(easy_access_sect?.can_sacrifice(the_item,user)) return easy_access_sect.on_sacrifice(the_item,user) return COMPONENT_NO_AFTERATTACK @@ -123,27 +131,13 @@ /// Select the sect, called from [/datum/component/religious_tool/proc/AttemptActions] /datum/component/religious_tool/proc/select_sect(mob/living/user, path) - if(!ispath(text2path(path), /datum/religion_sect)) - message_admins("[ADMIN_LOOKUPFLW(usr)] has tried to spawn an item when selecting a sect.") - return if(user.mind.holy_role != HOLY_ROLE_HIGHPRIEST) to_chat(user, span_warning("You are not the high priest, and therefore cannot select a religious sect.")) return if(!user.can_perform_action(parent, FORBID_TELEKINESIS_REACH)) to_chat(user,span_warning("You cannot select a sect at this time.")) return - if(GLOB.religious_sect) - return - GLOB.religious_sect = new path() - for(var/i in GLOB.player_list) - if(!isliving(i)) - continue - var/mob/living/am_i_holy_living = i - if(!am_i_holy_living.mind?.holy_role) - continue - GLOB.religious_sect.on_conversion(am_i_holy_living) - easy_access_sect = GLOB.religious_sect - after_sect_select_cb.Invoke() + set_new_religious_sect(text2path(path)) /// Perform the rite, called from [/datum/component/religious_tool/proc/AttemptActions] /datum/component/religious_tool/proc/perform_rite(mob/living/user, path) @@ -212,7 +206,7 @@ * Generates an english list (so string) of wanted sac items. Returns null if no targets! */ /datum/component/religious_tool/proc/generate_sacrifice_list() - if(!easy_access_sect.desired_items) + if(!length(easy_access_sect?.desired_items)) return //specifically null so the data sends as such var/list/item_names = list() for(var/atom/sac_type as anything in easy_access_sect.desired_items) @@ -238,7 +232,7 @@ if(!can_i_see) return examine_list += span_notice("Use a bible to interact with this.") - if(!easy_access_sect) + if(isnull(easy_access_sect)) if(operation_flags & RELIGION_TOOL_SECTSELECT) examine_list += span_notice("This looks like it can be used to select a sect.") return diff --git a/code/datums/components/seclight_attachable.dm b/code/datums/components/seclight_attachable.dm index 56761cfd1bf..b3f36fe041a 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/supermatter_crystal.dm b/code/datums/components/supermatter_crystal.dm index 65c11ce2417..a9bdfc5b154 100644 --- a/code/datums/components/supermatter_crystal.dm +++ b/code/datums/components/supermatter_crystal.dm @@ -60,6 +60,10 @@ /datum/component/supermatter_crystal/proc/paw_hit(datum/source, mob/user, list/modifiers) SIGNAL_HANDLER + if(isliving(user)) + var/mob/living/living_mob = user + if(living_mob.incorporeal_move || living_mob.status_flags & GODMODE) + return if(isalien(user)) dust_mob(source, user, cause = "alien attack") return @@ -67,6 +71,8 @@ /datum/component/supermatter_crystal/proc/animal_hit(datum/source, mob/living/simple_animal/user, list/modifiers) SIGNAL_HANDLER + if(user.incorporeal_move || user.status_flags & GODMODE) + return var/atom/atom_source = source var/murder if(!user.melee_damage_upper && !user.melee_damage_lower) @@ -84,6 +90,10 @@ /datum/component/supermatter_crystal/proc/unarmed_hit(datum/source, mob/user, list/modifiers) SIGNAL_HANDLER + if(isliving(user)) + var/mob/living/living_mob = user + if(living_mob.incorporeal_move || living_mob.status_flags & GODMODE) + return var/atom/atom_source = source if(iscyborg(user) && atom_source.Adjacent(user)) dust_mob(source, user, cause = "cyborg attack") @@ -96,14 +106,12 @@ /datum/component/supermatter_crystal/proc/hand_hit(datum/source, mob/living/user, list/modifiers) SIGNAL_HANDLER - var/atom/atom_source = source if(user.incorporeal_move || user.status_flags & GODMODE) return - if(user.zone_selected != BODY_ZONE_PRECISE_MOUTH) dust_mob(source, user, cause = "hand") return - + var/atom/atom_source = source if(!user.is_mouth_covered()) if(user.combat_mode) dust_mob(source, user, @@ -185,6 +193,8 @@ return if(atom_source.Adjacent(user)) //if the item is stuck to the person, kill the person too instead of eating just the item. + if(user.incorporeal_move || user.status_flags & GODMODE) + return var/vis_msg = span_danger("[user] reaches out and touches [atom_source] with [item], inducing a resonance... [item] starts to glow briefly before the light continues up to [user]'s body. [user.p_They()] burst[user.p_s()] into flames before flashing into dust!") var/mob_msg = span_userdanger("You reach out and touch [atom_source] with [item]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\"") dust_mob(source, user, vis_msg, mob_msg) @@ -198,6 +208,10 @@ /datum/component/supermatter_crystal/proc/bumped_hit(datum/source, atom/movable/hit_object) SIGNAL_HANDLER + if(isliving(hit_object)) + var/mob/living/hit_mob = hit_object + if(hit_mob.incorporeal_move || hit_mob.status_flags & GODMODE) + return var/atom/atom_source = source var/obj/machinery/power/supermatter_crystal/our_supermatter = parent // Why is this a component? if(istype(our_supermatter)) @@ -224,9 +238,9 @@ return FALL_INTERCEPTED | FALL_NO_MESSAGE /datum/component/supermatter_crystal/proc/dust_mob(datum/source, mob/living/nom, vis_msg, mob_msg, cause) - var/atom/atom_source = source if(nom.incorporeal_move || nom.status_flags & GODMODE) //try to keep supermatter sliver's + hemostat's dust conditions in sync with this too return + var/atom/atom_source = source if(!vis_msg) vis_msg = span_danger("[nom] reaches out and touches [atom_source], inducing a resonance... [nom.p_their()] body starts to glow and burst into flames before flashing into dust!") if(!mob_msg) @@ -252,6 +266,9 @@ message_admins("[atom_source] has consumed [key_name_admin(consumed_mob)] [ADMIN_JMP(atom_source)].") atom_source.investigate_log("has consumed [key_name(consumed_mob)].", INVESTIGATE_ENGINE) consumed_mob.investigate_log("has been dusted by [atom_source].", INVESTIGATE_DEATHS) + if(istype(consumed_mob, /mob/living/simple_animal/parrot/poly)) // Dusting Poly creates a power surge + force_event(/datum/round_event_control/supermatter_surge/poly, "Poly's revenge") + notify_ghosts("[consumed_mob] has been dusted by [atom_source]!", source = atom_source, action = NOTIFY_JUMP, header = "Polytechnical Difficulties") consumed_mob.dust(force = TRUE) matter_increase += 100 * object_size if(is_clown_job(consumed_mob.mind?.assigned_role)) diff --git a/code/datums/components/twohanded.dm b/code/datums/components/twohanded.dm index 3b015c95383..37df7308217 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 00000000000..6164d39b001 --- /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 d9345d0107c..8754eb3b71d 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 72558f69ba9..ee695ffd5bc 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 f3c2285cd7e..77c162d6d85 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 5d52ac7281c..f865f4fb5be 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 1a4f05bfb8a..45d4e6672fb 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 8eb7f9f2b19..64bb59f01fd 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 16ce69fc181..dd75ea7cc62 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 8261718dc3c..5034a863f56 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 84913c234be..c2154736cc0 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 00000000000..11a83c79340 --- /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 49be7f5aafd..175738be5f6 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 7e26d3f7753..e30294bc08a 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 72e048b7908..c17547971b5 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 0ba3a581d9a..1bc70dc500f 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 1a177b03ab3..3ad3e272d34 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 217c11d4361..340938c430c 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 f60a922b9d7..b4f7cf1042f 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 00000000000..a85c5dc48b2 --- /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/movement_turf_changer.dm b/code/datums/elements/movement_turf_changer.dm index 1147c3a8353..c42ef287f81 100644 --- a/code/datums/elements/movement_turf_changer.dm +++ b/code/datums/elements/movement_turf_changer.dm @@ -26,7 +26,7 @@ SIGNAL_HANDLER var/turf/destination = target.loc - if(!isturf(destination) || istype(destination, turf_type) || isopenspaceturf(destination)) + if(!isturf(destination) || istype(destination, turf_type) || isgroundlessturf(destination)) return destination.PlaceOnTop(turf_type) diff --git a/code/datums/elements/openspace_item_click_handler.dm b/code/datums/elements/openspace_item_click_handler.dm index 43c7a60d1ef..c9de01f381c 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 ab3a17dc40d..b050dd0866f 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 5387f245d8c..3ff182ec231 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 f0f306344b5..84e3685f5f8 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 a53e3390e12..def4ec36fb2 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 af6df50e96f..0b8b2999f69 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/mapgen/Cavegens/LavalandGenerator.dm b/code/datums/mapgen/Cavegens/LavalandGenerator.dm index be8294fada6..6f8aa7ed1bb 100644 --- a/code/datums/mapgen/Cavegens/LavalandGenerator.dm +++ b/code/datums/mapgen/Cavegens/LavalandGenerator.dm @@ -8,8 +8,8 @@ /obj/effect/spawner/random/lavaland_mob/legion = 30, /obj/effect/spawner/random/lavaland_mob/watcher = 40, /mob/living/basic/mining/bileworm = 20, + /mob/living/basic/mining/brimdemon = 20, /mob/living/basic/mining/lobstrosity/lava = 20, - /mob/living/simple_animal/hostile/asteroid/brimdemon = 20, /mob/living/basic/mining/goldgrub = 10, /obj/structure/spawner/lavaland = 2, /obj/structure/spawner/lavaland/goliath = 3, diff --git a/code/datums/martial/plasma_fist.dm b/code/datums/martial/plasma_fist.dm index ed8ac5fe812..1bc353cc698 100644 --- a/code/datums/martial/plasma_fist.dm +++ b/code/datums/martial/plasma_fist.dm @@ -98,6 +98,7 @@ human_attacker.underwear = "Nude" human_attacker.undershirt = "Nude" human_attacker.socks = "Nude" + human_attacker.bra = "Nude" // SKYRAT EDIT ADDITION - Underwear and bra split human_attacker.update_body() var/turf/boomspot = get_turf(user) diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 68bd8798560..a5aa648ecee 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 28b88c246e3..9ab5d4b86ef 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/outfit.dm b/code/datums/outfit.dm index 8dc2c99f632..784e7a1b06f 100644 --- a/code/datums/outfit.dm +++ b/code/datums/outfit.dm @@ -220,6 +220,12 @@ if(socks) user.socks = initial(socks.name) + + // SKYRAT EDIT ADDITION START - Underwear and bra split + if(bra) + user.bra = initial(bra.name) + // SKYRAT EDIT END + if(accessory) var/obj/item/clothing/under/U = user.w_uniform if(U) diff --git a/code/datums/quirks/negative_quirks/allergic.dm b/code/datums/quirks/negative_quirks/allergic.dm new file mode 100644 index 00000000000..d6a510f62b6 --- /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 00000000000..b7c40636159 --- /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 00000000000..f3a5d967a01 --- /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 00000000000..778ea6af8c3 --- /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 00000000000..ce57e946fe9 --- /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 00000000000..c75007bacc2 --- /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 00000000000..6350a710882 --- /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 00000000000..15cc0128020 --- /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 00000000000..663d4138198 --- /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 00000000000..e0207d227dd --- /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 00000000000..8cf363753d4 --- /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 00000000000..4b99ff850b8 --- /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 00000000000..077bbe72aa5 --- /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 00000000000..0bf15516105 --- /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 00000000000..0fd08c68f21 --- /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 00000000000..6b806875ea2 --- /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 00000000000..33ad19add6d --- /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 00000000000..dea79683915 --- /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 00000000000..459b880fad2 --- /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 00000000000..f51e72fc256 --- /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 00000000000..8101985f8f7 --- /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 00000000000..1e30e7800d6 --- /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 00000000000..56b56a53812 --- /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 00000000000..269f6d2d96e --- /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 00000000000..5f82e2b9cd7 --- /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 00000000000..44706c4d434 --- /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 00000000000..6a5397b6504 --- /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 03b4354b9cb..00000000000 --- 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 00000000000..e1dbb0e6480 --- /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 00000000000..cd4f28cb302 --- /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 00000000000..af891a2058a --- /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 00000000000..58e1c4ba31e --- /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 00000000000..b543aeda076 --- /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 00000000000..d86feb809b0 --- /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 00000000000..8634e13bf63 --- /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 00000000000..f6f0e304a6d --- /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 00000000000..6330035b5a7 --- /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 00000000000..663d8173759 --- /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 00000000000..493cdf0b71c --- /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 00000000000..3d140bd80a0 --- /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 00000000000..41be5f1aca0 --- /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 00000000000..5a4ab4b1357 --- /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 00000000000..5d39776eeba --- /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 00000000000..8a760f6ceef --- /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 00000000000..f82fd5bf6fe --- /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 00000000000..566b469c7a7 --- /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 00000000000..5622956ba5b --- /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 00000000000..da317a7e66a --- /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 00000000000..0ab2e780480 --- /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 00000000000..1df079c0e45 --- /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 00000000000..51f6f3e785e --- /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 00000000000..dd66220cb56 --- /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 8917b361df0..00000000000 --- 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 00000000000..664aaf1d9de --- /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 00000000000..224401f0670 --- /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 00000000000..d2284df240c --- /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 00000000000..f17eb4224ec --- /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 00000000000..c342e14769c --- /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 00000000000..488c0a2bccb --- /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 00000000000..29f1def3761 --- /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 00000000000..ab273f1ae53 --- /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 00000000000..0ade72acafe --- /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 00000000000..6458513007d --- /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 00000000000..170cb6f5d44 --- /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 00000000000..324054198b8 --- /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 00000000000..984b0f7a6e4 --- /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 00000000000..fbab2503b4e --- /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 00000000000..3379f8a97c4 --- /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 00000000000..541d2b1cc44 --- /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 00000000000..8ab0003639b --- /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 00000000000..7f6c334ba9d --- /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 00000000000..80418b79b9d --- /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 00000000000..5145b4a2240 --- /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 00000000000..9d5e10f5f82 --- /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 00000000000..808a213db51 --- /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 23cfc9f2a44..00000000000 --- 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 00000000000..4991ebc540b --- /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 00000000000..022d08659ef --- /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 00000000000..81402c050cd --- /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 00000000000..df0a2f34c5d --- /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 00000000000..24bbac8e556 --- /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 4e0adcf73cd..24dc91fa627 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 00000000000..b08fe8b60c6 --- /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 00000000000..5aba24d850a --- /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 00000000000..5157b399009 --- /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 00000000000..68073304f0d --- /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 69e2d10a67f..968e6df544e 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 a43470d46f5..4862aa5e274 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 af87dc641d8..5e8553c69ee 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/sprite_accessories.dm b/code/datums/sprite_accessories.dm index 22e2473f2e4..16ce537b840 100644 --- a/code/datums/sprite_accessories.dm +++ b/code/datums/sprite_accessories.dm @@ -1162,6 +1162,8 @@ use_static = TRUE + +/* SKYRAT EDIT REMOVAL START - Underwear and bra split //FEMALE UNDERWEAR /datum/sprite_accessory/underwear/female_bikini name = "Bikini" @@ -1263,6 +1265,7 @@ icon_state = "female_kinky" gender = FEMALE use_static = TRUE +*/ // SKYRAT EDIT END //////////////////////////// // Undershirt Definitions // @@ -1458,7 +1461,7 @@ name = "Short-sleeved Shirt (White)" icon_state = "whiteshortsleeve" gender = NEUTER - +/* SKYRAT EDIT REMOVAL START - Underwear and bra split /datum/sprite_accessory/undershirt/sports_bra name = "Sports Bra" icon_state = "sports_bra" @@ -1468,7 +1471,7 @@ name = "Sports Bra (Alt)" icon_state = "sports_bra_alt" gender = NEUTER - +*/ // SKYRAT EDIT END /datum/sprite_accessory/undershirt/blueshirtsport name = "Sports Shirt (Blue)" icon_state = "blueshirtsport" diff --git a/code/datums/station_traits/_station_trait.dm b/code/datums/station_traits/_station_trait.dm index e42ce87f3e5..1205673c565 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 0b5a2df246c..165cc4c2ad4 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 637b731adbe..b9747d54acc 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 f626cb52be5..c16b946aa02 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 50fe9690b41..8c8f910fd57 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 2e844a61b19..705fcc60eeb 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 f893a1d379f..abdd07d3cd5 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 5da74ef7722..6ec793c5672 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 f1ce13f9fa5..1be31c33d2a 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 00000000000..329da73c2dc --- /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 4d28e80a910..7a59ea57413 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 11f2dc6a63d..faf1ef87057 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 8a9c34e163d..219b7dd8805 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 eed0fb1d883..59e64db1ccf 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 7ef1cd68268..a97706c8e16 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 d396b3a469f..4fb5cad387f 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 72b9b3f2846..ec166584632 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 bf33af3fefc..774d8cc5265 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 e8165368952..4475d95f508 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 fc968699df0..f63798aca62 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 aeedad9bf56..26dfcb4be76 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 @@ -456,11 +458,22 @@ GLOBAL_LIST_EMPTY(dynamic_station_traits) //To new_player and such, and we want the datums to just free when the roundstart work is done var/list/roundstart_rules = init_rulesets(/datum/dynamic_ruleset/roundstart) + SSjob.DivideOccupations(pure = TRUE, allow_all = TRUE) for(var/i in GLOB.new_player_list) var/mob/dead/new_player/player = i if(player.ready == PLAYER_READY_TO_PLAY && player.mind && player.check_preferences()) - roundstart_pop_ready++ - candidates.Add(player) + if(is_unassigned_job(player.mind.assigned_role)) + var/list/job_data = list() + var/job_prefs = player.client.prefs.job_preferences + for(var/job in job_prefs) + var/priority = job_prefs[job] + job_data += "[job]: [SSjob.job_priority_level_to_string(priority)]" + to_chat(player, span_danger("You were unable to qualify for any roundstart antagonist role because you could not qualify for any of the roundstart jobs you were trying to qualify for, along with 'return to lobby if job is unavailable' enabled.")) + log_admin("[player.ckey] failed to qualify for any job and has [player.client.prefs.be_special.len] antag preferences enabled. They will be unable to qualify for any roundstart antagonist role. These are their job preferences - [job_data.Join(" | ")]") + else + roundstart_pop_ready++ + candidates.Add(player) + SSjob.ResetOccupations() log_dynamic("Listing [roundstart_rules.len] round start rulesets, and [candidates.len] players ready.") if (candidates.len <= 0) log_dynamic("[candidates.len] candidates.") @@ -858,7 +871,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 975b5dc7e2b..df078c462d9 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/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm index c8c951a9fd4..2240f220e48 100644 --- a/code/game/gamemodes/objective_items.dm +++ b/code/game/gamemodes/objective_items.dm @@ -355,6 +355,7 @@ /datum/objective_item/steal/documents name = "any set of secret documents of any organization" + valid_containers = list(/obj/item/folder) targetitem = /obj/item/documents exists_on_map = TRUE diff --git a/code/game/machinery/bank_machine.dm b/code/game/machinery/bank_machine.dm index c48671a6e18..4d276b6ebae 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 69f13be11ac..764bd99b4ff 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 f1c85a293c7..f77e11151e0 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 21a718d8705..5824f93dcc7 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 a47115a9f60..42f28a8b3ee 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 37907a5ba29..786a2c3a39a 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 faef0370ad0..8d56b8a2f90 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 738a05043fd..f32eff91c4e 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 7177da8f4ee..dd8a051cc8e 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 b03ed092269..ceb3c2e923e 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 d212f2ba45d..cb12a399260 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 0bfb8aeba72..d0b695428af 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 814fe788f8c..e84e21314b3 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 9d0c10e8666..5d4568a535c 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 4c5e080c653..73ae0994eb5 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 be630c0a19e..5292c3a950c 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 8d3c4febd70..8075b51dcab 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 3144ff93c83..4104d7b93f8 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 73f527ca7d5..060b29c4d20 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 816814b1bcf..7c73d2b6f65 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 f3f463bcae7..5400cccf2f2 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 5bc618162f0..c9b220bb0cd 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 f925dfdbdc3..e3922415a66 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 54cda76f989..254467fc217 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 73192dac2b7..cd10a23150c 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 98cce390010..1ae08c066f0 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 79b421fa8de..fc646a3483e 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 b19a8032e7d..701d6222369 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 89f41386691..86b1df20e7f 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 a855c2d5523..037b4692fc7 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 cc6ead40627..99e7540a352 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 49a5b60ad70..dbdf86dac37 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 612928dbdec..76c82dd39dd 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/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm index 402185e0928..516f5ec8453 100644 --- a/code/game/machinery/syndicatebomb.dm +++ b/code/game/machinery/syndicatebomb.dm @@ -409,12 +409,14 @@ /obj/item/bombcore/badmin/summon/detonate() var/obj/machinery/syndicatebomb/B = loc - spawn_and_random_walk(summon_path, src, amt_summon, walk_chance=50, admin_spawn=TRUE) + spawn_and_random_walk(summon_path, src, amt_summon, walk_chance=50, admin_spawn=TRUE, cardinals_only = FALSE) qdel(B) qdel(src) /obj/item/bombcore/badmin/summon/clown - summon_path = /mob/living/simple_animal/hostile/retaliate/clown + name = "bananium payload" + desc = "Clowns delivered fast and cheap!" + summon_path = /mob/living/basic/clown amt_summon = 50 /obj/item/bombcore/badmin/summon/clown/defuse() diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 93fbafeb43d..8b6601dd471 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 e113eec5a36..4f4b2543792 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 fc07a229251..d329de34a5f 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 61306e4eceb..6a519650d10 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 65e6cc3900c..d248b5e691d 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/effect_system/fluid_spread/effects_foam.dm b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm index 914b19e6a88..787ce602a3a 100644 --- a/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm +++ b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm @@ -459,6 +459,20 @@ allow_duplicate_results = FALSE result_type = /obj/effect/decal/cleanable/dirt +/obj/effect/spawner/foam_starter + var/datum/effect_system/fluid_spread/foam/foam_type = /datum/effect_system/fluid_spread/foam + var/foam_size = 4 + +/obj/effect/spawner/foam_starter/Initialize(mapload) + . = ..() + + var/datum/effect_system/fluid_spread/foam/foam = new foam_type() + foam.set_up(foam_size, holder = src, location = loc) + foam.start() + +/obj/effect/spawner/foam_starter/small + foam_size = 2 + #undef MINIMUM_FOAM_DILUTION_RANGE #undef MINIMUM_FOAM_DILUTION #undef FOAM_REAGENT_SCALE diff --git a/code/game/objects/effects/phased_mob.dm b/code/game/objects/effects/phased_mob.dm index 7a0317c4c77..273a4c772a5 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/spawners/random/food_or_drink.dm b/code/game/objects/effects/spawners/random/food_or_drink.dm index 5338eb52897..b2639b2df68 100644 --- a/code/game/objects/effects/spawners/random/food_or_drink.dm +++ b/code/game/objects/effects/spawners/random/food_or_drink.dm @@ -56,6 +56,7 @@ /obj/item/seeds/liberty = 5, /obj/item/seeds/replicapod = 5, /obj/item/seeds/reishi = 5, + /obj/item/seeds/seedling = 5, /obj/item/seeds/nettle/death = 1, /obj/item/seeds/plump/walkingmushroom = 1, /obj/item/seeds/cannabis/rainbow = 1, @@ -272,3 +273,53 @@ if(!HAS_TRAIT(SSstation, STATION_TRAIT_BIRTHDAY)) spawn_loot_chance = 0 return ..() + +/obj/effect/spawner/random/food_or_drink/donuts + name = "donut spawner" + icon_state = "donut" + loot = list( + /obj/item/food/donut/apple = 3, + /obj/item/food/donut/berry = 3, + /obj/item/food/donut/caramel = 3, + /obj/item/food/donut/choco = 3, + /obj/item/food/donut/plain = 3, + /obj/item/food/donut/blumpkin = 2, + /obj/item/food/donut/bungo = 2, + /obj/item/food/donut/laugh = 2, + /obj/item/food/donut/matcha = 2, + /obj/item/food/donut/trumpet = 2, + /obj/item/food/donut/chaos = 1, + /obj/item/food/donut/meat = 1, + ) + +/obj/effect/spawner/random/food_or_drink/jelly_donuts + name = "jelly donut spawner" + icon_state = "jelly_donut" + loot = list( + /obj/item/food/donut/jelly/apple = 3, + /obj/item/food/donut/jelly/berry = 3, + /obj/item/food/donut/jelly/caramel = 3, + /obj/item/food/donut/jelly/choco = 3, + /obj/item/food/donut/jelly/plain = 3, + /obj/item/food/donut/jelly/blumpkin = 2, + /obj/item/food/donut/jelly/bungo = 2, + /obj/item/food/donut/jelly/laugh = 2, + /obj/item/food/donut/jelly/matcha = 2, + /obj/item/food/donut/jelly/trumpet = 2, + ) + +/obj/effect/spawner/random/food_or_drink/slime_jelly_donuts + name = "slime jelly donut spawner" + icon_state = "slime_jelly_donut" + loot = list( + /obj/item/food/donut/jelly/slimejelly/apple = 3, + /obj/item/food/donut/jelly/slimejelly/berry = 3, + /obj/item/food/donut/jelly/slimejelly/caramel = 3, + /obj/item/food/donut/jelly/slimejelly/choco = 3, + /obj/item/food/donut/jelly/slimejelly/plain = 3, + /obj/item/food/donut/jelly/slimejelly/blumpkin = 2, + /obj/item/food/donut/jelly/slimejelly/bungo = 2, + /obj/item/food/donut/jelly/slimejelly/laugh = 2, + /obj/item/food/donut/jelly/slimejelly/matcha = 2, + /obj/item/food/donut/jelly/slimejelly/trumpet = 2, + ) diff --git a/code/game/objects/effects/spawners/random/lavaland_mobs.dm b/code/game/objects/effects/spawners/random/lavaland_mobs.dm index 7ad2b3e6e30..8aa20cc90e7 100644 --- a/code/game/objects/effects/spawners/random/lavaland_mobs.dm +++ b/code/game/objects/effects/spawners/random/lavaland_mobs.dm @@ -7,11 +7,11 @@ icon_state = "large_egg" loot = list( /mob/living/basic/mining/bileworm = 1, + /mob/living/basic/mining/brimdemon = 1, /mob/living/basic/mining/goldgrub = 1, /mob/living/basic/mining/goliath = 1, /mob/living/basic/mining/lobstrosity/lava = 1, /mob/living/basic/mining/watcher = 1, - /mob/living/simple_animal/hostile/asteroid/brimdemon = 1, /mob/living/simple_animal/hostile/asteroid/hivelord/legion = 1, ) diff --git a/code/game/objects/effects/spawners/random/structure.dm b/code/game/objects/effects/spawners/random/structure.dm index bf8e77a9fcd..cf037b91b5c 100644 --- a/code/game/objects/effects/spawners/random/structure.dm +++ b/code/game/objects/effects/spawners/random/structure.dm @@ -235,3 +235,24 @@ /obj/structure/musician/piano, /obj/structure/musician/piano/minimoog, ) + +/obj/effect/spawner/random/structure/shipping_container + name = "shipping container spawner" + icon = 'icons/obj/fluff/containers.dmi' + icon_state = "random_container" + loot = list( + /obj/structure/shipping_container/conarex = 3, + /obj/structure/shipping_container/deforest = 3, + /obj/structure/shipping_container/kahraman = 3, + /obj/structure/shipping_container/kahraman/alt = 3, + /obj/structure/shipping_container/kosmologistika = 3, + /obj/structure/shipping_container/interdyne = 3, + /obj/structure/shipping_container/nakamura = 3, + /obj/structure/shipping_container/nanotrasen = 3, + /obj/structure/shipping_container/nthi = 3, + /obj/structure/shipping_container/vitezstvi = 3, + /obj/structure/shipping_container/cybersun = 2, + /obj/structure/shipping_container/donk_co = 2, + /obj/structure/shipping_container/gorlex = 1, + /obj/structure/shipping_container/gorlex/red = 1, + ) diff --git a/code/game/objects/effects/spawners/random/trash.dm b/code/game/objects/effects/spawners/random/trash.dm index 020724772dd..b10dbc1f7f8 100644 --- a/code/game/objects/effects/spawners/random/trash.dm +++ b/code/game/objects/effects/spawners/random/trash.dm @@ -266,3 +266,22 @@ /obj/item/food/breadslice/moldy/bacteria, /obj/item/food/pizzaslice/moldy/bacteria, ) + +/obj/effect/spawner/random/trash/crushed_can + name = "crushed can spawner" + icon_state = "crushed_can" + loot = list(/obj/item/trash/can) + /// Whether the can will spawn with this spawner's icon_state instead of a random one (used for mapedits) + var/soda_icons = list( + "energy_drink", "monkey_energy", "thirteen_loko", "space_mountain_wind", "dr_gibb", "starkist", + "sodawater", "tonic", "cola", "purple_can", "ice_tea_can", + "sol_dry", "wellcheers", "space beer", "ebisu", "shimauma", "moonlabor", + "space_up", "lemon_lime", "shamblers", "shamblerseldritch", "air", "laughter", + "volt_energy", "melon_soda", + ) + +/obj/effect/spawner/random/trash/crushed_can/make_item(spawn_loc, type_path_to_make) + var/obj/item/trash/can/crushed_can = .. () + if(istype(crushed_can)) + crushed_can.icon_state = pick(soda_icons) + return crushed_can diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index 74c232b55ea..e88753d25c1 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -655,6 +655,13 @@ . = ..() 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" diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 9eb0daadb73..c10c04a9fa1 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/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index b0807aff466..e5b7144dc8c 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 00000000000..2c96d1844b1 --- /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 4b03fd8013a..a8fa34ed5f8 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,56 @@ . += 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 + new_ai.grant_language(/datum/language/codespeak, source = LANGUAGE_MIND) // 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 +155,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 00517f78915..e2936c0f538 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 14fc91ea7d0..ecf94d58f70 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) + 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 025f5fa5e88..17f5e7d4902 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 4c2e611bd25..13a054ec8e4 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 918f241d16d..dcb7ddc1936 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 cfaaf01d3e2..50c42c5f753 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 7b8354b0a77..737ba7e947c 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 2b7e4b4cf36..69cfdde4668 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 08722f101c5..ba1845bb40d 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 311d87b3192..191cc0eaf25 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/donuts.dm b/code/game/objects/items/food/donuts.dm index a9491b87edb..0d2e2f91d30 100644 --- a/code/game/objects/items/food/donuts.dm +++ b/code/game/objects/items/food/donuts.dm @@ -44,7 +44,7 @@ return "[icon_state]_inbox" ///Override for checkliked in edible component, because all cops LOVE donuts -/obj/item/food/donut/proc/check_liked(fraction, mob/living/carbon/human/consumer) +/obj/item/food/donut/proc/check_liked(mob/living/carbon/human/consumer) var/obj/item/organ/internal/liver/liver = consumer.get_organ_slot(ORGAN_SLOT_LIVER) if(!HAS_TRAIT(consumer, TRAIT_AGEUSIA) && liver && HAS_TRAIT(liver, TRAIT_LAW_ENFORCEMENT_METABOLISM)) return FOOD_LIKED diff --git a/code/game/objects/items/food/misc.dm b/code/game/objects/items/food/misc.dm index aaf730f2617..67e74496260 100644 --- a/code/game/objects/items/food/misc.dm +++ b/code/game/objects/items/food/misc.dm @@ -491,7 +491,7 @@ . = ..() AddComponent(/datum/component/edible, check_liked = CALLBACK(src, PROC_REF(check_liked))) -/obj/item/food/pickle/proc/check_liked(fraction, mob/living/carbon/human/consumer) +/obj/item/food/pickle/proc/check_liked(mob/living/carbon/human/consumer) var/obj/item/organ/internal/liver/liver = consumer.get_organ_slot(ORGAN_SLOT_LIVER) if(!HAS_TRAIT(consumer, TRAIT_AGEUSIA) && liver && HAS_TRAIT(liver, TRAIT_CORONER_METABOLISM)) return FOOD_LIKED diff --git a/code/game/objects/items/food/packaged.dm b/code/game/objects/items/food/packaged.dm index 59f6d6a4db6..edcc0bd09ed 100644 --- a/code/game/objects/items/food/packaged.dm +++ b/code/game/objects/items/food/packaged.dm @@ -315,5 +315,5 @@ . = ..() AddComponent(/datum/component/edible, check_liked = CALLBACK(src, PROC_REF(check_liked))) -/obj/item/food/rationpack/proc/check_liked(fraction, mob/mob) //Nobody likes rationpacks. Nobody. +/obj/item/food/rationpack/proc/check_liked(mob/mob) //Nobody likes rationpacks. Nobody. return FOOD_DISLIKED diff --git a/code/game/objects/items/food/pancakes.dm b/code/game/objects/items/food/pancakes.dm index 6e4d33fb350..52829ab4c3a 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 02782c3e3f1..46da05dea14 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/food/sandwichtoast.dm b/code/game/objects/items/food/sandwichtoast.dm index f1d4f6bd7ee..8d6e8c8d147 100644 --- a/code/game/objects/items/food/sandwichtoast.dm +++ b/code/game/objects/items/food/sandwichtoast.dm @@ -264,8 +264,12 @@ . = ..() AddComponent(/datum/component/edible, check_liked = CALLBACK(src, PROC_REF(check_liked))) -///Eat it right, or you die. -/obj/item/food/sandwich/death/proc/check_liked(fraction, mob/living/carbon/human/consumer) +/** +* Callback to be used with the edible component. +* If you eat the sandwich with the right clothes and hairstyle, you like it. +* If you don't, you contract a deadly disease. +*/ +/obj/item/food/sandwich/death/proc/check_liked(mob/living/carbon/human/consumer) /// Closest thing to a mullet we have if(consumer.hairstyle == "Gelled Back" && istype(consumer.get_item_by_slot(ITEM_SLOT_ICLOTHING), /obj/item/clothing/under/rank/civilian/cookjorts)) return FOOD_LIKED diff --git a/code/game/objects/items/grenades/spawnergrenade.dm b/code/game/objects/items/grenades/spawnergrenade.dm index 860812021e2..1b9d9ff27d0 100644 --- a/code/game/objects/items/grenades/spawnergrenade.dm +++ b/code/game/objects/items/grenades/spawnergrenade.dm @@ -61,7 +61,7 @@ desc = "A sleek device often given to clowns on their 10th birthdays for protection. You can hear faint scratching coming from within." icon_state = "clown_ball" inhand_icon_state = null - spawner_type = list(/mob/living/simple_animal/hostile/retaliate/clown/fleshclown, /mob/living/simple_animal/hostile/retaliate/clown/clownhulk, /mob/living/simple_animal/hostile/retaliate/clown/longface, /mob/living/simple_animal/hostile/retaliate/clown/clownhulk/chlown, /mob/living/simple_animal/hostile/retaliate/clown/clownhulk/honcmunculus, /mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton, /mob/living/simple_animal/hostile/retaliate/clown/banana, /mob/living/simple_animal/hostile/retaliate/clown/honkling, /mob/living/simple_animal/hostile/retaliate/clown/lube) + spawner_type = list(/mob/living/basic/clown/fleshclown, /mob/living/basic/clown/clownhulk, /mob/living/basic/clown/longface, /mob/living/basic/clown/clownhulk/chlown, /mob/living/basic/clown/clownhulk/honkmunculus, /mob/living/basic/clown/mutant/glutton, /mob/living/basic/clown/banana, /mob/living/basic/clown/honkling, /mob/living/basic/clown/lube) deliveryamt = 1 /obj/item/grenade/spawnergrenade/clown_broken @@ -69,5 +69,5 @@ desc = "A sleek device often given to clowns on their 10th birthdays for protection. While a typical C.L.U.W.N.E only holds one creature, sometimes foolish young clowns try to cram more in, often to disasterous effect." icon_state = "clown_broken" inhand_icon_state = null - spawner_type = /mob/living/simple_animal/hostile/retaliate/clown/mutant + spawner_type = /mob/living/basic/clown/mutant deliveryamt = 5 diff --git a/code/game/objects/items/hand_items.dm b/code/game/objects/items/hand_items.dm index b136fc68cda..5dfb27e77ea 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 6e7f5a99d95..74a0c8637e8 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 f24efb7d263..cd196ed48cf 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 832dcfd2cd6..a747f813ace 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/generic.dm b/code/game/objects/items/robot/items/generic.dm index 65436e5c8f4..4db09ab3804 100644 --- a/code/game/objects/items/robot/items/generic.dm +++ b/code/game/objects/items/robot/items/generic.dm @@ -142,7 +142,9 @@ if (!COOLDOWN_FINISHED(src, shock_cooldown)) return if(ishuman(attacked_mob)) - attacked_mob.electrocute_act(5, "[user]", flags = SHOCK_NOGLOVES) + attacked_mob.electrocute_act(5, "[user]", flags = SHOCK_NOGLOVES | SHOCK_NOSTUN) + attacked_mob.dropItemToGround(attacked_mob.get_active_held_item()) + attacked_mob.dropItemToGround(attacked_mob.get_inactive_held_item()) user.visible_message(span_userdanger("[user] electrocutes [attacked_mob] with [user.p_their()] touch!"), \ span_danger("You electrocute [attacked_mob] with your touch!")) else diff --git a/code/game/objects/items/robot/items/storage.dm b/code/game/objects/items/robot/items/storage.dm index 25f85644a1c..6570e159b6a 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 496e4b39a46..94432b35d3d 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 d071e3465af..081ab5d78e0 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 9257035d8de..289920c8889 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 54fb4866835..7050309268c 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 484797ca29c..a67d85979f1 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 658b07a3980..335ccbe7185 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/lockbox.dm b/code/game/objects/items/storage/lockbox.dm index 7eec46eb2f0..b5b38efc698 100644 --- a/code/game/objects/items/storage/lockbox.dm +++ b/code/game/objects/items/storage/lockbox.dm @@ -192,6 +192,8 @@ /obj/item/storage/lockbox/medal/med/PopulateContents() new /obj/item/clothing/accessory/medal/med_medal(src) new /obj/item/clothing/accessory/medal/med_medal2(src) + for(var/i in 1 to 3) + new /obj/item/clothing/accessory/medal/silver/emergency_services/medical(src) /obj/item/storage/lockbox/medal/sec/PopulateContents() for(var/i in 1 to 3) @@ -222,6 +224,16 @@ for(var/i in 1 to 3) new /obj/item/clothing/accessory/medal/plasma/nobel_science(src) +/obj/item/storage/lockbox/medal/engineering + name = "engineering medal box" + desc = "A locked box used to store awards to be given to members of the engineering department." + req_access = list(ACCESS_CE) + +/obj/item/storage/lockbox/medal/engineering/PopulateContents() + for(var/i in 1 to 3) + new /obj/item/clothing/accessory/medal/silver/emergency_services/engineering(src) + new /obj/item/clothing/accessory/medal/silver/elder_atmosian(src) + /obj/item/storage/lockbox/order name = "order lockbox" desc = "A box used to secure small cargo orders from being looted by those who didn't order it. Yeah, cargo tech, that means you." diff --git a/code/game/objects/items/storage/secure.dm b/code/game/objects/items/storage/secure.dm index 46eb8356c79..ad4be8d6e40 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 5ef5bfdae7a..dfe83baabdb 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" @@ -12,28 +35,14 @@ w_class = WEIGHT_CLASS_BULKY slowdown = 1 item_flags = SLOWS_WHILE_IN_HAND + pass_flags = NONE /// 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 +75,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 +112,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 @@ -117,11 +121,11 @@ if(is_portable) interaction_flags_item |= INTERACT_ITEM_ATTACK_HAND_PICKUP - pass_flags |= PASSTABLE + passtable_on(src, type) RemoveElement(/datum/element/noisy_movement) else interaction_flags_item &= ~INTERACT_ITEM_ATTACK_HAND_PICKUP - pass_flags &= ~PASSTABLE + passtable_off(src, type) AddElement(/datum/element/noisy_movement) update_appearance() @@ -154,54 +158,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 2eef8cc116e..c7f93c6ea68 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 3cfafe74f97..48142778a92 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/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 5b05cddb806..470448ab244 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -620,6 +620,100 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 desc = "A bust of the famous Greek physician Hippocrates of Kos, often referred to as the father of western medicine." icon_state = "hippocratic" impressiveness = 50 + // If it hits the prob(reference_chance) chance, this is set to TRUE. Adds medical HUD when wielded, but has a 10% slower attack speed and is too bloody to make an oath with. + var/reference = FALSE + // Chance for above. + var/reference_chance = 1 + // Minimum time inbetween oaths. + COOLDOWN_DECLARE(oath_cd) + +/obj/item/statuebust/hippocratic/evil + reference_chance = 100 + +/obj/item/statuebust/hippocratic/Initialize(mapload) + . = ..() + if(prob(reference_chance)) + name = "Solemn Vow" + desc = "Art lovers will cherish the bust of Hippocrates, commemorating a time when medics still thought doing no harm was a good idea." + attack_speed = CLICK_CD_SLOW + reference = TRUE + +/obj/item/statuebust/hippocratic/examine(mob/user) + . = ..() + if(reference) + . += span_notice("You could activate the bust in-hand to swear or forswear a Hippocratic Oath... but it seems like somebody decided it was more of a Hippocratic Suggestion. This thing is caked with bits of blood and gore.") + return + . += span_notice("You can activate the bust in-hand to swear or forswear a Hippocratic Oath! This has no effects except pacifism or bragging rights. Does not remove other sources of pacifism. Do not eat.") + +/obj/item/statuebust/hippocratic/equipped(mob/living/carbon/human/user, slot) + ..() + if(!(slot & ITEM_SLOT_HANDS)) + return + var/datum/atom_hud/our_hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] + our_hud.show_to(user) + ADD_TRAIT(user, TRAIT_MEDICAL_HUD, type) + +/obj/item/statuebust/hippocratic/dropped(mob/living/carbon/human/user) + ..() + if(HAS_TRAIT_NOT_FROM(user, TRAIT_MEDICAL_HUD, type)) + return + var/datum/atom_hud/our_hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] + our_hud.hide_from(user) + REMOVE_TRAIT(user, TRAIT_MEDICAL_HUD, type) + +/obj/item/statuebust/hippocratic/attack_self(mob/user) + if(!iscarbon(user)) + to_chat(user, span_warning("You remember how the Hippocratic Oath specifies 'my fellow human beings' and realize that it's completely meaningless to you.")) + return + + if(reference) + to_chat(user, span_warning("As you prepare yourself to swear the Oath, you realize that doing so on a blood-caked bust is probably not a good idea.")) + return + + if(!COOLDOWN_FINISHED(src, oath_cd)) + to_chat(user, span_warning("You've sworn or forsworn an oath too recently to undo your decisions. The bust looks at you with disgust.")) + return + + COOLDOWN_START(src, oath_cd, 5 MINUTES) + + if(HAS_TRAIT_FROM(user, TRAIT_PACIFISM, type)) + to_chat(user, span_warning("You've already sworn a vow. You start preparing to rescind it...")) + if(do_after(user, 5 SECONDS, target = user)) + user.say("Yeah this Hippopotamus thing isn't working out. I quit!", forced = "hippocratic hippocrisy") + REMOVE_TRAIT(user, TRAIT_PACIFISM, type) + + // they can still do it for rp purposes + if(HAS_TRAIT_NOT_FROM(user, TRAIT_PACIFISM, type)) + to_chat(user, span_warning("You already don't want to harm people, this isn't going to do anything!")) + + + to_chat(user, span_notice("You remind yourself of the Hippocratic Oath's contents and prepare to swear yourself to it...")) + if(do_after(user, 4 SECONDS, target = user)) + user.say("I swear to fulfill, to the best of my ability and judgment, this covenant:", forced = "hippocratic oath") + else + return fuck_it_up(user) + if(do_after(user, 2 SECONDS, target = user)) + user.say("I will apply, for the benefit of the sick, all measures that are required, avoiding those twin traps of overtreatment and therapeutic nihilism.", forced = "hippocratic oath") + else + return fuck_it_up(user) + if(do_after(user, 3 SECONDS, target = user)) + user.say("I will remember that I remain a member of society, with special obligations to all my fellow human beings, those sound of mind and body as well as the infirm.", forced = "hippocratic oath") + else + + return fuck_it_up(user) + if(do_after(user, 3 SECONDS, target = user)) + user.say("If I do not violate this oath, may I enjoy life and art, respected while I live and remembered with affection thereafter. May I always act so as to preserve the finest traditions of my calling and may I long experience the joy of healing those who seek my help.", forced = "hippocratic oath") + else + return fuck_it_up(user) + + to_chat(user, span_notice("Contentment, understanding, and purpose washes over you as you finish the oath. You consider for a second the concept of harm and shudder.")) + ADD_TRAIT(user, TRAIT_PACIFISM, type) + +// Bully the guy for fucking up. +/obj/item/statuebust/hippocratic/proc/fuck_it_up(mob/living/carbon/user) + to_chat(user, span_warning("You forget what comes next like a dumbass. The Hippocrates bust looks down on you, disappointed.")) + user.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2) + COOLDOWN_RESET(src, oath_cd) /obj/item/tailclub name = "tail club" diff --git a/code/game/objects/structures/containers.dm b/code/game/objects/structures/containers.dm index f8272c19de9..bf56f7850f8 100644 --- a/code/game/objects/structures/containers.dm +++ b/code/game/objects/structures/containers.dm @@ -53,6 +53,7 @@ name = "\improper Nanotrasen shipping container" desc = "A standard-measure shipping container for bulk transport of goods. This one prominently features Nanotrasen's logo, and so presumably could be carrying anything." icon_state = "nanotrasen" + /obj/structure/shipping_container/nthi name = "\improper Nanotrasen Heavy Industries shipping container" desc = "A standard-measure shipping container for bulk transport of goods. This one is from NTHI: Nanotrasen's mining and refining subdivision." diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 1e05bae6298..db1122465f3 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) @@ -638,7 +646,7 @@ return TRUE -/// returns TRUE if attackBy call shouldn't be continued (because tool weaponas used/closet weaponas of weaponrong type), FALSE if otherweaponise +/// returns TRUE if attackBy call shouldn't be continued (because tool was used/closet was of wrong type), FALSE if otherwise /obj/structure/closet/proc/tool_interact(obj/item/weapon, mob/living/user) . = TRUE var/obj/item/card/id/id = null @@ -735,11 +743,11 @@ id_card = null switch(choice) - if("Personal") //only the player weaponho sweaponiped their id has access. + if("Personal") //only the player who swiped their id has access. id_card = WEAKREF(id) name = "[id.registered_name] locker" desc = "now owned by [id.registered_name]. [initial(desc)]" - if("Departmental") //anyone weaponho has the same access permissions as this id has access + if("Departmental") //anyone who has the same access permissions as this id has access name = "[id.assignment] closet" desc = "Its a [id.assignment] closet. [initial(desc)]" set_access(id.GetAccess()) @@ -800,14 +808,14 @@ span_hear("You hear weaponelding.")) deconstruct(TRUE) return - else // for example cardboard box is cut weaponith weaponirecutters + else // for example cardboard box is cut with wirecutters user.visible_message(span_notice("[user] cut apart \the [src]."), \ span_notice("You cut \the [src] apart weaponith \the [weapon].")) deconstruct(TRUE) return if (user.combat_mode) return - if(user.transferItemToLoc(weapon, drop_location())) // so weapone put in unlit weaponelder too + if(user.transferItemToLoc(weapon, drop_location())) // so we put in unlit welder too return else if(weapon.tool_behaviour == TOOL_WELDER && can_weld_shut) @@ -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/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm index 88bbff40340..556230808bc 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm @@ -13,7 +13,7 @@ new /obj/item/holosign_creator/atmos(src) new /obj/item/assembly/flash/handheld(src) new /obj/item/door_remote/chief_engineer(src) - + new /obj/item/storage/lockbox/medal/engineering(src) new /obj/item/circuitboard/machine/techfab/department/engineering(src) new /obj/item/extinguisher/advanced(src) new /obj/item/storage/photo_album/ce(src) 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 8f7f34164c0..9700a3e80fa 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 fdba3e10adb..aab8e4b8582 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 4059839641c..1f8322ad5dc 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 ce000e91e69..62638f44eeb 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/dresser.dm b/code/game/objects/structures/dresser.dm index 6644b088f08..a6de88c5f8a 100644 --- a/code/game/objects/structures/dresser.dm +++ b/code/game/objects/structures/dresser.dm @@ -36,7 +36,7 @@ to_chat(dressing_human, span_warning("You are not capable of wearing underwear.")) return - var/choice = tgui_input_list(user, "Underwear, Undershirt, or Socks?", "Changing", list("Underwear", "Underwear Color", "Undershirt", "Socks", "Undershirt Color", "Socks Color")) //SKYRAT EDIT ADDITION - Colorable Undershirt/Socks + var/choice = tgui_input_list(user, "Underwear, Bra, Undershirt, or Socks?", "Changing", list("Underwear", "Underwear Color", "Bra", "Bra Color", "Undershirt", "Undershirt Color", "Socks", "Socks Color")) //SKYRAT EDIT ADDITION - Colorable Undershirt/Socks/Bra if(isnull(choice)) return @@ -59,7 +59,7 @@ var/new_socks = tgui_input_list(user, "Select your socks", "Changing", GLOB.socks_list) if(new_socks) dressing_human.socks = new_socks - //SKYRAT EDIT ADDITION BEGIN - Colorable Undershirt/Socks + //SKYRAT EDIT ADDITION BEGIN - Colorable Undershirt/Socks/Bras if("Undershirt Color") var/new_undershirt_color = input(dressing_human, "Choose your undershirt color", "Undershirt Color", dressing_human.undershirt_color) as color|null if(new_undershirt_color) @@ -68,7 +68,18 @@ var/new_socks_color = input(dressing_human, "Choose your socks color", "Socks Color", dressing_human.socks_color) as color|null if(new_socks_color) dressing_human.socks_color = sanitize_hexcolor(new_socks_color) - //SKYRAT EDIT ADDITION END - Colorable Undershirt/Socks + + if("Bra") + var/new_bra = tgui_input_list(user, "Select your Bra", "Changing", GLOB.bra_list) + if(new_bra) + dressing_human.bra = new_bra + + if("Bra Color") + var/new_bra_color = input(dressing_human, "Choose your Bra color", "Bra Color", dressing_human.bra_color) as color|null + if(new_bra_color) + dressing_human.bra_color = sanitize_hexcolor(new_bra_color) + + //SKYRAT EDIT ADDITION END - Colorable Undershirt/Socks/Bras add_fingerprint(dressing_human) dressing_human.update_body() diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm index 04e48e489ac..56d9147867d 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 75294549ebe..59a00618b0e 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/icemoon/cave_entrance.dm b/code/game/objects/structures/icemoon/cave_entrance.dm index ded6851914b..10f7a56c7f9 100644 --- a/code/game/objects/structures/icemoon/cave_entrance.dm +++ b/code/game/objects/structures/icemoon/cave_entrance.dm @@ -187,7 +187,7 @@ GLOBAL_LIST_INIT(ore_probability, list( if(24) new /obj/structure/elite_tumor(loc) if(25) - new /mob/living/simple_animal/hostile/retaliate/clown/clownhulk(loc) + new /mob/living/basic/clown/clownhulk(loc) if(26) new /obj/item/clothing/shoes/winterboots/ice_boots(loc) if(27) diff --git a/code/game/objects/structures/mannequin.dm b/code/game/objects/structures/mannequin.dm index ad9588d5aa8..618b935e690 100644 --- a/code/game/objects/structures/mannequin.dm +++ b/code/game/objects/structures/mannequin.dm @@ -109,6 +109,12 @@ var/datum/sprite_accessory/socks/socks = GLOB.socks_list[socks_name] if(socks) . += mutable_appearance(socks.icon, socks.icon_state, -BODY_LAYER) + //SKYRAT EDIT ADDITION BEGIN - Underwear and Bra split + var/datum/sprite_accessory/bra/bra = GLOB.bra_list[bra_name] + if(bra) + . += mutable_appearance(bra.icon, bra.icon_state, -BODY_LAYER) + //SKYRAT EDIT END + for(var/slot_flag in worn_items) var/obj/item/worn_item = worn_items[slot_flag] if(!worn_item) @@ -162,7 +168,7 @@ . = ..() if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) return - var/choice = tgui_input_list(user, "Underwear, Undershirt, or Socks?", "Changing", list("Underwear","Undershirt","Socks")) + var/choice = tgui_input_list(user, "Underwear, Bra, Undershirt, or Socks?", "Changing", list("Underwear", "Bra", "Undershirt","Socks")) //SKYRAT EDIT ADDITION - Underwear and Bra split if(!Adjacent(user)) return switch(choice) @@ -178,6 +184,12 @@ var/new_socks = tgui_input_list(user, "Select the mannequin's socks", "Changing", GLOB.socks_list) if(new_socks) socks_name = new_socks + //SKYRAT EDIT ADDITION BEGIN - Underwear and Bra split + if("Bra") + var/new_bra = tgui_input_list(user, "Select the mannequin's bra", "Changing", GLOB.bra_list) + if(new_bra) + bra_name = new_bra + //SKYRAT EDIT END update_appearance() /obj/structure/mannequin/wood diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 21767551886..3c99aee7233 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 19e43c8bc37..c8a97f0cb8a 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 9d09a747018..534622619d1 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 cdb7ba0811f..b8709334c37 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/spawner.dm b/code/game/objects/structures/spawner.dm index 011b5718d79..7bbafd21ff2 100644 --- a/code/game/objects/structures/spawner.dm +++ b/code/game/objects/structures/spawner.dm @@ -54,16 +54,16 @@ max_mobs = 15 spawn_time = 15 SECONDS mob_types = list( - /mob/living/simple_animal/hostile/retaliate/clown, - /mob/living/simple_animal/hostile/retaliate/clown/banana, - /mob/living/simple_animal/hostile/retaliate/clown/clownhulk, - /mob/living/simple_animal/hostile/retaliate/clown/clownhulk/chlown, - /mob/living/simple_animal/hostile/retaliate/clown/clownhulk/honcmunculus, - /mob/living/simple_animal/hostile/retaliate/clown/fleshclown, - /mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton, - /mob/living/simple_animal/hostile/retaliate/clown/honkling, - /mob/living/simple_animal/hostile/retaliate/clown/longface, - /mob/living/simple_animal/hostile/retaliate/clown/lube, + /mob/living/basic/clown, + /mob/living/basic/clown/banana, + /mob/living/basic/clown/clownhulk, + /mob/living/basic/clown/clownhulk/chlown, + /mob/living/basic/clown/clownhulk/honkmunculus, + /mob/living/basic/clown/fleshclown, + /mob/living/basic/clown/mutant/glutton, + /mob/living/basic/clown/honkling, + /mob/living/basic/clown/longface, + /mob/living/basic/clown/lube, ) spawn_text = "climbs out of" faction = list(FACTION_CLOWN) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 70829118234..3e55612936e 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 @@ -165,16 +165,13 @@ if(HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, span_danger("Throwing [pushed_mob] onto the table might hurt them!")) return - var/added_passtable = FALSE - if(!(pushed_mob.pass_flags & PASSTABLE)) - added_passtable = TRUE - pushed_mob.pass_flags |= PASSTABLE + var/passtable_key = REF(user) + passtable_on(pushed_mob, passtable_key) for (var/obj/obj in user.loc.contents) if(!obj.CanAllowThrough(pushed_mob)) return pushed_mob.Move(src.loc) - if(added_passtable) - pushed_mob.pass_flags &= ~PASSTABLE + passtable_off(pushed_mob, passtable_key) if(pushed_mob.loc != loc) //Something prevented the tabling return pushed_mob.Knockdown(30) @@ -238,7 +235,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 +281,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() @@ -905,4 +902,3 @@ R.add_fingerprint(user) qdel(src) building = FALSE - diff --git a/code/game/objects/structures/toiletbong.dm b/code/game/objects/structures/toiletbong.dm index cb8d9830512..45ce79f9c32 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 ec0ae01fbf6..b991bc0c274 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 b4498699bf7..46eb13ee2b7 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 4d6a96ca12c..159dab78cee 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 6a7f533e4de..f5b40238ed6 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 5d913f19601..8ccaabc46c0 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 00000000000..b364ad428d0 --- /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 72e056288f3..24c4c4914ec 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 cf7e07e75f3..c15261a9880 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 6e8acf576cb..a0d1a191bc6 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 12c7ade160c..91437e727a7 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 3e3f7b0c55e..02d56a3be1e 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 6010df76cd3..3e2f43517aa 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 380448d9fcf..e851bb992d4 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 71bc966acf4..761bfc3ff74 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 00000000000..845399e0761 --- /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 913a0c55e53..0b731c61373 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -90,6 +90,7 @@ GLOBAL_PROTECT(admin_verbs_admin) /client/proc/list_fingerprints, /client/proc/list_law_changes, /client/proc/list_signalers, + /client/proc/manage_sect, /*manage chaplain religious sect*/ /client/proc/message_pda, /*send a message to somebody on PDA*/ /client/proc/respawn_character, /client/proc/show_manifest, @@ -833,6 +834,33 @@ GLOBAL_PROTECT(admin_verbs_poll) if(holder) src.holder.output_ai_laws() +/client/proc/manage_sect() + set name = "Manage Religious Sect" + set category = "Admin.Game" + + if (!isnull(GLOB.religious_sect)) + var/you_sure = tgui_alert( + usr, + "The Chaplain has already chosen [GLOB.religious_sect.name], override their selection?", + "Replace God?", + list("Yes", "Cancel"), + ) + if (you_sure != "Yes") + return + + var/static/list/choices = list() + if (!length(choices)) + choices["nothing"] = null + for(var/datum/religion_sect/sect as anything in subtypesof(/datum/religion_sect)) + choices[initial(sect.name)] = sect + var/choice = tgui_input_list(usr, "Set new Chaplain sect", "God Picker", choices) + if(isnull(choice)) + return + if(choice == "nothing") + reset_religious_sect() + return + set_new_religious_sect(choices[choice], reset_existing = TRUE) + /client/proc/deadmin() set name = "Deadmin" set category = "Admin" @@ -1059,7 +1087,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 5544f90fb74..cf816fef8a7 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 00000000000..5f1af4bee28 --- /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 db68a1cd3a2..c970e920f22 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 5d859669a68..a3031ce13ff 100644 --- a/code/modules/admin/smites/boneless.dm +++ b/code/modules/admin/smites/boneless.dm @@ -11,11 +11,9 @@ 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_weight(list( + WOUND_SEVERITY_MODERATE = 1, + WOUND_SEVERITY_SEVERE = 2, + WOUND_SEVERITY_CRITICAL = 2, )) - 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 22ed8836df3..00000000000 --- 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 32734a21d94..b1e0327510a 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 13178d32a5d..8bc58a7876c 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/ai_triumvirate.dm b/code/modules/admin/verbs/ai_triumvirate.dm index ca7ebfe7cc4..d63994a25c3 100644 --- a/code/modules/admin/verbs/ai_triumvirate.dm +++ b/code/modules/admin/verbs/ai_triumvirate.dm @@ -13,14 +13,15 @@ GLOBAL_DATUM(triple_ai_controller, /datum/triple_ai_controller) . = ..() RegisterSignal(SSjob, COMSIG_OCCUPATIONS_DIVIDED, PROC_REF(on_occupations_divided)) -/datum/triple_ai_controller/proc/on_occupations_divided(datum/source) +/datum/triple_ai_controller/proc/on_occupations_divided(datum/source, pure, allow_all) SIGNAL_HANDLER for(var/datum/job/ai/ai_datum in SSjob.joinable_occupations) ai_datum.spawn_positions = 3 - for(var/obj/effect/landmark/start/ai/secondary/secondary_ai_spawn in GLOB.start_landmarks_list) - secondary_ai_spawn.latejoin_active = TRUE - qdel(src) + if(!pure) + for(var/obj/effect/landmark/start/ai/secondary/secondary_ai_spawn in GLOB.start_landmarks_list) + secondary_ai_spawn.latejoin_active = TRUE + qdel(src) /datum/triple_ai_controller/Destroy(force) UnregisterSignal(SSjob, COMSIG_OCCUPATIONS_DIVIDED) diff --git a/code/modules/admin/view_variables/debug_variables.dm b/code/modules/admin/view_variables/debug_variables.dm index 24ee0032a33..230a0e46284 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 067179e1ecc..a5b2af68c77 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 f97ecaeb42b..5bbbfaa40b8 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 a8e01a45eee..2fa677cba0e 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 c167dd8a329..0d709579cc8 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 e3c966e3b6c..faebce9fc87 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 deef0a390cb..7a797273785 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 6f9456eed98..5c44acd5fc0 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 @@ -177,11 +178,16 @@ else RegisterSignal(living_mob, COMSIG_MOB_HUD_CREATED, PROC_REF(on_hud_created)) + make_brain_decoy(living_mob) + +/datum/antagonist/changeling/proc/make_brain_decoy(mob/living/ling) + var/obj/item/organ/internal/brain/our_ling_brain = ling.get_organ_slot(ORGAN_SLOT_BRAIN) + if(isnull(our_ling_brain) || our_ling_brain.decoy_override) + return + // Brains are optional for lings. - var/obj/item/organ/internal/brain/our_ling_brain = living_mob.get_organ_slot(ORGAN_SLOT_BRAIN) - if(our_ling_brain) - our_ling_brain.organ_flags &= ~ORGAN_VITAL - our_ling_brain.decoy_override = TRUE + // This is automatically cleared if the ling is. + our_ling_brain.AddComponent(/datum/component/ling_decoy_brain, src) /datum/antagonist/changeling/proc/generate_name() var/honorific @@ -225,15 +231,10 @@ QDEL_NULL(lingchemdisplay) QDEL_NULL(lingstingdisplay) + // The old body's brain still remains a decoy, I guess? + /datum/antagonist/changeling/on_removal() remove_changeling_powers(include_innate = TRUE) - if(!iscarbon(owner.current)) - return - var/mob/living/carbon/carbon_owner = owner.current - var/obj/item/organ/internal/brain/not_ling_brain = carbon_owner.get_organ_slot(ORGAN_SLOT_BRAIN) - if(not_ling_brain && (not_ling_brain.decoy_override != initial(not_ling_brain.decoy_override))) - not_ling_brain.organ_flags |= ORGAN_VITAL - not_ling_brain.decoy_override = FALSE return ..() /datum/antagonist/changeling/farewell() @@ -282,23 +283,29 @@ /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. + * Signal proc for [COMSIG_LIVING_POST_FULLY_HEAL] */ -/datum/antagonist/changeling/proc/on_fullhealed(datum/source, heal_flags) +/datum/antagonist/changeling/proc/on_fullhealed(mob/living/source, heal_flags) SIGNAL_HANDLER + // Aheal restores all chemicals if(heal_flags & HEAL_ADMIN) adjust_chemicals(INFINITY) + // Makes sure the brain, if recreated, is a decoy as expected + make_brain_decoy(source) + /** * Signal proc for [COMSIG_MOB_MIDDLECLICKON] and [COMSIG_MOB_ALTCLICKON]. * Allows the changeling to sting people with a click. @@ -545,9 +552,12 @@ new_profile.socks = target.socks // SKYRAT EDIT START + new_profile.bra = target.bra + new_profile.underwear_color = target.underwear_color new_profile.undershirt_color = target.undershirt_color new_profile.socks_color = target.socks_color + new_profile.bra_color = target.bra_color new_profile.eye_color_left = target.eye_color_left new_profile.eye_color_right = target.eye_color_right new_profile.emissive_eyes = target.emissive_eyes @@ -787,9 +797,12 @@ user.socks = chosen_profile.socks // SKYRAT EDIT START + user.bra = chosen_profile.bra + user.underwear_color = chosen_profile.underwear_color user.undershirt_color = chosen_profile.undershirt_color user.socks_color = chosen_profile.socks_color + user.bra_color = chosen_profile.bra_color user.emissive_eyes = chosen_profile.emissive_eyes user.dna.mutant_bodyparts = chosen_dna.mutant_bodyparts.Copy() user.dna.body_markings = chosen_dna.body_markings.Copy() @@ -971,27 +984,6 @@ /// ID HUD icon associated with the profile var/id_icon - /// SKYRAT EDIT START - var/underwear_color - var/undershirt_color - var/socks_color - var/eye_color_left - var/eye_color_right - var/emissive_eyes - var/list/grad_style = list("None", "None") - var/list/grad_color = list(null, null) - - var/physique - var/list/worn_icon_digi_list = list() - var/list/worn_icon_monkey_list = list() - var/list/worn_icon_teshari_list = list() - var/list/worn_icon_vox_list = list() - var/list/supports_variations_flags_list = list() - var/scream_type - var/laugh_type - var/age - var/list/quirks = list() - /// SKYRAT EDIT END /// The TTS voice of the profile source var/voice @@ -1034,6 +1026,8 @@ new_profile.underwear_color = underwear_color new_profile.undershirt_color = undershirt_color new_profile.socks_color = socks_color + new_profile.bra = bra + new_profile.bra_color = bra_color new_profile.eye_color_left = eye_color_left new_profile.eye_color_right = eye_color_right new_profile.emissive_eyes = emissive_eyes diff --git a/code/modules/antagonists/changeling/powers/lesserform.dm b/code/modules/antagonists/changeling/powers/lesserform.dm index 854234af965..87bd7c7c8b6 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/mmi_talk.dm b/code/modules/antagonists/changeling/powers/mmi_talk.dm new file mode 100644 index 00000000000..f68968c223e --- /dev/null +++ b/code/modules/antagonists/changeling/powers/mmi_talk.dm @@ -0,0 +1,140 @@ +/datum/action/changeling/mmi_talk + name = "MMI Talk" + desc = "Our decoy brain has been implanted into a Man-Machine Interface. \ + In order to maintain our secrecy, we can speak through the decoy as if a normal brain. \ + The decoy brain will relay speech it hears to you in purple." + button_icon = 'icons/obj/assemblies/assemblies.dmi' + button_icon_state = "mmi_off" + dna_cost = CHANGELING_POWER_UNOBTAINABLE + ignores_fakedeath = TRUE // Can be used while fake dead + req_stat = DEAD // Can be used while real dead too + + /** + * Reference to the brain we're talking through. + * + * Set when created via the ling decoy component. + * If the brain ends up being qdelled, this action will also be qdelled, and thus this ref is cleared. + */ + VAR_FINAL/obj/item/organ/internal/brain/brain_ref + + /// A map view of the area around the MMI. + VAR_FINAL/atom/movable/screen/map_view/mmi_view + /// The background for the MMI map view. + VAR_FINAL/atom/movable/screen/background/mmi_view_background + /// The key that the map view uses. + VAR_FINAL/mmi_view_key + /// A movement detector that updates the map view when the MMI moves around. + VAR_FINAL/datum/movement_detector/update_view_tracker + +/datum/action/changeling/mmi_talk/Destroy() + brain_ref = null + QDEL_NULL(mmi_view) + QDEL_NULL(mmi_view_background) + QDEL_NULL(update_view_tracker) + return ..() + +/datum/action/changeling/mmi_talk/Remove(mob/remove_from) + . = ..() + SStgui.close_uis(src) + +/datum/action/changeling/mmi_talk/can_sting(mob/living/user, mob/living/target) + . = ..() + if(!.) + return FALSE + // This generally shouldn't happen, but just in case + if(isnull(brain_ref)) + stack_trace("[type] can_sting was called with a null brain!") + return FALSE + if(!istype(brain_ref.loc, /obj/item/mmi)) + stack_trace("[type] can_sting was called with a brain not located in an MMI!") + return FALSE + return TRUE + +/datum/action/changeling/mmi_talk/sting_action(mob/living/user, mob/living/target) + ..() + ui_interact(user) + return TRUE + +/datum/action/changeling/mmi_talk/ui_state(mob/user) + return GLOB.always_state + +/datum/action/changeling/mmi_talk/ui_status(mob/user, datum/ui_state/state) + if(user != owner) + return UI_CLOSE + return ..() + +/datum/action/changeling/mmi_talk/ui_static_data(mob/user) + var/list/data = list() + data["mmi_view"] = mmi_view_key + return data + +/datum/action/changeling/mmi_talk/ui_interact(mob/user, datum/tgui/ui) + if(isnull(mmi_view_key)) + // it's worth noting a ling could have multiple of these actions. + mmi_view_key = "ling_mmi_[REF(src)]_view" + // Generate background + mmi_view_background = new() + mmi_view_background.assigned_map = mmi_view_key + mmi_view_background.del_on_map_removal = FALSE + mmi_view_background.fill_rect(1, 1, 5, 5) + // Generate map view + mmi_view = new() + mmi_view.generate_view(mmi_view_key) + // Generate movement detector (to update the view on MMI movement) + update_view_tracker = new(brain_ref, CALLBACK(src, PROC_REF(update_mmi_view))) + + // Shows the view to the user foremost + mmi_view.display_to(user) + user.client.register_map_obj(mmi_view_background) + update_mmi_view() + // Makes the MMI relay heard messages + if(!HAS_TRAIT_FROM(brain_ref.loc, TRAIT_HEARING_SENSITIVE, REF(src))) + var/obj/item/mmi/mmi = brain_ref.loc + mmi.become_hearing_sensitive(REF(src)) + RegisterSignal(mmi, COMSIG_MOVABLE_HEAR, PROC_REF(relay_hearing)) + // Actually open the UI + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "LingMMITalk") + ui.open() + +/datum/action/changeling/mmi_talk/ui_close(mob/user) + var/obj/item/mmi/mmi = brain_ref.loc + UnregisterSignal(mmi, COMSIG_MOVABLE_HEAR) + mmi.lose_hearing_sensitivity(REF(src)) + +/datum/action/changeling/mmi_talk/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return TRUE + + if(action != "send_mmi_message") + return FALSE + + var/obj/item/mmi/mmi = brain_ref.loc + if(mmi.brainmob.stat != CONSCIOUS) + to_chat(usr, span_warning("Our decoy brain is too damaged to speak.")) + else + // Say will perform input sanitization and such for us + mmi.brainmob.say(params["message"], sanitize = TRUE) + return TRUE + +/// Used in callbacks to update the map view when the MMI moves. +/datum/action/changeling/mmi_talk/proc/update_mmi_view() + mmi_view.vis_contents.Cut() + for(var/turf/visible_turf in view(2, get_turf(brain_ref))) + mmi_view.vis_contents += visible_turf + +/// Signal proc for [COMSIG_MOVABLE_HEAR] to relay stuff the MMI hears to the ling. +/// Not super good, but it works. +/datum/action/changeling/mmi_talk/proc/relay_hearing(obj/item/mmi/source, list/hear_args) + SIGNAL_HANDLER + + // We can likely already hear them, so do not bother + if(can_see(owner, hear_args[HEARING_SPEAKER], 7)) + return + + var/list/new_args = hear_args.Copy() + new_args[HEARING_SPANS] |= "purple" + new_args[HEARING_RANGE] = INFINITY // so we can hear it from any distance away + owner.Hear(arglist(new_args)) diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index 309cffc0a75..bf4f8c2b3da 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 683fe7e16b6..25a267e03df 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/changeling/powers/regenerate.dm b/code/modules/antagonists/changeling/powers/regenerate.dm index 6595e331195..a83adade98d 100644 --- a/code/modules/antagonists/changeling/powers/regenerate.dm +++ b/code/modules/antagonists/changeling/powers/regenerate.dm @@ -15,22 +15,16 @@ ..() to_chat(user, span_notice("You feel an itching, both inside and outside as your tissues knit and reknit.")) var/mob/living/carbon/carbon_user = user - if(length(carbon_user.get_missing_limbs())) + var/got_limbs_back = length(carbon_user.get_missing_limbs()) >= 1 + carbon_user.fully_heal(HEAL_BODY) + // Occurs after fully heal so the ling themselves can hear the sound effects (if deaf prior) + if(got_limbs_back) playsound(user, 'sound/magic/demon_consume.ogg', 50, TRUE) carbon_user.visible_message( span_warning("[user]'s missing limbs reform, making a loud, grotesque sound!"), span_userdanger("Your limbs regrow, making a loud, crunchy sound and giving you great pain!"), span_hear("You hear organic matter ripping and tearing!"), ) - carbon_user.emote("scream") - carbon_user.fully_heal(HEAL_BODY) - - // Make sure the brain's nonvital - // Shouldn't be necessary but you can never be certain with lingcode - var/obj/item/organ/internal/brain/replacement_brain = user.get_organ_slot(ORGAN_SLOT_BRAIN) - replacement_brain.organ_flags &= ~ORGAN_VITAL - replacement_brain.decoy_override = TRUE - return TRUE diff --git a/code/modules/antagonists/fugitive/hunters/hunter_gear.dm b/code/modules/antagonists/fugitive/hunters/hunter_gear.dm index 71082f199e0..013359e9a68 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 5865f76e999..7df6818cdc4 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 d06977d2a63..7133066f856 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 b536fd730a5..a0f0d86d33f 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() @@ -516,6 +519,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. @@ -591,6 +595,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 c074e13c8d3..63493a5dc4b 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 00000000000..0498ba9e8a2 --- /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 00000000000..140453842c0 --- /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 26395396c06..07fa2718185 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 00000000000..fcb2c6ceb4c --- /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 375a1b78590..3e37c173923 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 a31f0a7cc97..983bbee32c6 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 4a315575d61..6439840fed5 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 00000000000..97218ce5e94 --- /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 00000000000..801104dddf9 --- /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 00000000000..4395b4a54b3 --- /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 00000000000..7bb6960354e --- /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 00000000000..87f3a69dad1 --- /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/furious_steel.dm b/code/modules/antagonists/heretic/magic/furious_steel.dm index f9b12612306..1c82f36e024 100644 --- a/code/modules/antagonists/heretic/magic/furious_steel.dm +++ b/code/modules/antagonists/heretic/magic/furious_steel.dm @@ -43,12 +43,12 @@ unset_click_ability(source, refund_cooldown = TRUE) -/datum/action/cooldown/spell/pointed/projectile/furious_steel/InterceptClickOn(mob/living/caller, params, atom/click_target) +/datum/action/cooldown/spell/pointed/projectile/furious_steel/InterceptClickOn(mob/living/caller, params, atom/target) // Let the caster prioritize using items like guns over blade casts if(caller.get_active_held_item()) return FALSE // Let the caster prioritize melee attacks like punches and shoves over blade casts - if(get_dist(caller, click_target) <= 1) + if(get_dist(caller, target) <= 1) return FALSE return ..() 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 00000000000..3b78b56ddc0 --- /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 743aa2c5a01..f1c96c51ad4 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 3c7715111be..c286c7b5092 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 c454ebdc462..068570f76c7 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 00000000000..85face85609 --- /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 73f2f02f847..88331353657 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 b371f12c2e7..4c014da1863 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 63adacca1e8..7c921fdd228 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 ff9678ad519..57eb95a978c 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 1857223df6b..e88730f7026 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 7cb9df6ed25..2480b186600 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 3813009be42..aaf162c15f8 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 d912be2384a..0540d83601c 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 fc15d0b014b..3e4cf0766f5 100644 --- a/code/modules/antagonists/wizard/equipment/artefact.dm +++ b/code/modules/antagonists/wizard/equipment/artefact.dm @@ -86,7 +86,7 @@ /obj/item/veilrender/honkrender name = "honk render" desc = "A wicked curved blade of alien origin, recovered from the ruins of a vast circus." - spawn_type = /mob/living/simple_animal/hostile/retaliate/clown + spawn_type = /mob/living/basic/clown spawn_amt = 10 activate_descriptor = "depression" rend_desc = "Gently wafting with the sounds of endless laughter." @@ -97,7 +97,7 @@ /obj/item/veilrender/honkrender/honkhulkrender name = "superior honk render" desc = "A wicked curved blade of alien origin, recovered from the ruins of a vast circus. This one gleams with a special light." - spawn_type = /mob/living/simple_animal/hostile/retaliate/clown/clownhulk + spawn_type = /mob/living/basic/clown/clownhulk spawn_amt = 5 activate_descriptor = "depression" rend_desc = "Gently wafting with the sounds of mirthful grunting." @@ -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 45f7b671f12..1e8df43cfbe 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 14258663d9b..2fcf2b803e3 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 3ef5c9a4d33..a11f439ec31 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 7ea5b827d4a..84753354018 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 d4977eb6454..1685a027a5f 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 269091d4bdf..452d5d7b243 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 6449dc49357..3422f3e3adf 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 b03a29a43f4..9dab4e65b58 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 189d88822ec..632b01d509d 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 ced067c0c39..3dcdc8608c6 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 b918d7708ca..169715c51d9 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 4cfb6680031..12ec7d5b129 100644 --- a/code/modules/cargo/goodies.dm +++ b/code/modules/cargo/goodies.dm @@ -301,3 +301,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 f40e4fa1447..6115b1e1557 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 9c50372b6a8..fca1a201ac1 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/packs/organic.dm b/code/modules/cargo/packs/organic.dm index c02a4d56db9..73c98cb4b3a 100644 --- a/code/modules/cargo/packs/organic.dm +++ b/code/modules/cargo/packs/organic.dm @@ -62,18 +62,20 @@ including one replica-pod seed and two mystery seeds!" cost = CARGO_CRATE_VALUE * 3 access_view = ACCESS_HYDROPONICS - contains = list(/obj/item/seeds/nettle, - /obj/item/seeds/replicapod, - /obj/item/seeds/plump, - /obj/item/seeds/liberty, - /obj/item/seeds/amanita, - /obj/item/seeds/reishi, - /obj/item/seeds/bamboo, - /obj/item/seeds/eggplant/eggy, - /obj/item/seeds/rainbow_bunch, - /obj/item/seeds/shrub, - /obj/item/seeds/random = 2, - ) + contains = list( + /obj/item/seeds/amanita, + /obj/item/seeds/bamboo, + /obj/item/seeds/eggplant/eggy, + /obj/item/seeds/liberty, + /obj/item/seeds/nettle, + /obj/item/seeds/plump, + /obj/item/seeds/replicapod, + /obj/item/seeds/reishi, + /obj/item/seeds/rainbow_bunch, + /obj/item/seeds/seedling, + /obj/item/seeds/shrub, + /obj/item/seeds/random = 2, + ) crate_name = "exotic seeds crate" crate_type = /obj/structure/closet/crate/hydroponics diff --git a/code/modules/cargo/supplypod_beacon.dm b/code/modules/cargo/supplypod_beacon.dm index 436a0ca6b93..89c474635fa 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 c3c6bd24425..2e655e91651 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 cbebcff5550..9c7b5e3e943 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 f6ccccae971..e63e2c3bee3 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 688b63bddbb..fc665e57c8f 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 fd30bdd742f..4022e259505 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 0a6967753e1..8bc37aaba22 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 61f293a97fe..3ed9be8cb1d 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 a0f6e6d1047..60cbcae1473 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/clothing/under/accessories/medals.dm b/code/modules/clothing/under/accessories/medals.dm index 90db5198ee6..cc91e286e2c 100644 --- a/code/modules/clothing/under/accessories/medals.dm +++ b/code/modules/clothing/under/accessories/medals.dm @@ -178,3 +178,29 @@ /obj/item/clothing/accessory/medal/plasma/nobel_science name = "nobel sciences award" desc = "A plasma medal which represents significant contributions to the field of science or engineering." + +/obj/item/clothing/accessory/medal/silver/emergency_services + name = "emergency services award" + desc = "A silver medal awarded to the outstanding emergency service workers of Nanotrasen, those who work tirelessly together through adversity to keep their crew safe and breathing in the harsh environments of outer space." + icon_state = "emergencyservices" + + /// Flavor text that is appended to the description. + var/insignia_desc = null + +/obj/item/clothing/accessory/medal/silver/emergency_services/Initialize(mapload) + . = ..() + if(istext(insignia_desc)) + desc += " [insignia_desc]" + +/obj/item/clothing/accessory/medal/silver/emergency_services/engineering + icon_state = "emergencyservices_engi" + insignia_desc = "The back of the medal bears an orange wrench." + +/obj/item/clothing/accessory/medal/silver/emergency_services/medical + icon_state = "emergencyservices_med" + insignia_desc = "The back of the medal bears a dark blue cross." + +/obj/item/clothing/accessory/medal/silver/elder_atmosian + name = "atmospheric mastery award" + desc = "Often referred to as the \"elder atmosian\" award, this medal is awarded to the exemplary scientists and technicians who push the boundaries and demonstrate mastery of atmospherics." + icon_state = "elderatmosian" diff --git a/code/modules/events/_event.dm b/code/modules/events/_event.dm index e1366ed0e04..bd192dbef22 100644 --- a/code/modules/events/_event.dm +++ b/code/modules/events/_event.dm @@ -1,5 +1,4 @@ #define RANDOM_EVENT_ADMIN_INTERVENTION_TIME (3 MINUTES) //SKYRAT EDIT CHANGE -#define NEVER_TRIGGERED_BY_WIZARDS -1 //this singleton datum is used by the events controller to dictate how it selects events /datum/round_event_control @@ -344,4 +343,3 @@ Runs the event return ..() #undef RANDOM_EVENT_ADMIN_INTERVENTION_TIME -#undef NEVER_TRIGGERED_BY_WIZARDS diff --git a/code/modules/events/brain_trauma.dm b/code/modules/events/brain_trauma.dm index 1e5c09aff48..e063c89e152 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 a323c7d83f0..4f251e871c7 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 fb6bfd5be97..f690b1c4a8d 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 8a8902d5724..f073676c5b4 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 3cc5a15a507..424eb157efe 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 00000000000..6c790c84f8d --- /dev/null +++ b/code/modules/events/supermatter_surge.dm @@ -0,0 +1,140 @@ +#define SURGE_DURATION_MIN 240 EVENT_SECONDS +#define SURGE_DURATION_MAX 270 EVENT_SECONDS +#define SURGE_SEVERITY_MIN 1 +#define SURGE_SEVERITY_MAX 4 +#define SURGE_SEVERITY_RANDOM 5 +/// 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_RANDOM + /// 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 = SURGE_SEVERITY_MIN + max_value = SURGE_SEVERITY_MAX + +/datum/event_admin_setup/input_number/surge_spiciness/prompt_admins() + default_value = rand(SURGE_SEVERITY_MIN, SURGE_SEVERITY_MAX) + 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(surge_class == SURGE_SEVERITY_RANDOM) + var/severity_weight = rand(1, 100) + switch(severity_weight) + if(1 to 14) + surge_class = 1 + if(15 to 34) + surge_class = 2 + if(35 to 69) + surge_class = 3 + if(70 to 100) + surge_class = 4 + + end_when = rand(SURGE_DURATION_MIN, SURGE_DURATION_MAX) + +/datum/round_event/supermatter_surge/announce(fake) + priority_announce("The Crystal Integrity Monitoring System has detected unusual atmospheric properties in the supermatter chamber, 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 + +/datum/round_event_control/supermatter_surge/poly + name = "Supermatter Surge: Poly's Revenge" + typepath = /datum/round_event/supermatter_surge/poly + category = EVENT_CATEGORY_ENGINEERING + weight = 0 + max_occurrences = 0 + description = "For when Poly is sacrificed to the SM. Not really useful to run manually." + min_wizard_trigger_potency = NEVER_TRIGGERED_BY_WIZARDS + max_wizard_trigger_potency = NEVER_TRIGGERED_BY_WIZARDS + admin_setup = null + +/datum/round_event/supermatter_surge/poly + announce_when = 4 + surge_class = 4 + fakeable = FALSE + +/datum/round_event/supermatter_surge/poly/announce(fake) + priority_announce("The Crystal Integrity Monitoring System has detected unusual parrot type resonance in the supermatter chamber, energy output from the supermatter crystal has increased significantly. Engineering intervention is required to stabilize the engine.", "Class P Supermatter Surge Alert", 'sound/machines/engine_alert3.ogg') + +#undef SURGE_DURATION_MIN +#undef SURGE_DURATION_MAX +#undef SURGE_SEVERITY_MIN +#undef SURGE_SEVERITY_MAX +#undef SURGE_SEVERITY_RANDOM +#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 b3964eb4015..8d665378159 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 6c7fb38e279..bec868ad24e 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 e8752acb1de..652b0aba8aa 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 e94e13ed4e8..6169b41fd88 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 cdec5c54be6..478279749e4 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 58936d29534..7e01f693dd5 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() @@ -157,7 +160,7 @@ if(!istype(user)) return var/beam_color = line?.line_color || default_line_color - var/datum/beam/fishing_line/fishing_line_beam = new(user, target, icon_state = "fishing_line", beam_color = beam_color, override_target_pixel_y = target_py) + var/datum/beam/fishing_line/fishing_line_beam = new(user, target, icon_state = "fishing_line", beam_color = beam_color, emissive = FALSE, override_target_pixel_y = target_py) fishing_line_beam.lefthand = user.get_held_index_of_item(src) % 2 == 1 RegisterSignal(fishing_line_beam, COMSIG_BEAM_BEFORE_DRAW, PROC_REF(check_los)) RegisterSignal(fishing_line_beam, COMSIG_QDELETING, PROC_REF(clear_line)) @@ -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 @@ -574,6 +577,31 @@ // Is the fishing rod held in left side hand var/lefthand = FALSE + // Make these inline with final sprites + var/righthand_s_px = 13 + var/righthand_s_py = 16 + + var/righthand_e_px = 18 + var/righthand_e_py = 16 + + var/righthand_w_px = -20 + var/righthand_w_py = 18 + + var/righthand_n_px = -14 + var/righthand_n_py = 16 + + var/lefthand_s_px = -13 + var/lefthand_s_py = 15 + + var/lefthand_e_px = 24 + var/lefthand_e_py = 18 + + var/lefthand_w_px = -17 + var/lefthand_w_py = 16 + + var/lefthand_n_px = 13 + var/lefthand_n_py = 15 + /datum/beam/fishing_line/Start() update_offsets(origin.dir) . = ..() @@ -602,29 +630,3 @@ if(NORTH) override_origin_pixel_x = lefthand ? lefthand_n_px : righthand_n_px override_origin_pixel_y = lefthand ? lefthand_n_py : righthand_n_py - -// Make these inline with final sprites -/datum/beam/fishing_line - var/righthand_s_px = 13 - var/righthand_s_py = 16 - - var/righthand_e_px = 18 - var/righthand_e_py = 16 - - var/righthand_w_px = -20 - var/righthand_w_py = 18 - - var/righthand_n_px = -14 - var/righthand_n_py = 16 - - var/lefthand_s_px = -13 - var/lefthand_s_py = 15 - - var/lefthand_e_px = 24 - var/lefthand_e_py = 18 - - var/lefthand_w_px = -17 - var/lefthand_w_py = 16 - - var/lefthand_n_px = 13 - var/lefthand_n_py = 15 diff --git a/code/modules/fishing/sources/_fish_source.dm b/code/modules/fishing/sources/_fish_source.dm index e8156f26cba..5a34db9ce5f 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 cea97005f28..ffb37753881 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 5bb772c7398..8978c975c5e 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 5057dbfe08a..2c1b0b9d3b3 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 a3292872362..1454f1e6917 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 7e84fe4f5c0..1da96fc0aae 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 9f946aede28..24cb557b239 100644 --- a/code/modules/food_and_drinks/recipes/food_mixtures.dm +++ b/code/modules/food_and_drinks/recipes/food_mixtures.dm @@ -257,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 6e78c0f5f2f..ad2caa84ca6 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 ea2c1270303..47bd455cd85 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 c01379a5a55..09e481bbfe6 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 @@ -379,13 +382,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! @@ -396,6 +399,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") @@ -410,7 +414,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() @@ -432,7 +436,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") @@ -472,6 +476,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." @@ -495,7 +500,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!" @@ -525,13 +530,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" @@ -580,7 +585,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") @@ -602,7 +607,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" @@ -631,7 +636,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!" @@ -645,20 +650,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() @@ -695,7 +698,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() @@ -810,7 +813,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 55cfec74be6..ef4815de066 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 86a8dbc4095..098c6e81ce6 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 fca26ebe978..64979b048cb 100644 --- a/code/modules/hydroponics/grown/banana.dm +++ b/code/modules/hydroponics/grown/banana.dm @@ -39,7 +39,7 @@ desc += " The curve on this one looks particularly acute." ///Clowns will always like bananas. -/obj/item/food/grown/banana/proc/check_liked(fraction, mob/living/carbon/human/consumer) +/obj/item/food/grown/banana/proc/check_liked(mob/living/carbon/human/consumer) var/obj/item/organ/internal/liver/liver = consumer.get_organ_slot(ORGAN_SLOT_LIVER) if (!HAS_TRAIT(consumer, TRAIT_AGEUSIA) && liver && HAS_TRAIT(liver, TRAIT_COMEDY_METABOLISM)) return FOOD_LIKED @@ -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/grown/melon.dm b/code/modules/hydroponics/grown/melon.dm index 83f6ac45466..80962a2d182 100644 --- a/code/modules/hydroponics/grown/melon.dm +++ b/code/modules/hydroponics/grown/melon.dm @@ -78,7 +78,7 @@ * Checks whether or not the person eating the holymelon * is a holy_role (chaplain), as chaplains love holymelons. */ -/obj/item/food/grown/holymelon/proc/check_holyness(fraction, mob/mob_eating) +/obj/item/food/grown/holymelon/proc/check_holyness(mob/mob_eating) if(!ishuman(mob_eating)) return var/mob/living/carbon/human/holy_person = mob_eating diff --git a/code/modules/hydroponics/grown/seedling.dm b/code/modules/hydroponics/grown/seedling.dm new file mode 100644 index 00000000000..57fd11280b6 --- /dev/null +++ b/code/modules/hydroponics/grown/seedling.dm @@ -0,0 +1,28 @@ +/obj/item/seeds/seedling + name = "pack of seedling seeds" + desc = "These seeds grow into a floral assistant which can help look after other plants!" + icon_state = "seed-seedling" + growing_icon = 'icons/obj/service/hydroponics/growing_fruits.dmi' + species = "seedling" + plantname = "Seedling Plant" + product = /mob/living/basic/seedling + lifespan = 40 + endurance = 7 + maturation = 10 + production = 1 + growthstages = 2 + yield = 1 + instability = 15 + potency = 30 + +/obj/item/seeds/seedling/harvest(mob/harvester) + var/obj/machinery/hydroponics/parent = loc + var/list/grow_locations = get_adjacent_open_turfs(parent) + var/turf/final_location = length(grow_locations) ? pick(grow_locations) : get_turf(parent) + var/mob/living/basic/seedling/seed_pet = new product(final_location) + seed_pet.befriend(harvester) + parent.update_tray(user = harvester, product_count = 1) + +/obj/item/seeds/seedling/evil + product = /mob/living/basic/seedling/meanie + icon_state = "seed-seedling-evil" diff --git a/code/modules/hydroponics/growninedible.dm b/code/modules/hydroponics/growninedible.dm index 26fb90236a3..2b2556790e2 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 52be3e98f0c..36653ebafb9 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 2a5a14b066d..5b64770175c 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 a5a68b7152a..89e7d04742c 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 15dd39861a4..3e752910a29 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/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm index 92c272167a0..998c19a215d 100644 --- a/code/modules/jobs/job_types/chief_medical_officer.dm +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -38,7 +38,7 @@ /obj/effect/spawner/random/medical/surgery_tool_advanced = 4, /obj/effect/spawner/random/medical/surgery_tool_alien = 1 ) - family_heirlooms = list(/obj/item/storage/medkit/ancient/heirloom, /obj/item/scalpel, /obj/item/hemostat, /obj/item/circular_saw, /obj/item/retractor, /obj/item/cautery) + family_heirlooms = list(/obj/item/storage/medkit/ancient/heirloom, /obj/item/scalpel, /obj/item/hemostat, /obj/item/circular_saw, /obj/item/retractor, /obj/item/cautery, /obj/item/statuebust/hippocratic) rpg_title = "High Cleric" job_flags = STATION_JOB_FLAGS | JOB_BOLD_SELECT_TEXT | JOB_CANNOT_OPEN_SLOTS diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm index 6f7359ddb7a..e3a396609eb 100644 --- a/code/modules/jobs/job_types/medical_doctor.dm +++ b/code/modules/jobs/job_types/medical_doctor.dm @@ -24,7 +24,7 @@ /datum/job_department/medical, ) - family_heirlooms = list(/obj/item/storage/medkit/ancient/heirloom, /obj/item/scalpel, /obj/item/hemostat, /obj/item/circular_saw, /obj/item/retractor, /obj/item/cautery) + family_heirlooms = list(/obj/item/storage/medkit/ancient/heirloom, /obj/item/scalpel, /obj/item/hemostat, /obj/item/circular_saw, /obj/item/retractor, /obj/item/cautery, /obj/item/statuebust/hippocratic) mail_goodies = list( /obj/item/healthanalyzer/advanced = 15, diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm index 39cbc0ccce7..bdbfd7d687c 100644 --- a/code/modules/jobs/job_types/virologist.dm +++ b/code/modules/jobs/job_types/virologist.dm @@ -26,7 +26,7 @@ /datum/job_department/medical, ) - family_heirlooms = list(/obj/item/reagent_containers/syringe) + family_heirlooms = list(/obj/item/reagent_containers/syringe, /obj/item/statuebust/hippocratic) mail_goodies = list( /obj/item/reagent_containers/cup/bottle/random_virus = 15, diff --git a/code/modules/mafia/controller.dm b/code/modules/mafia/controller.dm index a0e5b26b5d9..1916a65f7b1 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 6ab0ed2f387..424e1db299e 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 ca2b6ec39c9..fc79c82e780 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 30477657ab5..237ae9f2d52 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 d1fc4a79cf7..cec7932f4f5 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 96b555457d7..14a8fdf6b94 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 01a91a10c2a..a7b9480a34e 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 f2331eb5146..b0e2ff7fa06 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 52ac76e343a..2809ae65e6c 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 a1edd69ba3e..caee1bbac8d 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 ba9b3548ab8..65d3a1ad3b3 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 4c0ca13dcd2..ce045a81298 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 dc15e28a927..840c8e92900 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 d7381d48e66..286317a5d74 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 7cb099f6585..a38fe171174 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 9b8a192260f..a1c7c0371b0 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 ff2e414dd70..0688778b048 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 44c11bdc056..aebb54770d7 100644 --- a/code/modules/mob/living/basic/basic.dm +++ b/code/modules/mob/living/basic/basic.dm @@ -11,7 +11,7 @@ var/basic_mob_flags = NONE - ///Defines how fast the basic mob can move. This is a multiplier + ///Defines how fast the basic mob can move. This is not a multiplier var/speed = 1 ///How much stamina the mob recovers per second var/stamina_recovery = 5 @@ -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/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/basic/clown/clown.dm similarity index 62% rename from code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm rename to code/modules/mob/living/basic/clown/clown.dm index 529c3025479..78715361356 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm +++ b/code/modules/mob/living/basic/clown/clown.dm @@ -1,4 +1,4 @@ -/mob/living/simple_animal/hostile/retaliate/clown +/mob/living/basic/clown name = "Clown" desc = "A denizen of clown planet." icon = 'icons/mob/simple/clown_mobs.dmi' @@ -8,191 +8,113 @@ icon_gib = "clown_gib" health_doll_icon = "clown" //if >32x32, it will use this generic. for all the huge clown mobs that subtype from this mob_biotypes = MOB_ORGANIC|MOB_HUMANOID - turns_per_move = 5 response_disarm_continuous = "gently pushes aside" response_disarm_simple = "gently push aside" response_harm_continuous = "robusts" response_harm_simple = "robust" - speak = list("HONK", "Honk!", "Welcome to clown planet!") - emote_see = list("honks", "squeaks") - speak_chance = 1 combat_mode = TRUE maxHealth = 75 health = 75 - speed = 1 - harm_intent_damage = 8 melee_damage_lower = 10 melee_damage_upper = 10 attack_sound = 'sound/items/bikehorn.ogg' - obj_damage = 0 + attacked_sound = 'sound/items/bikehorn.ogg' environment_smash = ENVIRONMENT_SMASH_NONE - del_on_death = 1 - loot = list(/obj/effect/mob_spawn/corpse/human/clown) + basic_mob_flags = DEL_ON_DEATH initial_language_holder = /datum/language_holder/clown - atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 270 - maxbodytemp = 370 + habitable_atmos = list("min_oxy" = 5, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) + minimum_survivable_temperature = T0C + maximum_survivable_temperature = (T0C + 100) unsuitable_atmos_damage = 10 unsuitable_heat_damage = 15 - footstep_type = FOOTSTEP_MOB_SHOE faction = list(FACTION_CLOWN) - var/attack_reagent + ai_controller = /datum/ai_controller/basic_controller/clown + speed = 1.4 //roughly close to simpleanimal clowns + ///list of stuff we drop on death + var/list/loot = list(/obj/effect/mob_spawn/corpse/human/clown) + ///blackboard emote list + var/list/emotes = list( + BB_EMOTE_SAY = list("HONK", "Honk!", "Welcome to clown planet!"), + BB_EMOTE_HEAR = list("honks", "squeaks"), + BB_EMOTE_SOUND = list('sound/items/bikehorn.ogg'), //WE LOVE TO PARTY + BB_EMOTE_CHANCE = 5, + ) + ///do we waddle (honk) + var/waddles = TRUE -/mob/living/simple_animal/hostile/retaliate/clown/Initialize(mapload) +/mob/living/basic/clown/Initialize(mapload) . = ..() - if(attack_reagent) - var/static/list/injection_range - if(!injection_range) - injection_range = string_numbers_list(list(1, 5)) - AddElement(/datum/element/venomous, attack_reagent, injection_range) - -/mob/living/simple_animal/hostile/retaliate/clown/attack_hand(mob/living/carbon/human/user, list/modifiers) - ..() - playsound(loc, 'sound/items/bikehorn.ogg', 50, TRUE) - -/mob/living/simple_animal/hostile/retaliate/clown/AttackingTarget(atom/attacked_target) - if(!istype(attacked_target, /obj/item/food/grown/banana/bunch)) + AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_SHOE) + AddComponent(/datum/component/ai_retaliate_advanced, CALLBACK(src, PROC_REF(retaliate_callback))) + ai_controller.set_blackboard_key(BB_BASIC_MOB_SPEAK_LINES, emotes) + //im not putting dynamic humans or whatever its called here because this is the base path of nonhuman clownstrosities + if(waddles) + AddElement(/datum/element/waddling) + if(length(loot)) + loot = string_list(loot) + AddElement(/datum/element/death_drops, loot) + +/mob/living/basic/clown/proc/retaliate_callback(mob/living/attacker) + if (!istype(attacker)) + return + for (var/mob/living/basic/clown/harbringer in oview(src, 7)) + harbringer.ai_controller.insert_blackboard_key_lazylist(BB_BASIC_MOB_RETALIATE_LIST, attacker) + +/mob/living/basic/clown/melee_attack(atom/target, list/modifiers, ignore_cooldown = FALSE) + if(!istype(target, /obj/item/food/grown/banana/bunch)) return ..() - var/obj/item/food/grown/banana/bunch/unripe_bunch = attacked_target + var/obj/item/food/grown/banana/bunch/unripe_bunch = target unripe_bunch.start_ripening() - log_combat(src, attacked_target, "honksposivley ripened") + log_combat(src, target, "explosively ripened") -/mob/living/simple_animal/hostile/retaliate/clown/lube +/mob/living/basic/clown/lube name = "Living Lube" desc = "A puddle of lube brought to life by the honkmother." icon_state = "lube" icon_living = "lube" - turns_per_move = 1 response_help_continuous = "dips a finger into" response_help_simple = "dip a finger into" response_disarm_continuous = "gently scoops and pours aside" response_disarm_simple = "gently scoop and pour aside" - emote_see = list("bubbles", "oozes") - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/particle_effect/fluid/foam) + emotes = list( + BB_EMOTE_SAY = list("HONK", "Honk!", "Welcome to clown planet!"), + BB_EMOTE_HEAR = list("bubbles", "oozes"), + ) + waddles = FALSE + loot = list( + /obj/effect/spawner/foam_starter/small, + /obj/item/clothing/mask/gas/clown_hat, + ) -/mob/living/simple_animal/hostile/retaliate/clown/lube/Initialize(mapload) +/mob/living/basic/clown/lube/Initialize(mapload) . = ..() AddElement(/datum/element/snailcrawl) -/mob/living/simple_animal/hostile/retaliate/clown/banana - name = "Clownana" - desc = "A fusion of clown and banana DNA birthed from a botany experiment gone wrong." - icon_state = "banana tree" - icon_living = "banana tree" - response_disarm_continuous = "peels" - response_disarm_simple = "peel" - response_harm_continuous = "peels" - response_harm_simple = "peel" - turns_per_move = 1 - speak = list("HONK", "Honk!", "YA-HONK!!!") - emote_see = list("honks", "bites into the banana", "plucks a banana off its head", "photosynthesizes") - maxHealth = 120 - health = 120 - speed = -1 - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap, /obj/item/seeds/banana) - ///Our peel dropping ability - var/datum/action/cooldown/rustle/banana_rustle - ///Our banana bunch spawning ability - var/datum/action/cooldown/exquisite_bunch/banana_bunch - -/mob/living/simple_animal/hostile/retaliate/clown/banana/Initialize(mapload) - . = ..() - banana_rustle = new() - banana_rustle.Grant(src) - banana_bunch = new() - banana_bunch.Grant(src) - -/mob/living/simple_animal/hostile/retaliate/clown/banana/Destroy() - . = ..() - QDEL_NULL(banana_rustle) - QDEL_NULL(banana_bunch) - -///drops peels around the mob when activated -/datum/action/cooldown/rustle - name = "Rustle" - desc = "Shake loose a few banana peels." - cooldown_time = 8 SECONDS - button_icon_state = "rustle" - button_icon = 'icons/mob/actions/actions_clown.dmi' - background_icon_state = "bg_nature" - overlay_icon_state = "bg_nature_border" - ///which type of peel to spawn - var/banana_type = /obj/item/grown/bananapeel - ///How many peels to spawn - var/peel_amount = 3 - -/datum/action/cooldown/rustle/Activate(atom/target) - . = ..() - var/list/reachable_turfs = list() - for(var/turf/adjacent_turf in RANGE_TURFS(1, owner.loc)) - if(adjacent_turf == owner.loc || !owner.CanReach(adjacent_turf) || !isopenturf(adjacent_turf)) - continue - reachable_turfs += adjacent_turf - - var/peels_to_spawn = min(peel_amount, reachable_turfs.len) - for(var/i in 1 to peels_to_spawn) - new banana_type(pick_n_take(reachable_turfs)) - playsound(owner, 'sound/creatures/clown/clownana_rustle.ogg', 60) - animate(owner, time = 1, pixel_x = 6, easing = CUBIC_EASING | EASE_OUT) - animate(time = 2, pixel_x = -8, easing = CUBIC_EASING) - animate(time = 1, pixel_x = 0, easing = CUBIC_EASING | EASE_IN) - StartCooldown() - -///spawns a plumb bunch of bananas imbued with mystical power. -/datum/action/cooldown/exquisite_bunch - name = "Exquisite Bunch" - desc = "Pluck your finest bunch of bananas from your head. This bunch is especially nutrious to monkeykind. A gentle tap will trigger an explosive ripening process." - button_icon = 'icons/obj/service/hydroponics/harvest.dmi' - cooldown_time = 60 SECONDS - button_icon_state = "banana_bunch" - background_icon_state = "bg_nature" - overlay_icon_state = "bg_nature_border" - ///If we are currently activating our ability. - var/activating = FALSE - -/datum/action/cooldown/exquisite_bunch/Trigger(trigger_flags, atom/target) - if(activating) - return - var/bunch_turf = get_step(owner.loc, owner.dir) - if(!bunch_turf) - return - if(!owner.CanReach(bunch_turf) || !isopenturf(bunch_turf)) - owner.balloon_alert(owner, "can't do that here!") - return - activating = TRUE - if(!do_after(owner, 1 SECONDS)) - activating = FALSE - return - playsound(owner, 'sound/creatures/clown/hehe.ogg', 100) - if(!do_after(owner, 1 SECONDS)) - activating = FALSE - return - activating = FALSE - return ..() - -/datum/action/cooldown/exquisite_bunch/Activate(atom/target) - . = ..() - new /obj/item/food/grown/banana/bunch(get_step(owner.loc, owner.dir)) - playsound(owner, 'sound/items/bikehorn.ogg', 60) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound), owner, 'sound/creatures/clown/hohoho.ogg', 100, 1), 1 SECONDS) - StartCooldown() - -/mob/living/simple_animal/hostile/retaliate/clown/honkling +/mob/living/basic/clown/honkling name = "Honkling" desc = "A divine being sent by the Honkmother to spread joy. It's not dangerous, but it's a bit of a nuisance." icon_state = "honkling" icon_living = "honkling" - turns_per_move = 1 - speed = -10 - harm_intent_damage = 1 + speed = 1.1 melee_damage_lower = 1 melee_damage_upper = 1 attack_verb_continuous = "cheers up" attack_verb_simple = "cheer up" - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap, /obj/item/seeds/banana/bluespace) - attack_reagent = /datum/reagent/consumable/laughter + loot = list( + /obj/item/clothing/mask/gas/clown_hat, + /obj/effect/gibspawner/human, + /obj/item/soap, + /obj/item/seeds/banana/bluespace, + ) + +/mob/living/basic/clown/honkling/Initialize(mapload) + . = ..() + var/static/list/injection_range + if(!injection_range) + injection_range = string_numbers_list(list(1, 5)) + AddElement(/datum/element/venomous, /datum/reagent/consumable/laughter, injection_range) -/mob/living/simple_animal/hostile/retaliate/clown/fleshclown +/mob/living/basic/clown/fleshclown name = "Fleshclown" desc = "A being forged out of the pure essence of pranking, cursed into existence by a cruel maker." icon_state = "fleshclown" @@ -203,52 +125,70 @@ response_disarm_simple = "sink your hands into the spongy flesh of" response_harm_continuous = "cleanses the world of" response_harm_simple = "cleanse the world of" - speak = list("HONK", "Honk!", "I didn't ask for this", "I feel constant and horrible pain", "YA-HONK!!!", "this body is a merciless and unforgiving prison", "I was born out of mirthful pranking but I live in suffering") - emote_see = list("honks", "sweats", "jiggles", "contemplates its existence") - speak_chance = 5 - dextrous = TRUE - hud_type = /datum/hud/dextrous maxHealth = 140 health = 140 - speed = -5 + speed = 1 melee_damage_upper = 15 attack_verb_continuous = "limply slaps" attack_verb_simple = "limply slap" obj_damage = 5 - loot = list(/obj/item/clothing/suit/hooded/bloated_human, /obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap) - -/mob/living/simple_animal/hostile/retaliate/clown/fleshclown/Initialize(mapload) + loot = list( + /obj/effect/gibspawner/human, + /obj/item/clothing/mask/gas/clown_hat, + /obj/item/soap, + /obj/item/clothing/suit/hooded/bloated_human, + ) + emotes = list( + BB_EMOTE_SAY = list( + "HONK", + "Honk!", + "I didn't ask for this", + "I feel constant and horrible pain", + "I was born out of mirthful pranking but I live in suffering", + "This body is a merciless and unforgiving prison", + "YA-HONK!!!", + ), + BB_EMOTE_HEAR = list("honks", "contemplates its existence"), + BB_EMOTE_SEE = list("sweats", "jiggles"), + BB_EMOTE_CHANCE = 5, + ) + +/mob/living/basic/clown/fleshclown/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) -/mob/living/simple_animal/hostile/retaliate/clown/longface +/mob/living/basic/clown/longface name = "Longface" desc = "Often found walking into the bar." icon_state = "long face" icon_living = "long face" move_resist = INFINITY - turns_per_move = 10 response_help_continuous = "tries to awkwardly hug" response_help_simple = "try to awkwardly hug" response_disarm_continuous = "pushes the unwieldy frame of" response_disarm_simple = "push the unwieldy frame of" response_harm_continuous = "tries to shut up" response_harm_simple = "try to shut up" - speak = list("YA-HONK!!!") - emote_see = list("honks", "squeaks") - speak_chance = 60 maxHealth = 150 health = 150 pixel_x = -16 base_pixel_x = -16 - speed = 10 - harm_intent_damage = 5 + speed = 3 melee_damage_lower = 5 attack_verb_continuous = "YA-HONKs" attack_verb_simple = "YA-HONK" - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap) + loot = list( + /obj/effect/gibspawner/human, + /obj/item/soap, + /obj/item/clothing/mask/gas/clown_hat, + ) + emotes = list( + BB_EMOTE_SAY = list("YA-HONK!!!"), + BB_EMOTE_HEAR = list("honks", "squeaks"), + BB_EMOTE_CHANCE = 60, + ) -/mob/living/simple_animal/hostile/retaliate/clown/clownhulk +/mob/living/basic/clown/clownhulk name = "Honk Hulk" desc = "A cruel and fearsome clown. Don't make him angry." icon_state = "honkhulk" @@ -261,24 +201,30 @@ response_disarm_simple = "foolishly push" response_harm_continuous = "angers" response_harm_simple = "anger" - speak = list("HONK", "Honk!", "HAUAUANK!!!", "GUUURRRRAAAHHH!!!") - emote_see = list("honks", "sweats", "grunts") - speak_chance = 5 maxHealth = 400 health = 400 pixel_x = -16 base_pixel_x = -16 speed = 2 - harm_intent_damage = 15 melee_damage_lower = 15 melee_damage_upper = 20 attack_verb_continuous = "pummels" attack_verb_simple = "pummel" obj_damage = 30 environment_smash = ENVIRONMENT_SMASH_WALLS - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap) + loot = list( + /obj/effect/gibspawner/human, + /obj/item/soap, + /obj/item/clothing/mask/gas/clown_hat, + ) + emotes = list( + BB_EMOTE_SAY = list("HONK", "Honk!", "HAUAUANK!!!", "GUUURRRRAAAHHH!!!"), + BB_EMOTE_HEAR = list("honks", "grunts"), + BB_EMOTE_SEE = list("sweats"), + BB_EMOTE_CHANCE = 5, + ) -/mob/living/simple_animal/hostile/retaliate/clown/clownhulk/chlown +/mob/living/basic/clown/clownhulk/chlown name = "Chlown" desc = "A real lunkhead who somehow gets all the girls." icon_state = "chlown" @@ -290,18 +236,26 @@ response_disarm_simple = "try to assert dominance over" response_harm_continuous = "makes a weak beta attack at" response_harm_simple = "make a weak beta attack at" - speak = list("HONK", "Honk!", "Bruh", "cheeaaaahhh?") - emote_see = list("asserts his dominance", "emasculates everyone implicitly") maxHealth = 500 health = 500 - speed = -2 + speed = -2 //ridicilously fast but i dont even know what this is used for armour_penetration = 20 attack_verb_continuous = "steals the girlfriend of" attack_verb_simple = "steal the girlfriend of" attack_sound = 'sound/items/airhorn2.ogg' - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/effect/particle_effect/fluid/foam, /obj/item/soap) + loot = list( + /obj/effect/gibspawner/human, + /obj/effect/spawner/foam_starter/small, + /obj/item/soap, + /obj/item/clothing/mask/gas/clown_hat, + ) + emotes = list( + BB_EMOTE_SAY = list("HONK", "Honk!", "Bruh", "cheeaaaahhh?"), + BB_EMOTE_SEE = list("asserts his dominance", "emasculates everyone implicitly"), + BB_EMOTE_CHANCE = 5, + ) -/mob/living/simple_animal/hostile/retaliate/clown/clownhulk/honcmunculus +/mob/living/basic/clown/clownhulk/honkmunculus name = "Honkmunculus" desc = "A slender wiry figure of alchemical origin." icon_state = "honkmunculus" @@ -310,82 +264,107 @@ response_help_simple = "skeptically poke" response_disarm_continuous = "pushes the unwieldy frame of" response_disarm_simple = "push the unwieldy frame of" - speak = list("honk") - emote_see = list("squirms", "writhes") - speak_chance = 1 maxHealth = 200 health = 200 - speed = -5 - harm_intent_damage = 5 + speed = 1 melee_damage_lower = 5 melee_damage_upper = 10 attack_verb_continuous = "ferociously mauls" attack_verb_simple = "ferociously maul" environment_smash = ENVIRONMENT_SMASH_NONE - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/effect/particle_effect/fluid/foam, /obj/item/soap) - attack_reagent = /datum/reagent/peaceborg/confuse + loot = list( + /obj/effect/gibspawner/xeno/bodypartless, + /obj/effect/spawner/foam_starter/small, + /obj/item/soap, + /obj/item/clothing/mask/gas/clown_hat, + ) + emotes = list( + BB_EMOTE_SAY = list("honk"), + BB_EMOTE_SEE = list("squirms", "writhes"), + ) + +/mob/living/basic/clown/clownhulk/honkmunculus/Initialize(mapload) + . = ..() + var/static/list/injection_range + if(!injection_range) + injection_range = string_numbers_list(list(1, 5)) + AddElement(/datum/element/venomous, /datum/reagent/peaceborg/confuse, injection_range) -/mob/living/simple_animal/hostile/retaliate/clown/clownhulk/destroyer +/mob/living/basic/clown/clownhulk/destroyer name = "The Destroyer" desc = "An ancient being born of arcane honking." icon_state = "destroyer" icon_living = "destroyer" response_disarm_continuous = "bounces off of" response_harm_continuous = "bounces off of" - speak = list("HONK!!!", "The Honkmother is merciful, so I must act out her wrath.", "parce mihi ad beatus honkmother placet mihi ut peccata committere,", "DIE!!!") maxHealth = 400 health = 400 speed = 5 - harm_intent_damage = 30 melee_damage_lower = 20 melee_damage_upper = 40 armour_penetration = 30 - stat_attack = HARD_CRIT attack_verb_continuous = "acts out divine vengeance on" attack_verb_simple = "act out divine vengeance on" obj_damage = 50 environment_smash = ENVIRONMENT_SMASH_RWALLS - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/effect/particle_effect/fluid/foam, /obj/item/soap) + ai_controller = /datum/ai_controller/basic_controller/clown/murder + loot = list( + /obj/effect/gibspawner/human, + /obj/effect/spawner/foam_starter/small, + /obj/item/soap, + /obj/item/clothing/mask/gas/clown_hat, + ) + emotes = list( + BB_EMOTE_SAY = list("HONK!!!", "The Honkmother is merciful, so I must act out her wrath.", "parce mihi ad beatus honkmother placet mihi ut peccata committere,", "DIE!!!"), + BB_EMOTE_HEAR = list("honks", "grunts"), + BB_EMOTE_SEE = list("sweats"), + BB_EMOTE_CHANCE = 5, + ) -/mob/living/simple_animal/hostile/retaliate/clown/mutant +/mob/living/basic/clown/mutant name = "Unknown" desc = "Kill it for its own sake." icon_state = "mutant" icon_living = "mutant" move_resist = INFINITY - turns_per_move = 10 response_help_continuous = "reluctantly sinks a finger into" response_help_simple = "reluctantly sink a finger into" response_disarm_continuous = "squishes into" response_disarm_simple = "squish into" response_harm_continuous = "squishes into" response_harm_simple = "squish into" - speak = list("aaaaaahhhhuuhhhuhhhaaaaa", "AAAaaauuuaaAAAaauuhhh", "huuuuuh... hhhhuuuooooonnnnkk", "HuaUAAAnKKKK") - emote_see = list("squirms", "writhes", "pulsates", "froths", "oozes") - speak_chance = 10 maxHealth = 130 health = 130 pixel_x = -16 base_pixel_x = -16 speed = -5 - harm_intent_damage = 10 melee_damage_lower = 10 melee_damage_upper = 20 attack_verb_continuous = "awkwardly flails at" attack_verb_simple = "awkwardly flail at" - loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/item/soap, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic/animal, /obj/effect/gibspawner/human/bodypartless, /obj/effect/gibspawner/human) + loot = list( + /obj/effect/gibspawner/generic, + /obj/effect/gibspawner/generic/animal, + /obj/effect/gibspawner/human, + /obj/effect/gibspawner/human/bodypartless, + /obj/effect/gibspawner/xeno/bodypartless, + /obj/item/soap, + /obj/item/clothing/mask/gas/clown_hat, + ) + emotes = list( + BB_EMOTE_SAY = list("aaaaaahhhhuuhhhuhhhaaaaa", "AAAaaauuuaaAAAaauuhhh", "huuuuuh... hhhhuuuooooonnnnkk", "HuaUAAAnKKKK"), + BB_EMOTE_SEE = list("squirms", "writhes", "pulsates", "froths", "oozes"), + BB_EMOTE_CHANCE = 10, + ) -/mob/living/simple_animal/hostile/retaliate/clown/mutant/slow +/mob/living/basic/clown/mutant/slow speed = 20 - move_to_delay = 60 -/mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton +/mob/living/basic/clown/mutant/glutton name = "banana glutton" desc = "Something that was once a clown" icon_state = "glutton" icon_living = "glutton" - speak = list("hey, buddy", "HONK!!!", "H-h-h-H-HOOOOONK!!!!", "HONKHONKHONK!!!", "HEY, BUCKO, GET BACK HERE!!!", "HOOOOOOOONK!!!") - emote_see = list("jiggles", "wobbles") health = 200 mob_size = MOB_SIZE_LARGE speed = 1 @@ -395,37 +374,47 @@ damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 2, STAMINA = 0, OXY = 1) attack_verb_continuous = "slams" attack_verb_simple = "slam" - loot = list(/obj/effect/gibspawner/xeno/bodypartless, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic/animal, /obj/effect/gibspawner/human/bodypartless) + loot = list( + /obj/effect/gibspawner/generic, + /obj/effect/gibspawner/generic/animal, + /obj/effect/gibspawner/human/bodypartless, + /obj/effect/gibspawner/xeno/bodypartless, + ) + emotes = list( + BB_EMOTE_SAY = list("hey, buddy", "HONK!!!", "H-h-h-H-HOOOOONK!!!!", "HONKHONKHONK!!!", "HEY, BUCKO, GET BACK HERE!!!", "HOOOOOOOONK!!!"), + BB_EMOTE_SEE = list("jiggles", "wobbles"), + ) death_sound = 'sound/misc/sadtrombone.ogg' + waddles = FALSE ///This is the list of items we are ready to regurgitate, var/list/prank_pouch = list() -/mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton/Initialize(mapload) +/mob/living/basic/clown/mutant/glutton/Initialize(mapload) . = ..() var/datum/action/cooldown/regurgitate/spit = new(src) spit.Grant(src) - add_cell_sample() + AddElement(/datum/element/swabable, CELL_LINE_TABLE_GLUTTON, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/cheesiehonkers, /obj/item/food/cornchips), tame_chance = 30, bonus_tame_chance = 0, after_tame = CALLBACK(src, PROC_REF(tamed))) -/mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton/attacked_by(obj/item/I, mob/living/user) - if(!check_edible(I)) +/mob/living/basic/clown/mutant/glutton/attacked_by(obj/item/item, mob/living/user) + if(!check_edible(item)) return ..() - eat_atom(I) + eat_atom(item) -/mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton/AttackingTarget(atom/attacked_target) - if(!check_edible(attacked_target)) +/mob/living/basic/clown/mutant/glutton/melee_attack(atom/target, list/modifiers, ignore_cooldown = FALSE) + if(!check_edible(target)) return ..() - eat_atom(attacked_target) + eat_atom(target) -/mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton/UnarmedAttack(atom/A, proximity_flag, list/modifiers) - if(!check_edible(A)) +/mob/living/basic/clown/mutant/glutton/UnarmedAttack(atom/victim, proximity_flag, list/modifiers) + if(!check_edible(victim)) return ..() - eat_atom(A) + eat_atom(victim) ///Returns whether or not the supplied movable atom is edible. -/mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton/proc/check_edible(atom/movable/potential_food) +/mob/living/basic/clown/mutant/glutton/proc/check_edible(atom/movable/potential_food) if(isliving(potential_food)) var/mob/living/living_morsel = potential_food if(living_morsel.mob_size > MOB_SIZE_SMALL) @@ -440,7 +429,7 @@ return TRUE ///This proc eats the atom, certain funny items are stored directly in the prank pouch while bananas grant a heal based on their potency and the peels are retained in the pouch. -/mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton/proc/eat_atom(atom/movable/eaten_atom) +/mob/living/basic/clown/mutant/glutton/proc/eat_atom(atom/movable/eaten_atom) var/static/funny_items = list( /obj/item/food/pie/cream, @@ -464,14 +453,11 @@ playsound(loc,'sound/items/eatfood.ogg', rand(30,50), TRUE) flick("glutton_mouth", src) -/mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton/proc/tamed(mob/living/tamer) +/mob/living/basic/clown/mutant/glutton/proc/tamed(mob/living/tamer) buckle_lying = 0 AddElement(/datum/element/ridable, /datum/component/riding/creature/glutton) -/mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton/add_cell_sample() - AddElement(/datum/element/swabable, CELL_LINE_TABLE_GLUTTON, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) - -/mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton/Exited(atom/movable/gone, direction) +/mob/living/basic/clown/mutant/glutton/Exited(atom/movable/gone, direction) . = ..() prank_pouch -= gone @@ -512,12 +498,12 @@ return FALSE // Hardcoded to only work with gluttons. Come back next year - return istype(owner, /mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton) + return istype(owner, /mob/living/basic/clown/mutant/glutton) /datum/action/cooldown/regurgitate/Activate(atom/spit_at) StartCooldown(cooldown_time / 4) - var/mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton/pouch_owner = owner + var/mob/living/basic/clown/mutant/glutton/pouch_owner = owner if(!length(pouch_owner.prank_pouch)) pouch_owner.icon_state = initial(pouch_owner.icon_state) to_chat(pouch_owner, span_notice("Your prank pouch is empty.")) @@ -531,3 +517,113 @@ StartCooldown() return TRUE + +/mob/living/basic/clown/banana + name = "Clownana" + desc = "A fusion of clown and banana DNA birthed from a botany experiment gone wrong." + icon_state = "banana tree" + icon_living = "banana tree" + response_disarm_continuous = "peels" + response_disarm_simple = "peel" + response_harm_continuous = "peels" + response_harm_simple = "peel" + maxHealth = 120 + health = 120 + speed = -1 + loot = list( + /obj/effect/gibspawner/human, + /obj/item/seeds/banana, + /obj/item/soap, + /obj/item/clothing/mask/gas/clown_hat, + ) + emotes = list( + BB_EMOTE_SAY = list("HONK", "Honk!", "YA-HONK!!!"), + BB_EMOTE_SEE = list("bites into the banana", "plucks a banana off its head", "photosynthesizes"), + BB_EMOTE_SOUND = list('sound/items/bikehorn.ogg'), + ) + ///Our peel dropping ability + var/datum/action/cooldown/rustle/banana_rustle + ///Our banana bunch spawning ability + var/datum/action/cooldown/exquisite_bunch/banana_bunch + +/mob/living/basic/clown/banana/Initialize(mapload) + . = ..() + banana_rustle = new() + banana_rustle.Grant(src) + banana_bunch = new() + banana_bunch.Grant(src) + +/mob/living/basic/clown/banana/Destroy() + . = ..() + QDEL_NULL(banana_rustle) + QDEL_NULL(banana_bunch) + +///drops peels around the mob when activated +/datum/action/cooldown/rustle + name = "Rustle" + desc = "Shake loose a few banana peels." + cooldown_time = 8 SECONDS + button_icon_state = "rustle" + button_icon = 'icons/mob/actions/actions_clown.dmi' + background_icon_state = "bg_nature" + overlay_icon_state = "bg_nature_border" + ///which type of peel to spawn + var/banana_type = /obj/item/grown/bananapeel + ///How many peels to spawn + var/peel_amount = 3 + +/datum/action/cooldown/rustle/Activate(atom/target) + . = ..() + var/list/reachable_turfs = list() + for(var/turf/adjacent_turf in RANGE_TURFS(1, owner.loc)) + if(adjacent_turf == owner.loc || !owner.CanReach(adjacent_turf) || !isopenturf(adjacent_turf)) + continue + reachable_turfs += adjacent_turf + + var/peels_to_spawn = min(peel_amount, reachable_turfs.len) + for(var/i in 1 to peels_to_spawn) + new banana_type(pick_n_take(reachable_turfs)) + playsound(owner, 'sound/creatures/clown/clownana_rustle.ogg', 60) + animate(owner, time = 1, pixel_x = 6, easing = CUBIC_EASING | EASE_OUT) + animate(time = 2, pixel_x = -8, easing = CUBIC_EASING) + animate(time = 1, pixel_x = 0, easing = CUBIC_EASING | EASE_IN) + StartCooldown() + +///spawns a plumb bunch of bananas imbued with mystical power. +/datum/action/cooldown/exquisite_bunch + name = "Exquisite Bunch" + desc = "Pluck your finest bunch of bananas from your head. This bunch is especially nutrious to monkeykind. A gentle tap will trigger an explosive ripening process." + button_icon = 'icons/obj/service/hydroponics/harvest.dmi' + cooldown_time = 60 SECONDS + button_icon_state = "banana_bunch" + background_icon_state = "bg_nature" + overlay_icon_state = "bg_nature_border" + ///If we are currently activating our ability. + var/activating = FALSE + +/datum/action/cooldown/exquisite_bunch/Trigger(trigger_flags, atom/target) + if(activating) + return + var/bunch_turf = get_step(owner.loc, owner.dir) + if(!bunch_turf) + return + if(!owner.CanReach(bunch_turf) || !isopenturf(bunch_turf)) + owner.balloon_alert(owner, "can't do that here!") + return + activating = TRUE + if(!do_after(owner, 1 SECONDS)) + activating = FALSE + return + playsound(owner, 'sound/creatures/clown/hehe.ogg', 100) + if(!do_after(owner, 1 SECONDS)) + activating = FALSE + return + activating = FALSE + return ..() + +/datum/action/cooldown/exquisite_bunch/Activate(atom/target) + . = ..() + new /obj/item/food/grown/banana/bunch(get_step(owner.loc, owner.dir)) + playsound(owner, 'sound/items/bikehorn.ogg', 60) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound), owner, 'sound/creatures/clown/hohoho.ogg', 100, 1), 1 SECONDS) + StartCooldown() diff --git a/code/modules/mob/living/basic/clown/clown_ai.dm b/code/modules/mob/living/basic/clown/clown_ai.dm new file mode 100644 index 00000000000..b2e6418dde7 --- /dev/null +++ b/code/modules/mob/living/basic/clown/clown_ai.dm @@ -0,0 +1,19 @@ +/datum/ai_controller/basic_controller/clown + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_BASIC_MOB_SPEAK_LINES = null, + ) + + 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/basic_melee_attack_subtree, + /datum/ai_planning_subtree/random_speech/blackboard, + ) + +/datum/ai_controller/basic_controller/clown/murder + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/attack_until_dead, + BB_BASIC_MOB_SPEAK_LINES = null, + ) diff --git a/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm b/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm index c57b190418b..017eac3cb51 100644 --- a/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm +++ b/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm @@ -93,6 +93,10 @@ return FALSE var/mob/living/mob_target = target + + if(mob_target.mob_biotypes & MOB_PLANT) + return FALSE + var/datum/ai_controller/basic_controller/bee_ai = owner.ai_controller if(isnull(bee_ai)) return FALSE diff --git a/code/modules/mob/living/basic/farm_animals/pony.dm b/code/modules/mob/living/basic/farm_animals/pony.dm index 434caa5ef51..4bc09391cb7 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 099efd80172..b739da0831a 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 465d724944b..292766be07b 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 08c5fda3fd8..5951bd6b7fe 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) @@ -70,14 +69,10 @@ /datum/ai_planning_subtree/sculpt_statues /datum/ai_planning_subtree/sculpt_statues/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - var/obj/target = controller.blackboard[BB_TARGET_ROCK] - - if(QDELETED(target)) - controller.queue_behavior(/datum/ai_behavior/find_and_set, BB_TARGET_ROCK, /obj/structure/flora/rock/icy) - return - - controller.queue_behavior(/datum/ai_behavior/sculpt_statue, BB_TARGET_ROCK) - return SUBTREE_RETURN_FINISH_PLANNING + if(controller.blackboard_key_exists(BB_TARGET_ROCK)) + controller.queue_behavior(/datum/ai_behavior/sculpt_statue, BB_TARGET_ROCK) + return SUBTREE_RETURN_FINISH_PLANNING + controller.queue_behavior(/datum/ai_behavior/find_and_set, BB_TARGET_ROCK, /obj/structure/flora/rock/icy) /datum/ai_behavior/sculpt_statue behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION @@ -136,16 +131,13 @@ /datum/ai_planning_subtree/burn_trees/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/datum/action/cooldown/using_action = controller.blackboard[BB_WHELP_STRAIGHTLINE_FIRE] - if (!using_action.IsAvailable()) - return - - var/obj/structure/target = controller.blackboard[BB_TARGET_TREE] - if(QDELETED(target)) - controller.queue_behavior(/datum/ai_behavior/set_target_tree, BB_TARGET_TREE) + if (!using_action?.IsAvailable()) return - controller.queue_behavior(/datum/ai_behavior/targeted_mob_ability/and_clear_target/burn_trees, BB_WHELP_STRAIGHTLINE_FIRE, BB_TARGET_TREE) - return SUBTREE_RETURN_FINISH_PLANNING + if(controller.blackboard_key_exists(BB_TARGET_TREE)) + controller.queue_behavior(/datum/ai_behavior/targeted_mob_ability/and_clear_target/burn_trees, BB_WHELP_STRAIGHTLINE_FIRE, BB_TARGET_TREE) + return SUBTREE_RETURN_FINISH_PLANNING + controller.queue_behavior(/datum/ai_behavior/set_target_tree, BB_TARGET_TREE) /datum/ai_behavior/set_target_tree diff --git a/code/modules/mob/living/basic/jungle/seedling/seedling.dm b/code/modules/mob/living/basic/jungle/seedling/seedling.dm new file mode 100644 index 00000000000..998f693d6da --- /dev/null +++ b/code/modules/mob/living/basic/jungle/seedling/seedling.dm @@ -0,0 +1,348 @@ +#define SEEDLING_STATE_NEUTRAL 0 +#define SEEDLING_STATE_WARMUP 1 +#define SEEDLING_STATE_ACTIVE 2 + +/** + * A mobile plant with a rapid ranged attack. + * It can pick up watering cans and look after plants. + */ +/mob/living/basic/seedling + name = "seedling" + desc = "This oversized, predatory flower conceals what can only be described as an organic energy cannon." + icon = 'icons/mob/simple/jungle/seedling.dmi' + icon_state = "seedling" + icon_living = "seedling" + icon_dead = "seedling_dead" + habitable_atmos = list("min_oxy" = 2, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) + minimum_survivable_temperature = 0 + maximum_survivable_temperature = 450 + mob_biotypes = MOB_ORGANIC | MOB_PLANT + maxHealth = 100 + health = 100 + pixel_y = -14 + base_pixel_y = -14 + pixel_x = -14 + base_pixel_x = -14 + response_harm_continuous = "strikes" + response_harm_simple = "strike" + melee_damage_lower = 30 + melee_damage_upper = 30 + lighting_cutoff_green = 20 + lighting_cutoff_blue = 25 + mob_size = MOB_SIZE_LARGE + attack_sound = 'sound/weapons/bladeslice.ogg' + attack_vis_effect = ATTACK_EFFECT_SLASH + ai_controller = /datum/ai_controller/basic_controller/seedling + ///the state of combat we are in + var/combatant_state = SEEDLING_STATE_NEUTRAL + ///the colors our petals can have + var/static/list/possible_colors = list(COLOR_RED, COLOR_YELLOW, COLOR_OLIVE, COLOR_CYAN) + ///appearance when we are in our normal state + var/mutable_appearance/petal_neutral + ///appearance when we are in our warmup state + var/mutable_appearance/petal_warmup + ///appearance when we are in the firing state + var/mutable_appearance/petal_active + ///appearance when we are dead + var/mutable_appearance/petal_dead + ///the bucket we carry + var/obj/item/reagent_containers/cup/held_can + ///commands we follow + var/list/seedling_commands = list( + /datum/pet_command/idle, + /datum/pet_command/free, + /datum/pet_command/follow, + ) + +/mob/living/basic/seedling/Initialize(mapload) + . = ..() + var/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/seedling/seed_attack = new(src) + seed_attack.Grant(src) + ai_controller.set_blackboard_key(BB_RAPIDSEEDS_ABILITY, seed_attack) + var/datum/action/cooldown/mob_cooldown/solarbeam/beam_attack = new(src) + beam_attack.Grant(src) + ai_controller.set_blackboard_key(BB_SOLARBEAM_ABILITY, beam_attack) + + var/petal_color = pick(possible_colors) + + petal_neutral = mutable_appearance(icon, "[icon_state]_overlay") + petal_neutral.color = petal_color + + petal_warmup = mutable_appearance(icon, "[icon_state]_charging_overlay") + petal_warmup.color = petal_color + + petal_active = mutable_appearance(icon, "[icon_state]_fire_overlay") + petal_active.color = petal_color + + petal_dead = mutable_appearance(icon, "[icon_state]_dead_overlay") + petal_dead.color = petal_color + + AddElement(/datum/element/wall_smasher) + AddComponent(/datum/component/obeys_commands, seedling_commands) + RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack)) + RegisterSignal(src, COMSIG_KB_MOB_DROPITEM_DOWN, PROC_REF(drop_can)) + update_appearance() + +/mob/living/basic/seedling/proc/pre_attack(mob/living/puncher, atom/target) + SIGNAL_HANDLER + + if(istype(target, /obj/machinery/hydroponics)) + treat_hydro_tray(target) + return COMPONENT_HOSTILE_NO_ATTACK + + if(isnull(held_can)) + return + + if(istype(target, /obj/structure/sink) || istype(target, /obj/structure/reagent_dispensers)) + INVOKE_ASYNC(held_can, TYPE_PROC_REF(/obj/item, melee_attack_chain), src, target) + return COMPONENT_HOSTILE_NO_ATTACK + + +///seedlings can water trays, remove weeds, or remove dead plants +/mob/living/basic/seedling/proc/treat_hydro_tray(obj/machinery/hydroponics/hydro) + + if(hydro.plant_status == HYDROTRAY_PLANT_DEAD) + balloon_alert(src, "dead plant removed") + hydro.set_seed(null) + return + + if(hydro.weedlevel > 0) + balloon_alert(src, "weeds uprooted") + hydro.set_weedlevel(0) + return + + var/list/can_reagents = held_can?.reagents.reagent_list + + if(!length(can_reagents)) + return + + if((locate(/datum/reagent/water) in can_reagents) && (hydro.waterlevel < hydro.maxwater)) + INVOKE_ASYNC(held_can, TYPE_PROC_REF(/obj/item, melee_attack_chain), src, hydro) + return + +/mob/living/basic/seedling/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers) + . = ..() + + if(!. || !proximity_flag || held_can) + return + + if(!istype(attack_target, /obj/item/reagent_containers/cup/watering_can)) + return + + var/obj/item/can_target = attack_target + can_target.forceMove(src) + +/mob/living/basic/seedling/proc/change_combatant_state(state) + combatant_state = state + update_appearance() + +/mob/living/basic/seedling/attackby(obj/item/can, mob/living/carbon/human/user, list/modifiers) + if(istype(can, /obj/item/reagent_containers/cup/watering_can) && isnull(held_can)) + can.forceMove(src) + return + + return ..() + +/mob/living/basic/seedling/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) + if(istype(arrived, /obj/item/reagent_containers/cup/watering_can)) + held_can = arrived + update_appearance() + + return ..() + +/mob/living/basic/seedling/update_overlays() + . = ..() + if(stat == DEAD) + . += petal_dead + return + + switch(combatant_state) + if(SEEDLING_STATE_NEUTRAL) + . += petal_neutral + if(held_can) + . += mutable_appearance(icon, "seedling_can_overlay") + if(SEEDLING_STATE_WARMUP) + . += petal_warmup + if(SEEDLING_STATE_ACTIVE) + . += petal_active + +/mob/living/basic/seedling/update_icon_state() + . = ..() + if(stat == DEAD) + return + switch(combatant_state) + if(SEEDLING_STATE_NEUTRAL) + icon_state = "seedling" + if(SEEDLING_STATE_WARMUP) + icon_state = "seedling_charging" + if(SEEDLING_STATE_ACTIVE) + icon_state = "seedling_fire" + +/mob/living/basic/seedling/proc/drop_can(mob/living/user) + SIGNAL_HANDLER + + if(isnull(held_can)) + return + dropItemToGround(held_can) + return COMSIG_KB_ACTIVATED + +/mob/living/basic/seedling/Exited(atom/movable/gone, direction) + . = ..() + if(gone != held_can) + return + held_can = null + update_appearance() + +/mob/living/basic/seedling/death(gibbed) + . = ..() + if(isnull(held_can)) + return + held_can.forceMove(drop_location()) + +/mob/living/basic/seedling/Destroy() + QDEL_NULL(held_can) + return ..() + +/mob/living/basic/seedling/meanie + maxHealth = 400 + health = 400 + faction = list(FACTION_JUNGLE) + ai_controller = /datum/ai_controller/basic_controller/seedling/meanie + seedling_commands = list( + /datum/pet_command/idle, + /datum/pet_command/free, + /datum/pet_command/follow, + /datum/pet_command/point_targetting/attack, + /datum/pet_command/point_targetting/use_ability/solarbeam, + /datum/pet_command/point_targetting/use_ability/rapidseeds, + ) + +//abilities +/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/seedling + name = "Solar Energy" + button_icon = 'icons/obj/weapons/guns/projectiles.dmi' + button_icon_state = "seedling" + desc = "Fire small beams of solar energy." + cooldown_time = 10 SECONDS + projectile_type = /obj/projectile/seedling + default_projectile_spread = 10 + shot_count = 10 + shot_delay = 0.2 SECONDS + melee_cooldown_time = 0 SECONDS + shared_cooldown = NONE + ///how long we must charge up before firing off + var/charge_up_timer = 3 SECONDS + ///is the owner of this ability a seedling? + var/is_seedling = FALSE + +/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/seedling/Grant(mob/grant_to) + . = ..() + if(isnull(owner)) + return + is_seedling = istype(owner, /mob/living/basic/seedling) + +/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/seedling/IsAvailable(feedback) + . = ..() + if(!.) + return FALSE + if(!is_seedling) + return TRUE + var/mob/living/basic/seedling/seed_owner = owner + if(seed_owner.combatant_state != SEEDLING_STATE_NEUTRAL) + if(feedback) + seed_owner.balloon_alert(seed_owner, "charging!") + return FALSE + return TRUE + +/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/seedling/Activate(atom/target) + if(is_seedling) + var/mob/living/basic/seedling/seed_owner = owner + seed_owner.change_combatant_state(state = SEEDLING_STATE_WARMUP) + addtimer(CALLBACK(src, PROC_REF(attack_sequence), owner, target), charge_up_timer) + StartCooldown() + return TRUE + +/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/seedling/attack_sequence(mob/living/firer, atom/target) + if(is_seedling) + var/mob/living/basic/seedling/seed_owner = owner + seed_owner.change_combatant_state(state = SEEDLING_STATE_ACTIVE) + addtimer(CALLBACK(seed_owner, TYPE_PROC_REF(/mob/living/basic/seedling, change_combatant_state), SEEDLING_STATE_NEUTRAL), 4 SECONDS) + + return ..() + + +/datum/action/cooldown/mob_cooldown/solarbeam + name = "Solar Beam" + button_icon = 'icons/effects/beam.dmi' + button_icon_state = "solar_beam" + desc = "Concentrate the power of the sun onto your target!" + cooldown_time = 30 SECONDS + shared_cooldown = NONE + ///how long will it take for us to charge up the beam + var/beam_charge_up = 3 SECONDS + ///is the owner of this ability a seedling? + var/is_seedling = FALSE + +/datum/action/cooldown/mob_cooldown/solarbeam/Grant(mob/grant_to) + . = ..() + if(isnull(owner)) + return + is_seedling = istype(owner, /mob/living/basic/seedling) + +/datum/action/cooldown/mob_cooldown/solarbeam/IsAvailable(feedback) + . = ..() + if(!.) + return FALSE + if(!is_seedling) + return TRUE + var/mob/living/basic/seedling/seed_owner = owner + if(seed_owner.combatant_state != SEEDLING_STATE_NEUTRAL) + if(feedback) + seed_owner.balloon_alert(seed_owner, "charging!") + return FALSE + return TRUE + +/datum/action/cooldown/mob_cooldown/solarbeam/Activate(atom/target) + if(is_seedling) + var/mob/living/basic/seedling/seed_owner = owner + seed_owner.change_combatant_state(state = SEEDLING_STATE_WARMUP) + + var/turf/target_turf = get_turf(target) + playsound(owner, 'sound/effects/seedling_chargeup.ogg', 100, FALSE) + + var/obj/effect/temp_visual/solarbeam_killsat/owner_beam = new(get_turf(owner)) + animate(owner_beam, transform = matrix().Scale(1, 32), alpha = 255, time = beam_charge_up) + + var/obj/effect/temp_visual/solarbeam_killsat/target_beam = new(target_turf) + animate(target_beam, transform = matrix().Scale(2, 1), alpha = 255, time = beam_charge_up) + + addtimer(CALLBACK(src, PROC_REF(launch_beam), owner, target_turf), beam_charge_up) + StartCooldown() + return TRUE + +///the solarbeam will damage people, otherwise it will heal plants +/datum/action/cooldown/mob_cooldown/solarbeam/proc/launch_beam(mob/living/firer, turf/target_turf) + for(var/atom/target_atom as anything in target_turf) + + if(istype(target_atom, /obj/machinery/hydroponics)) + var/obj/machinery/hydroponics/hydro = target_atom + hydro.adjust_plant_health(10) + new /obj/effect/temp_visual/heal(target_turf, COLOR_HEALING_CYAN) + + if(!isliving(target_atom)) + continue + + var/mob/living/living_target = target_atom + living_target.adjust_fire_stacks(0.2) + living_target.ignite_mob() + living_target.adjustFireLoss(30) + + playsound(target_turf, 'sound/magic/lightningbolt.ogg', 50, TRUE) + if(!is_seedling) + return + var/mob/living/basic/seedling/seed_firer = firer + seed_firer.change_combatant_state(state = SEEDLING_STATE_NEUTRAL) + +#undef SEEDLING_STATE_NEUTRAL +#undef SEEDLING_STATE_WARMUP +#undef SEEDLING_STATE_ACTIVE diff --git a/code/modules/mob/living/basic/jungle/seedling/seedling_ai.dm b/code/modules/mob/living/basic/jungle/seedling/seedling_ai.dm new file mode 100644 index 00000000000..4d67a71d4d4 --- /dev/null +++ b/code/modules/mob/living/basic/jungle/seedling/seedling_ai.dm @@ -0,0 +1,178 @@ +/datum/ai_controller/basic_controller/seedling + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/not_friends, + BB_WEEDLEVEL_THRESHOLD = 3, + BB_WATERLEVEL_THRESHOLD = 90, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/pet_planning, + /datum/ai_planning_subtree/find_and_hunt_target/watering_can, + /datum/ai_planning_subtree/find_and_hunt_target/fill_watercan, + /datum/ai_planning_subtree/find_and_hunt_target/treat_hydroplants, + /datum/ai_planning_subtree/find_and_hunt_target/beamable_hydroplants, + ) + +/datum/ai_planning_subtree/find_and_hunt_target/watering_can + target_key = BB_WATERCAN_TARGET + finding_behavior = /datum/ai_behavior/find_hunt_target + hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target + hunt_targets = list(/obj/item/reagent_containers/cup/watering_can) + hunt_range = 7 + +/datum/ai_planning_subtree/find_and_hunt_target/watering_can/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/mob/living/living_pawn = controller.pawn + if(locate(/obj/item/reagent_containers/cup/watering_can) in living_pawn) //we already have what we came for! + return + return ..() + +/datum/ai_planning_subtree/find_and_hunt_target/treat_hydroplants + target_key = BB_HYDROPLANT_TARGET + finding_behavior = /datum/ai_behavior/find_and_set/treatable_hydro + hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/treat_hydroplant + hunt_targets = list(/obj/machinery/hydroponics) + hunt_range = 7 + +/datum/ai_behavior/find_and_set/treatable_hydro + +/datum/ai_behavior/find_and_set/treatable_hydro/search_tactic(datum/ai_controller/controller, locate_path, search_range) + var/list/possible_trays = list() + var/mob/living/living_pawn = controller.pawn + var/waterlevel_threshold = controller.blackboard[BB_WATERLEVEL_THRESHOLD] + var/weedlevel_threshold = controller.blackboard[BB_WEEDLEVEL_THRESHOLD] + var/watering_can = locate(/obj/item/reagent_containers/cup/watering_can) in living_pawn + + for(var/obj/machinery/hydroponics/hydro in oview(search_range, controller.pawn)) + if(isnull(hydro.myseed)) + continue + if(hydro.waterlevel < waterlevel_threshold && watering_can) + possible_trays += hydro + continue + if(hydro.weedlevel > weedlevel_threshold || hydro.plant_status == HYDROTRAY_PLANT_DEAD) + possible_trays += hydro + continue + + if(possible_trays.len) + return pick(possible_trays) + +/datum/ai_behavior/hunt_target/unarmed_attack_target/treat_hydroplant + hunt_cooldown = 2 SECONDS + always_reset_target = TRUE + +/datum/ai_behavior/hunt_target/unarmed_attack_target/treat_hydroplant/target_caught(mob/living/living_pawn, obj/machinery/hydroponics/hydro_target) + if(QDELETED(hydro_target) || QDELETED(hydro_target.myseed)) + return + + if(hydro_target.plant_status == HYDROTRAY_PLANT_DEAD) + living_pawn.manual_emote("weeps...") //weep over the dead plants + return ..() + + +/datum/ai_planning_subtree/find_and_hunt_target/beamable_hydroplants + target_key = BB_BEAMABLE_HYDROPLANT_TARGET + finding_behavior = /datum/ai_behavior/find_and_set/beamable_hydroplants + hunting_behavior = /datum/ai_behavior/hunt_target/use_ability_on_target/solarbeam + hunt_targets = list(/obj/machinery/hydroponics) + hunt_range = 7 + +/datum/ai_planning_subtree/find_and_hunt_target/beamable_hydroplants/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/datum/action/cooldown/solar_ability = controller.blackboard[BB_SOLARBEAM_ABILITY] + if(QDELETED(solar_ability) || !solar_ability.IsAvailable()) + return + return ..() + +/datum/ai_behavior/hunt_target/use_ability_on_target/solarbeam + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + required_distance = 2 + action_cooldown = 1 MINUTES + ability_key = BB_SOLARBEAM_ABILITY + +/datum/ai_behavior/hunt_target/use_ability_on_target/solarbeam/setup(datum/ai_controller/controller, target_key, ability_key) + . = ..() + var/obj/target = controller.blackboard[target_key] + if(QDELETED(target)) + return FALSE + set_movement_target(controller, target) + +/datum/ai_behavior/find_and_set/beamable_hydroplants/search_tactic(datum/ai_controller/controller, locate_path, search_range) + var/list/possible_trays = list() + + for(var/obj/machinery/hydroponics/hydro in oview(search_range, controller.pawn)) + if(isnull(hydro.myseed)) + continue + if(hydro.plant_health < hydro.myseed.endurance) + possible_trays += hydro + + if(possible_trays.len) + return pick(possible_trays) + +/datum/ai_planning_subtree/find_and_hunt_target/fill_watercan + target_key = BB_LOW_PRIORITY_HUNTING_TARGET + finding_behavior = /datum/ai_behavior/find_hunt_target/suitable_dispenser + hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/water_source + hunt_targets = list(/obj/structure/sink, /obj/structure/reagent_dispensers) + hunt_range = 7 + +/datum/ai_planning_subtree/find_and_hunt_target/fill_watercan/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/mob/living/living_pawn = controller.pawn + var/obj/item/reagent_containers/can = locate(/obj/item/reagent_containers/cup/watering_can) in living_pawn + + if(isnull(can)) + return + if(locate(/datum/reagent/water) in can.reagents.reagent_list) + return + + return ..() + +/datum/ai_behavior/find_hunt_target/suitable_dispenser + +/datum/ai_behavior/find_hunt_target/suitable_dispenser/valid_dinner(mob/living/source, obj/structure/water_source, radius) + if(!(locate(/datum/reagent/water) in water_source.reagents.reagent_list)) + return FALSE + + return can_see(source, water_source, radius) + +/datum/ai_behavior/hunt_target/unarmed_attack_target/water_source + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + hunt_cooldown = 5 SECONDS + +/datum/ai_controller/basic_controller/seedling/meanie + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/not_friends, + ) + planning_subtrees = list( + /datum/ai_planning_subtree/pet_planning, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/targeted_mob_ability/seedling_rapid, + /datum/ai_planning_subtree/targeted_mob_ability/solarbeam, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) + +/datum/ai_planning_subtree/targeted_mob_ability/seedling_rapid + ability_key = BB_RAPIDSEEDS_ABILITY + finish_planning = FALSE + +/datum/ai_planning_subtree/targeted_mob_ability/solarbeam + ability_key = BB_SOLARBEAM_ABILITY + finish_planning = FALSE + +///pet commands +/datum/pet_command/point_targetting/use_ability/solarbeam + command_name = "Launch solarbeam" + command_desc = "Command your pet to launch a solarbeam at your target!" + radial_icon = 'icons/effects/beam.dmi' + radial_icon_state = "solar_beam" + speech_commands = list("beam", "solar") + pet_ability_key = BB_SOLARBEAM_ABILITY + +/datum/pet_command/point_targetting/use_ability/rapidseeds + command_name = "Rapid seeds" + command_desc = "Command your pet to launch a volley of seeds at your target!" + radial_icon = 'icons/obj/weapons/guns/projectiles.dmi' + radial_icon_state = "seedling" + speech_commands = list("rapid", "seeds", "volley") + pet_ability_key = BB_RAPIDSEEDS_ABILITY diff --git a/code/modules/mob/living/basic/jungle/seedling/seedling_projectiles.dm b/code/modules/mob/living/basic/jungle/seedling/seedling_projectiles.dm new file mode 100644 index 00000000000..726b8105933 --- /dev/null +++ b/code/modules/mob/living/basic/jungle/seedling/seedling_projectiles.dm @@ -0,0 +1,32 @@ +/obj/projectile/seedling + name = "solar energy" + icon_state = "seedling" + damage = 10 + damage_type = BURN + light_range = 2 + armor_flag = ENERGY + light_color = LIGHT_COLOR_DIM_YELLOW + speed = 1.6 + hitsound = 'sound/weapons/sear.ogg' + hitsound_wall = 'sound/weapons/effects/searwall.ogg' + nondirectional_sprite = TRUE + +/obj/projectile/seedling/on_hit(atom/target) + if(!isliving(target)) + return ..() + + var/mob/living/living_target = target + if(FACTION_JUNGLE in living_target.faction) + return + + return ..() + +/obj/effect/temp_visual/solarbeam_killsat + name = "beam of solar energy" + icon_state = "solar_beam" + icon = 'icons/effects/beam.dmi' + plane = LIGHTING_PLANE + layer = LIGHTING_PRIMARY_LAYER + duration = 3 SECONDS + alpha = 200 + randomdir = FALSE diff --git a/code/modules/mob/living/basic/lavaland/bileworm/bileworm_ai.dm b/code/modules/mob/living/basic/lavaland/bileworm/bileworm_ai.dm index 11d7168776b..0093e69220c 100644 --- a/code/modules/mob/living/basic/lavaland/bileworm/bileworm_ai.dm +++ b/code/modules/mob/living/basic/lavaland/bileworm/bileworm_ai.dm @@ -15,9 +15,7 @@ /datum/ai_planning_subtree/bileworm_attack /datum/ai_planning_subtree/bileworm_attack/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - - var/mob/living/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] - if(QDELETED(target)) + if (!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)) return var/datum/action/cooldown/mob_cooldown/resurface = controller.blackboard[BB_BILEWORM_RESURFACE] diff --git a/code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm b/code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm new file mode 100644 index 00000000000..29a3de60029 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm @@ -0,0 +1,126 @@ +/// Fires a bloody beam. Brimdemon Blast! +/datum/action/cooldown/mob_cooldown/brimbeam + name = "brimstone blast" + desc = "Unleash a barrage of infernal energies in the targeted direction." + button_icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi' + button_icon_state = "brimdemon_firing" + background_icon_state = "bg_demon" + overlay_icon_state = "bg_demon_border" + click_to_activate = TRUE + cooldown_time = 5 SECONDS + melee_cooldown_time = 0 + check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_INCAPACITATED + /// How far does our beam go? + var/beam_range = 10 + /// How long does our beam last? + var/beam_duration = 2 SECONDS + /// How long do we wind up before firing? + var/charge_duration = 1 SECONDS + /// Overlay we show when we're about to fire + var/static/image/direction_overlay = image('icons/mob/simple/lavaland/lavaland_monsters.dmi', "brimdemon_telegraph_dir") + /// A list of all the beam parts. + var/list/beam_parts = list() + +/datum/action/cooldown/mob_cooldown/brimbeam/Destroy() + extinguish_laser() + return ..() + +/datum/action/cooldown/mob_cooldown/brimbeam/Activate(atom/target) + StartCooldown(360 SECONDS) + + owner.face_atom(target) + owner.move_resist = MOVE_FORCE_VERY_STRONG + owner.add_overlay(direction_overlay) + owner.balloon_alert_to_viewers("charging...") + + var/fully_charged = do_after(owner, delay = charge_duration, target = owner) + owner.cut_overlay(direction_overlay) + if (!fully_charged) + StartCooldown() + return TRUE + + if (!fire_laser()) + var/static/list/fail_emotes = list("coughs.", "wheezes.", "belches out a puff of black smoke.") + owner.manual_emote(pick(fail_emotes)) + StartCooldown() + return TRUE + + do_after(owner, delay = beam_duration, target = owner) + extinguish_laser() + StartCooldown() + return TRUE + +/// Create a laser in the direction we are facing +/datum/action/cooldown/mob_cooldown/brimbeam/proc/fire_laser() + owner.visible_message(span_danger("[owner] fires a brimbeam!")) + playsound(owner, 'sound/creatures/brimdemon.ogg', 150, FALSE, 0, 3) + var/turf/target_turf = get_ranged_target_turf(owner, owner.dir, beam_range) + var/turf/origin_turf = get_turf(owner) + var/list/affected_turfs = get_line(origin_turf, target_turf) - origin_turf + for(var/turf/affected_turf in affected_turfs) + if(affected_turf.opacity) + break + var/blocked = FALSE + for(var/obj/potential_block in affected_turf.contents) + if(potential_block.opacity) + blocked = TRUE + break + if(blocked) + break + var/atom/new_brimbeam = new /obj/effect/brimbeam(affected_turf) + new_brimbeam.dir = owner.dir + beam_parts += new_brimbeam + for(var/mob/living/hit_mob in affected_turf.contents) + hit_mob.apply_damage(damage = 25, damagetype = BURN) + to_chat(hit_mob, span_userdanger("You're blasted by [owner]'s brimbeam!")) + RegisterSignal(new_brimbeam, COMSIG_QDELETING, PROC_REF(extinguish_laser)) // In case idk a singularity eats it or something + if(!length(beam_parts)) + return FALSE + var/atom/last_brimbeam = beam_parts[length(beam_parts)] + last_brimbeam.icon_state = "brimbeam_end" + var/atom/first_brimbeam = beam_parts[1] + first_brimbeam.icon_state = "brimbeam_start" + return TRUE + +/// Get rid of our laser when we are done with it +/datum/action/cooldown/mob_cooldown/brimbeam/proc/extinguish_laser() + if(!length(beam_parts)) + return FALSE + owner.move_resist = initial(owner.move_resist) + for(var/obj/effect/brimbeam/beam in beam_parts) + beam.disperse() + beam_parts = list() + +/// Segments of the actual beam, these hurt if you stand in them +/obj/effect/brimbeam + name = "brimbeam" + icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi' + icon_state = "brimbeam_mid" + layer = ABOVE_MOB_LAYER + plane = ABOVE_GAME_PLANE + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + light_color = LIGHT_COLOR_BLOOD_MAGIC + light_power = 3 + light_range = 2 + +/obj/effect/brimbeam/Initialize(mapload) + . = ..() + START_PROCESSING(SSfastprocess, src) + +/obj/effect/brimbeam/Destroy() + STOP_PROCESSING(SSfastprocess, src) + return ..() + +/obj/effect/brimbeam/process() + for(var/mob/living/hit_mob in get_turf(src)) + damage(hit_mob) + +/// Hurt the passed mob +/obj/effect/brimbeam/proc/damage(mob/living/hit_mob) + hit_mob.apply_damage(damage = 5, damagetype = BURN) + to_chat(hit_mob, span_danger("You're damaged by [src]!")) + +/// Disappear +/obj/effect/brimbeam/proc/disperse() + animate(src, time = 0.5 SECONDS, alpha = 0) + QDEL_IN(src, 0.5 SECONDS) diff --git a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon.dm b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon.dm new file mode 100644 index 00000000000..2c22977d9c6 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon.dm @@ -0,0 +1,87 @@ +/// Lavaland mob which tries to line up with its target and fire a laser +/mob/living/basic/mining/brimdemon + name = "brimdemon" + desc = "A volatile creature resembling an enormous horned skull. Its response to almost any stimulus is to unleash a beam of infernal energy." + icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi' + icon_state = "brimdemon" + icon_living = "brimdemon" + icon_dead = "brimdemon_dead" + speed = 3 + maxHealth = 250 + health = 250 + friendly_verb_continuous = "scratches at" + friendly_verb_simple = "scratch at" + speak_emote = list("cackles") + melee_damage_lower = 7.5 + melee_damage_upper = 7.5 + attack_sound = 'sound/weapons/bite.ogg' + melee_attack_cooldown = 0.6 SECONDS + attack_vis_effect = ATTACK_EFFECT_BITE + attack_verb_continuous = "bites" + attack_verb_simple = "bite" + death_message = "wails as infernal energy escapes from its wounds, leaving it an empty husk." + death_sound = 'sound/magic/demon_dies.ogg' + light_color = LIGHT_COLOR_BLOOD_MAGIC + light_power = 5 + light_range = 1.4 + + ai_controller = /datum/ai_controller/basic_controller/brimdemon + + crusher_loot = /obj/item/crusher_trophy/brimdemon_fang + butcher_results = list( + /obj/item/food/meat/slab = 2, + /obj/effect/decal/cleanable/brimdust = 1, + /obj/item/organ/internal/monster_core/brimdust_sac = 1, + ) + /// How we get blasting + var/datum/action/cooldown/mob_cooldown/brimbeam/beam + +/mob/living/basic/mining/brimdemon/Initialize(mapload) + . = ..() + AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW) + beam = new(src) + beam.Grant(src) + ai_controller.set_blackboard_key(BB_TARGETTED_ACTION, beam) + +/mob/living/basic/mining/brimdemon/Destroy() + QDEL_NULL(beam) + return ..() + +/mob/living/basic/mining/brimdemon/RangedAttack(atom/target, modifiers) + beam.Trigger(target = target) + +/mob/living/basic/mining/brimdemon/death(gibbed) + . = ..() + if (gibbed) + return + var/obj/effect/temp_visual/brim_burst/bang = new(loc) + forceMove(bang) + +/// Show a funny animation before doing an explosion +/obj/effect/temp_visual/brim_burst + name = "bursting brimdemon" + icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi' + icon_state = "brimdemon_dead" + duration = 1.9 SECONDS + +/obj/effect/temp_visual/brim_burst/Initialize(mapload) + . = ..() + addtimer(CALLBACK(src, PROC_REF(bang)), duration - (1 DECISECONDS), TIMER_DELETE_ME) + animate(src, color = "#ff8888", transform = matrix().Scale(1.1), time = 0.7 SECONDS) + animate(color = "#ffffff", transform = matrix(), time = 0.2 SECONDS) + animate(color = "#ff4444", transform = matrix().Scale(1.3), time = 0.5 SECONDS) + animate(color = "#ffffff", transform = matrix(), time = 0.2 SECONDS) + animate(color = "#ff0000", transform = matrix().Scale(1.5), time = 0.3 SECONDS) + +/// Make an explosion +/obj/effect/temp_visual/brim_burst/proc/bang() + var/turf/origin_turf = get_turf(src) + playsound(origin_turf, 'sound/effects/pop_expl.ogg', 50) + new /obj/effect/temp_visual/explosion/fast(origin_turf) + var/list/possible_targets = range(1, origin_turf) + for(var/mob/living/target in possible_targets) + var/armor = target.run_armor_check(attack_flag = BOMB) + target.apply_damage(20, damagetype = BURN, blocked = armor, spread_damage = TRUE) + + for (var/atom/movable/thing as anything in contents) + thing.forceMove(loc) diff --git a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm new file mode 100644 index 00000000000..e5d793fa150 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_ai.dm @@ -0,0 +1,50 @@ +/** + * Slap someone who is nearby, line up with target, blast with a beam + */ +/datum/ai_controller/basic_controller/brimdemon + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/brimdemon, + ) + + ai_traits = PAUSE_DURING_DO_AFTER + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk/no_target + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic, + /datum/ai_planning_subtree/move_to_cardinal/brimdemon, + /datum/ai_planning_subtree/targeted_mob_ability/brimbeam, + ) + +/datum/targetting_datum/basic/brimdemon + stat_attack = HARD_CRIT + +/datum/ai_planning_subtree/move_to_cardinal/brimdemon + move_behaviour = /datum/ai_behavior/move_to_cardinal/brimdemon + +/datum/ai_behavior/move_to_cardinal/brimdemon + minimum_distance = 2 + +/datum/ai_behavior/move_to_cardinal/brimdemon/finish_action(datum/ai_controller/controller, succeeded, target_key) + . = ..() + if (!succeeded) + return + var/mob/living/target = controller.blackboard[target_key] + var/datum/action/cooldown/ability = controller.blackboard[BB_TARGETTED_ACTION] + if(!ability?.IsAvailable()) + return + ability.InterceptClickOn(caller = controller.pawn, target = target) + +/datum/ai_planning_subtree/targeted_mob_ability/brimbeam + use_ability_behaviour = /datum/ai_behavior/targeted_mob_ability/brimbeam + +/datum/ai_behavior/targeted_mob_ability/brimbeam + /// Don't shoot if too far away + var/max_target_distance = 9 + +/datum/ai_behavior/targeted_mob_ability/brimbeam/perform(seconds_per_tick, datum/ai_controller/controller, ability_key, target_key) + var/mob/living/target = controller.blackboard[target_key] + if (QDELETED(target) || !(get_dir(controller.pawn, target) in GLOB.cardinals) || get_dist(controller.pawn, target) > max_target_distance) + finish_action(controller, succeeded = FALSE, ability_key = ability_key, target_key = target_key) + return + return ..() diff --git a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_loot.dm b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_loot.dm new file mode 100644 index 00000000000..9a45ed99e1c --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_loot.dm @@ -0,0 +1,56 @@ +/// Brimdemon crusher trophy, it... makes a funny sound? +/obj/item/crusher_trophy/brimdemon_fang + name = "brimdemon's fang" + icon_state = "brimdemon_fang" + desc = "A fang from a brimdemon's corpse." + denied_type = /obj/item/crusher_trophy/brimdemon_fang + /// Cartoon punching vfx + var/static/list/comic_phrases = list("BOOM", "BANG", "KABLOW", "KAPOW", "OUCH", "BAM", "KAPOW", "WHAM", "POW", "KABOOM") + +/obj/item/crusher_trophy/brimdemon_fang/effect_desc() + return "mark detonation creates visual and audiosensory effects on the target" + +/obj/item/crusher_trophy/brimdemon_fang/on_mark_detonation(mob/living/target, mob/living/user) + target.balloon_alert_to_viewers("[pick(comic_phrases)]!") + playsound(target, 'sound/lavaland/brimdemon_crush.ogg', 100) + +/// Reagent pool left by dying brimdemon +/obj/effect/decal/cleanable/brimdust + name = "brimdust" + desc = "Dust from a brimdemon. It is considered valuable for its' botanical abilities." + icon_state = "brimdust" + icon = 'icons/obj/mining.dmi' + layer = FLOOR_CLEAN_LAYER + mergeable_decal = FALSE + +/obj/effect/decal/cleanable/brimdust/Initialize(mapload) + . = ..() + reagents.add_reagent(/datum/reagent/brimdust, 15) + +/// Ashwalker ore sensor crafted from brimdemon ash +/obj/item/ore_sensor + name = "ore sensor" + desc = "Using demonic frequencies, this ear-mounted tool detects ores in the nearby terrain." + icon_state = "oresensor" + icon = 'icons/obj/mining.dmi' + slot_flags = ITEM_SLOT_EARS + var/range = 5 + var/cooldown = 4 SECONDS //between the standard and the advanced ore scanner in strength + COOLDOWN_DECLARE(ore_sensing_cooldown) + +/obj/item/ore_sensor/equipped(mob/user, slot, initial) + . = ..() + if(slot & ITEM_SLOT_EARS) + START_PROCESSING(SSobj, src) + else + STOP_PROCESSING(SSobj, src) + +/obj/item/ore_sensor/dropped(mob/user, silent) + . = ..() + STOP_PROCESSING(SSobj, src) + +/obj/item/ore_sensor/process(seconds_per_tick) + if(!COOLDOWN_FINISHED(src, ore_sensing_cooldown)) + return + COOLDOWN_START(src, ore_sensing_cooldown, cooldown) + mineral_scan_pulse(get_turf(src), range) diff --git a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm index 96c9b3d556e..58efaf1f81b 100644 --- a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm +++ b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm @@ -108,10 +108,15 @@ if(!dig_ability.IsAvailable()) return - var/mob/living/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] + var/has_target = controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET) //a storm is coming or someone is nearby, its time to escape - if(currently_underground || !currently_underground && storm_approaching || !QDELETED(target)) + if(currently_underground) + if(has_target) + return + controller.queue_behavior(/datum/ai_behavior/use_mob_ability/burrow, BB_BURROW_ABILITY) + return SUBTREE_RETURN_FINISH_PLANNING + if(storm_approaching || has_target) controller.queue_behavior(/datum/ai_behavior/use_mob_ability/burrow, BB_BURROW_ABILITY) return SUBTREE_RETURN_FINISH_PLANNING @@ -122,14 +127,10 @@ /datum/ai_planning_subtree/grub_mine /datum/ai_planning_subtree/grub_mine/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - var/turf/target_wall = controller.blackboard[BB_TARGET_MINERAL_WALL] - - if(QDELETED(target_wall)) - controller.queue_behavior(/datum/ai_behavior/find_mineral_wall, BB_TARGET_MINERAL_WALL) - return - - controller.queue_behavior(/datum/ai_behavior/mine_wall, BB_TARGET_MINERAL_WALL) - return SUBTREE_RETURN_FINISH_PLANNING + if(controller.blackboard_key_exists(BB_TARGET_MINERAL_WALL)) + controller.queue_behavior(/datum/ai_behavior/mine_wall, BB_TARGET_MINERAL_WALL) + return SUBTREE_RETURN_FINISH_PLANNING + controller.queue_behavior(/datum/ai_behavior/find_mineral_wall, BB_TARGET_MINERAL_WALL) /datum/ai_behavior/mine_wall behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION @@ -168,7 +169,7 @@ /datum/pet_command/grub_spit/execute_action(datum/ai_controller/controller) var/datum/action/cooldown/spit_ability = controller.blackboard[BB_SPIT_ABILITY] - if(QDELETED(spit_ability) || !spit_ability.IsAvailable()) + if(!spit_ability?.IsAvailable()) return controller.queue_behavior(/datum/ai_behavior/use_mob_ability, BB_SPIT_ABILITY) controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) 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 83369de8862..7e723f5d93a 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, @@ -96,8 +96,7 @@ var/target_key = BB_GOLIATH_HOLE_TARGET /datum/ai_planning_subtree/goliath_dig/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - var/turf/target_turf = controller.blackboard[target_key] - if (QDELETED(target_turf)) + if (!controller.blackboard_key_exists(target_key)) return controller.queue_behavior(/datum/ai_behavior/goliath_dig, target_key) return SUBTREE_RETURN_FINISH_PLANNING diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm index 6463fc94979..18cd7321936 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 dcbeb1e670c..8e4dfe9e294 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 b94ba914298..28ed712d061 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 b08245963f4..1f310ac229f 100644 --- a/code/modules/mob/living/basic/lavaland/watcher/watcher_ai.dm +++ b/code/modules/mob/living/basic/lavaland/watcher/watcher_ai.dm @@ -3,44 +3,27 @@ BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, ) + ai_traits = PAUSE_DURING_DO_AFTER 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 e4eb9562f53..9426db41cca 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 36ad2d61b4c..0c8194c524a 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/minebots/minebot_ai.dm b/code/modules/mob/living/basic/minebots/minebot_ai.dm index 9ee1d93c1e0..897cddb1401 100644 --- a/code/modules/mob/living/basic/minebots/minebot_ai.dm +++ b/code/modules/mob/living/basic/minebots/minebot_ai.dm @@ -19,14 +19,10 @@ ///find dead humans and report their location on the radio /datum/ai_planning_subtree/locate_dead_humans/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - var/mob/living/dead_target = controller.blackboard[BB_NEARBY_DEAD_MINER] - - if(QDELETED(dead_target)) - controller.queue_behavior(/datum/ai_behavior/find_and_set/unconscious_human, BB_NEARBY_DEAD_MINER, /mob/living/carbon/human) - return - - controller.queue_behavior(/datum/ai_behavior/send_sos_message, BB_NEARBY_DEAD_MINER) - return SUBTREE_RETURN_FINISH_PLANNING + if(controller.blackboard_key_exists(BB_NEARBY_DEAD_MINER)) + controller.queue_behavior(/datum/ai_behavior/send_sos_message, BB_NEARBY_DEAD_MINER) + return SUBTREE_RETURN_FINISH_PLANNING + controller.queue_behavior(/datum/ai_behavior/find_and_set/unconscious_human, BB_NEARBY_DEAD_MINER, /mob/living/carbon/human) /datum/ai_behavior/find_and_set/unconscious_human/search_tactic(datum/ai_controller/controller, locate_path, search_range) for(var/mob/living/carbon/human/target in oview(search_range, controller.pawn)) @@ -73,18 +69,12 @@ ///mine walls if we are on automated mining mode /datum/ai_planning_subtree/minebot_mining/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - var/turf/mineral_target = controller.blackboard[BB_TARGET_MINERAL_TURF] - var/automated_mining = controller.blackboard[BB_AUTOMATED_MINING] - - if(!automated_mining) - return - - if(QDELETED(mineral_target)) - controller.queue_behavior(/datum/ai_behavior/find_mineral_wall/minebot, BB_TARGET_MINERAL_TURF) + if(!controller.blackboard[BB_AUTOMATED_MINING]) return - - controller.queue_behavior(/datum/ai_behavior/minebot_mine_turf, BB_TARGET_MINERAL_TURF) - return SUBTREE_RETURN_FINISH_PLANNING + if(controller.blackboard_key_exists(BB_TARGET_MINERAL_TURF)) + controller.queue_behavior(/datum/ai_behavior/minebot_mine_turf, BB_TARGET_MINERAL_TURF) + return SUBTREE_RETURN_FINISH_PLANNING + controller.queue_behavior(/datum/ai_behavior/find_mineral_wall/minebot, BB_TARGET_MINERAL_TURF) /datum/ai_behavior/find_mineral_wall/minebot @@ -190,7 +180,7 @@ /datum/pet_command/minebot_ability/execute_action(datum/ai_controller/controller) var/datum/action/cooldown/ability = controller.blackboard[ability_key] - if(QDELETED(ability) || !ability.IsAvailable()) + if(!ability?.IsAvailable()) return controller.queue_behavior(/datum/ai_behavior/use_mob_ability, ability_key) controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) diff --git a/code/modules/mob/living/basic/pets/dog/_dog.dm b/code/modules/mob/living/basic/pets/dog/_dog.dm index 93947173cd9..dd3b3b3a463 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 d072a1c897e..cb0df08d198 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 8d0a5ab0cde..107973135c7 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 6e716ddf411..7c57349524f 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 244c600d89f..851c0bb8029 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 6ce40d8c1a3..9a4b149fd1a 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 c0f5143f18c..b1343a7aeed 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 ..() @@ -43,9 +34,7 @@ /datum/ai_planning_subtree/find_nearest_magicarp_spell_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/datum/action/cooldown/using_action = controller.blackboard[BB_MAGICARP_SPELL] - if (QDELETED(using_action)) - return - if (!using_action.IsAvailable()) + if (!using_action?.IsAvailable()) return var/spell_targetting = controller.blackboard[BB_MAGICARP_SPELL_SPECIAL_TARGETTING] diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm index 88a9f6706f2..d220325ca15 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm @@ -12,9 +12,10 @@ if (!rift_behaviour) CRASH("Forgot to specify rift behaviour for [src]") - var/mob/living/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] + if (!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)) + return var/datum/action/cooldown/using_action = controller.blackboard[BB_CARP_RIFT] - if (QDELETED(target) || QDELETED(using_action) || !using_action.IsAvailable()) + if (!using_action?.IsAvailable()) return controller.queue_behavior(rift_behaviour, BB_CARP_RIFT, BB_BASIC_MOB_CURRENT_TARGET) 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 f4c446d088b..b3097014535 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 5051335a557..32f02b880db 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/eyeball/eyeball_ai_subtree.dm b/code/modules/mob/living/basic/space_fauna/eyeball/eyeball_ai_subtree.dm index d20873f0ce9..a3c8e22071d 100644 --- a/code/modules/mob/living/basic/space_fauna/eyeball/eyeball_ai_subtree.dm +++ b/code/modules/mob/living/basic/space_fauna/eyeball/eyeball_ai_subtree.dm @@ -17,14 +17,10 @@ /datum/ai_planning_subtree/heal_the_blind /datum/ai_planning_subtree/heal_the_blind/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - var/mob/living/carbon/target = controller.blackboard[BB_BLIND_TARGET] - - if(QDELETED(target)) - controller.queue_behavior(/datum/ai_behavior/find_the_blind, BB_BLIND_TARGET, BB_EYE_DAMAGE_THRESHOLD) - return - - controller.queue_behavior(/datum/ai_behavior/heal_eye_damage, BB_BLIND_TARGET) - return SUBTREE_RETURN_FINISH_PLANNING + if(controller.blackboard_key_exists(BB_BLIND_TARGET)) + controller.queue_behavior(/datum/ai_behavior/heal_eye_damage, BB_BLIND_TARGET) + return SUBTREE_RETURN_FINISH_PLANNING + controller.queue_behavior(/datum/ai_behavior/find_the_blind, BB_BLIND_TARGET, BB_EYE_DAMAGE_THRESHOLD) /datum/targetting_datum/basic/eyeball/can_attack(mob/living/owner, atom/target) . = ..() diff --git a/code/modules/mob/living/basic/space_fauna/faithless.dm b/code/modules/mob/living/basic/space_fauna/faithless.dm index b279856412c..c1dc297ea46 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 9b57eba8fe2..d9dfc3c5343 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 b0fba4fadc1..a417b6c1394 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/hivebot/hivebot_subtree.dm b/code/modules/mob/living/basic/space_fauna/hivebot/hivebot_subtree.dm index c5173e3d7f9..347219d0ef0 100644 --- a/code/modules/mob/living/basic/space_fauna/hivebot/hivebot_subtree.dm +++ b/code/modules/mob/living/basic/space_fauna/hivebot/hivebot_subtree.dm @@ -54,14 +54,10 @@ if(!SPT_PROB(relay_chance, seconds_per_tick)) return - var/mob/hive_target = controller.blackboard[BB_HIVE_PARTNER] - - if(QDELETED(hive_target)) - controller.queue_behavior(/datum/ai_behavior/find_and_set/hive_partner, BB_HIVE_PARTNER, /mob/living/basic/hivebot) - return - - controller.queue_behavior(/datum/ai_behavior/relay_message, BB_HIVE_PARTNER) - return SUBTREE_RETURN_FINISH_PLANNING + if (controller.blackboard_key_exists(BB_HIVE_PARTNER)) + controller.queue_behavior(/datum/ai_behavior/relay_message, BB_HIVE_PARTNER) + return SUBTREE_RETURN_FINISH_PLANNING + controller.queue_behavior(/datum/ai_behavior/find_and_set/hive_partner, BB_HIVE_PARTNER, /mob/living/basic/hivebot) /datum/ai_planning_subtree/find_and_hunt_target/repair_machines target_key = BB_MACHINE_TARGET diff --git a/code/modules/mob/living/basic/space_fauna/lightgeist.dm b/code/modules/mob/living/basic/space_fauna/lightgeist.dm index 28debb6c0a1..c70588f4502 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 5e52dabae75..e6d47e2db5c 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 35d597e53ca..5a7bb075f19 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 5fabbf2afb2..b38ada0f6e1 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 57d90da264a..18dca95013e 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 e423b5ff852..7a30f88b4c2 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/spider/giant_spider/giant_spider_ai.dm b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_ai.dm index 6838f3ba1ab..f998b7b53cd 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_ai.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_ai.dm @@ -4,7 +4,7 @@ BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(), ) - ai_traits = STOP_MOVING_WHEN_PULLED + ai_traits = STOP_MOVING_WHEN_PULLED | PAUSE_DURING_DO_AFTER ai_movement = /datum/ai_movement/basic_avoidance idle_behavior = /datum/idle_behavior/idle_random_walk/less_walking diff --git a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_subtrees.dm b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_subtrees.dm index 4b65138b041..56aacb11a96 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_subtrees.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spider_subtrees.dm @@ -62,12 +62,9 @@ var/target_key = BB_SPIDER_WEB_TARGET /datum/ai_planning_subtree/spin_web/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - var/datum/action/cooldown/using_action = controller.blackboard[action_key] - var/turf/target_turf = controller.blackboard[target_key] - if (QDELETED(using_action) || QDELETED(target_turf)) - return - controller.queue_behavior(/datum/ai_behavior/spin_web, action_key, target_key) - return SUBTREE_RETURN_FINISH_PLANNING + if (controller.blackboard_key_exists(action_key) && controller.blackboard_key_exists(target_key)) + controller.queue_behavior(/datum/ai_behavior/spin_web, action_key, target_key) + return SUBTREE_RETURN_FINISH_PLANNING /// Move to an unwebbed nearby turf and web it up /datum/ai_behavior/spin_web 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 7d13ee9a1ab..bce35146ecf 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 f632a38dc1b..9d3a09c5348 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 e13bef35482..bf8be2051d8 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 c11d592cd3b..a4fd0981198 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 be24b37441a..be84c1a5685 100644 --- a/code/modules/mob/living/basic/syndicate/syndicate_ai.dm +++ b/code/modules/mob/living/basic/syndicate/syndicate_ai.dm @@ -1,6 +1,6 @@ /datum/ai_controller/basic_controller/syndicate blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/syndicate() + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/attack_until_dead ) ai_movement = /datum/ai_movement/basic_avoidance @@ -8,12 +8,9 @@ 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 diff --git a/code/modules/mob/living/basic/tree.dm b/code/modules/mob/living/basic/tree.dm index f93ab14a37f..2a0806b105c 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 7aff4a844d3..5c69ad90447 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 282ed17b00c..191ea12b4df 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 1f2a5c7e41e..0b3645b3e0f 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 9608db4d4c6..9354f02e2b2 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/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm index 3dc3d08d399..e182c51f54f 100644 --- a/code/modules/mob/living/brain/MMI.dm +++ b/code/modules/mob/living/brain/MMI.dm @@ -57,7 +57,7 @@ if(newbrain.suicided) to_chat(user, span_warning("[newbrain] is completely useless.")) return - if(!newbrain.brainmob?.mind || !newbrain.brainmob) + if(!newbrain.brainmob) var/install = tgui_alert(user, "[newbrain] is inactive, slot it in anyway?", "Installing Brain", list("Yes", "No")) if(install != "Yes") return @@ -73,7 +73,7 @@ if(!user.transferItemToLoc(O, src)) return var/mob/living/brain/B = newbrain.brainmob - if(!B.key) + if(!B.key && !newbrain.decoy_override) B.notify_ghost_cloning("Someone has put your brain in a MMI!", source = src) user.visible_message(span_notice("[user] sticks \a [newbrain] into [src]."), span_notice("[src]'s indicator light turn on as you insert [newbrain].")) @@ -241,14 +241,23 @@ . = ..() if(radio) . += span_notice("There is a switch to toggle the radio system [radio.is_on() ? "off" : "on"].[brain ? " It is currently being covered by [brain]." : null]") - if(brainmob) - var/mob/living/brain/B = brainmob - if(!B.key || !B.mind || B.stat == DEAD) - . += span_warning("\The [src] indicates that the brain is completely unresponsive.") - else if(!B.client) - . += span_warning("\The [src] indicates that the brain is currently inactive; it might change.") + + if(!isnull(brain)) + // It's dead, show it as much + if((brain.organ_flags & ORGAN_FAILING) || brainmob?.stat == DEAD) + if(brain.suicided || (brainmob && HAS_TRAIT(brainmob, TRAIT_SUICIDED))) + . += span_warning("[src] indicator light is red.") + else + . += span_warning("[src] indicator light is yellow - perhaps you should check the brain for damage.") + // If we have a client, OR it's a decoy brain, show as active + else if(brain.decoy_override || brainmob?.client) + . += span_notice("[src] indicates that the brain is active.") + // If we have a brainmob and it has a mind, it may just be DC'd + else if(brainmob?.mind) + . += span_warning("[src] indicates that the brain is currently inactive; it might change.") + // No brainmob, no mind, and not a decoy, it's a dead brain else - . += span_notice("\The [src] indicates that the brain is active.") + . += span_warning("[src] indicates that the brain is completely unresponsive.") /obj/item/mmi/relaymove(mob/living/user, direction) return //so that the MMI won't get a warning about not being able to move if it tries to move @@ -259,6 +268,10 @@ if(user) to_chat(user, span_warning("\The [src] indicates that there is no mind present!")) return FALSE + if(brain.decoy_override) + if(user) + to_chat(user, span_warning("This [name] does not seem to fit!")) + return FALSE if(!B.key || !B.mind) if(user) to_chat(user, span_warning("\The [src] indicates that their mind is completely unresponsive!")) diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm index ac8f503df45..4bd275b5df1 100644 --- a/code/modules/mob/living/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -54,17 +54,23 @@ brain_owner.update_body_parts() return - // Not a ling? Now you get to assume direct control. if(brainmob) - if(brain_owner.key) - brain_owner.ghostize() + // If it's a ling decoy brain, nothing to transfer, just throw it out + if(decoy_override) + if(brainmob?.key) + stack_trace("Decoy override brain with a key assigned - This should never happen.") - if(brainmob.mind) - brainmob.mind.transfer_to(brain_owner) + // Not a ling - assume direct control else - brain_owner.key = brainmob.key + if(brain_owner.key) + brain_owner.ghostize() - brain_owner.set_suicide(HAS_TRAIT(brainmob, TRAIT_SUICIDED)) + if(brainmob.mind) + brainmob.mind.transfer_to(brain_owner) + else + brain_owner.key = brainmob.key + + brain_owner.set_suicide(HAS_TRAIT(brainmob, TRAIT_SUICIDED)) QDEL_NULL(brainmob) else @@ -126,8 +132,13 @@ /obj/item/organ/internal/brain/proc/transfer_identity(mob/living/L) name = "[L.name]'s [initial(name)]" - if(brainmob || decoy_override) - return + if(brainmob) + if(!decoy_override) + return + + // it's just a dummy, throw it out + QDEL_NULL(brainmob) + if(!L.mind) return brainmob = new(src) @@ -146,9 +157,10 @@ // Hack, fucked dna needs to follow the brain to prevent memes, so we need to copy over the trait sources and shit for(var/source in GET_TRAIT_SOURCES(L, TRAIT_BADDNA)) ADD_TRAIT(brainmob, TRAIT_BADDNA, source) - if(L.mind && L.mind.current) + + if(L.mind && L.mind.current && !decoy_override) L.mind.transfer_to(brainmob) - to_chat(brainmob, span_notice("You feel slightly disoriented. That's normal when you're just a brain.")) + to_chat(brainmob, span_notice("You feel slightly disoriented. That's normal when you're just a brain.")) /obj/item/organ/internal/brain/attackby(obj/item/O, mob/user, params) user.changeNext_move(CLICK_CD_MELEE) @@ -214,7 +226,7 @@ if(suicided) . += span_info("It's started turning slightly grey. They must not have been able to handle the stress of it all.") return - if((brainmob && (brainmob.client || brainmob.get_ghost())) || decoy_override) + if(brainmob && (decoy_override || brainmob.client || brainmob.get_ghost())) if(organ_flags & ORGAN_FAILING) . += span_info("It seems to still have a bit of energy within it, but it's rather damaged... You may be able to restore it with some mannitol.") else if(damage >= BRAIN_DAMAGE_DEATH*0.5) @@ -262,13 +274,11 @@ ..() /obj/item/organ/internal/brain/Destroy() //copypasted from MMIs. - if(brainmob) - QDEL_NULL(brainmob) + QDEL_NULL(brainmob) QDEL_LIST(traumas) destroy_all_skillchips() - if(owner?.mind) //You aren't allowed to return to brains that don't exist - owner.mind.set_current(null) + owner?.mind?.set_current(null) //You aren't allowed to return to brains that don't exist return ..() /obj/item/organ/internal/brain/on_life(seconds_per_tick, times_fired) diff --git a/code/modules/mob/living/carbon/alien/organs.dm b/code/modules/mob/living/carbon/alien/organs.dm index 00c8a617c64..5ef9b23c418 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 36399dbc71d..de77200f940 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 @@ -1438,27 +1461,3 @@ our_splatter.blood_dna_info = get_blood_dna_list() var/turf/targ = get_ranged_target_turf(src, splatter_direction, splatter_strength) our_splatter.fly_towards(targ, splatter_strength) - -/mob/living/carbon/update_fire_overlay(stacks, on_fire, last_icon_state, suffix = "") - var/fire_icon = "generic_burning[suffix]" - - if(!GLOB.fire_appearances[fire_icon]) - var/mutable_appearance/new_fire_overlay = mutable_appearance('icons/mob/effects/onfire.dmi', fire_icon, -FIRE_LAYER) - new_fire_overlay.appearance_flags = RESET_COLOR - GLOB.fire_appearances[fire_icon] = new_fire_overlay - - if((stacks > 0 && on_fire) || HAS_TRAIT(src, TRAIT_PERMANENTLY_ONFIRE)) - if(fire_icon == last_icon_state) - return last_icon_state - - remove_overlay(FIRE_LAYER) - overlays_standing[FIRE_LAYER] = GLOB.fire_appearances[fire_icon] - apply_overlay(FIRE_LAYER) - return fire_icon - - if(!last_icon_state) - return last_icon_state - - remove_overlay(FIRE_LAYER) - apply_overlay(FIRE_LAYER) - return null diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 3ab34e70230..8b97685d0a8 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]!" @@ -431,7 +444,7 @@ bodypart.emp_act(severity) ///Adds to the parent by also adding functionality to propagate shocks through pulling and doing some fluff effects. -/mob/living/carbon/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE) +/mob/living/carbon/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE, jitter_time = 20 SECONDS, stutter_time = 4 SECONDS, stun_duration = 4 SECONDS) . = ..() if(!.) return @@ -452,24 +465,32 @@ //Found our victims, now lets shock them all for(var/victim in shocking_queue) var/mob/living/carbon/C = victim - C.electrocute_act(shock_damage*0.75, src, 1, flags) + C.electrocute_act(shock_damage*0.75, src, 1, flags, jitter_time, stutter_time, stun_duration) //Stun var/should_stun = (!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN) - if(should_stun) - StaminaKnockdown(10, TRUE) - //Paralyze(40) - SKYRAT EDIT REMOVAL + var/paralyze = !(flags & SHOCK_KNOCKDOWN) + var/immediately_stun = should_stun && !(flags & SHOCK_DELAY_STUN) + if (immediately_stun) + if (paralyze) + //Paralyze(40) - SKYRAT EDIT REMOVAL + StaminaKnockdown(10, TRUE) // SKYRAT EDIT ADDITION + else + Knockdown(stun_duration) //Jitter and other fluff. do_jitter_animation(300) - adjust_jitter(20 SECONDS) - adjust_stutter(4 SECONDS) - addtimer(CALLBACK(src, PROC_REF(secondary_shock), should_stun), 2 SECONDS) + adjust_jitter(jitter_time) + adjust_stutter(stutter_time) + if (should_stun) + addtimer(CALLBACK(src, PROC_REF(secondary_shock), paralyze, stun_duration * 1.5), 2 SECONDS) return shock_damage ///Called slightly after electrocute act to apply a secondary stun. -/mob/living/carbon/proc/secondary_shock(should_stun) - if(should_stun) +/mob/living/carbon/proc/secondary_shock(paralyze, stun_duration) + if (paralyze) //Paralyze(60) - SKYRAT EDIT REMOVAL StaminaKnockdown(10, TRUE) //SKYRAT EDIT ADDITION + else + Knockdown(stun_duration) /mob/living/carbon/proc/help_shake_act(mob/living/carbon/helper) var/nosound = FALSE //SKYRAT EDIT ADDITION - EMOTES @@ -776,14 +797,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 +820,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 +875,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 ec44dcec13e..bcf5f495715 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 98827ae3ce3..6e0c7cef867 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)) @@ -157,12 +157,14 @@ //////////////////////////////////////////// ///Returns a list of damaged bodyparts -/mob/living/carbon/proc/get_damaged_bodyparts(brute = FALSE, burn = FALSE, required_bodytype) +/mob/living/carbon/proc/get_damaged_bodyparts(brute = FALSE, burn = FALSE, required_bodytype = NONE, target_zone = null) var/list/obj/item/bodypart/parts = list() for(var/X in bodyparts) var/obj/item/bodypart/BP = X if(required_bodytype && !(BP.bodytype & required_bodytype)) continue + if(!isnull(target_zone) && BP.body_zone != target_zone) + continue if((brute && BP.brute_dam) || (burn && BP.burn_dam)) parts += BP return parts @@ -197,8 +199,8 @@ * * It automatically updates health status */ -/mob/living/carbon/heal_bodypart_damage(brute = 0, burn = 0, updating_health = TRUE, required_bodytype) - var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute, burn, required_bodytype) +/mob/living/carbon/heal_bodypart_damage(brute = 0, burn = 0, updating_health = TRUE, required_bodytype = NONE, target_zone = null) + var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute, burn, required_bodytype, target_zone) if(!parts.len) return var/obj/item/bodypart/picked = pick(parts) diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index eb4bb54ea80..17718190ba5 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) @@ -844,6 +845,7 @@ GLOBAL_LIST_EMPTY(features_by_species) human_mob.undershirt = random_undershirt(human_mob.gender) human_mob.underwear = random_underwear(human_mob.gender) human_mob.socks = random_socks(human_mob.gender) + human_mob.bra = random_bra(human_mob.gender) //SKYRAT EDIT ADDITION - Underwear and Bra split ///Proc that will randomise the underwear (i.e. top, pants and socks) of a species' associated mob /datum/species/proc/randomize_active_underwear(mob/living/carbon/human/human_mob) @@ -1086,7 +1088,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 +1708,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 47cbbe12188..d4fc0b40365 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 2601aed8731..1fc148e7b64 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 427d9cf1003..40e4bf095d5 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/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 1475d61ed38..bc951d49bb7 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -484,7 +484,7 @@ ///Calculates the siemens coeff based on clothing and species, can also restart hearts. -/mob/living/carbon/human/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE) +/mob/living/carbon/human/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE, jitter_time = 20 SECONDS, stutter_time = 4 SECONDS, stun_duration = 4 SECONDS) //Calculates the siemens coeff based on clothing. Completely ignores the arguments if(flags & SHOCK_TESLA) //I hate this entire block. This gets the siemens_coeff for tesla shocks if(gloves && gloves.siemens_coefficient <= 0) @@ -521,7 +521,8 @@ var/obj/item/organ/internal/heart/heart = get_organ_slot(ORGAN_SLOT_HEART) if(heart.Restart() && stat == CONSCIOUS) to_chat(src, span_notice("You feel your heart beating again!")) - electrocution_animation(40) + if (!(flags & SHOCK_NO_HUMAN_ANIM)) + electrocution_animation(4 SECONDS) /mob/living/carbon/human/acid_act(acidpwr, acid_volume, bodyzone_hit) //todo: update this to utilize check_obscured_slots() //and make sure it's check_obscured_slots(TRUE) to stop aciding through visors etc var/list/damaged = list() diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 818ca1cf860..62fc77bc6ce 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -247,7 +247,6 @@ destination.socks = socks destination.jumpsuit_style = jumpsuit_style - /// Fully randomizes everything according to the given flags. /mob/living/carbon/human/proc/randomize_human_appearance(randomize_flags = ALL) var/datum/preferences/preferences = new(new /datum/client_interface) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index c468d9b750c..c91fc7d6638 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 9546a659e41..42c718477bc 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/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm index 495299574fb..243c1be83b3 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -49,13 +49,13 @@ /datum/species/monkey/on_species_gain(mob/living/carbon/human/H, datum/species/old_species) . = ..() - H.pass_flags |= PASSTABLE + passtable_on(H, SPECIES_TRAIT) H.dna.add_mutation(/datum/mutation/human/race, MUT_NORMAL) H.dna.activate_mutation(/datum/mutation/human/race) /datum/species/monkey/on_species_loss(mob/living/carbon/C) . = ..() - C.pass_flags = initial(C.pass_flags) + passtable_off(C, SPECIES_TRAIT) C.dna.remove_mutation(/datum/mutation/human/race) /datum/species/monkey/spec_unarmedattack(mob/living/carbon/human/user, atom/target, modifiers) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 45c441a13c2..e66d72a2c44 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 439101151c6..dfae5d2baf1 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)) @@ -323,7 +323,7 @@ * * needs to return amount healed in order to calculate things like tend wounds xp gain */ -/mob/living/proc/heal_bodypart_damage(brute = 0, burn = 0, updating_health = TRUE, required_bodytype) +/mob/living/proc/heal_bodypart_damage(brute = 0, burn = 0, updating_health = TRUE, required_bodytype = NONE, target_zone = null) . = (adjustBruteLoss(-brute, FALSE) + adjustFireLoss(-burn, FALSE)) //zero as argument for no instant health update if(updating_health) updatehealth() diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 6c3f397f6ba..c157603ea83 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 e5bcd813b7e..45924e2fe98 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 59db1264a30..8ee146508a4 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 9732222f0cf..30559e616b5 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 b4b4dd80f7f..71008588465 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 d01e36c334b..12f33dec723 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 8c46d8bec9c..220c4a5ccce 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 5af3e6ebad4..9c06465b8a5 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 b095016827f..a0f078acd92 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 38c3585271a..d4353c95c82 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 b57ae45e1b7..ebd5658f07f 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 4269f847d92..2c0b9ba983a 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/jungle/seedling.dm b/code/modules/mob/living/simple_animal/hostile/jungle/seedling.dm deleted file mode 100644 index 5cb22b75521..00000000000 --- a/code/modules/mob/living/simple_animal/hostile/jungle/seedling.dm +++ /dev/null @@ -1,240 +0,0 @@ -#define SEEDLING_STATE_NEUTRAL 0 -#define SEEDLING_STATE_WARMUP 1 -#define SEEDLING_STATE_ACTIVE 2 -#define SEEDLING_STATE_RECOVERY 3 - -//A plant rooted in the ground that forfeits its melee attack in favor of ranged barrages. -//It will fire flurries of solar energy, and occasionally charge up a powerful blast that makes it vulnerable to attack. -/mob/living/simple_animal/hostile/jungle/seedling - name = "seedling" - desc = "This oversized, predatory flower conceals what can only be described as an organic energy cannon, and it will not die until its hidden vital organs are sliced out. \ - The concentrated streams of energy it sometimes produces require its full attention, attacking it during this time will prevent it from finishing its attack." - icon = 'icons/mob/simple/jungle/seedling.dmi' - icon_state = "seedling" - icon_living = "seedling" - icon_dead = "seedling_dead" - mob_biotypes = MOB_ORGANIC | MOB_PLANT - maxHealth = 100 - health = 100 - melee_damage_lower = 30 - melee_damage_upper = 30 - SET_BASE_PIXEL(-16, -14) - - minimum_distance = 3 - move_to_delay = 20 - vision_range = 9 - aggro_vision_range = 15 - ranged = TRUE - ranged_cooldown_time = 10 - projectiletype = /obj/projectile/seedling - projectilesound = 'sound/weapons/pierce.ogg' - robust_searching = TRUE - stat_attack = HARD_CRIT - move_resist = MOVE_FORCE_EXTREMELY_STRONG - var/combatant_state = SEEDLING_STATE_NEUTRAL - var/mob/living/beam_debuff_target - var/solar_beam_identifier = 0 - -/obj/projectile/seedling - name = "solar energy" - icon_state = "seedling" - damage = 10 - damage_type = BURN - light_range = 2 - armor_flag = ENERGY - light_color = LIGHT_COLOR_DIM_YELLOW - hitsound = 'sound/weapons/sear.ogg' - hitsound_wall = 'sound/weapons/effects/searwall.ogg' - nondirectional_sprite = TRUE - -/obj/projectile/seedling/Bump(atom/A)//Stops seedlings from destroying other jungle mobs through FF - if(isliving(A)) - var/mob/living/L = A - if(FACTION_JUNGLE in L.faction) - return FALSE - return ..() - -/obj/effect/temp_visual/solarbeam_killsat - name = "beam of solar energy" - icon_state = "solar_beam" - icon = 'icons/effects/beam.dmi' - plane = LIGHTING_PLANE - layer = LIGHTING_PRIMARY_LAYER - duration = 5 - randomdir = FALSE - -/datum/status_effect/seedling_beam_indicator - id = "seedling beam indicator" - duration = 3 SECONDS - status_type = STATUS_EFFECT_MULTIPLE - alert_type = null - tick_interval = 0.2 SECONDS - var/atom/movable/screen/seedling/seedling_screen_object - var/atom/target - - -/datum/status_effect/seedling_beam_indicator/on_creation(mob/living/new_owner, target_plant) - . = ..() - if(.) - target = target_plant - tick() - -/datum/status_effect/seedling_beam_indicator/on_apply() - if(owner.client) - seedling_screen_object = new /atom/movable/screen/seedling() - owner.client.screen += seedling_screen_object - tick() - return ..() - -/datum/status_effect/seedling_beam_indicator/Destroy() - if(owner) - if(owner.client) - owner.client.screen -= seedling_screen_object - return ..() - -/datum/status_effect/seedling_beam_indicator/tick(seconds_between_ticks) - var/target_angle = get_angle(owner, target) - var/matrix/final = matrix() - final.Turn(target_angle) - seedling_screen_object.transform = final - -/atom/movable/screen/seedling - icon = 'icons/mob/simple/jungle/arachnid.dmi' - icon_state = "seedling_beam_indicator" - screen_loc = "CENTER:-16,CENTER:-16" - -/mob/living/simple_animal/hostile/jungle/seedling/Goto() - if(combatant_state != SEEDLING_STATE_NEUTRAL) - return - return ..() - -/mob/living/simple_animal/hostile/jungle/seedling/AttackingTarget() - if(isliving(target)) - if(ranged_cooldown <= world.time && combatant_state == SEEDLING_STATE_NEUTRAL) - OpenFire(target) - return - return ..() - -/mob/living/simple_animal/hostile/jungle/seedling/OpenFire() - WarmupAttack() - -/mob/living/simple_animal/hostile/jungle/seedling/proc/WarmupAttack() - if(combatant_state == SEEDLING_STATE_NEUTRAL) - combatant_state = SEEDLING_STATE_WARMUP - SSmove_manager.stop_looping(src) - update_icons() - var/target_dist = get_dist(src,target) - var/living_target_check = isliving(target) - if(living_target_check) - if(target_dist > 7)//Offscreen check - SolarBeamStartup(target) - return - if(get_dist(src,target) >= 4 && prob(40)) - SolarBeamStartup(target) - return - addtimer(CALLBACK(src, PROC_REF(Volley)), 5) - -/mob/living/simple_animal/hostile/jungle/seedling/proc/SolarBeamStartup(mob/living/living_target)//It's more like requiem than final spark - if(combatant_state == SEEDLING_STATE_WARMUP && target) - combatant_state = SEEDLING_STATE_ACTIVE - living_target.apply_status_effect(/datum/status_effect/seedling_beam_indicator, src) - beam_debuff_target = living_target - playsound(src,'sound/effects/seedling_chargeup.ogg', 100, FALSE) - if(get_dist(src,living_target) > 7) - playsound(living_target,'sound/effects/seedling_chargeup.ogg', 100, FALSE) - solar_beam_identifier = world.time - addtimer(CALLBACK(src, PROC_REF(Beamu), living_target, solar_beam_identifier), 35) - -/mob/living/simple_animal/hostile/jungle/seedling/proc/Beamu(mob/living/living_target, beam_id = 0) - if(combatant_state == SEEDLING_STATE_ACTIVE && living_target && beam_id == solar_beam_identifier) - if(living_target.z == z) - update_icons() - var/obj/effect/temp_visual/solarbeam_killsat/S = new (get_turf(src)) - var/matrix/starting = matrix() - starting.Scale(1,32) - starting.Translate(0,520) - S.transform = starting - var/obj/effect/temp_visual/solarbeam_killsat/K = new (get_turf(living_target)) - var/matrix/final = matrix() - final.Scale(1,32) - final.Translate(0,512) - K.transform = final - living_target.adjustFireLoss(30) - living_target.adjust_fire_stacks(0.2)//Just here for the showmanship - living_target.ignite_mob() - playsound(living_target,'sound/weapons/sear.ogg', 50, TRUE) - addtimer(CALLBACK(src, PROC_REF(AttackRecovery)), 5) - return - AttackRecovery() - -/mob/living/simple_animal/hostile/jungle/seedling/proc/Volley() - if(combatant_state == SEEDLING_STATE_WARMUP && target) - combatant_state = SEEDLING_STATE_ACTIVE - update_icons() - var/datum/callback/cb = CALLBACK(src, PROC_REF(InaccurateShot)) - for(var/i in 1 to 13) - addtimer(cb, i) - addtimer(CALLBACK(src, PROC_REF(AttackRecovery)), 14) - -/mob/living/simple_animal/hostile/jungle/seedling/proc/InaccurateShot() - if(!QDELETED(target) && combatant_state == SEEDLING_STATE_ACTIVE && !stat) - if(get_dist(src,target) <= 3)//If they're close enough just aim straight at them so we don't miss at point blank ranges - Shoot(target) - return - var/turf/our_turf = get_turf(src) - var/obj/projectile/seedling/readied_shot = new /obj/projectile/seedling(our_turf) - readied_shot.preparePixelProjectile(target, src, null, rand(-10, 10)) - readied_shot.fire() - playsound(src, projectilesound, 100, TRUE) - -/mob/living/simple_animal/hostile/jungle/seedling/proc/AttackRecovery() - if(combatant_state == SEEDLING_STATE_ACTIVE) - combatant_state = SEEDLING_STATE_RECOVERY - update_icons() - ranged_cooldown = world.time + ranged_cooldown_time - if(target) - face_atom(target) - addtimer(CALLBACK(src, PROC_REF(ResetNeutral)), 10) - -/mob/living/simple_animal/hostile/jungle/seedling/proc/ResetNeutral() - combatant_state = SEEDLING_STATE_NEUTRAL - if(target && !stat) - update_icons() - Goto(target, move_to_delay, minimum_distance) - -/mob/living/simple_animal/hostile/jungle/seedling/adjustHealth(amount, updating_health = TRUE, forced = FALSE) - . = ..() - if(combatant_state == SEEDLING_STATE_ACTIVE && beam_debuff_target) - beam_debuff_target.remove_status_effect(/datum/status_effect/seedling_beam_indicator) - beam_debuff_target = null - solar_beam_identifier = 0 - AttackRecovery() - -/mob/living/simple_animal/hostile/jungle/seedling/update_icons() - . = ..() - if(!stat) - switch(combatant_state) - if(SEEDLING_STATE_NEUTRAL) - icon_state = "seedling" - if(SEEDLING_STATE_WARMUP) - icon_state = "seedling_charging" - if(SEEDLING_STATE_ACTIVE) - icon_state = "seedling_fire" - if(SEEDLING_STATE_RECOVERY) - icon_state = "seedling" - -/mob/living/simple_animal/hostile/jungle/seedling/GiveTarget() - if(target) - if(combatant_state == SEEDLING_STATE_WARMUP || combatant_state == SEEDLING_STATE_ACTIVE)//So it doesn't 180 and blast you in the face while it's firing at someone else - return - return ..() - -/mob/living/simple_animal/hostile/jungle/seedling/LoseTarget() - if(combatant_state == SEEDLING_STATE_WARMUP || combatant_state == SEEDLING_STATE_ACTIVE) - return - return ..() - -#undef SEEDLING_STATE_NEUTRAL -#undef SEEDLING_STATE_WARMUP -#undef SEEDLING_STATE_ACTIVE -#undef SEEDLING_STATE_RECOVERY 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 360381c9c1c..3484c27375d 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/brimdemon.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/brimdemon.dm deleted file mode 100644 index d9bd88cb889..00000000000 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/brimdemon.dm +++ /dev/null @@ -1,242 +0,0 @@ -#define BRIMBEAM_RANGE 10 - -/mob/living/simple_animal/hostile/asteroid/brimdemon - name = "brimdemon" - desc = "A misshapen demon with big, red eyes and a hinged mouth. Not much is known about the creatures \ - due to their response to any unexpected stimulus being \"brimbeam\", a deadly blood-laser barrage." - icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi' - icon_state = "brimdemon" - icon_living = "brimdemon" - icon_dead = "brimdemon_dead" - mob_biotypes = MOB_ORGANIC|MOB_BEAST - speak_emote = list("cackles") - emote_taunt = list("screeches") - emote_hear = list("cackles","screeches") - combat_mode = TRUE - stat_attack = HARD_CRIT - ranged_cooldown_time = 5 SECONDS - vision_range = 9 - retreat_distance = 2 - speed = 3 - move_to_delay = 5 - maxHealth = 250 - health = 250 - obj_damage = 15 - melee_damage_lower = 7.5 - melee_damage_upper = 7.5 - rapid_melee = 2 // every second attack - attack_verb_continuous = "bites" - attack_verb_simple = "bite" - attack_sound = 'sound/weapons/bite.ogg' - attack_vis_effect = ATTACK_EFFECT_BITE - butcher_results = list( - /obj/item/food/meat/slab = 2, - /obj/effect/decal/cleanable/brimdust = 1, - /obj/item/organ/internal/monster_core/brimdust_sac = 1, - ) - loot = list() - robust_searching = TRUE - footstep_type = FOOTSTEP_MOB_CLAW - death_message = "wails as infernal energy escapes from its wounds, leaving it an empty husk." - death_sound = 'sound/magic/demon_dies.ogg' - light_color = LIGHT_COLOR_BLOOD_MAGIC - light_power = 5 - light_range = 1.4 - crusher_loot = /obj/item/crusher_trophy/brimdemon_fang - /// Are we charging/firing? If yes stops our movement. - var/firing = FALSE - /// A list of all the beam parts. - var/list/beamparts = list() - -/mob/living/simple_animal/hostile/asteroid/brimdemon/Destroy() - QDEL_LIST(beamparts) - return ..() - -/mob/living/simple_animal/hostile/asteroid/brimdemon/Login() - ranged = TRUE - return ..() - -/mob/living/simple_animal/hostile/asteroid/brimdemon/Logout() - ranged = FALSE - return ..() - -/mob/living/simple_animal/hostile/asteroid/brimdemon/death() - firing = FALSE - cut_overlay("brimdemon_telegraph_dir") - move_resist = initial(move_resist) - return ..() - -/mob/living/simple_animal/hostile/asteroid/brimdemon/Goto(target, delay, minimum_distance) - if(firing) - return FALSE - return ..() - -/mob/living/simple_animal/hostile/asteroid/brimdemon/MoveToTarget(list/possible_targets) - if(firing) - return FALSE - return ..() - -/mob/living/simple_animal/hostile/asteroid/brimdemon/AttackingTarget(atom/attacked_target) - if(firing) - return FALSE - return ..() - -/mob/living/simple_animal/hostile/asteroid/brimdemon/Move(atom/newloc, dir, step_x , step_y) - if(firing) - return FALSE - return ..() - -/mob/living/simple_animal/hostile/asteroid/brimdemon/OpenFire() - if(firing) - balloon_alert(src, "already firing!") - return - if(!COOLDOWN_FINISHED(src, ranged_cooldown)) - balloon_alert(src, "on cooldown!") - return - firing = TRUE - set_dir_on_move = FALSE - icon_state = "brimdemon_firing" - move_resist = MOVE_FORCE_VERY_STRONG - add_overlay("brimdemon_telegraph_dir") - visible_message(span_danger("[src] starts charging!")) - balloon_alert(src, "charging...") - addtimer(CALLBACK(src, PROC_REF(fire_laser)), 1 SECONDS) - COOLDOWN_START(src, ranged_cooldown, ranged_cooldown_time) - -/mob/living/simple_animal/hostile/asteroid/brimdemon/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) - . = ..() - check_fire() - -/mob/living/simple_animal/hostile/asteroid/brimdemon/proc/check_fire() - if(key || QDELETED(target) || get_dist(src, target) > BRIMBEAM_RANGE || !(get_dir(src, target) in GLOB.cardinals)) - return - face_atom(target) - OpenFire() - -/// Fires a brimbeam, getting a line of turfs between it and the direction to the target and creating a brimbeam effect on every one of them. -/mob/living/simple_animal/hostile/asteroid/brimdemon/proc/fire_laser() - if(stat == DEAD) - return - visible_message(span_danger("[src] fires a brimbeam!")) - balloon_alert(src, "brimbeam fired") - playsound(src, 'sound/creatures/brimdemon.ogg', 150, FALSE, 0, 3) - cut_overlay("brimdemon_telegraph_dir") - var/turf/target_turf = get_ranged_target_turf(src, dir, BRIMBEAM_RANGE) - var/turf/origin_turf = get_turf(src) - var/list/affected_turfs = get_line(origin_turf, target_turf) - origin_turf - for(var/turf/affected_turf in affected_turfs) - var/blocked = FALSE - if(affected_turf.opacity) - blocked = TRUE - for(var/obj/potential_block in affected_turf.contents) - if(potential_block.opacity) - blocked = TRUE - break - if(blocked) - break - var/atom/new_brimbeam = new /obj/effect/brimbeam(affected_turf) - new_brimbeam.dir = dir - beamparts += new_brimbeam - for(var/mob/living/hit_mob in affected_turf.contents) - hit_mob.adjustFireLoss(25) - to_chat(hit_mob, span_userdanger("You're hit by [src]'s brimbeam!")) - if(length(beamparts)) - var/atom/last_brimbeam = beamparts[length(beamparts)] - last_brimbeam.icon_state = "brimbeam_end" - var/atom/first_brimbeam = beamparts[1] - first_brimbeam.icon_state = "brimbeam_start" - addtimer(CALLBACK(src, PROC_REF(end_laser)), 2 SECONDS) - -/// Deletes all the brimbeam parts and sets variables back to their initial ones. -/mob/living/simple_animal/hostile/asteroid/brimdemon/proc/end_laser() - if(stat != DEAD) - icon_state = initial(icon_state) - move_resist = initial(move_resist) - set_dir_on_move = initial(set_dir_on_move) - firing = FALSE - for(var/obj/effect/brimbeam/beam in beamparts) - animate(beam, time = 0.5 SECONDS, alpha = 0) - QDEL_IN(beam, 0.5 SECONDS) - beamparts -= beam - -/obj/effect/brimbeam - name = "brimbeam" - icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi' - icon_state = "brimbeam_mid" - layer = ABOVE_MOB_LAYER - plane = ABOVE_GAME_PLANE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - light_color = LIGHT_COLOR_BLOOD_MAGIC - light_power = 3 - light_range = 2 - -/obj/effect/brimbeam/Initialize(mapload) - . = ..() - START_PROCESSING(SSfastprocess, src) - -/obj/effect/brimbeam/Destroy() - STOP_PROCESSING(SSfastprocess, src) - return ..() - -/obj/effect/brimbeam/process() - for(var/mob/living/hit_mob in get_turf(src)) - damage(hit_mob) - -/obj/effect/brimbeam/proc/damage(mob/living/hit_mob) - hit_mob.adjustFireLoss(5) - to_chat(hit_mob, span_danger("You're damaged by [src]!")) - -/obj/item/crusher_trophy/brimdemon_fang - name = "brimdemon's fang" - icon_state = "brimdemon_fang" - desc = "A fang from a brimdemon's corpse." - denied_type = /obj/item/crusher_trophy/brimdemon_fang - var/static/list/comic_phrases = list("BOOM", "BANG", "KABLOW", "KAPOW", "OUCH", "BAM", "KAPOW", "WHAM", "POW", "KABOOM") - -/obj/item/crusher_trophy/brimdemon_fang/effect_desc() - return "mark detonation creates visual and audiosensory effects on the target" - -/obj/item/crusher_trophy/brimdemon_fang/on_mark_detonation(mob/living/target, mob/living/user) - target.balloon_alert_to_viewers("[pick(comic_phrases)]!") - playsound(target, 'sound/lavaland/brimdemon_crush.ogg', 100) - -/obj/effect/decal/cleanable/brimdust - name = "brimdust" - desc = "Dust from a brimdemon. It is considered valuable for its' botanical abilities." - icon_state = "brimdust" - icon = 'icons/obj/mining.dmi' - layer = FLOOR_CLEAN_LAYER - mergeable_decal = FALSE - -/obj/effect/decal/cleanable/brimdust/Initialize(mapload) - . = ..() - reagents.add_reagent(/datum/reagent/brimdust, 15) - -/obj/item/ore_sensor - name = "ore sensor" - desc = "Using demonic frequencies, this ear-mounted tool detects ores in the nearby terrain." - icon_state = "oresensor" - icon = 'icons/obj/mining.dmi' - slot_flags = ITEM_SLOT_EARS - var/range = 5 - var/cooldown = 4 SECONDS //between the standard and the advanced ore scanner in strength - COOLDOWN_DECLARE(ore_sensing_cooldown) - -/obj/item/ore_sensor/equipped(mob/user, slot, initial) - . = ..() - if(slot & ITEM_SLOT_EARS) - START_PROCESSING(SSobj, src) - else - STOP_PROCESSING(SSobj, src) - -/obj/item/ore_sensor/dropped(mob/user, silent) - . = ..() - STOP_PROCESSING(SSobj, src) - -/obj/item/ore_sensor/process(seconds_per_tick) - if(!COOLDOWN_FINISHED(src, ore_sensing_cooldown)) - return - COOLDOWN_START(src, ore_sensing_cooldown, cooldown) - mineral_scan_pulse(get_turf(src), range) - -#undef BRIMBEAM_RANGE diff --git a/code/modules/mob/living/simple_animal/revenant.dm b/code/modules/mob/living/simple_animal/revenant.dm index 82c2be6920a..6e2ec11afea 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 cefd88c72ef..09ce3b3c65c 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/mob_spawn/mob_spawn.dm b/code/modules/mob_spawn/mob_spawn.dm index a254c5511aa..a853d48c0ec 100644 --- a/code/modules/mob_spawn/mob_spawn.dm +++ b/code/modules/mob_spawn/mob_spawn.dm @@ -58,6 +58,7 @@ spawned_human.underwear = "Nude" spawned_human.undershirt = "Nude" spawned_human.socks = "Nude" + spawned_human.bra = "Nude" //SKYRAT EDIT ADDITION if(hairstyle) spawned_human.hairstyle = hairstyle else diff --git a/code/modules/mod/mod_actions.dm b/code/modules/mod/mod_actions.dm index d82912055e2..111ea425b6a 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 521dd6f0240..9adaaf4f146 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 2f2be1dc86e..f11c6b9b4b9 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 d5699986ee9..a3067e0c150 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 f64d808b7a7..6d47a5b60ba 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 da83445a641..21d2b8352fb 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 bc57f359784..a4b08f2d90f 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 2e1eb52add5..01afaa08c19 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 28a6e12843f..00000000000 --- 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 31cbe153f9e..9586ec6e861 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 8d62bf784cb..a5902a9df5a 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 33c22c66aef..1c0e360ed75 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 6b48e29da52..d928164ff01 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 5e3c3b0f5d3..e70977bc1f4 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 7b3a62c9939..a8e6e7ae3ac 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 b9f60aea016..fb9fd389c17 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 3ab8ece250f..f36c9b13038 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 2486a6500c1..ed4b2159cab 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 5a8f406b86c..05d9533c79e 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 d3e4fe9e808..0a797a2d7d6 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 15fba3cc8fe..654ea805440 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 5c68669e6e2..452b37e0541 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 c9df8496389..505dc36f02c 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 9641adc29b5..e492afb776b 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 e1f233d51f8..53ff1f8a350 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 788c0f7810d..808cbdfbfe7 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 bedfab7b235..24fba4b9ba4 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 c6737fd3cab..9135e3ec5b9 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 ddacb419bbe..e76af741a18 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' @@ -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 61dcb1748e4..576ba6395be 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 d9443719a7e..5d33b3fce51 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 68479abbf47..8869da14a59 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 6644accd8a5..eed27478755 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 60bec6ac3b0..2f5fa84c441 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 446654a3489..639939e150f 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/curse.dm b/code/modules/projectiles/projectile/special/curse.dm index 3eaf6e8c7e3..624af8867eb 100644 --- a/code/modules/projectiles/projectile/special/curse.dm +++ b/code/modules/projectiles/projectile/special/curse.dm @@ -1,7 +1,5 @@ /obj/effect/ebeam/curse_arm name = "curse arm" - layer = LARGE_MOB_LAYER - plane = GAME_PLANE_UPPER_FOV_HIDDEN /obj/projectile/curse_hand name = "curse hand" diff --git a/code/modules/projectiles/projectile/special/lightbreaker.dm b/code/modules/projectiles/projectile/special/lightbreaker.dm new file mode 100644 index 00000000000..fd7d3d89e7a --- /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 cb8a30f61b8..902ccf35e6a 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 dc0c51edd53..26ebfa1d18d 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 016253baa3e..8de1d98cc2e 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 2299cab5493..817e5ed98bf 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 665ecb2577e..693404431fa 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 d40ca4fd85b..f67b813be0c 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 83aa18eebb5..36444d6229b 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 060351a8c88..23d6010f1a9 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 e8a50d832e0..1e0559d6034 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)) @@ -685,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" @@ -724,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 d14df37ce96..f7eaba3c211 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 8e09b318d1c..db98ed9d622 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 86978985ff8..30fae4db9c7 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" @@ -590,7 +597,7 @@ ..() /datum/reagent/medicine/ephedrine/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - if(SPT_PROB(10 * (1-creation_purity), seconds_per_tick) && iscarbon(affected_mob)) + if(SPT_PROB(10 * (1.5-creation_purity), seconds_per_tick) && iscarbon(affected_mob)) var/obj/item/I = affected_mob.get_active_held_item() if(I && affected_mob.dropItemToGround(I)) to_chat(affected_mob, span_notice("Your hands spaz out and you drop what you were holding!")) @@ -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) . = ..() @@ -844,14 +854,13 @@ ..() /datum/reagent/medicine/epinephrine/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - . = TRUE if(holder.has_reagent(/datum/reagent/toxin/lexorin)) holder.remove_reagent(/datum/reagent/toxin/lexorin, 2 * REM * seconds_per_tick) holder.remove_reagent(/datum/reagent/medicine/epinephrine, 1 * REM * seconds_per_tick) 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) @@ -868,6 +877,7 @@ if(SPT_PROB(10, seconds_per_tick)) affected_mob.AdjustAllImmobility(-20) ..() + return TRUE /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 54fa4391790..2a46d537233 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 0d52ca4e825..6f99273ad4e 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 a9735cd7e75..d655698646c 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 cd755532fb3..e3f1fd1acef 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 1c77ff5f6c1..b632bc7b6c8 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 990ace10830..592a281ed73 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 b4e80e01cd0..0fcae783d89 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 ad83d2c439c..b5930955a31 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 a19e7fbe7f3..28c26c5d356 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 5f8ebecd990..ef48a50af21 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 84173388518..cb1a0800c51 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 a4b914d66b8..06f4e52a31c 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/religion_sects.dm b/code/modules/religion/religion_sects.dm index 0a2486595b2..a322303b00d 100644 --- a/code/modules/religion/religion_sects.dm +++ b/code/modules/religion/religion_sects.dm @@ -58,6 +58,13 @@ to_chat(chap, "\"[quote]\"") to_chat(chap, "[desc]") +/// Activates if religious sect is reset by admins, should clean up anything you added on conversion. +/datum/religion_sect/proc/on_deconversion(mob/living/chap) + SHOULD_CALL_PARENT(TRUE) + to_chat(chap, span_boldnotice("You have lost the approval of \the [name].")) + if(chap.mind.holy_role == HOLY_ROLE_HIGHPRIEST) + to_chat(chap, span_notice("Return to an altar to reform your sect.")) + /// Returns TRUE if the item can be sacrificed. Can be modified to fit item being tested as well as person offering. Returning TRUE will stop the attackby sequence and proceed to on_sacrifice. /datum/religion_sect/proc/can_sacrifice(obj/item/I, mob/living/chap) . = TRUE @@ -292,6 +299,11 @@ return new_convert.gain_trauma(/datum/brain_trauma/special/burdened, TRAUMA_RESILIENCE_MAGIC) +/datum/religion_sect/burden/on_deconversion(mob/living/carbon/human/new_convert) + if (ishuman(new_convert)) + new_convert.cure_trauma_type(/datum/brain_trauma/special/burdened, TRAUMA_RESILIENCE_MAGIC) + return ..() + /datum/religion_sect/burden/tool_examine(mob/living/carbon/human/burdened) //display burden level if(!ishuman(burdened)) return FALSE @@ -333,6 +345,11 @@ return FALSE new_convert.gain_trauma(/datum/brain_trauma/special/honorbound, TRAUMA_RESILIENCE_MAGIC) +/datum/religion_sect/honorbound/on_deconversion(mob/living/carbon/human/new_convert) + if (ishuman(new_convert)) + new_convert.cure_trauma_type(/datum/brain_trauma/special/honorbound, TRAUMA_RESILIENCE_MAGIC) + return ..() + #define MINIMUM_YUCK_REQUIRED 5 /datum/religion_sect/maintenance diff --git a/code/modules/religion/religion_structures.dm b/code/modules/religion/religion_structures.dm index e9dcfffff48..ae61004b46e 100644 --- a/code/modules/religion/religion_structures.dm +++ b/code/modules/religion/religion_structures.dm @@ -61,7 +61,10 @@ . += list(span_notice("Chaplains: [chaplains].")) /obj/structure/altar_of_gods/proc/reflect_sect_in_icons() - if(GLOB.religious_sect) + if(isnull(GLOB.religious_sect)) + icon = initial(icon) + icon_state = initial(icon_state) + else sect_to_altar = GLOB.religious_sect if(sect_to_altar.altar_icon) icon = sect_to_altar.altar_icon diff --git a/code/modules/religion/rites.dm b/code/modules/religion/rites.dm index c7e38145349..d907191c33d 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 6597c12fbec..1c44e8bc4fb 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 a9afd6b3a08..0c1e3498dc1 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/designs/tool_designs.dm b/code/modules/research/designs/tool_designs.dm index ed617fb9ac1..ee1e09b1143 100644 --- a/code/modules/research/designs/tool_designs.dm +++ b/code/modules/research/designs/tool_designs.dm @@ -39,7 +39,6 @@ departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING autolathe_exportable = FALSE -/* SKYRAT EDIT - MOVED TO modular_skyrat/modules/electric_welder/code/electric_welder.dm /datum/design/exwelder name = "Experimental Welding Tool" desc = "An experimental welder capable of self-fuel generation." @@ -51,7 +50,6 @@ RND_CATEGORY_TOOLS + RND_SUBCATEGORY_TOOLS_ENGINEERING_ADVANCED ) departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING -*/ /datum/design/rangedanalyzer name = "Experimental Long-range Gas Analyzer" diff --git a/code/modules/research/server.dm b/code/modules/research/server.dm index b79bf3f8e02..45a0a520fa0 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 bdeeec6df4a..86b9f2dfafe 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 e3fcdba9d64..2ec692f0575 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) @@ -1219,6 +1221,8 @@ design_ids = list( "comm_monitor", "comm_server", + "gigabeacon", + "message_monitor", "ntnet_relay", "s_amplifier", "s_analyzer", @@ -1235,7 +1239,6 @@ "s_server", "s_transmitter", "s_treatment", - "gigabeacon", ) /datum/techweb_node/integrated_hud diff --git a/code/modules/research/xenobiology/crossbreeding/_misc.dm b/code/modules/research/xenobiology/crossbreeding/_misc.dm index 8fc4d50a98c..8eb166bf820 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 a7287055794..61f4e7a72e0 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 cb7070c83a4..8941057453b 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 43bfd2dbe8a..007bacf8bb7 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/research/xenobiology/vatgrowing/samples/cell_lines/common.dm b/code/modules/research/xenobiology/vatgrowing/samples/cell_lines/common.dm index bec3092d8ea..abb764d0689 100644 --- a/code/modules/research/xenobiology/vatgrowing/samples/cell_lines/common.dm +++ b/code/modules/research/xenobiology/vatgrowing/samples/cell_lines/common.dm @@ -481,7 +481,7 @@ /datum/micro_organism/cell_line/clown/fuck_up_growing(obj/machinery/plumbing/growing_vat/vat) vat.visible_message(span_warning("The biological sample in [vat] seems to have created something horrific!")) - var/mob/selected_mob = pick(list(/mob/living/simple_animal/hostile/retaliate/clown/mutant/slow, /mob/living/simple_animal/hostile/retaliate/clown/fleshclown)) + var/mob/selected_mob = pick(list(/mob/living/basic/clown/mutant/slow, /mob/living/basic/clown/fleshclown)) new selected_mob(get_turf(vat)) if(SEND_SIGNAL(vat.biological_sample, COMSIG_SAMPLE_GROWTH_COMPLETED) & SPARE_SAMPLE) @@ -509,7 +509,7 @@ /datum/reagent/consumable/nothing = -2, /datum/reagent/fuel/oil = -1) - resulting_atoms = list(/mob/living/simple_animal/hostile/retaliate/clown/banana = 1) + resulting_atoms = list(/mob/living/basic/clown/banana = 1) /datum/micro_organism/cell_line/clown/glutton desc = "hyperadipogenic clown stem cells" @@ -535,7 +535,7 @@ /datum/reagent/consumable/nothing = -2, /datum/reagent/toxin/bad_food = -1) - resulting_atoms = list(/mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton = 1) + resulting_atoms = list(/mob/living/basic/clown/mutant/glutton = 1) /datum/micro_organism/cell_line/clown/longclown desc = "long clown bits" @@ -558,7 +558,7 @@ /datum/reagent/consumable/nothing = -2, /datum/reagent/sulfur = -1) - resulting_atoms = list(/mob/living/simple_animal/hostile/retaliate/clown/longface = 1) + resulting_atoms = list(/mob/living/basic/clown/longface = 1) /datum/micro_organism/cell_line/frog desc = "anura amphibian cells" diff --git a/code/modules/security_levels/security_level_datums.dm b/code/modules/security_levels/security_level_datums.dm index 8ed94e50411..175b79d1c87 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 3542102b329..ab2be975307 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 2ef513bb015..4ae1c241d06 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 aad6135c45a..966f618376d 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/pointed/_pointed.dm b/code/modules/spells/spell_types/pointed/_pointed.dm index 3d1c5b91b81..04c3ed47944 100644 --- a/code/modules/spells/spell_types/pointed/_pointed.dm +++ b/code/modules/spells/spell_types/pointed/_pointed.dm @@ -64,17 +64,17 @@ build_all_button_icons() return TRUE -/datum/action/cooldown/spell/pointed/InterceptClickOn(mob/living/caller, params, atom/click_target) +/datum/action/cooldown/spell/pointed/InterceptClickOn(mob/living/caller, params, atom/target) var/atom/aim_assist_target - if(aim_assist && isturf(click_target)) + if(aim_assist && isturf(target)) // Find any human in the list. We aren't picky, it's aim assist after all - aim_assist_target = locate(/mob/living/carbon/human) in click_target + aim_assist_target = locate(/mob/living/carbon/human) in target if(!aim_assist_target) // If we didn't find a human, we settle for any living at all - aim_assist_target = locate(/mob/living) in click_target + aim_assist_target = locate(/mob/living) in target - return ..(caller, params, aim_assist_target || click_target) + return ..(caller, params, aim_assist_target || target) /datum/action/cooldown/spell/pointed/is_valid_target(atom/cast_on) if(cast_on == owner) diff --git a/code/modules/spells/spell_types/pointed/swap.dm b/code/modules/spells/spell_types/pointed/swap.dm index ddeb08b4b8a..6b4a5e45e14 100644 --- a/code/modules/spells/spell_types/pointed/swap.dm +++ b/code/modules/spells/spell_types/pointed/swap.dm @@ -35,27 +35,27 @@ return FALSE return TRUE -/datum/action/cooldown/spell/pointed/swap/InterceptClickOn(mob/living/caller, params, atom/click_target) +/datum/action/cooldown/spell/pointed/swap/InterceptClickOn(mob/living/caller, params, atom/target) if(LAZYACCESS(params2list(params), RIGHT_CLICK)) if(!IsAvailable(feedback = TRUE)) return FALSE if(!target) return FALSE - if(!isliving(click_target) || isturf(click_target)) + if(!isliving(target) || isturf(target)) // Find any living being in the list. We aren't picky, it's aim assist after all - click_target = locate(/mob/living) in click_target - if(!click_target) + target = locate(/mob/living) in target + if(!target) to_chat(owner, span_warning("You can only select living beings as secondary target!")) return FALSE - if(click_target == owner) + if(target == owner) if(!isnull(second_target)) to_chat(owner, span_notice("You cancel your secondary swap target!")) second_target = null else to_chat(owner, span_warning("You have no secondary swap target!")) return FALSE - second_target = click_target - to_chat(owner, span_notice("You select [click_target.name] as a secondary swap target!")) + second_target = target + to_chat(owner, span_notice("You select [target.name] as a secondary swap target!")) return FALSE return ..() 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 e10bdaebcc5..231b6927e50 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 9ac99c86b3c..ec29b326ae9 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 5967e3502dc..4b9c0114024 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 22a325f1974..5a7343f8a0b 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 d022e003f2f..4207f3541f6 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 0382f4b048f..37b6cef9897 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 db1407953b6..1b50dbc8fd1 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/organic_steps.dm b/code/modules/surgery/organic_steps.dm index a4c087059d6..73e48db857f 100644 --- a/code/modules/surgery/organic_steps.dm +++ b/code/modules/surgery/organic_steps.dm @@ -77,7 +77,7 @@ /datum/surgery_step/clamp_bleeders/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results) if(locate(/datum/surgery_step/saw) in surgery.steps) - target.heal_bodypart_damage(20,0) + target.heal_bodypart_damage(20, 0, target_zone = target_zone) if (ishuman(target)) var/mob/living/carbon/human/human_target = target var/obj/item/bodypart/target_bodypart = human_target.get_bodypart(target_zone) @@ -137,7 +137,7 @@ /datum/surgery_step/close/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results) if(locate(/datum/surgery_step/saw) in surgery.steps) - target.heal_bodypart_damage(45,0) + target.heal_bodypart_damage(45, 0, target_zone = target_zone) if (ishuman(target)) var/mob/living/carbon/human/human_target = target var/obj/item/bodypart/target_bodypart = human_target.get_bodypart(target_zone) diff --git a/code/modules/surgery/organs/autosurgeon.dm b/code/modules/surgery/organs/autosurgeon.dm index d28ffa4062c..0987df92bd9 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/external/wings/functional_wings.dm b/code/modules/surgery/organs/external/wings/functional_wings.dm index d2b4716df50..0cdca01f72c 100644 --- a/code/modules/surgery/organs/external/wings/functional_wings.dm +++ b/code/modules/surgery/organs/external/wings/functional_wings.dm @@ -107,12 +107,12 @@ if(!HAS_TRAIT_FROM(human, TRAIT_MOVE_FLYING, SPECIES_FLIGHT_TRAIT)) human.physiology.stun_mod *= 2 human.add_traits(list(TRAIT_NO_FLOATING_ANIM, TRAIT_MOVE_FLYING), SPECIES_FLIGHT_TRAIT) - passtable_on(human, SPECIES_TRAIT) + passtable_on(human, SPECIES_FLIGHT_TRAIT) open_wings() else human.physiology.stun_mod *= 0.5 human.remove_traits(list(TRAIT_NO_FLOATING_ANIM, TRAIT_MOVE_FLYING), SPECIES_FLIGHT_TRAIT) - passtable_off(human, SPECIES_TRAIT) + passtable_off(human, SPECIES_FLIGHT_TRAIT) close_wings() human.update_body_parts() diff --git a/code/modules/surgery/organs/internal/appendix/_appendix.dm b/code/modules/surgery/organs/internal/appendix/_appendix.dm index 835d7e62bed..a52479c10a7 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 55624e88bf1..0a7332c0dd8 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 54d35628f85..52f5d740520 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 f871fbd84db..fe5ca01df4f 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 ba66721433f..5e4e0648067 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 4f83b7844a4..bebeaacf110 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 1f26a63cc6a..e199df0ffd9 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 e469f16740a..20ca34d5259 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" @@ -162,6 +161,7 @@ #include "leash.dm" #include "lesserform.dm" #include "limbsanity.dm" +#include "ling_decap.dm" #include "liver.dm" #include "load_map_security.dm" #include "lungs.dm" diff --git a/code/modules/unit_tests/byond_status.dm b/code/modules/unit_tests/byond_status.dm deleted file mode 100644 index e2788831556..00000000000 --- 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 86b0cc69d1c..b767b010495 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 6c4a278a396..1ef15f8d0f5 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/ling_decap.dm b/code/modules/unit_tests/ling_decap.dm new file mode 100644 index 00000000000..0c964f9a043 --- /dev/null +++ b/code/modules/unit_tests/ling_decap.dm @@ -0,0 +1,45 @@ +/// Test lings don't die when decapitated. +/datum/unit_test/ling_decap + +/datum/unit_test/ling_decap/Run() + var/mob/living/carbon/human/ling = allocate(/mob/living/carbon/human/consistent) + ling.mind_initialize() + ling.mind.add_antag_datum(/datum/antagonist/changeling) + + var/obj/item/bodypart/head/noggin = ling.get_bodypart(BODY_ZONE_HEAD) + noggin.dismember() + TEST_ASSERT_NULL(ling.get_bodypart(BODY_ZONE_HEAD), "Changeling failed to be decapitated.") + TEST_ASSERT_NULL(noggin.brainmob.mind, "Changeling's mind was moved to their head after decapitation, but it should have remained in their body.") + + var/obj/item/organ/internal/brain/oldbrain = noggin.brain + noggin.drop_organs() + TEST_ASSERT_NULL(noggin.brain, "Changeling's head failed to drop its brain.") + TEST_ASSERT_NULL(oldbrain.brainmob.mind, "Changeling's mind was moved to their brain after decapitation and organ dropping, but it should have remained in their body.") + + TEST_ASSERT_EQUAL(ling.stat, CONSCIOUS, "Changeling was not conscious after losing their head.") + + // Cleanup + qdel(noggin) + for(var/obj/item/organ/leftover in ling.loc) + qdel(leftover) + +/// Tests people get decapitated properly. +/datum/unit_test/normal_decap + +/datum/unit_test/normal_decap/Run() + var/mob/living/carbon/human/normal_guy = allocate(/mob/living/carbon/human/consistent) + normal_guy.mind_initialize() + var/my_guys_mind = normal_guy.mind + + var/obj/item/bodypart/head/noggin = normal_guy.get_bodypart(BODY_ZONE_HEAD) + noggin.dismember() + TEST_ASSERT_EQUAL(noggin.brainmob.mind, my_guys_mind, "Dummy's mind was not moved to their head after decapitation.") + + var/obj/item/organ/internal/brain/oldbrain = noggin.brain + noggin.drop_organs() + TEST_ASSERT_EQUAL(oldbrain.brainmob.mind, my_guys_mind, "Dummy's mind was not moved to their brain after being removed from their head.") + + // Cleanup + qdel(noggin) + for(var/obj/item/organ/leftover in normal_guy.loc) + qdel(leftover) diff --git a/code/modules/unit_tests/medical_wounds.dm b/code/modules/unit_tests/medical_wounds.dm index 0838b2d18be..161492a726a 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 06ef0119d1c..fefeec4ad1d 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 2bba9484914..e53e0a86697 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 38dc4457973..e1bdbea1058 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 38dc4457973..e1bdbea1058 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 1bddc8f5011..76694152323 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/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index e6056b3e227..8de11513eaa 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -51,7 +51,6 @@ /mob/living/simple_animal/hostile/alien/queen/large, /mob/living/simple_animal/hostile/alien/sentinel, /mob/living/simple_animal/hostile/asteroid, - /mob/living/simple_animal/hostile/asteroid/brimdemon, /mob/living/simple_animal/hostile/asteroid/curseblob, /mob/living/simple_animal/hostile/asteroid/elite, /mob/living/simple_animal/hostile/asteroid/elite/broodmother, @@ -136,7 +135,6 @@ /mob/living/simple_animal/hostile/jungle, /mob/living/simple_animal/hostile/jungle/leaper, /mob/living/simple_animal/hostile/jungle/mook, - /mob/living/simple_animal/hostile/jungle/seedling, /mob/living/simple_animal/hostile/megafauna, /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner, /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/doom, @@ -178,19 +176,6 @@ /mob/living/simple_animal/hostile/pirate/ranged, /mob/living/simple_animal/hostile/pirate/ranged/space, /mob/living/simple_animal/hostile/retaliate, - /mob/living/simple_animal/hostile/retaliate/clown, - /mob/living/simple_animal/hostile/retaliate/clown/banana, - /mob/living/simple_animal/hostile/retaliate/clown/clownhulk, - /mob/living/simple_animal/hostile/retaliate/clown/clownhulk/chlown, - /mob/living/simple_animal/hostile/retaliate/clown/clownhulk/destroyer, - /mob/living/simple_animal/hostile/retaliate/clown/clownhulk/honcmunculus, - /mob/living/simple_animal/hostile/retaliate/clown/fleshclown, - /mob/living/simple_animal/hostile/retaliate/clown/honkling, - /mob/living/simple_animal/hostile/retaliate/clown/longface, - /mob/living/simple_animal/hostile/retaliate/clown/lube, - /mob/living/simple_animal/hostile/retaliate/clown/mutant, - /mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton, - /mob/living/simple_animal/hostile/retaliate/clown/mutant/slow, /mob/living/simple_animal/hostile/retaliate/goat, /mob/living/simple_animal/hostile/retaliate/goose, /mob/living/simple_animal/hostile/retaliate/goose/vomit, diff --git a/code/modules/unit_tests/teleporters.dm b/code/modules/unit_tests/teleporters.dm index 2cb047304fb..e1af0a71a35 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 20792cfae70..8a83e7450c5 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/job.dm b/code/modules/uplink/uplink_items/job.dm index 7ae06fb79df..b971e07619c 100644 --- a/code/modules/uplink/uplink_items/job.dm +++ b/code/modules/uplink/uplink_items/job.dm @@ -328,3 +328,10 @@ cost = 14 //High cost because of the potential for extreme damage in the hands of a skilled scientist. restricted_roles = list(JOB_RESEARCH_DIRECTOR, JOB_SCIENTIST) surplus = 5 + +/datum/uplink_item/role_restricted/evil_seedling + name = "Evil Seedling" + desc = "A rare seed we have recovered that grows into a dangerous species that will aid you with your tasks!" + item = /obj/item/seeds/seedling/evil + cost = 8 + restricted_roles = list(JOB_BOTANIST) diff --git a/code/modules/uplink/uplink_items/nukeops.dm b/code/modules/uplink/uplink_items/nukeops.dm index e25763350a8..632d4cc2717 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 f08e30a7554..1fd230bb47a 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/vehicles/vehicle_actions.dm b/code/modules/vehicles/vehicle_actions.dm index c1b48f04771..1fbf394d270 100644 --- a/code/modules/vehicles/vehicle_actions.dm +++ b/code/modules/vehicles/vehicle_actions.dm @@ -359,10 +359,10 @@ animate(vehicle, pixel_y = -6, time = 3) playsound(vehicle, 'sound/vehicles/skateboard_ollie.ogg', 50, TRUE) passtable_on(rider, VEHICLE_TRAIT) - vehicle.pass_flags |= PASSTABLE + passtable_on(vehicle, VEHICLE_TRAIT) rider.Move(landing_turf, vehicle_target.dir) passtable_off(rider, VEHICLE_TRAIT) - vehicle.pass_flags &= ~PASSTABLE + passtable_off(vehicle, VEHICLE_TRAIT) /datum/action/vehicle/ridden/scooter/skateboard/kickflip name = "Kickflip" diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index 298af4a7cf9..ab882bf7997 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 ec633084fd8..23b1bcf2c71 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 d12f43a880d..da2c08e04c9 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 7faa8d0f9c0..3b3e0d0746e 100644 --- a/config/config.txt +++ b/config/config.txt @@ -394,7 +394,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 7b951c28e46..6ac8f8f08c2 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/archive/2023-09.yml b/html/changelogs/archive/2023-09.yml index 972b5895d05..aa41425b439 100644 --- a/html/changelogs/archive/2023-09.yml +++ b/html/changelogs/archive/2023-09.yml @@ -349,3 +349,626 @@ 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 +2023-09-22: + A.C.M.O.: + - bugfix: Fixed dildos, allowing them to be used orally only when the target mouth + is uncovered. + - bugfix: Fixed custom dildos, allowing their size and color to be customized with + Alt-Click. + GoldenAlpharex: + - code_imp: Removed some old fire overlay code, which might or might not fix some + fire overlay issues. We'll have to see. + - 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. + LT3: + - image: Added donator items for grasshand + Literallynotpickles: + - rscadd: Added SHORTER Shorts to the Loadout Menu. (Misc Under) + SkyratBot: + - balance: Peacekeeper cyborg's emagged hug is no longer a hardstun. + - image: resprites t-ray scanner. + - admin: Admins can transform misbehaving players into arbitrary objects at will. + - 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 + - bugfix: fixed moonicorns making space/chasm/lava/water bridges with their fairy + grass + jjpark-kb: + - 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 + vinylspiders: + - image: added digi resprite for shorter shorts +2023-09-23: + LT3: + - bugfix: Ghosts and godmode mobs will no longer create resonance when touching + the supermatter crystal + - rscadd: Poly now causes a power surge when dusted by the supermatter crystal + - balance: Delam panic button run time increased by 2 seconds to match the new 15 + second delam timer + - balance: Delam suppression freon changed to be less instantly lethal to organics, + less of a plasma fire waiting to happen + Lunar248: + - bugfix: Replaces the incorrect MOD cores with working ones. + Paxilmaniac: + - rscdel: The ability to change a flashlight's intensity has been removed due to + the fact they no longer have cells to draw more or less power from in those + modes. + - qol: Flashlights no longer pointlessly require power cells to function + SkyratBot: + - refactor: seedlings have been refactored into basic mobs please report any bugs + - rscadd: seedlings now can have different colored petals and can look after botanys + plants + - rscadd: seedlings are re-added to the game! they grow out of seedling seeds obtainable + from exotic seed crates or traitor uplink + - rscadd: The Message Monitor console's board can now be obtained via the telecoms + research node. + - bugfix: Conveyor belts now properly show their new screentips on mouseover with + tools. + - bugfix: clown bomb payload is no longer named badmin payload and no longer disperses + clowns in cardinal directions only + - bugfix: Foods that have special conditions for liking/disliking them (such as + donuts for sec officers) have these conditions again. + - bugfix: Characters with ageusia properly ignore non-toxic food types that they + eat. + - bugfix: If you examine toxic food, it can no longer appear to you as edible. + - admin: Boneless smite should work properly again. + distributivgesetz, CoiledLamb: + - rscadd: 'Added two new awards specifically for engineering and medical: The "Emergency + Services Award" and the "Atmospheric Mastery Award". CEs get 3 Emergency Services + Awards and 1 Atmospheric Mastery Award and CMOs get 3 Emergency Services Awards.' + softcerv: + - rscdel: The electric welding tool has been removed from the techweb and the experimental + welding tool has been reinstated in it's place. + vinylspiders: + - bugfix: using sand or volcanic ash on a seed mesh will no longer have the possibility + to spawn a generic buggy 'lavaland seed' item +2023-09-24: + LT3: + - bugfix: Fixed supermatter surges always being the lowest severity + Melbert: + - bugfix: Maybe fixes some weird occurrences where you lose the ability to pass + over tables when you shouldn't, and visa versa + SkyratBot: + - bugfix: Epinephrine will now update health properly. + - rscadd: Brimdemon corpses release an explosion shortly after death, just to keep + you on your toes. + - refactor: Brimdemons now use the basic mob framework which (should) improve their + pathfinding somewhat. Please bug report any unusual behaviour. + - admin: The brimdemon's beam ability can be given to any mob, for your Binding + of Isaac event + - refactor: clowns are basicmobs now + - admin: Admins can now reset or modify the chaplain's sect from a UI panel + lukevale: + - rscadd: Adds bras as a selectable preference in the same vein as underwear. Separates + all tops from undershirts. diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index f7615fc045b..29e59dc6c71 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 40d4ea80df2..8b7738f3b46 100644 Binary files a/icons/effects/eldritch.dmi and b/icons/effects/eldritch.dmi differ diff --git a/icons/effects/random_spawners.dmi b/icons/effects/random_spawners.dmi index f96676da097..c03b196a137 100644 Binary files a/icons/effects/random_spawners.dmi and b/icons/effects/random_spawners.dmi differ diff --git a/icons/hud/fishing_hud.dmi b/icons/hud/fishing_hud.dmi new file mode 100644 index 00000000000..b68acee09b7 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 944337b18e5..a1fc01434e4 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 a684dd1fbe6..747b57949be 100644 Binary files a/icons/mob/actions/actions_ecult.dmi and b/icons/mob/actions/actions_ecult.dmi differ diff --git a/icons/mob/clothing/accessories.dmi b/icons/mob/clothing/accessories.dmi index 389cffe7cf2..2c6bf510724 100644 Binary files a/icons/mob/clothing/accessories.dmi and b/icons/mob/clothing/accessories.dmi differ diff --git a/icons/mob/inhands/64x64_lefthand.dmi b/icons/mob/inhands/64x64_lefthand.dmi index 26c177f7293..8a6bab69776 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 79c30f5cb19..251458590bd 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 b582d0406f9..2e14a3ed0bb 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/jungle/seedling.dmi b/icons/mob/simple/jungle/seedling.dmi index 01e91c6c292..c4a76ebb2d1 100644 Binary files a/icons/mob/simple/jungle/seedling.dmi and b/icons/mob/simple/jungle/seedling.dmi differ diff --git a/icons/obj/clothing/accessories.dmi b/icons/obj/clothing/accessories.dmi index 2711333118a..fdba37254eb 100644 Binary files a/icons/obj/clothing/accessories.dmi and b/icons/obj/clothing/accessories.dmi differ diff --git a/icons/obj/clothing/modsuit/mod_modules.dmi b/icons/obj/clothing/modsuit/mod_modules.dmi index d548f615c44..f1d19c29da1 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 b6ccf1b8c41..d89ee6e5d64 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/icons/obj/fluff/containers.dmi b/icons/obj/fluff/containers.dmi index af9abe7073e..8aed1ffbb9a 100644 Binary files a/icons/obj/fluff/containers.dmi and b/icons/obj/fluff/containers.dmi differ diff --git a/icons/obj/machines/floor.dmi b/icons/obj/machines/floor.dmi index 38ea510f37b..6f858465dcd 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 32aedcc1b7a..1da2b5f2a9b 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 de419374151..9a6dffaaee2 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 d41fc3b167a..b4b26e4f848 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 6c5560438c6..54b19553b84 100644 Binary files a/icons/obj/mining.dmi and b/icons/obj/mining.dmi differ diff --git a/icons/obj/service/hydroponics/equipment.dmi b/icons/obj/service/hydroponics/equipment.dmi index dc164c5b1c9..afcc4de5235 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/hydroponics/growing_fruits.dmi b/icons/obj/service/hydroponics/growing_fruits.dmi index 7e535cdaf9b..92c52b55dbf 100644 Binary files a/icons/obj/service/hydroponics/growing_fruits.dmi and b/icons/obj/service/hydroponics/growing_fruits.dmi differ diff --git a/icons/obj/service/hydroponics/seeds.dmi b/icons/obj/service/hydroponics/seeds.dmi index b31590560d8..ffef219193a 100644 Binary files a/icons/obj/service/hydroponics/seeds.dmi and b/icons/obj/service/hydroponics/seeds.dmi differ diff --git a/icons/obj/service/janitor.dmi b/icons/obj/service/janitor.dmi index 8c73a99b416..0e814ca4545 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 dfd8aca6b89..8229c1fc394 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 a04a34edd31..e6679c8c518 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 07ac342a36d..97b75335b91 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 4bbd4d5f0f9..ab7a0c252cb 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 83309e4d18e..c9decbc5a3a 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 ad34dfd16f0..b3e64c9d09f 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 20dabae9210..00000000000 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 b6e2487bdc4..00000000000 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 8596115fd96..00000000000 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 620317122b2..b74721c63ae 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/game/objects/structures/mannequin.dm b/modular_skyrat/master_files/code/game/objects/structures/mannequin.dm new file mode 100644 index 00000000000..9604fb7ac5f --- /dev/null +++ b/modular_skyrat/master_files/code/game/objects/structures/mannequin.dm @@ -0,0 +1,3 @@ +/obj/structure/mannequin + /// String for the bra we use. + var/bra_name diff --git a/modular_skyrat/master_files/code/modules/antagonists/changeling/changeling.dm b/modular_skyrat/master_files/code/modules/antagonists/changeling/changeling.dm index 5c7b4c4bbd1..92f0b0786dc 100644 --- a/modular_skyrat/master_files/code/modules/antagonists/changeling/changeling.dm +++ b/modular_skyrat/master_files/code/modules/antagonists/changeling/changeling.dm @@ -1,2 +1,46 @@ /datum/antagonist/changeling/forge_objectives() return + + +/datum/changeling_profile + /// The bra worn by the profile source - Skyrats addition + var/bra + /// The color of the underwear used by the profile source - Skyrats addition + var/underwear_color + /// The color of the undershirt used by the profile source - Skyrats addition + var/undershirt_color + /// The color of the socks used by the profile source - Skyrats addition + var/socks_color + /// The color of the bra used by the profile source - Skyrats addition + var/bra_color + /// The profile source's left eye color - Skyrats addition + var/eye_color_left + /// The profile source's right eye color - Skyrats addition + var/eye_color_right + /// Does the profile source's eyes glow - Skyrats addition + var/emissive_eyes + /// The profile sorce's gradient styles - Skyrats addition + var/list/grad_style = list("None", "None") + /// The colors for the profile source's gradients - Skyrats addition + var/list/grad_color = list(null, null) + + /// The physique used by the profile source - Skyrats addition + var/physique + /// Profile source digi leg icons - Skyrats addition + var/list/worn_icon_digi_list = list() + /// profile source monkey icons - Skyrats addition + var/list/worn_icon_monkey_list = list() + /// Profile source vox icons - Skyrats addition + var/list/worn_icon_teshari_list = list() + /// The bra worn by the profile source - Skyrats addition + var/list/worn_icon_vox_list = list() + /// Support variation flags used by the profile source - Skyrats addition + var/list/supports_variations_flags_list = list() + /// The profile source scream type - Skyrats addition + var/scream_type + /// The profile source laugh type - Skyrats addition + var/laugh_type + /// The profile source's age - Skyrats addition + var/age + /// The quirks used by the profile source - Skyrats addition + var/list/quirks = list() 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 00000000000..e1b032bbc33 --- /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 c640b4b95d7..b1d301120e7 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/client/preferences/clothing.dm b/modular_skyrat/master_files/code/modules/client/preferences/clothing.dm index 8041e751783..f542e867fc6 100644 --- a/modular_skyrat/master_files/code/modules/client/preferences/clothing.dm +++ b/modular_skyrat/master_files/code/modules/client/preferences/clothing.dm @@ -35,3 +35,50 @@ var/species_type = preferences.read_preference(/datum/preference/choiced/species) var/datum/species/species = new species_type return !(TRAIT_NO_UNDERWEAR in species.inherent_traits) + +/datum/preference/choiced/bra + savefile_key = "bra" + savefile_identifier = PREFERENCE_CHARACTER + main_feature_name = "Bra" + category = PREFERENCE_CATEGORY_CLOTHING + should_generate_icons = TRUE + +/datum/preference/choiced/bra/init_possible_values() + return assoc_to_keys_features(GLOB.bra_list) + +/datum/preference/choiced/bra/icon_for(value) + var/static/icon/body + if (isnull(body)) + body = icon('icons/mob/human/bodyparts_greyscale.dmi', "human_r_arm") + body.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_l_arm"), ICON_OVERLAY) + body.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_r_hand"), ICON_OVERLAY) + body.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_l_hand"), ICON_OVERLAY) + body.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_chest_m"), ICON_OVERLAY) + + var/icon/icon_with_bra = icon(body) + + if (value != "Nude") + var/datum/sprite_accessory/accessory = GLOB.bra_list[value] + icon_with_bra.Blend(icon(accessory.icon, accessory.icon_state), ICON_OVERLAY) + + icon_with_bra.Crop(10, 11, 22, 23) // SKYRAT EDIT CHANGE : ORIGINAL - icon_with_undershirt.Crop(9, 9, 23, 23) + icon_with_bra.Scale(32, 32) + return icon_with_bra + +/datum/preference/choiced/bra/apply_to_human(mob/living/carbon/human/target, value) + target.bra = value + +/datum/preference/choiced/bra/compile_constant_data() + var/list/data = ..() + + data[SUPPLEMENTAL_FEATURE_KEY] = "bra_color" + + return data + +/datum/preference/choiced/bra/is_accessible(datum/preferences/preferences) + if (!..(preferences)) + return FALSE + + var/species_type = preferences.read_preference(/datum/preference/choiced/species) + var/datum/species/species = new species_type + return !(TRAIT_NO_UNDERWEAR in species.inherent_traits) diff --git a/modular_skyrat/master_files/code/modules/client/preferences/underwear_color.dm b/modular_skyrat/master_files/code/modules/client/preferences/underwear_color.dm index a1819c64b3f..f7e5a86d5ea 100644 --- a/modular_skyrat/master_files/code/modules/client/preferences/underwear_color.dm +++ b/modular_skyrat/master_files/code/modules/client/preferences/underwear_color.dm @@ -49,3 +49,20 @@ var/datum/species/species = new species_type return !(TRAIT_NO_UNDERWEAR in species.inherent_traits) // SKYRAT EDIT ADDITION END - Colorable Undershirt/Socks + + +/datum/preference/color/bra_color + savefile_key = "bra_color" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES + +/datum/preference/color/bra_color/apply_to_human(mob/living/carbon/human/target, value) + target.bra_color = value + +/datum/preference/color/bra_color/is_accessible(datum/preferences/preferences) + if (!..(preferences)) + return FALSE + + var/species_type = preferences.read_preference(/datum/preference/choiced/species) + var/datum/species/species = new species_type + return !(TRAIT_NO_UNDERWEAR in species.inherent_traits) diff --git a/modular_skyrat/master_files/code/modules/client/preferences_savefile.dm b/modular_skyrat/master_files/code/modules/client/preferences_savefile.dm index 641a5c3537a..f7ffc6fddd6 100644 --- a/modular_skyrat/master_files/code/modules/client/preferences_savefile.dm +++ b/modular_skyrat/master_files/code/modules/client/preferences_savefile.dm @@ -3,10 +3,18 @@ * You can't really use the non-modular version, least you eventually want asinine merge * conflicts and/or potentially disastrous issues to arise, so here's your own. */ -#define MODULAR_SAVEFILE_VERSION_MAX 3 +#define MODULAR_SAVEFILE_VERSION_MAX 4 #define MODULAR_SAVEFILE_UP_TO_DATE -1 +#define VERSION_GENITAL_TOGGLES 1 +#define VERSION_BREAST_SIZE_CHANGE 2 +#define VERSION_SYNTH_REFACTOR 3 +#define VERSION_UNDERSHIRT_BRA_SPLIT 4 + +#define INDEX_UNDERWEAR 1 +#define INDEX_BRA 2 + /** * Checks if the modular side of the savefile is up to date. * If the return value is higher than 0, update_character_skyrat() will be called later. @@ -16,8 +24,10 @@ if(savefile_version < MODULAR_SAVEFILE_VERSION_MAX) return savefile_version + return MODULAR_SAVEFILE_UP_TO_DATE + /// Loads the modular customizations of a character from the savefile /datum/preferences/proc/load_character_skyrat(list/save_data) if(!save_data) @@ -89,9 +99,10 @@ if(needs_update >= 0) update_character_skyrat(needs_update, save_data) // needs_update == savefile_version if we need an update (positive integer) + /// Brings a savefile up to date with modular preferences. Called if savefile_needs_update_skyrat() returned a value higher than 0 /datum/preferences/proc/update_character_skyrat(current_version, list/save_data) - if(current_version < 1) + if(current_version < VERSION_GENITAL_TOGGLES) // removed genital toggles, with the new choiced prefs paths as assoc var/static/list/old_toggles if(!old_toggles) @@ -114,14 +125,14 @@ for(var/pref_type in subtypesof(/datum/preference/toggle/genital_skin_tone)) write_preference(GLOB.preference_entries[pref_type], TRUE) - if(current_version < 2) + if(current_version < VERSION_BREAST_SIZE_CHANGE) var/list/old_breast_prefs old_breast_prefs = save_data["breasts_size"] if(isnum(old_breast_prefs)) // Can't be too careful // You weren't meant to be able to pick sizes over this anyways. write_preference(GLOB.preference_entries[/datum/preference/choiced/breasts_size], GLOB.breast_size_translation["[min(old_breast_prefs, 10)]"]) - if(current_version < 3) + if(current_version < VERSION_SYNTH_REFACTOR) var/old_species = save_data["species"] if(istext(old_species) && (old_species in list("synthhuman", "synthliz", "synthmammal", "ipc"))) @@ -156,11 +167,99 @@ write_preference(GLOB.preference_entries[/datum/preference/color/mutant/synth_chassis], new_color) write_preference(GLOB.preference_entries[/datum/preference/color/mutant/synth_head], new_color) + if(current_version < VERSION_UNDERSHIRT_BRA_SPLIT) + var/static/list/underwear_to_underwear_bra = list( + "Panties" = list("Panties - Basic", null), // Just a rename + "Bikini" = list("Panties - Slim", "Bra"), + "Lace Bikini" = list("Panties - Thin", "Bra - Thin"), + "Bralette w/ Boyshorts" = list("Boyshorts (Alt)", "Bra, Sports"), + "Sports Bra w/ Boyshorts" = list("Boyshorts", "Bra, Sports - Alt"), + "Strapless Bikini" = list("Panties - Slim", "Strapless Swimsuit Top (Alt)"), + "Babydoll" = list("Thong - Alt", null), // Got moved to an undershirt, actual underwear part is now a thong. + "Two-Piece Swimsuit" = list("Panties - Swimsuit", "Swimsuit Top"), + "Strapless Two-Piece Swimsuit" = list("Panties - Swimsuit", "Strapless Swimsuit Top"), + "Halter Swimsuit" = list("Panties - Basic", "Bra - Halterneck - (Alt)"), + "Neko Bikini (White)" = list("Panties - Neko", "Bra - Neko"), + "Neko Bikini (Black)" = list("Panties - Neko", "Bra - Neko"), + "UK Biniki" = list("Panties - UK", "Bra - UK"), + ) + + var/current_underwear = save_data["underwear"] + var/migrated_underwear_bra = underwear_to_underwear_bra[current_underwear] + + if(migrated_underwear_bra) + var/migrated_color = save_data["underwear_color"] + var/migrated_underwear = migrated_underwear_bra[INDEX_UNDERWEAR] + var/migrated_bra = migrated_underwear_bra[INDEX_BRA] + + if(migrated_underwear) + write_preference(GLOB.preference_entries[/datum/preference/choiced/underwear], migrated_underwear) + + if(migrated_bra) + write_preference(GLOB.preference_entries[/datum/preference/choiced/bra], migrated_bra) + write_preference(GLOB.preference_entries[/datum/preference/color/bra_color], migrated_color) + + var/current_undershirt = save_data["undershirt"] + + // This one has a different treatment because it's an underwear that has been moved mainly to an undershirt, + // ending up as a thong for the underwear part itself. We only want to override the undershirt if there's none, + // though. + if(current_underwear == "Babydoll" && current_undershirt == "Nude") + var/migrated_color = save_data["underwear_color"] + + write_preference(GLOB.preference_entries[/datum/preference/choiced/undershirt], "Babydoll") + write_preference(GLOB.preference_entries[/datum/preference/color/undershirt_color], migrated_color) + + var/static/list/undershirt_to_bra = list( + "Bra, Sports" = "Bra, Sports", + "Sports Bra (Alt)" = "Sports Bra (Alt)", + "LIZARED Top" = "LIZARED Top", + "Bra" = "Bra", + "Bra - Alt" = "Bra - Alt", + "Bra - Thin" = "Bra - Thin", + "Bra - Kinky Black" = "Bra - Kinky Black", + "Bra - Freedom" = "Bra - Freedom", + "Bra - Commie" = "Bra - Commie", + "Bra - Bee-kini" = "Bra - Bee-kini", + "Bra - UK" = "Bra - UK", + "Bra - Neko" = "Bra - Neko", + "Bra - Halterneck" = "Bra - Halterneck", + "Bra - Sports - Alt" = "Bra - Sports - Alt", + "Bra - Strapless" = "Bra - Strapless", + "Bra - Latex" = "Bra - Latex", + "Bra - Striped" = "Bra - Striped", + "Bra - Sarashi" = "Bra - Sarashi", + "Fishnet - Sleeved" = "Fishnet - Sleeved", + "Fishnet - Sleeved (Greyscaled)" = "Fishnet - Sleeved (Greyscaled)", + "Fishnet - Sleeveless" = "Fishnet - Sleeveless", + "Fishnet - Sleeveless (Greyscaled)" = "Fishnet - Sleeveless (Greyscaled)", + "Swimsuit Top" = "Bra - Halterneck - (Alt)", + "Chastity Bra" = "Chastity Bra", + "Pasties" = "Pasties", + "Pasties - Alt" = "Pasties - Alt", + "Shibari" = "Shibari", + "Shibari Sleeves" = "Shibari Sleeves", + "Binder" = "Binder", + "Binder - Strapless" = "Binder - Strapless", + "Safekini" = "Safekini", + ) + + var/migrated_bra_from_undershirt = undershirt_to_bra[current_undershirt] + + if(migrated_bra_from_undershirt) + var/migrated_color = save_data["undershirt_color"] + + write_preference(GLOB.preference_entries[/datum/preference/choiced/bra], migrated_bra_from_undershirt) + write_preference(GLOB.preference_entries[/datum/preference/color/bra_color], migrated_color) + write_preference(GLOB.preference_entries[/datum/preference/choiced/undershirt], "Nude") + + /datum/preferences/proc/check_migration() if(!tgui_prefs_migration) to_chat(parent, examine_block(span_redtext("CRITICAL FAILURE IN PREFERENCE MIGRATION, REPORT THIS IMMEDIATELY."))) message_admins("PREFERENCE MIGRATION: [ADMIN_LOOKUPFLW(parent)] has failed the process for migrating PREFERENCES. Check runtimes.") + /// Saves the modular customizations of a character on the savefile /datum/preferences/proc/save_character_skyrat(list/save_data) save_data["loadout_list"] = loadout_list @@ -176,6 +275,7 @@ save_data["headshot"] = headshot save_data["modular_version"] = MODULAR_SAVEFILE_VERSION_MAX + /datum/preferences/proc/update_mutant_bodyparts(datum/preference/preference) if (!preference.relevant_mutant_bodypart) return @@ -202,6 +302,7 @@ if (part in mutant_bodyparts) mutant_bodyparts[part][MUTANT_INDEX_COLOR_LIST] = value + /datum/preferences/proc/update_markings(list/markings) if (islist(markings)) for (var/marking in markings) @@ -210,5 +311,11 @@ markings[marking][title] = list(sanitize_hexcolor(markings[marking][title]), FALSE) return markings + #undef MODULAR_SAVEFILE_VERSION_MAX #undef MODULAR_SAVEFILE_UP_TO_DATE + +#undef VERSION_GENITAL_TOGGLES +#undef VERSION_BREAST_SIZE_CHANGE +#undef VERSION_SYNTH_REFACTOR +#undef VERSION_UNDERSHIRT_BRA_SPLIT 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 adbbbd0dc5b..8fe26c3b342 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/clothing/under/shorts_pants.dm b/modular_skyrat/master_files/code/modules/clothing/under/shorts_pants.dm index 2a1ddaea65d..3bc3d7c2a7b 100644 --- a/modular_skyrat/master_files/code/modules/clothing/under/shorts_pants.dm +++ b/modular_skyrat/master_files/code/modules/clothing/under/shorts_pants.dm @@ -68,6 +68,16 @@ greyscale_colors = "#787878#723E0E#202020" flags_1 = IS_PLAYER_COLORABLE_1 +/obj/item/clothing/under/shorts/skyrat/shortershorts + name = "shorter shorts" + desc = "Show those legs off with these even shorter shorts!" + icon_state = "shortershorts" + greyscale_config = /datum/greyscale_config/shortershorts + greyscale_config_worn = /datum/greyscale_config/shortershorts/worn + greyscale_config_worn_digi = /datum/greyscale_config/shortershorts/worn/digi + greyscale_colors = "#787878#723E0E#202020" + flags_1 = IS_PLAYER_COLORABLE_1 + /* * MISC (Technically belongs in this file as a shorts/pants/shirt combo) * Here's hoping TG gives these their own typepath, but for now this is gonna be under/pants/skyrat. No, it's not all pants, but it's better than a whole new type diff --git a/modular_skyrat/master_files/code/modules/mob/dead/new_player/preferences_setup.dm b/modular_skyrat/master_files/code/modules/mob/dead/new_player/preferences_setup.dm index 180f6081277..c2b04c99382 100644 --- a/modular_skyrat/master_files/code/modules/mob/dead/new_player/preferences_setup.dm +++ b/modular_skyrat/master_files/code/modules/mob/dead/new_player/preferences_setup.dm @@ -23,14 +23,14 @@ if(PREVIEW_PREF_UNDERWEAR) mannequin.underwear_visibility = NONE if(PREVIEW_PREF_NAKED) - mannequin.underwear_visibility = UNDERWEAR_HIDE_UNDIES | UNDERWEAR_HIDE_SHIRT | UNDERWEAR_HIDE_SOCKS + mannequin.underwear_visibility = UNDERWEAR_HIDE_UNDIES | UNDERWEAR_HIDE_SHIRT | UNDERWEAR_HIDE_SOCKS | UNDERWEAR_HIDE_BRA for(var/organ_key in list(ORGAN_SLOT_VAGINA, ORGAN_SLOT_PENIS, ORGAN_SLOT_BREASTS, ORGAN_SLOT_ANUS)) var/obj/item/organ/external/genital/gent = mannequin.get_organ_slot(organ_key) if(gent) gent.aroused = AROUSAL_NONE gent.update_sprite_suffix() if(PREVIEW_PREF_NAKED_AROUSED) - mannequin.underwear_visibility = UNDERWEAR_HIDE_UNDIES | UNDERWEAR_HIDE_SHIRT | UNDERWEAR_HIDE_SOCKS + mannequin.underwear_visibility = UNDERWEAR_HIDE_UNDIES | UNDERWEAR_HIDE_SHIRT | UNDERWEAR_HIDE_SOCKS | UNDERWEAR_HIDE_BRA for(var/organ_key in list(ORGAN_SLOT_VAGINA, ORGAN_SLOT_PENIS, ORGAN_SLOT_BREASTS, ORGAN_SLOT_ANUS)) var/obj/item/organ/external/genital/gent = mannequin.get_organ_slot(organ_key) if(gent) 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 4cffb1a2045..d7b16d45d49 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,14 @@ 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...") + +///copies over clothing preferences like underwear to another human +/mob/living/carbon/human/copy_clothing_prefs(mob/living/carbon/human/destination) + . = ..() + + destination.bra = bra + destination.bra_color = bra_color diff --git a/modular_skyrat/master_files/code/modules/religion/religious_sects.dm b/modular_skyrat/master_files/code/modules/religion/religious_sects.dm index e7b718b485a..1a465d8421e 100644 --- a/modular_skyrat/master_files/code/modules/religion/religious_sects.dm +++ b/modular_skyrat/master_files/code/modules/religion/religious_sects.dm @@ -2,7 +2,7 @@ /datum/religion_sect/on_select() . = ..() - + // if the same religious sect gets selected, carry the favor over if(istype(src, GLOB.prev_sect_type)) set_favor(GLOB.prev_favor) @@ -25,10 +25,8 @@ GLOB.prev_favor = GLOB.religious_sect.favor GLOB.prev_sect_type = GLOB.religious_sect.type - // set the altar references to the old religious_sect to null - for(var/obj/structure/altar_of_gods/altar in GLOB.chaplain_altars) - altar.GetComponent(/datum/component/religious_tool).easy_access_sect = null - altar.sect_to_altar = null + // set the altar references to the old religious_sect to null + SEND_GLOBAL_SIGNAL(COMSIG_RELIGIOUS_SECT_RESET) QDEL_NULL(GLOB.religious_sect) // queue for removal but also set it to null, in case a new chaplain joins before it can be deleted diff --git a/modular_skyrat/master_files/code/modules/research/designs/tool_designs.dm b/modular_skyrat/master_files/code/modules/research/designs/tool_designs.dm index 9951c2bebe5..44c01471845 100644 --- a/modular_skyrat/master_files/code/modules/research/designs/tool_designs.dm +++ b/modular_skyrat/master_files/code/modules/research/designs/tool_designs.dm @@ -1,2 +1,5 @@ /datum/design/rpd departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_CARGO + +/datum/design/exwelder + departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_SCIENCE 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 00000000000..296696d559f --- /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 835a46c9d16..94d19052982 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 cf43274be05..c00b68f50cf 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 6f988460699..9a8042cf0a0 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 b975af5de8c..c4ecb9e4f81 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/under/shorts_pants_shirts_digi.dmi b/modular_skyrat/master_files/icons/mob/clothing/under/shorts_pants_shirts_digi.dmi index 8d0800f7eea..11f4729aa7c 100644 Binary files a/modular_skyrat/master_files/icons/mob/clothing/under/shorts_pants_shirts_digi.dmi and b/modular_skyrat/master_files/icons/mob/clothing/under/shorts_pants_shirts_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 bb41c5562b6..3d9209905cb 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 bd26b776ee5..fb582bf495c 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 e2a568e2c91..45b23619f89 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 bc6d0043e13..fccbf88fbc9 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/master_files/icons/obj/clothing/under/shorts_pants_shirts.dmi b/modular_skyrat/master_files/icons/obj/clothing/under/shorts_pants_shirts.dmi index 619b0246b24..d82f9b63e17 100644 Binary files a/modular_skyrat/master_files/icons/obj/clothing/under/shorts_pants_shirts.dmi and b/modular_skyrat/master_files/icons/obj/clothing/under/shorts_pants_shirts.dmi differ diff --git a/modular_skyrat/master_files/sound/effects/flashlight.ogg b/modular_skyrat/master_files/sound/effects/flashlight.ogg deleted file mode 100644 index 627675997cf..00000000000 Binary files a/modular_skyrat/master_files/sound/effects/flashlight.ogg and /dev/null differ diff --git a/modular_skyrat/modules/GAGS/greyscale_configs.dm b/modular_skyrat/modules/GAGS/greyscale_configs.dm index d560d196031..36870626d5d 100644 --- a/modular_skyrat/modules/GAGS/greyscale_configs.dm +++ b/modular_skyrat/modules/GAGS/greyscale_configs.dm @@ -740,6 +740,19 @@ name = "Jean Shorts (Worn, Digi)" icon_file = SHORTS_PANTS_SHIRTS_DIGIFILE +/datum/greyscale_config/shortershorts + name = "Shorter Shorts" + icon_file = 'modular_skyrat/modules/GAGS/icons/shorts_pants.dmi' + json_config = 'modular_skyrat/modules/GAGS/json_configs/pants_shorts_skirts_dresses/shortershorts.json' + +/datum/greyscale_config/shortershorts/worn + name = "Shorter Shorts (Worn)" + icon_file = 'modular_skyrat/modules/GAGS/icons/shorts_pants.dmi' + +/datum/greyscale_config/shortershorts/worn/digi + name = "Ripped Shorts (Worn, Digi)" + icon_file = SHORTS_PANTS_SHIRTS_DIGIFILE + /datum/greyscale_config/shorts_ripped name = "Ripped Shorts" icon_file = 'modular_skyrat/master_files/icons/obj/clothing/under/shorts_pants_shirts.dmi' diff --git a/modular_skyrat/modules/GAGS/icons/shorts_pants.dmi b/modular_skyrat/modules/GAGS/icons/shorts_pants.dmi index c4427049f06..97a799c0f0c 100644 Binary files a/modular_skyrat/modules/GAGS/icons/shorts_pants.dmi and b/modular_skyrat/modules/GAGS/icons/shorts_pants.dmi differ diff --git a/modular_skyrat/modules/GAGS/json_configs/pants_shorts_skirts_dresses/shortershorts.json b/modular_skyrat/modules/GAGS/json_configs/pants_shorts_skirts_dresses/shortershorts.json new file mode 100644 index 00000000000..0058e310800 --- /dev/null +++ b/modular_skyrat/modules/GAGS/json_configs/pants_shorts_skirts_dresses/shortershorts.json @@ -0,0 +1,22 @@ +{ + "shortershorts": [ + { + "type": "icon_state", + "icon_state": "buckle", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "belt", + "blend_mode": "overlay", + "color_ids": [ 2 ] + }, + { + "type": "icon_state", + "icon_state": "shortershorts", + "blend_mode": "overlay", + "color_ids": [ 3 ] + } + ] +} 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 e62c81552d5..d7abb4e00f0 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 b49156bd0a1..e34a414cf8e 100644 --- a/modular_skyrat/modules/ashwalkers/code/effects/ash_rituals.dm +++ b/modular_skyrat/modules/ashwalkers/code/effects/ash_rituals.dm @@ -174,7 +174,7 @@ var/mob_type = pick( /mob/living/basic/mining/goliath, /mob/living/simple_animal/hostile/asteroid/hivelord/legion, - /mob/living/simple_animal/hostile/asteroid/brimdemon, + /mob/living/basic/mining/brimdemon, /mob/living/basic/mining/watcher, /mob/living/basic/mining/lobstrosity/lava, ) @@ -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/items/ash_seedmesh.dm b/modular_skyrat/modules/ashwalkers/code/items/ash_seedmesh.dm index b21994b71be..a79f0dfb883 100644 --- a/modular_skyrat/modules/ashwalkers/code/items/ash_seedmesh.dm +++ b/modular_skyrat/modules/ashwalkers/code/items/ash_seedmesh.dm @@ -3,6 +3,9 @@ desc = "A little mesh that, when paired with sand, has the possibility of filtering out large seeds." icon = 'modular_skyrat/modules/ashwalkers/icons/misc_tools.dmi' icon_state = "mesh" + var/list/static/seeds_blacklist = list( + /obj/item/seeds/lavaland, + ) /obj/item/seed_mesh/attackby(obj/item/attacking_item, mob/user, params) if(istype(attacking_item, /obj/item/stack/ore/glass)) @@ -16,7 +19,7 @@ if(prob(85)) user.balloon_alert(user, "[stack_item] reveals nothing!") return - var/spawn_seed = pick(subtypesof(/obj/item/seeds)) + var/spawn_seed = pick(subtypesof(/obj/item/seeds) - seeds_blacklist) new spawn_seed(get_turf(src)) user.balloon_alert(user, "[stack_item] revealed something!") return ..() diff --git a/modular_skyrat/modules/ashwalkers/code/species/Ashwalkers.dm b/modular_skyrat/modules/ashwalkers/code/species/Ashwalkers.dm index d24aa290ec0..0e60d2ed7e9 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 5c8d576f1a4..7ea4e5a52ea 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" @@ -20,5 +36,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 6b45258c051..e082ddabb42 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 deleted file mode 100644 index 01de50266e3..00000000000 --- a/modular_skyrat/modules/cell_component/code/flashlight.dm +++ /dev/null @@ -1,150 +0,0 @@ -#define FLASHLIGHT_MODE_LOW "low" -#define FLASHLIGHT_MODE_MEDIUM "medium" -#define FLASHLIGHT_MODE_HIGH "high" - -/obj/item/flashlight - /// Does this flashlight utilize batteries? - var/uses_battery = TRUE - /// What's this flashlight's special cell, if any? - var/cell_override - /// How much power (per process) does this flashlight use, if uses_battery = TRUE - power_use_amount = POWER_CELL_USE_MINIMUM - /// Mode of the flashlight, how strong the light is and how much the power usage is affected. - var/flashlight_mode = FLASHLIGHT_MODE_LOW - /// Does this flashlight have modes? - var/has_modes = TRUE - /// Does this flashlight make the extra noise upon being turned on? - var/makes_noise_when_lit = TRUE - -/obj/item/flashlight/Initialize(mapload) - . = ..() - if(icon_state == "[initial(icon_state)]-on") - turn_on(FALSE) - update_brightness() - register_context() - - if(uses_battery) - AddComponent(/datum/component/cell, cell_override, CALLBACK(src, PROC_REF(turn_off)), _has_cell_overlays = FALSE) - -/obj/item/flashlight/examine(mob/user) - . = ..() - if(has_modes) - . += "This flashlight has modes! Ctrl-click it to change the mode." - . += "It is currently set to [flashlight_mode] intensity." - -/obj/item/flashlight/CtrlClick(mob/user) - . = ..() - if(has_modes) - switch(flashlight_mode) - if(FLASHLIGHT_MODE_LOW) - flashlight_mode = FLASHLIGHT_MODE_MEDIUM - power_use_amount = POWER_CELL_USE_VERY_LOW - set_light_range(initial(light_range) + 1) - set_light_power(initial(light_power) + 1) - to_chat(user, span_notice("You set [src] to medium.")) - if(FLASHLIGHT_MODE_MEDIUM) - flashlight_mode = FLASHLIGHT_MODE_HIGH - power_use_amount = POWER_CELL_USE_LOW - set_light_range(initial(light_range) + 2) - set_light_power(initial(light_power) + 2) - to_chat(user, span_notice("You set [src] to high.")) - if(FLASHLIGHT_MODE_HIGH) - flashlight_mode = FLASHLIGHT_MODE_LOW - power_use_amount = POWER_CELL_USE_MINIMUM - set_light_range(initial(light_range)) - set_light_power(initial(light_power)) - to_chat(user, span_notice("You set [src] to low.")) - -/obj/item/flashlight/proc/toggle_light() - if(on) - turn_off() - else - 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() - -/** - * 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) - 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() - -/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() - -/obj/item/flashlight/update_icon_state() - . = ..() - if(on) - icon_state = "[initial(icon_state)]-on" - else - icon_state = initial(icon_state) - -/obj/item/flashlight/seclite - cell_override = /obj/item/stock_parts/cell/upgraded - -/obj/item/flashlight/lamp - uses_battery = FALSE - has_modes = FALSE - -/obj/item/flashlight/lantern - uses_battery = FALSE - has_modes = FALSE - makes_noise_when_lit = FALSE - -/obj/item/flashlight/slime - uses_battery = FALSE - has_modes = FALSE - makes_noise_when_lit = FALSE - -/obj/item/flashlight/flare - uses_battery = FALSE - has_modes = FALSE - makes_noise_when_lit = FALSE - -/obj/item/flashlight/emp/debug - uses_battery = FALSE - -/obj/item/flashlight/glowstick - uses_battery = FALSE - has_modes = FALSE - makes_noise_when_lit = FALSE - -/obj/item/flashlight/spotlight - uses_battery = FALSE - has_modes = FALSE - -/obj/item/flashlight/eyelight - uses_battery = FALSE - has_modes = FALSE - -/obj/item/flashlight/pen - cell_override = /obj/item/stock_parts/cell/potato - has_modes = FALSE - -#undef FLASHLIGHT_MODE_LOW -#undef FLASHLIGHT_MODE_MEDIUM -#undef FLASHLIGHT_MODE_HIGH diff --git a/modular_skyrat/modules/clock_cult/code/scriptures/_scripture.dm b/modular_skyrat/modules/clock_cult/code/scriptures/_scripture.dm index 2a11854456a..ad8f096188b 100644 --- a/modular_skyrat/modules/clock_cult/code/scriptures/_scripture.dm +++ b/modular_skyrat/modules/clock_cult/code/scriptures/_scripture.dm @@ -361,9 +361,8 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) return ..() -/datum/action/cooldown/spell/pointed/slab/InterceptClickOn(mob/living/caller, params, atom/clicked_atom) - parent_scripture?.click_on(clicked_atom) - +/datum/action/cooldown/spell/pointed/slab/InterceptClickOn(mob/living/caller, params, atom/target) + parent_scripture?.click_on(target) /// Generate all scriptures in a global assoc of name:ref. Only needs to be done once 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 27a3a48920f..3e6df12d124 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 47e7906254d..7d57f029f84 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/contractor/code/datums/outfit.dm b/modular_skyrat/modules/contractor/code/datums/outfit.dm new file mode 100644 index 00000000000..3364e2fbccb --- /dev/null +++ b/modular_skyrat/modules/contractor/code/datums/outfit.dm @@ -0,0 +1,2 @@ +/datum/outfit + var/datum/sprite_accessory/bra = null diff --git a/modular_skyrat/modules/customization/__HELPERS/global_lists.dm b/modular_skyrat/modules/customization/__HELPERS/global_lists.dm index 825737a6cf8..a2dca2e39be 100644 --- a/modular_skyrat/modules/customization/__HELPERS/global_lists.dm +++ b/modular_skyrat/modules/customization/__HELPERS/global_lists.dm @@ -152,3 +152,26 @@ if(!sprite_datum?.erp_accessory) continue GLOB.undershirt_m -= sprite_name + + + // Bras + for(var/sprite_name in GLOB.bra_list) + var/datum/sprite_accessory/sprite_datum = GLOB.bra_list[sprite_name] + if(!sprite_datum?.erp_accessory) + continue + + GLOB.bra_list -= sprite_name + + for(var/sprite_name in GLOB.bra_f) + var/datum/sprite_accessory/sprite_datum = GLOB.bra_f[sprite_name] + if(!sprite_datum?.erp_accessory) + continue + + GLOB.bra_f -= sprite_name + + for(var/sprite_name in GLOB.bra_m) + var/datum/sprite_accessory/sprite_datum = GLOB.bra_m[sprite_name] + if(!sprite_datum?.erp_accessory) + continue + + GLOB.bra_m -= sprite_name diff --git a/modular_skyrat/modules/customization/__HELPERS/mobs.dm b/modular_skyrat/modules/customization/__HELPERS/mobs.dm index 4e7fd400006..2707a172fe4 100644 --- a/modular_skyrat/modules/customization/__HELPERS/mobs.dm +++ b/modular_skyrat/modules/customization/__HELPERS/mobs.dm @@ -42,3 +42,15 @@ body_markings[zone] = list() body_markings[zone][set_name] = list(BM.get_default_color(features, pref_species), FALSE) return body_markings + +/proc/random_bra(gender) + if(!length(GLOB.bra_list)) + init_sprite_accessory_subtypes(/datum/sprite_accessory/bra, GLOB.bra_list, GLOB.bra_m, GLOB.bra_f) + + switch(gender) + if(MALE) + return pick(GLOB.bra_m) + if(FEMALE) + return pick(GLOB.bra_f) + else + return pick(GLOB.bra_list) diff --git a/modular_skyrat/modules/customization/_globalvars/lists.dm b/modular_skyrat/modules/customization/_globalvars/lists.dm index b684abf4e1c..86586e3f4d7 100644 --- a/modular_skyrat/modules/customization/_globalvars/lists.dm +++ b/modular_skyrat/modules/customization/_globalvars/lists.dm @@ -103,3 +103,11 @@ GLOBAL_LIST_INIT(color_list_ghoul, list( \ "Plutonium Blue" = "a5cfcc", \ "Marked Red" = "f05b68" \ )) + +//Bras +/// Stores all /datum/sprite_accessory/bra indexed by name. +GLOBAL_LIST_EMPTY(bra_list) +/// Stores only the bra names for male-compatible bras. +GLOBAL_LIST_EMPTY(bra_m) +/// Stores only the bra names for female-compatible bras. +GLOBAL_LIST_EMPTY(bra_f) diff --git a/modular_skyrat/modules/customization/modules/client/augment/limbs.dm b/modular_skyrat/modules/customization/modules/client/augment/limbs.dm index e1bc30db944..e5f8f4f14e7 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 07ce022f2a4..bb88ca325db 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/clothing/~donator/donator_clothing.dm b/modular_skyrat/modules/customization/modules/clothing/~donator/donator_clothing.dm index 2a8f0b11ed8..64a6c5c1339 100644 --- a/modular_skyrat/modules/customization/modules/clothing/~donator/donator_clothing.dm +++ b/modular_skyrat/modules/customization/modules/clothing/~donator/donator_clothing.dm @@ -1646,3 +1646,13 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/poster/contraband/korpstech, 32) ) ) +// Donation reward for grasshand +/obj/item/clothing/under/rank/civilian/chaplain/divine_archer/noble + name = "noble gambeson" + desc = "These clothes make you feel a little closer to space." + +/obj/item/clothing/shoes/jackboots/noble + name = "noble boots" + desc = "These boots make you feel like you can walk on space." + icon_state = "archerboots" + inhand_icon_state = "archerboots" diff --git a/modular_skyrat/modules/customization/modules/jobs/_job.dm b/modular_skyrat/modules/customization/modules/jobs/_job.dm index af223cbc67c..e6be489f524 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 cd22694da79..dd96f77df02 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 @@ -206,6 +206,7 @@ GLOBAL_LIST_EMPTY(cached_mutant_icon_files) /datum/sprite_accessory/socks icon = 'modular_skyrat/master_files/icons/mob/clothing/underwear.dmi' use_static = TRUE + /datum/sprite_accessory/socks/socks_norm name = "Normal (Greyscale)" icon_state = "white_norm" @@ -385,17 +386,17 @@ GLOBAL_LIST_EMPTY(cached_mutant_icon_files) gender = MALE use_static = TRUE +/datum/sprite_accessory/underwear/panties_basic + name = "Panties - Basic" + icon_state = "panties" + gender = FEMALE + /datum/sprite_accessory/underwear/female_beekini name = "Panties - Bee-kini" icon_state = "panties_bee-kini" gender = FEMALE use_static = TRUE -/datum/sprite_accessory/underwear/panties - name = "Panties" - icon_state = "panties" - gender = FEMALE - /datum/sprite_accessory/underwear/fishnet_lower name = "Panties - Fishnet" icon_state = "fishnet_lower" @@ -528,57 +529,39 @@ GLOBAL_LIST_EMPTY(cached_mutant_icon_files) has_digitigrade = TRUE gender = FEMALE +/datum/sprite_accessory/underwear/boyshorts_alt + name = "Boyshorts (Alt)" + icon_state = "boyshorts_alt" + gender = FEMALE + /* Adding hides_breasts to TG underwears where applicable */ -/datum/sprite_accessory/underwear/female_bikini - hides_breasts = TRUE - -/datum/sprite_accessory/underwear/female_lace - hides_breasts = TRUE - -/datum/sprite_accessory/underwear/female_bralette - hides_breasts = TRUE - -/datum/sprite_accessory/underwear/female_sport - hides_breasts = TRUE - -/datum/sprite_accessory/underwear/female_strapless - hides_breasts = TRUE - -/datum/sprite_accessory/underwear/female_babydoll - hides_breasts = TRUE /datum/sprite_accessory/underwear/swimsuit_onepiece + name = "One-Piece Swimsuit" + icon_state = "swim_onepiece" + gender = FEMALE hides_breasts = TRUE /datum/sprite_accessory/underwear/swimsuit_strapless_onepiece + name = "Strapless One-Piece Swimsuit" + icon_state = "swim_strapless_onepiece" + gender = FEMALE hides_breasts = TRUE - -/datum/sprite_accessory/underwear/swimsuit_twopiece - hides_breasts = TRUE - -/datum/sprite_accessory/underwear/swimsuit_strapless_twopiece - hides_breasts = TRUE - /datum/sprite_accessory/underwear/swimsuit_stripe + name = "Strapless Striped Swimsuit" + icon_state = "swim_stripe" + gender = FEMALE hides_breasts = TRUE -/datum/sprite_accessory/underwear/swimsuit_halter - hides_breasts = TRUE - -/datum/sprite_accessory/underwear/female_white_neko - hides_breasts = TRUE - -/datum/sprite_accessory/underwear/female_black_neko - hides_breasts = TRUE - -/datum/sprite_accessory/underwear/female_uk - hides_breasts = TRUE /* 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 @@ -603,219 +586,262 @@ GLOBAL_LIST_EMPTY(cached_mutant_icon_files) /datum/sprite_accessory/underwear/male_uk has_digitigrade = TRUE -/datum/sprite_accessory/underwear/female_sport - has_digitigrade = TRUE - /* End of adding has_digitigrade to TG stuff */ -/datum/sprite_accessory/undershirt - icon = 'modular_skyrat/master_files/icons/mob/clothing/underwear.dmi' - use_static = TRUE - ///Whether this underwear includes a bottom (For Leotards and the likes) - var/hides_groin = FALSE - -/datum/sprite_accessory/undershirt/tanktop_alt - name = "Tank Top - Alt" - icon_state = "tanktop_alt" - use_static = null -/datum/sprite_accessory/undershirt/tanktop_midriff - name = "Tank Top - Midriff" - icon_state = "tank_midriff" - gender = FEMALE - use_static = null - -/datum/sprite_accessory/undershirt/tanktop_midriff_alt - name = "Tank Top - Midriff Halterneck" - icon_state = "tank_midriff_alt" - gender = FEMALE - use_static = null - -/datum/sprite_accessory/undershirt/tankstripe - name = "Tank Top - Striped" - icon_state = "tank_stripes" - use_static = TRUE - -/datum/sprite_accessory/undershirt/tank_top_sun - name = "Tank top - Sun" - icon_state = "tank_sun" - use_static = TRUE +/// BRAS and all the fun stuff of moving these about. +/datum/sprite_accessory/bra + icon = 'modular_skyrat/master_files/icons/mob/clothing/underwear.dmi' + use_static = FALSE + em_block = TRUE -/datum/sprite_accessory/undershirt/babydoll - name = "Baby-Doll" - icon_state = "babydoll" - gender = FEMALE - use_static = null +/datum/sprite_accessory/bra/nude + name = "Nude" + icon_state = null + gender = NEUTER -/datum/sprite_accessory/undershirt/bra +/datum/sprite_accessory/bra/bra name = "Bra" icon_state = "bra" gender = FEMALE use_static = null -/datum/sprite_accessory/undershirt/bra_alt +/datum/sprite_accessory/bra/bra_alt name = "Bra - Alt" icon_state = "bra_alt" gender = FEMALE use_static = null -/datum/sprite_accessory/undershirt/bra_thin +/datum/sprite_accessory/bra/bra_thin name = "Bra - Thin" icon_state = "bra_thin" gender = FEMALE use_static = null -/datum/sprite_accessory/undershirt/bra_kinky +/datum/sprite_accessory/bra/bra_kinky name = "Bra - Kinky Black" icon_state = "bra_kinky" gender = FEMALE use_static = TRUE -/datum/sprite_accessory/undershirt/bra_freedom +/datum/sprite_accessory/bra/bra_freedom name = "Bra - Freedom" icon_state = "bra_assblastusa" gender = FEMALE use_static = TRUE -/datum/sprite_accessory/undershirt/bra_commie +/datum/sprite_accessory/bra/bra_commie name = "Bra - Commie" icon_state = "bra_commie" gender = FEMALE use_static = TRUE -/datum/sprite_accessory/undershirt/bra_beekini +/datum/sprite_accessory/bra/bra_beekini name = "Bra - Bee-kini" icon_state = "bra_bee-kini" gender = FEMALE use_static = TRUE -/datum/sprite_accessory/undershirt/bra_uk +/datum/sprite_accessory/bra/bra_uk name = "Bra - UK" icon_state = "bra_uk" gender = FEMALE use_static = TRUE -/datum/sprite_accessory/undershirt/bra_neko +/datum/sprite_accessory/bra/bra_neko name = "Bra - Neko" icon_state = "bra_neko" gender = FEMALE use_static = null -/datum/sprite_accessory/undershirt/halterneck_bra +/datum/sprite_accessory/bra/hi_vis_bra + name = "Safekini" + icon_state = "hi_vis_bra" + gender = FEMALE + use_static = TRUE + +/datum/sprite_accessory/bra/halterneck_bra name = "Bra - Halterneck" icon_state = "halterneck_bra" gender = FEMALE use_static = null -/datum/sprite_accessory/undershirt/sports_bra +/datum/sprite_accessory/bra/halterneck_alt + name = "Bra - Halterneck (Alt)" + icon_state = "bra_swimming" + gender = FEMALE + use_static = null + +/datum/sprite_accessory/bra/sports_bra name = "Bra, Sports" icon_state = "sports_bra" gender = FEMALE use_static = null -/datum/sprite_accessory/undershirt/sports_bra_alt +/datum/sprite_accessory/bra/sports_bra_alt name = "Bra, Sports - Alt" icon_state = "sports_bra_alt" gender = FEMALE use_static = null -/datum/sprite_accessory/undershirt/bra_strapless +/datum/sprite_accessory/bra/bra_strapless name = "Bra, Strapless" icon_state = "bra_strapless" gender = FEMALE use_static = null -/datum/sprite_accessory/undershirt/bra_latex +/datum/sprite_accessory/bra/bra_latex name = "Bra, Latex" icon_state = "bra_latex" gender = FEMALE use_static = TRUE erp_accessory = TRUE -/datum/sprite_accessory/undershirt/striped_bra +/datum/sprite_accessory/bra/striped_bra name = "Bra - Striped" icon_state = "striped_bra" gender = FEMALE use_static = null -/datum/sprite_accessory/undershirt/sarashi +/datum/sprite_accessory/bra/sarashi name = "Bra - Sarashi" icon_state = "bandages" gender = NEUTER use_static = null -/datum/sprite_accessory/undershirt/fishnet_sleeves +/datum/sprite_accessory/bra/fishnet_sleeves name = "Fishnet - Sleeved" icon_state = "fishnet_sleeves" gender = FEMALE use_static = TRUE -/datum/sprite_accessory/undershirt/fishnet_sleeves/alt +/datum/sprite_accessory/bra/fishnet_sleeves/alt name = "Fishnet - Sleeved (Greyscale)" icon_state = "fishnet_sleeves_alt" use_static = null -/datum/sprite_accessory/undershirt/fishnet_base +/datum/sprite_accessory/bra/fishnet_base name = "Fishnet - Sleeveless" icon_state = "fishnet_body" gender = FEMALE use_static = TRUE -/datum/sprite_accessory/undershirt/fishnet_base/alt +/datum/sprite_accessory/bra/fishnet_base/alt name = "Fishnet - Sleeveless (Greyscale)" icon_state = "fishnet_body_alt" use_static = null -/datum/sprite_accessory/undershirt/swimsuit - name = "Swimsuit Top" - icon_state = "bra_swimming" - gender = FEMALE - use_static = null - -/datum/sprite_accessory/undershirt/corset - name = "Corset" - icon_state = "corset" - gender = FEMALE - use_static = TRUE - hides_groin = TRUE - -/datum/sprite_accessory/undershirt/chastbra +/datum/sprite_accessory/bra/chastbra name = "Chastity Bra" icon_state = "chastbra" gender = FEMALE use_static = TRUE erp_accessory = TRUE -/datum/sprite_accessory/undershirt/pasties +/datum/sprite_accessory/bra/pasties name = "Pasties" icon_state = "pasties" gender = FEMALE use_static = null erp_accessory = TRUE -/datum/sprite_accessory/undershirt/pasties_alt +/datum/sprite_accessory/bra/pasties_alt name = "Pasties - Alt" icon_state = "pasties_alt" gender = FEMALE use_static = null erp_accessory = TRUE -/datum/sprite_accessory/undershirt/shibari +/datum/sprite_accessory/bra/shibari name = "Shibari" icon_state = "shibari" gender = FEMALE use_static = null erp_accessory = TRUE -/datum/sprite_accessory/undershirt/shibari_sleeves +/datum/sprite_accessory/bra/shibari_sleeves name = "Shibari Sleeves" icon_state = "shibari_sleeves" gender = FEMALE use_static = null erp_accessory = TRUE +/datum/sprite_accessory/bra/swimsuit + name = "Swimsuit Top" + icon_state = "bikini_bra" + gender = FEMALE + use_static = null + +/datum/sprite_accessory/bra/strapless_swimsuit + name = "Strapless Swimsuit Top" + icon_state = "strapless_biki_bra" + gender = FEMALE + use_static = null + +/datum/sprite_accessory/bra/strapless_swimsuit_alt + name = "Strapless Swimsuit Top (Alt)" + icon_state = "strapless_biki_bra_alt" + gender = FEMALE + use_static = null + +/datum/sprite_accessory/bra/binder + name = "Binder" + icon_state = "binder" + gender = MALE + use_static = null + +/datum/sprite_accessory/bra/binder/strapless + name = "Binder - Strapless" + icon_state = "binder_strapless" + +/datum/sprite_accessory/undershirt + icon = 'modular_skyrat/master_files/icons/mob/clothing/underwear.dmi' + use_static = TRUE + ///Whether this underwear includes a bottom (For Leotards and the likes) + var/hides_groin = FALSE + +/datum/sprite_accessory/undershirt/tanktop_alt + name = "Tank Top - Alt" + icon_state = "tanktop_alt" + use_static = null + +/datum/sprite_accessory/undershirt/tanktop_midriff + name = "Tank Top - Midriff" + icon_state = "tank_midriff" + gender = FEMALE + use_static = null + +/datum/sprite_accessory/undershirt/tanktop_midriff_alt + name = "Tank Top - Midriff Halterneck" + icon_state = "tank_midriff_alt" + gender = FEMALE + use_static = null + +/datum/sprite_accessory/undershirt/tankstripe + name = "Tank Top - Striped" + icon_state = "tank_stripes" + use_static = TRUE + +/datum/sprite_accessory/undershirt/tank_top_sun + name = "Tank top - Sun" + icon_state = "tank_sun" + use_static = TRUE + +/datum/sprite_accessory/undershirt/babydoll + name = "Babydoll" + icon_state = "babydoll" + gender = FEMALE + use_static = null + +/datum/sprite_accessory/undershirt/corset + name = "Corset" + icon_state = "corset" + gender = FEMALE + use_static = TRUE + hides_groin = TRUE + /datum/sprite_accessory/undershirt/bulletclub //4 life name = "Shirt - Black Skull" icon_state = "shirt_bc" @@ -831,16 +857,6 @@ GLOBAL_LIST_EMPTY(cached_mutant_icon_files) name = "Shirt - Blue Stripes" icon_state = "longstripe_blue" -/datum/sprite_accessory/undershirt/binder - name = "Binder" - icon_state = "binder" - gender = MALE - use_static = null - -/datum/sprite_accessory/undershirt/binder/strapless - name = "Binder - Strapless" - icon_state = "binder_strapless" - /datum/sprite_accessory/undershirt/turtleneck name = "Sweater - Turtleneck" icon_state = "turtleneck" diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/genitals.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/genitals.dm index 6930b5ef585..f5d314f1793 100644 --- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/genitals.dm +++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/genitals.dm @@ -45,6 +45,10 @@ else if(genital_location == CHEST && worn_underwear.hides_breasts) return TRUE + //Are they wearing a bra? + if(target_mob.bra != "Nude" && !(target_mob.underwear_visibility & UNDERWEAR_HIDE_BRA) && genital_location == CHEST) + return TRUE + //Nothing they're wearing will cover them else return FALSE diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm index 6b540a5cb7f..78c597e7864 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm @@ -83,21 +83,24 @@ var/underwear_button = underwear_visibility & UNDERWEAR_HIDE_UNDIES ? "Show underwear" : "Hide underwear" var/undershirt_button = underwear_visibility & UNDERWEAR_HIDE_SHIRT ? "Show shirt" : "Hide shirt" var/socks_button = underwear_visibility & UNDERWEAR_HIDE_SOCKS ? "Show socks" : "Hide socks" - var/list/choice_list = list("[underwear_button]" = 1,"[undershirt_button]" = 2,"[socks_button]" = 3,"Show all" = 4, "Hide all" = 5) + var/bra_button = underwear_visibility & UNDERWEAR_HIDE_BRA ? "Show bra" : "Hide bra" + var/list/choice_list = list("[underwear_button]" = "underwear", "[bra_button]" = "bra", "[undershirt_button]" = "shirt", "[socks_button]" = "socks","show all" = "show", "Hide all" = "hide") var/picked_visibility = input(src, "Choose visibility setting", "Show/Hide underwear") as null|anything in choice_list if(picked_visibility) var/picked_choice = choice_list[picked_visibility] switch(picked_choice) - if(1) + if("underwear") underwear_visibility ^= UNDERWEAR_HIDE_UNDIES - if(2) + if("bra") + underwear_visibility ^= UNDERWEAR_HIDE_BRA + if("shirt") underwear_visibility ^= UNDERWEAR_HIDE_SHIRT - if(3) + if("socks") underwear_visibility ^= UNDERWEAR_HIDE_SOCKS - if(4) + if("show") underwear_visibility = NONE - if(5) - underwear_visibility = UNDERWEAR_HIDE_UNDIES | UNDERWEAR_HIDE_SHIRT | UNDERWEAR_HIDE_SOCKS + if("hide") + underwear_visibility = UNDERWEAR_HIDE_UNDIES | UNDERWEAR_HIDE_SHIRT | UNDERWEAR_HIDE_SOCKS | UNDERWEAR_HIDE_BRA update_body() return diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human_defines.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human_defines.dm index 9e0f80c7c2c..2b5d1e83f9b 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human_defines.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human_defines.dm @@ -21,4 +21,7 @@ var/oversized_piggyknock = 3 SECONDS /// Alpha of the hair. Takes precedent over species hair_alpha if non-null. var/hair_alpha - + /// The selected bra. + var/bra = "Nude" + /// Color of the bra. + var/bra_color = "#FFFFFF" diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm index 712a5fd1757..3d0aaf94db5 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm @@ -133,6 +133,18 @@ GLOBAL_LIST_EMPTY(customizable_races) underwear_overlay.color = species_human.underwear_color standing += underwear_overlay + if(species_human.bra && !(species_human.underwear_visibility & UNDERWEAR_HIDE_BRA)) + var/datum/sprite_accessory/bra/bra = GLOB.bra_list[species_human.bra] + + if(bra) + var/mutable_appearance/bra_overlay + var/icon_state = bra.icon_state + bra_overlay = mutable_appearance(bra.icon, icon_state, -BODY_LAYER) + if(!bra.use_static) + bra_overlay.color = species_human.bra_color + + standing += bra_overlay + if(species_human.undershirt && !(species_human.underwear_visibility & UNDERWEAR_HIDE_SHIRT)) var/datum/sprite_accessory/undershirt/undershirt = GLOB.undershirt_list[species_human.undershirt] if(undershirt) 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 50fcc84f3f7..7471839e1db 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 5210b209775..bf731c941aa 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 801f65fb7e0..3af433695a9 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 25af43017e7..32391bd465e 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 00000000000..85b251c08b6 --- /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 8f1f2e7603a..d66f6fe2f4a 100644 --- a/modular_skyrat/modules/delam_emergency_stop/code/scram.dm +++ b/modular_skyrat/modules/delam_emergency_stop/code/scram.dm @@ -1,6 +1,6 @@ #define SM_PREVENT_EXPLOSION_THRESHOLD 100 -#define SM_COOLING_MIXTURE_MOLES 64000 -#define SM_COOLING_MIXTURE_TEMP 120 +#define SM_COOLING_MIXTURE_MOLES 16000 +#define SM_COOLING_MIXTURE_TEMP 170 #define DAMAGED_SUPERMATTER_COLOR list(1,0.1,0.2,0, 0,0.9,0.1,0, 0.1,-0.05,0.85,0, 0,0,0,0.9, 0,0,0,0) #define MISTAKES_WERE_MADE 0 #define MANUAL_INTERVENTION 0 @@ -15,12 +15,12 @@ #define SHATTER_LIGHT_RANGE 0 #define SHATTER_FLAME_RANGE 3 #define SHATTER_FLASH_RANGE 5 -#define SHATTER_MIN_TIME 13 SECONDS -#define SHATTER_MAX_TIME 15 SECONDS -#define EVAC_WARNING_TIMER 5 SECONDS -#define POWER_CUT_MIN_DURATION_SECONDS 19 -#define POWER_CUT_MAX_DURATION_SECONDS 21 -#define AIR_INJECT_RATE 33 +#define SHATTER_MIN_TIME 17 SECONDS +#define SHATTER_MAX_TIME 19 SECONDS +#define EVAC_WARNING_TIMER 3 SECONDS +#define POWER_CUT_MIN_DURATION_SECONDS 21 +#define POWER_CUT_MAX_DURATION_SECONDS 23 +#define AIR_INJECT_RATE 175 #define BUTTON_SOUND_RANGE 7 #define BUTTON_SOUND_FALLOFF_DISTANCE 7 #define MACHINE_SOUND_RANGE 15 @@ -176,7 +176,7 @@ notify_volume = 75, ) - radio.talk_into(src, "DELAMINATION SUPPRESSION SYSTEM FIRING IN [EVAC_WARNING_TIMER / 10] 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)), EVAC_WARNING_TIMER) diff --git a/modular_skyrat/modules/electric_welder/code/electric_welder.dm b/modular_skyrat/modules/electric_welder/code/electric_welder.dm index 368a37a7e19..a3426e2cf78 100644 --- a/modular_skyrat/modules/electric_welder/code/electric_welder.dm +++ b/modular_skyrat/modules/electric_welder/code/electric_welder.dm @@ -86,12 +86,3 @@ inhand_icon_state = "[initial(inhand_icon_state)]" return ..() -/datum/design/exwelder - name = "Electrical Welding Tool" - desc = "An experimental welding tool capable of welding using electricity." - id = "exwelder" - build_type = PROTOLATHE | AWAY_LATHE - materials = list(/datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, /datum/material/glass = SMALL_MATERIAL_AMOUNT * 5, /datum/material/plasma = HALF_SHEET_MATERIAL_AMOUNT, /datum/material/uranium = SMALL_MATERIAL_AMOUNT * 2) - build_path = /obj/item/weldingtool/electric - category = list(RND_CATEGORY_TOOLS + RND_SUBCATEGORY_TOOLS_ENGINEERING_ADVANCED) - departmental_flags = DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_ENGINEERING diff --git a/modular_skyrat/modules/gunsgalore/code/projectile.dm b/modular_skyrat/modules/gunsgalore/code/projectile.dm deleted file mode 100644 index 9de14ea5607..00000000000 --- 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 081b4a0853f..fd8e5462a6d 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 bc51c730b7d..4765f9f9df6 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 e87de1a4bf2..aea55dcc147 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 7f4e2bfde67..bd49fc1de17 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 00000000000..d55fd75aeb3 --- /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 fe3b6fea50d..b6122decd07 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 5725a349e52..2bc2ed4cdee 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 dc25e69d7dd..35066f09857 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/donator/personal/donator_personal.dm b/modular_skyrat/modules/loadouts/loadout_items/donator/personal/donator_personal.dm index 6a4927cfc9f..7b6e248a278 100644 --- a/modular_skyrat/modules/loadouts/loadout_items/donator/personal/donator_personal.dm +++ b/modular_skyrat/modules/loadouts/loadout_items/donator/personal/donator_personal.dm @@ -709,3 +709,13 @@ name = "Hardlight Wheelchair Projector" item_path = /obj/item/holosign_creator/hardlight_wheelchair ckeywhitelist = list("sqnztb") + +/datum/loadout_item/under/jumpsuit/noble_gambeson + name = "Noble Gambeson" + item_path = /obj/item/clothing/under/rank/civilian/chaplain/divine_archer/noble + ckeywhitelist = list("grasshand") + +/datum/loadout_item/shoes/noble_boots + name = "Noble Boots" + item_path = /obj/item/clothing/shoes/jackboots/noble + ckeywhitelist = list("grasshand") 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 8f788249efc..27bad258039 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 21ef8c9a290..528f8e6dc34 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 @@ -301,6 +301,10 @@ GLOBAL_LIST_INIT(loadout_miscunders, generate_loadout_items(/datum/loadout_item/ name = "Recolorable Ripped Jean Shorts" item_path = /obj/item/clothing/under/shorts/skyrat/shorts_ripped +/datum/loadout_item/under/miscellaneous/shortershorts + name = "Recolorable Shorter Shorts" + item_path = /obj/item/clothing/under/shorts/skyrat/shortershorts + /datum/loadout_item/under/miscellaneous/shorts name = "Recolorable Shorts" item_path = /obj/item/clothing/under/shorts @@ -672,10 +676,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 8a310ece882..8c24b2dcbec 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/lavaland_ruin_code.dm b/modular_skyrat/modules/mapping/code/lavaland_ruin_code.dm index 24b1c9abd96..c66faed0810 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 81a1d86f681..bfb7e2621d3 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 a31cf1a6bc0..1927413f51b 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 8fbc3c407be..808732c5572 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 00000000000..1d7eba6198f --- /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 7c6b0e11b3b..c1f9c3fc4c3 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 af6ecae38e4..8c83b8c615e 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 c1f0a5f908e..6e90ebfda46 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 18944df55f7..69c0a581c35 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 ce6aa14dfb2..c861b924d6f 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_items/lewd_items/code/lewd_items/dildo.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/dildo.dm index 95416eb183a..a94c833cc9b 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/dildo.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/dildo.dm @@ -136,7 +136,7 @@ user.adjust_pleasure(8) if(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_EYES) //Mouth only. Sorry, perverts. No eye/ear penetration for you today. - if(!target.is_mouth_covered()) + if(target.is_mouth_covered()) to_chat(user, span_danger("Looks like [target]'s mouth is covered!")) return FALSE @@ -227,6 +227,11 @@ GLOBAL_LIST_INIT(dildo_colors, list(//mostly neon colors color_changed = TRUE return TRUE +/obj/item/clothing/sextoy/dildo/custom_dildo/Initialize(mapload) + . = ..() + if(!length(dildo_sizes)) + populate_dildo_designs() + /// Choose a color and transparency level for the toy /obj/item/clothing/sextoy/dildo/custom_dildo/proc/customize(mob/living/user) if(!src || !user || user.incapacitated() || !in_range(user, src)) diff --git a/modular_skyrat/modules/modular_vending/code/wardrobes.dm b/modular_skyrat/modules/modular_vending/code/wardrobes.dm index 8cf3fb0f6da..e5f3e0210e7 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 247a9a82ba5..550af2c130e 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 e2b633a9c1e..8165a798a6f 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 4e008aa3a54..8778e469bec 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 4673264c92d..2a4da011635 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 bc58e789153..e07039ded74 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 8a49d1b6cf5..2df1919fbbf 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 12d2406d0b7..b9126f3a3a5 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 8e20fcda771..264d9f8bedc 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/primitive_cooking_additions/code/millstone.dm b/modular_skyrat/modules/primitive_cooking_additions/code/millstone.dm index d477528acd4..314390a7f54 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 747601cb1f1..7abf5585e08 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 fb7ecd3f43a..e41ac38f344 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 351903a3e49..00000000000 --- 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 b99291084f2..ef48f0bf947 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 00000000000..394bfed2a13 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 00000000000..87ca57302a2 Binary files /dev/null and b/sound/magic/hereticknock.ogg differ diff --git a/strings/tips.txt b/strings/tips.txt index 514a9dada7a..12248bb4124 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 b1eb84bb8b7..2a89f022002 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 d8c253873cc..0fd78bec8e4 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 218390d7cbe..40f533b939f 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" @@ -459,7 +462,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" @@ -767,6 +769,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" @@ -901,6 +904,7 @@ #include "code\datums\ai\basic_mobs\basic_ai_behaviors\travel_towards.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\ventcrawling.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\write_on_paper.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\attack_adjacent_target.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\attack_obstacle_in_path.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\climb_tree.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_food.dm" @@ -908,6 +912,7 @@ #include "code\datums\ai\basic_mobs\basic_subtrees\find_parent.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\flee_target.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\maintain_distance.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\move_to_cardinal.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\opportunistic_ventcrawler.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\ranged_skirmish.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\simple_attack_target.dm" @@ -1096,6 +1101,7 @@ #include "code\datums\components\label.dm" #include "code\datums\components\leash.dm" #include "code\datums\components\light_eater.dm" +#include "code\datums\components\ling_decoy_brain.dm" #include "code\datums\components\lock_on_cursor.dm" #include "code\datums\components\magnet.dm" #include "code\datums\components\manual_blinking.dm" @@ -1199,6 +1205,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" @@ -1230,6 +1237,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" @@ -1331,6 +1339,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" @@ -1394,6 +1403,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" @@ -1582,10 +1592,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" @@ -1698,6 +1787,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" @@ -2076,6 +2166,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" @@ -2530,6 +2621,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" @@ -2574,6 +2666,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" @@ -2613,11 +2706,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" @@ -2802,6 +2895,7 @@ #include "code\modules\antagonists\changeling\powers\headcrab.dm" #include "code\modules\antagonists\changeling\powers\lesserform.dm" #include "code\modules\antagonists\changeling\powers\mimic_voice.dm" +#include "code\modules\antagonists\changeling\powers\mmi_talk.dm" #include "code\modules\antagonists\changeling\powers\mutations.dm" #include "code\modules\antagonists\changeling\powers\panacea.dm" #include "code\modules\antagonists\changeling\powers\pheromone_receptors.dm" @@ -2859,17 +2953,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" @@ -2879,10 +2977,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" @@ -2910,12 +3012,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" @@ -3602,6 +3706,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" @@ -3856,6 +3961,7 @@ #include "code\modules\hydroponics\grown\random.dm" #include "code\modules\hydroponics\grown\replicapod.dm" #include "code\modules\hydroponics\grown\root.dm" +#include "code\modules\hydroponics\grown\seedling.dm" #include "code\modules\hydroponics\grown\sugarcane.dm" #include "code\modules\hydroponics\grown\tea_coffee.dm" #include "code\modules\hydroponics\grown\tobacco.dm" @@ -4254,6 +4360,8 @@ #include "code\modules\mob\living\basic\festivus_pole.dm" #include "code\modules\mob\living\basic\health_adjustment.dm" #include "code\modules\mob\living\basic\tree.dm" +#include "code\modules\mob\living\basic\clown\clown.dm" +#include "code\modules\mob\living\basic\clown\clown_ai.dm" #include "code\modules\mob\living\basic\farm_animals\deer.dm" #include "code\modules\mob\living\basic\farm_animals\pig.dm" #include "code\modules\mob\living\basic\farm_animals\pony.dm" @@ -4277,6 +4385,9 @@ #include "code\modules\mob\living\basic\jungle\mega_arachnid\mega_arachnid.dm" #include "code\modules\mob\living\basic\jungle\mega_arachnid\mega_arachnid_abilities.dm" #include "code\modules\mob\living\basic\jungle\mega_arachnid\mega_arachnid_ai.dm" +#include "code\modules\mob\living\basic\jungle\seedling\seedling.dm" +#include "code\modules\mob\living\basic\jungle\seedling\seedling_ai.dm" +#include "code\modules\mob\living\basic\jungle\seedling\seedling_projectiles.dm" #include "code\modules\mob\living\basic\lavaland\mining.dm" #include "code\modules\mob\living\basic\lavaland\basilisk\basilisk.dm" #include "code\modules\mob\living\basic\lavaland\basilisk\basilisk_overheat.dm" @@ -4286,6 +4397,10 @@ #include "code\modules\mob\living\basic\lavaland\bileworm\bileworm_instrument.dm" #include "code\modules\mob\living\basic\lavaland\bileworm\bileworm_loot.dm" #include "code\modules\mob\living\basic\lavaland\bileworm\bileworm_vileworm.dm" +#include "code\modules\mob\living\basic\lavaland\brimdemon\brimbeam.dm" +#include "code\modules\mob\living\basic\lavaland\brimdemon\brimdemon.dm" +#include "code\modules\mob\living\basic\lavaland\brimdemon\brimdemon_ai.dm" +#include "code\modules\mob\living\basic\lavaland\brimdemon\brimdemon_loot.dm" #include "code\modules\mob\living\basic\lavaland\goldgrub\goldgrub.dm" #include "code\modules\mob\living\basic\lavaland\goldgrub\goldgrub_abilities.dm" #include "code\modules\mob\living\basic\lavaland\goldgrub\goldgrub_ai.dm" @@ -4610,7 +4725,6 @@ #include "code\modules\mob\living\simple_animal\hostile\jungle\_jungle_mobs.dm" #include "code\modules\mob\living\simple_animal\hostile\jungle\leaper.dm" #include "code\modules\mob\living\simple_animal\hostile\jungle\mook.dm" -#include "code\modules\mob\living\simple_animal\hostile\jungle\seedling.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\_megafauna.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\blood_drunk_miner.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\bubblegum.dm" @@ -4621,7 +4735,6 @@ #include "code\modules\mob\living\simple_animal\hostile\megafauna\hierophant.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\legion.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\wendigo.dm" -#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\brimdemon.dm" #include "code\modules\mob\living\simple_animal\hostile\mining_mobs\curse_blob.dm" #include "code\modules\mob\living\simple_animal\hostile\mining_mobs\gutlunch.dm" #include "code\modules\mob\living\simple_animal\hostile\mining_mobs\hivelord.dm" @@ -4634,7 +4747,6 @@ #include "code\modules\mob\living\simple_animal\hostile\mining_mobs\elites\herald.dm" #include "code\modules\mob\living\simple_animal\hostile\mining_mobs\elites\legionnaire.dm" #include "code\modules\mob\living\simple_animal\hostile\mining_mobs\elites\pandora.dm" -#include "code\modules\mob\living\simple_animal\hostile\retaliate\clown.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\goose.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\retaliate.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\snake.dm" @@ -4688,7 +4800,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" @@ -4998,6 +5109,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" @@ -5776,6 +5888,7 @@ #include "modular_skyrat\master_files\code\game\objects\items\storage\backpack.dm" #include "modular_skyrat\master_files\code\game\objects\items\storage\boxes.dm" #include "modular_skyrat\master_files\code\game\objects\items\tools\weldingtool.dm" +#include "modular_skyrat\master_files\code\game\objects\structures\mannequin.dm" #include "modular_skyrat\master_files\code\game\objects\structures\railings.dm" #include "modular_skyrat\master_files\code\game\objects\structures\sauna_oven.dm" #include "modular_skyrat\master_files\code\game\objects\structures\tables_racks.dm" @@ -5801,6 +5914,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" @@ -6004,6 +6118,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" @@ -6270,7 +6385,6 @@ #include "modular_skyrat\modules\cargoborg\code\robot_items.dm" #include "modular_skyrat\modules\cargoborg\code\robot_modules.dm" #include "modular_skyrat\modules\cell_component\code\cell_component.dm" -#include "modular_skyrat\modules\cell_component\code\flashlight.dm" #include "modular_skyrat\modules\cellguns\code\cellgun_cells.dm" #include "modular_skyrat\modules\cellguns\code\cellguns.dm" #include "modular_skyrat\modules\cellguns\code\medigun_cells.dm" @@ -6385,6 +6499,7 @@ #include "modular_skyrat\modules\contractor\code\datums\contractor_tablet.dm" #include "modular_skyrat\modules\contractor\code\datums\mind_datum.dm" #include "modular_skyrat\modules\contractor\code\datums\objective.dm" +#include "modular_skyrat\modules\contractor\code\datums\outfit.dm" #include "modular_skyrat\modules\contractor\code\datums\midround\antag_datum.dm" #include "modular_skyrat\modules\contractor\code\datums\midround\event.dm" #include "modular_skyrat\modules\contractor\code\datums\midround\objective.dm" @@ -6617,6 +6732,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" @@ -6724,7 +6840,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" @@ -6768,6 +6883,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" @@ -6908,6 +7024,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" @@ -7393,7 +7510,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 57cc34e77e1..00000000000 --- 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 00000000000..b1077f6bdcb --- /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 904cf38e6f1..a4fb35edebc 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/CommunicationsConsole.js b/tgui/packages/tgui/interfaces/CommunicationsConsole.js index 6e8ac4f2b6d..0436887b242 100644 --- a/tgui/packages/tgui/interfaces/CommunicationsConsole.js +++ b/tgui/packages/tgui/interfaces/CommunicationsConsole.js @@ -19,7 +19,7 @@ const EMAG_SHUTTLE_NOTICE = const sortShuttles = sortBy( (shuttle) => !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 8f27f59a984..00000000000 --- 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 && ( -