diff --git a/_maps/RandomRuins/SpaceRuins/nova/gorilla.dmm b/_maps/RandomRuins/SpaceRuins/nova/gorilla.dmm deleted file mode 100644 index aecf79a010e..00000000000 --- a/_maps/RandomRuins/SpaceRuins/nova/gorilla.dmm +++ /dev/null @@ -1,134 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"a" = ( -/turf/template_noop, -/area/template_noop) -"b" = ( -/obj/structure/chair/sofa/right/brown{ - dir = 4 - }, -/mob/living/basic/gorilla{ - anchored = 1; - dir = 4; - faction = list("neutral") - }, -/turf/open/misc/beach/sand, -/area/ruin/space/has_grav/powered) -"p" = ( -/turf/open/misc/beach/sand, -/area/ruin/space/has_grav/powered) -"t" = ( -/obj/structure/table/wood, -/obj/item/flashlight/lamp/bananalamp, -/turf/open/misc/beach/sand, -/area/ruin/space/has_grav/powered) -"y" = ( -/obj/structure/flora/tree/palm, -/obj/structure/fans/tiny/invisible, -/turf/open/misc/beach/sand, -/area/ruin/space/has_grav/powered) -"C" = ( -/obj/structure/showcase/machinery/tv, -/turf/open/misc/beach/sand, -/area/ruin/space/has_grav/powered) -"H" = ( -/mob/living/basic/pet/dog/corgi{ - anchored = 1 - }, -/obj/structure/bed/dogbed, -/turf/open/misc/beach/sand, -/area/ruin/space/has_grav/powered) -"M" = ( -/obj/structure/fans/tiny/invisible, -/turf/open/misc/beach/sand, -/area/ruin/space/has_grav/powered) -"O" = ( -/obj/item/food/grown/banana, -/obj/item/food/grown/banana, -/obj/item/food/grown/banana, -/obj/item/food/grown/banana, -/obj/item/food/grown/banana, -/obj/item/food/grown/banana, -/obj/item/food/grown/banana, -/obj/item/food/grown/banana, -/obj/item/food/grown/banana, -/obj/item/food/grown/banana, -/obj/item/food/grown/banana, -/obj/item/food/grown/banana, -/obj/structure/closet/secure_closet/freezer/fridge/open, -/turf/open/misc/beach/sand, -/area/ruin/space/has_grav/powered) -"U" = ( -/obj/structure/chair/sofa/left/brown{ - dir = 4 - }, -/turf/open/misc/beach/sand, -/area/ruin/space/has_grav/powered) -"V" = ( -/obj/structure/water_source/puddle, -/obj/structure/fans/tiny/invisible, -/turf/open/misc/beach/sand, -/area/ruin/space/has_grav/powered) - -(1,1,1) = {" -a -a -a -a -a -a -a -"} -(2,1,1) = {" -a -M -M -M -M -y -a -"} -(3,1,1) = {" -a -y -U -b -t -M -a -"} -(4,1,1) = {" -a -V -p -p -p -M -a -"} -(5,1,1) = {" -a -M -O -C -H -M -a -"} -(6,1,1) = {" -a -M -M -M -y -M -a -"} -(7,1,1) = {" -a -a -a -a -a -a -a -"} diff --git a/_maps/RandomRuins/SpaceRuins/nova/shuttle8532.dmm b/_maps/RandomRuins/SpaceRuins/nova/shuttle8532.dmm index 07f76580455..cdb3ee7d85d 100644 --- a/_maps/RandomRuins/SpaceRuins/nova/shuttle8532.dmm +++ b/_maps/RandomRuins/SpaceRuins/nova/shuttle8532.dmm @@ -34,6 +34,7 @@ /obj/machinery/door/poddoor{ id = "abandonedshiphatch" }, +/obj/effect/mapping_helpers/airlock/locked, /turf/open/floor/plating/airless, /area/ruin/space/has_grav/shuttle8532crewquarters) "ay" = ( @@ -74,6 +75,14 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer4, /turf/open/floor/plating/airless, /area/ruin/space/has_grav/shuttle8532engineering) +"ba" = ( +/obj/structure/table/reinforced, +/obj/item/stack/sheet/glass/fifty, +/obj/item/stack/sheet/rglass/fifty{ + pixel_y = 6 + }, +/turf/open/floor/iron/airless, +/area/ruin/space/has_grav/shuttle8532engineering) "bo" = ( /obj/effect/turf_decal/trimline/green/filled/line, /obj/structure/chair/sofa/bench{ @@ -323,6 +332,14 @@ }, /turf/open/floor/iron/airless, /area/ruin/space/has_grav/shuttle8532cargohall) +"gE" = ( +/obj/structure/table/reinforced, +/obj/item/stack/sheet/iron/fifty, +/obj/item/stack/sheet/plastic/fifty{ + pixel_y = 5 + }, +/turf/open/floor/iron/airless, +/area/ruin/space/has_grav/shuttle8532engineering) "gI" = ( /obj/effect/mine/explosive, /obj/effect/decal/cleanable/blood, @@ -353,6 +370,7 @@ /area/ruin/space/has_grav/shuttle8532crewquarters) "hf" = ( /obj/machinery/door/airlock/maintenance_hatch, +/obj/effect/mapping_helpers/airlock/locked, /turf/open/floor/plating, /area/ruin/space/has_grav/shuttle8532bridge) "hh" = ( @@ -411,6 +429,7 @@ /obj/machinery/door/poddoor{ id = "abandonedshiphatch" }, +/obj/effect/mapping_helpers/airlock/locked, /turf/open/floor/plating/airless, /area/ruin/space/has_grav/shuttle8532crewquarters) "iG" = ( @@ -492,7 +511,7 @@ /turf/open/floor/iron/airless, /area/ruin/space/has_grav/shuttle8532researchbay) "jQ" = ( -/turf/closed/wall/r_wall, +/turf/closed/indestructible/syndicate, /area/ruin/space/has_grav/shuttle8532crewquarters) "kp" = ( /obj/structure/lattice/catwalk, @@ -509,7 +528,7 @@ nightshift_light_color = "#FF0000"; pixel_y = 32 }, -/turf/closed/wall/r_wall, +/turf/closed/indestructible/syndicate, /area/ruin/space/has_grav/shuttle8532bridge) "ky" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer4, @@ -712,7 +731,7 @@ /turf/open/floor/iron/airless, /area/ruin/space/has_grav/shuttle8532bridge) "pu" = ( -/turf/closed/wall/r_wall, +/turf/closed/wall/r_wall/syndicate, /area/ruin/space/has_grav/shuttle8532bridge) "py" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ @@ -993,7 +1012,7 @@ /area/ruin/space/has_grav/shuttle8532researchbay) "vE" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer4, -/turf/closed/wall/r_wall, +/turf/closed/indestructible/syndicate, /area/ruin/space/has_grav/shuttle8532engineering) "vG" = ( /obj/item/stack/cable_coil/cut, @@ -1104,6 +1123,9 @@ /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/iron/airless, /area/ruin/space/has_grav/shuttle8532researchbay) +"xO" = ( +/turf/closed/indestructible/syndicate, +/area/ruin/space/has_grav/shuttle8532bridge) "xR" = ( /obj/effect/turf_decal/trimline/blue/filled/line, /obj/structure/cable, @@ -1175,7 +1197,7 @@ /area/ruin/space/has_grav/shuttle8532crewquarters) "zz" = ( /obj/effect/decal/cleanable/dirt, -/turf/closed/wall/r_wall, +/turf/closed/indestructible/syndicate, /area/ruin/space/has_grav/shuttle8532engineering) "zA" = ( /obj/effect/decal/cleanable/cobweb, @@ -1331,7 +1353,7 @@ dir = 9; system_id = "ship_outer_turrets" }, -/turf/closed/wall/r_wall, +/turf/closed/indestructible/syndicate, /area/ruin/space/has_grav/shuttle8532researchbay) "BR" = ( /obj/item/chair{ @@ -1514,7 +1536,7 @@ nightshift_light_color = "#00FF00"; pixel_y = 32 }, -/turf/closed/wall/r_wall, +/turf/closed/indestructible/syndicate, /area/ruin/space/has_grav/shuttle8532bridge) "EQ" = ( /obj/effect/decal/cleanable/dirt, @@ -1567,6 +1589,12 @@ }, /turf/open/floor/iron/airless, /area/ruin/space/has_grav/shuttle8532cargohall) +"FW" = ( +/mob/living/basic/trooper/syndicate/melee/space/anthro/lizard{ + faction = null + }, +/turf/open/floor/iron/airless, +/area/ruin/space/has_grav/shuttle8532bridge) "Gv" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/mob_spawn/corpse/human/syndicatecommando, @@ -1632,11 +1660,10 @@ /turf/open/floor/iron/airless, /area/ruin/space/has_grav/shuttle8532bridge) "HP" = ( -/obj/structure/window/reinforced/fulltile, /obj/machinery/door/poddoor{ id = "abandonedshipbridgeblast" }, -/turf/open/floor/plating, +/turf/closed/indestructible/opsglass, /area/ruin/space/has_grav/shuttle8532bridge) "HW" = ( /obj/effect/decal/cleanable/dirt, @@ -1836,7 +1863,9 @@ /turf/open/floor/engine/airless, /area/ruin/space/has_grav/shuttle8532engineering) "MM" = ( -/mob/living/basic/trooper/syndicate/melee/space, +/mob/living/basic/trooper/syndicate/melee/sword/space/stormtrooper{ + faction = null + }, /turf/open/floor/iron/airless, /area/ruin/space/has_grav/shuttle8532engineering) "MO" = ( @@ -1966,6 +1995,12 @@ /obj/structure/sign/poster/official/random/directional/north, /turf/open/floor/iron/airless, /area/ruin/space/has_grav/shuttle8532researchbay) +"Pn" = ( +/mob/living/basic/trooper/syndicate/ranged/shotgun/space/stormtrooper/anthro/fox{ + faction = null + }, +/turf/open/floor/iron/airless, +/area/ruin/space/has_grav/shuttle8532bridge) "Ps" = ( /obj/effect/decal/cleanable/blood, /obj/effect/mapping_helpers/broken_floor, @@ -2026,7 +2061,7 @@ /turf/template_noop, /area/template_noop) "QR" = ( -/turf/closed/wall/r_wall, +/turf/closed/indestructible/syndicate, /area/ruin/space/has_grav/shuttle8532engineering) "Ra" = ( /obj/structure/table/reinforced, @@ -2069,7 +2104,7 @@ dir = 5; system_id = "ship_outer_turrets" }, -/turf/closed/wall/r_wall, +/turf/closed/indestructible/syndicate, /area/ruin/space/has_grav/shuttle8532researchbay) "RY" = ( /obj/effect/decal/cleanable/dirt, @@ -2114,7 +2149,7 @@ /turf/open/floor/plating/airless, /area/ruin/space/has_grav/shuttle8532crewquarters) "SJ" = ( -/turf/closed/wall/r_wall, +/turf/closed/indestructible/syndicate, /area/ruin/space/has_grav/shuttle8532researchbay) "Tq" = ( /turf/open/floor/engine/airless, @@ -2183,8 +2218,7 @@ /turf/open/floor/iron/airless, /area/ruin/space/has_grav/shuttle8532bridge) "Uy" = ( -/mob/living/basic/trooper/syndicate/melee/space, -/turf/open/floor/iron/airless, +/turf/closed/wall/r_wall/syndicate/nodiagonal, /area/ruin/space/has_grav/shuttle8532bridge) "UN" = ( /obj/effect/turf_decal/trimline/green/filled/line{ @@ -2272,7 +2306,7 @@ /turf/open/floor/iron/airless, /area/ruin/space/has_grav/shuttle8532researchbay) "Wz" = ( -/turf/closed/wall/r_wall, +/turf/closed/indestructible/syndicate, /area/ruin/space/has_grav/shuttle8532cargohall) "WH" = ( /obj/effect/turf_decal/trimline/blue/filled/line, @@ -2490,7 +2524,7 @@ qb qb kx -pu +xO qb qb qb @@ -2553,7 +2587,7 @@ qb qb by ZK -pu +xO jQ jQ qb @@ -2616,7 +2650,7 @@ qb qb OQ vK -pu +xO Vf jQ qb @@ -2742,7 +2776,7 @@ qb qb ZN bs -pu +xO Fu jQ jQ @@ -2803,9 +2837,9 @@ qb "} (6,1,1) = {" qb -pu +xO EE -pu +xO Lt NJ La @@ -2866,11 +2900,11 @@ qb "} (7,1,1) = {" qb -pu -pu -pu -pu -pu +xO +xO +xO +xO +xO xK jQ jQ @@ -2929,11 +2963,11 @@ qb "} (8,1,1) = {" pu -pu +Uy XQ fp HK -pu +xO cg Hs oR @@ -2994,9 +3028,9 @@ qb pu zA ZU -Uy +Vi ks -pu +xO jQ jQ iy @@ -3057,9 +3091,9 @@ qb HP eV Wq -Vi +Pn ff -pu +xO VB BK DY @@ -3122,7 +3156,7 @@ eV Gv Vi BS -pu +xO sH Ds uq @@ -3185,7 +3219,7 @@ ji Vi NK ps -pu +xO ha Ds wU @@ -3248,7 +3282,7 @@ Ji fn zG Ep -pu +xO RE uK wU @@ -3311,7 +3345,7 @@ eV Vi eC ER -pu +xO UN Ds re @@ -3437,7 +3471,7 @@ eV nd Vj xR -pu +xO uG yz Nx @@ -3500,7 +3534,7 @@ Ra jJ OZ ff -pu +xO RE Ds yv @@ -3563,7 +3597,7 @@ zX Vi Qv Se -pu +xO Ue TM Ip @@ -3623,10 +3657,10 @@ hP (19,1,1) = {" HP eV -Uy +Vi Vi Ux -pu +xO ac TM yv @@ -3687,9 +3721,9 @@ qb HP eV Wq -Vi +FW Hg -pu +xO jh iP ef @@ -3747,12 +3781,12 @@ YO qb "} (21,1,1) = {" -pu +xO eV vS Vi qP -pu +xO jQ jQ aw @@ -3810,12 +3844,12 @@ YO qb "} (22,1,1) = {" -pu -pu +xO +xO Yk Ci HK -pu +xO lt VF NJ @@ -3874,11 +3908,11 @@ ve "} (23,1,1) = {" qb -pu -pu -pu -pu -pu +xO +xO +xO +xO +xO NJ jQ jQ @@ -3939,7 +3973,7 @@ hP ts OQ nx -pu +xO CG Fu Ff @@ -4002,7 +4036,7 @@ qb qb OQ Xu -pu +xO NJ jQ jQ @@ -4128,7 +4162,7 @@ qb qb tP bs -pu +xO Qn jQ qb @@ -4189,9 +4223,9 @@ ve "} (28,1,1) = {" qb -pu +xO ds -pu +xO jQ jQ qb @@ -4242,8 +4276,8 @@ QR QR oJ kL -Yq -JB +gE +ba QR HW Tt @@ -4254,7 +4288,7 @@ hP qb qb EM -pu +xO qb qb qb diff --git a/_maps/RandomRuins/SpaceRuins/nova/spacehotel.dmm b/_maps/RandomRuins/SpaceRuins/nova/spacehotel.dmm index c055ff2272c..7c74de2a09d 100644 --- a/_maps/RandomRuins/SpaceRuins/nova/spacehotel.dmm +++ b/_maps/RandomRuins/SpaceRuins/nova/spacehotel.dmm @@ -4478,6 +4478,9 @@ /obj/effect/turf_decal/siding/dark{ dir = 4 }, +/obj/structure/disposalpipe/junction/flip{ + dir = 1 + }, /turf/open/floor/carpet/black, /area/ruin/space/has_grav/hotel) "xD" = ( diff --git a/_maps/map_files/generic/CentCom_nova_z2.dmm b/_maps/map_files/generic/CentCom_nova_z2.dmm index 7f12a58bb35..7a4a72b2015 100644 --- a/_maps/map_files/generic/CentCom_nova_z2.dmm +++ b/_maps/map_files/generic/CentCom_nova_z2.dmm @@ -41,6 +41,13 @@ }, /turf/open/floor/fakebasalt, /area/centcom/holding/cafepark) +"abV" = ( +/obj/machinery/conveyor{ + dir = 4; + id = "cafesposals" + }, +/turf/open/indestructible/plating, +/area/centcom/holding/cafe) "abZ" = ( /obj/machinery/vending/clothing, /obj/effect/turf_decal/bot, @@ -82,7 +89,10 @@ /area/centcom/holding/cafe) "adU" = ( /obj/effect/turf_decal/delivery, -/obj/structure/closet/crate/bin, +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, /turf/open/floor/iron, /area/centcom/interlink) "aer" = ( @@ -329,6 +339,7 @@ /obj/item/tank/internals/plasmaman/belt/full, /obj/item/tank/internals/plasmaman/belt/full, /obj/item/tank/internals/plasmaman/belt/full, +/obj/structure/disposalpipe/segment, /turf/open/indestructible/hotelwood, /area/centcom/holding/cafe) "ahI" = ( @@ -738,6 +749,15 @@ "amx" = ( /turf/closed/wall/mineral/stone, /area/centcom/holding/cafepark) +"amA" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/warning{ + dir = 1 + }, +/obj/structure/disposalpipe/junction/yjunction{ + dir = 4 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "amD" = ( /obj/structure/sink/directional/east, /obj/machinery/button/door{ @@ -938,7 +958,11 @@ /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 6 }, -/obj/structure/closet/crate/bin, +/obj/effect/turf_decal/delivery, +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, /turf/open/indestructible/hoteltile{ icon_state = "floor" }, @@ -1116,7 +1140,6 @@ /turf/open/misc/grass/planet, /area/centcom/holding/cafepark) "aqX" = ( -/obj/structure/closet/crate/bin, /obj/effect/turf_decal/delivery, /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 1 @@ -1131,6 +1154,10 @@ /obj/effect/turf_decal/tile/neutral{ dir = 1 }, +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, /turf/open/indestructible/hoteltile{ icon_state = "floor" }, @@ -1406,6 +1433,10 @@ pixel_y = 16; pixel_x = -2 }, +/obj/item/clothing/neck/necklace/translator/hearthkin, +/obj/item/clothing/neck/necklace/translator/hearthkin, +/obj/item/clothing/neck/necklace/translator/hearthkin, +/obj/item/clothing/neck/necklace/translator/hearthkin, /turf/open/indestructible/hotelwood, /area/centcom/holding/cafepark) "avn" = ( @@ -1700,6 +1731,9 @@ }, /obj/effect/turf_decal/trimline/blue/filled/line, /obj/machinery/light/directional/south, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /turf/open/indestructible/hoteltile{ icon_state = "floor" }, @@ -2038,6 +2072,9 @@ /obj/effect/turf_decal/weather/dirt{ dir = 8 }, +/obj/structure/disposalpipe/junction{ + dir = 1 + }, /turf/open/indestructible/plating, /area/centcom/holding/cafepark) "aBd" = ( @@ -2120,6 +2157,7 @@ dir = 1 }, /obj/machinery/light/directional/north, +/obj/structure/disposalpipe/segment, /turf/open/indestructible/hoteltile{ icon_state = "floor" }, @@ -2263,6 +2301,7 @@ /obj/effect/turf_decal/tile/blue{ dir = 4 }, +/obj/structure/disposalpipe/segment, /turf/open/indestructible/hoteltile{ icon_state = "floor" }, @@ -2506,6 +2545,7 @@ /obj/effect/spawner/random/bedsheet/double, /obj/effect/spawner/random/bedsheet/double, /obj/effect/spawner/random/bedsheet/double, +/obj/structure/disposalpipe/segment, /turf/open/indestructible/hotelwood, /area/centcom/holding/cafe) "aHb" = ( @@ -2762,6 +2802,12 @@ "aKc" = ( /turf/open/indestructible/cobble/side, /area/centcom/holding/cafepark) +"aKp" = ( +/obj/structure/disposalpipe/junction/flip{ + dir = 1 + }, +/turf/open/indestructible/hotelwood, +/area/centcom/holding/cafe) "aKu" = ( /obj/structure/flora/bush/jungle/b, /turf/open/misc/grass/planet, @@ -3873,6 +3919,7 @@ /obj/item/clothing/mask/breath/vox, /obj/item/clothing/mask/breath/vox, /obj/item/clothing/mask/breath/vox, +/obj/structure/disposalpipe/segment, /turf/open/indestructible/hotelwood, /area/centcom/holding/cafe) "aWi" = ( @@ -3906,6 +3953,7 @@ /obj/effect/turf_decal/tile/blue{ dir = 8 }, +/obj/structure/disposalpipe/segment, /turf/open/indestructible/hoteltile{ icon_state = "floor" }, @@ -4262,6 +4310,15 @@ }, /turf/open/floor/carpet, /area/centcom/holding/cafe) +"bif" = ( +/obj/structure/disposaloutlet{ + dir = 4 + }, +/obj/structure/disposalpipe/trunk{ + dir = 2 + }, +/turf/open/indestructible/plating, +/area/centcom/holding/cafe) "bit" = ( /obj/machinery/door/airlock{ id_tag = "room7"; @@ -4335,6 +4392,9 @@ dir = 1 }, /obj/effect/landmark/latejoin, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /turf/open/floor/iron, /area/centcom/interlink) "blD" = ( @@ -4389,6 +4449,11 @@ }, /turf/open/floor/iron, /area/centcom/interlink) +"bpP" = ( +/obj/machinery/light/directional/east, +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron, +/area/centcom/interlink) "bqc" = ( /obj/structure/table/wood, /obj/effect/turf_decal/siding/wood{ @@ -4521,6 +4586,15 @@ }, /turf/open/floor/bamboo, /area/centcom/holding/cafe) +"bAX" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/warning{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "bBV" = ( /obj/structure/showcase/fakeid{ dir = 4 @@ -4617,6 +4691,17 @@ /obj/machinery/biogenerator, /turf/closed/indestructible/wood, /area/centcom/holding/cafe) +"bIs" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/corner, +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron, +/area/centcom/interlink) +"bIG" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "bIL" = ( /obj/effect/turf_decal/tile/purple/anticorner/contrasted{ dir = 4 @@ -5258,6 +5343,15 @@ }, /turf/open/indestructible/carpet, /area/centcom/holding/cafe) +"cHy" = ( +/obj/effect/turf_decal/siding/dark{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "cHY" = ( /obj/effect/turf_decal/weather/dirt{ dir = 6 @@ -5295,6 +5389,13 @@ /obj/effect/turf_decal/delivery/blue, /turf/open/floor/iron, /area/centcom/interlink) +"cMd" = ( +/obj/structure/disposaloutlet{ + dir = 4 + }, +/obj/structure/disposalpipe/trunk, +/turf/open/floor/plating, +/area/centcom/interlink) "cMh" = ( /obj/structure/table/wood, /obj/item/clipboard, @@ -5558,6 +5659,11 @@ /obj/machinery/duct, /turf/open/floor/iron/white, /area/centcom/interlink) +"dkH" = ( +/obj/structure/chair/stool/bar/directional/north, +/obj/structure/disposalpipe/segment, +/turf/open/indestructible/hotelwood, +/area/centcom/holding/cafe) "dkR" = ( /obj/effect/light_emitter/interlink, /obj/effect/turf_decal/weather/dirt{ @@ -6202,6 +6308,16 @@ /obj/machinery/light/small/directional/west, /turf/open/floor/iron/dark, /area/centcom/interlink) +"eGs" = ( +/obj/machinery/recycler{ + dir = 8 + }, +/obj/machinery/conveyor{ + dir = 4; + id = "intersposals" + }, +/turf/open/floor/plating, +/area/centcom/interlink) "eHo" = ( /obj/effect/turf_decal/siding/dark{ dir = 1 @@ -6304,6 +6420,22 @@ /obj/effect/landmark/latejoin, /turf/open/floor/iron/dark, /area/centcom/interlink) +"ePa" = ( +/obj/effect/turf_decal/box, +/obj/effect/turf_decal/caution/stand_clear, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/wood/glass{ + desc = "A strange small bar. It's actually remarkably close to Space Station 13."; + name = "The Snoozy Floofer" + }, +/obj/structure/fans/tiny/invisible, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/indestructible/hoteltile{ + icon_state = "darkfull" + }, +/area/centcom/holding/cafe) "ePw" = ( /obj/effect/turf_decal/siding/white{ dir = 8 @@ -6357,6 +6489,20 @@ /obj/structure/chair/stool/bar/directional/west, /turf/open/floor/iron, /area/centcom/interlink) +"eXn" = ( +/obj/machinery/conveyor{ + dir = 4; + id = "intersposals" + }, +/turf/open/floor/plating, +/area/centcom/interlink) +"eXw" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/line{ + dir = 4 + }, +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron, +/area/centcom/interlink) "eYD" = ( /obj/structure/closet/secure_closet/brig{ id = "Cell 3"; @@ -6505,10 +6651,23 @@ /obj/structure/wall_torch/spawns_lit/directional/east, /turf/open/indestructible/hotelwood, /area/centcom/holding/cafepark) +"fkF" = ( +/obj/machinery/door/airlock/public/glass{ + name = "Interlink Shuttle" + }, +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron, +/area/centcom/interlink) "fmq" = ( /obj/structure/frame/computer, /turf/open/floor/plating, /area/centcom/interlink) +"fmr" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/indestructible/hotelwood, +/area/centcom/holding/cafe) "foq" = ( /obj/structure/sign/poster/official/cleanliness/directional/east, /obj/structure/noticeboard/directional/north, @@ -6530,10 +6689,11 @@ /turf/open/indestructible/hotelwood, /area/centcom/holding/cafe) "fov" = ( -/turf/closed/indestructible/fakedoor{ - desc = "Why would you want to go back, you just got here!"; - name = "Central Command Dock" +/obj/machinery/door/airlock/hatch{ + name = "Custodial Closet" }, +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron/dark, /area/centcom/interlink) "foI" = ( /obj/machinery/status_display/evac/directional/north, @@ -6738,6 +6898,14 @@ }, /turf/open/indestructible/hotelwood, /area/centcom/holding/cafe) +"fLG" = ( +/obj/machinery/disposal/bin, +/obj/effect/turf_decal/delivery, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/centcom/interlink) "fMM" = ( /obj/machinery/duct, /turf/open/floor/iron/dark, @@ -6926,6 +7094,16 @@ }, /turf/open/floor/wood, /area/centcom/holding/cafepark) +"gcJ" = ( +/obj/machinery/recycler{ + dir = 8 + }, +/obj/machinery/conveyor{ + dir = 4; + id = "cafesposals" + }, +/turf/open/indestructible/plating, +/area/centcom/holding/cafe) "gdL" = ( /obj/structure/towel_bin, /obj/structure/table/wood, @@ -7142,6 +7320,15 @@ }, /turf/open/floor/wood, /area/centcom/interlink/dorm_rooms) +"guN" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/corner{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "gxF" = ( /obj/effect/turf_decal/siding/wood, /obj/effect/turf_decal/siding/wood{ @@ -7165,6 +7352,9 @@ /obj/effect/turf_decal/trimline/dark_green/filled/line{ dir = 1 }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /turf/open/floor/iron, /area/centcom/interlink) "gyS" = ( @@ -7247,6 +7437,10 @@ }, /turf/open/floor/iron/dark, /area/centcom/interlink) +"gLS" = ( +/obj/structure/disposalpipe/segment, +/turf/closed/indestructible/steel, +/area/centcom/holding/cafe) "gMw" = ( /turf/closed/wall/mineral/sandstone, /area/centcom/holding/cafedorms) @@ -7348,6 +7542,12 @@ /obj/structure/flora/bush/jungle/b, /turf/open/misc/grass/planet, /area/centcom/holding/cafepark) +"gWk" = ( +/obj/structure/disposalpipe/junction{ + dir = 1 + }, +/turf/open/floor/iron/dark, +/area/centcom/interlink) "gWT" = ( /obj/structure/table/wood, /obj/item/toy/cards/deck/cas/black, @@ -7365,6 +7565,10 @@ /area/centcom/interlink) "gZK" = ( /obj/structure/table/wood, +/obj/item/clothing/neck/necklace/translator, +/obj/item/clothing/neck/necklace/translator, +/obj/item/clothing/neck/necklace/translator, +/obj/item/clothing/neck/necklace/translator, /turf/open/floor/fakebasalt, /area/centcom/holding/cafepark) "gZM" = ( @@ -7656,6 +7860,12 @@ /obj/effect/landmark/latejoin, /turf/open/floor/mineral/titanium, /area/centcom/interlink) +"huK" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/centcom/interlink) "hvy" = ( /obj/machinery/door/poddoor/shuttledock/interlink, /turf/open/floor/plating, @@ -8077,6 +8287,15 @@ "iki" = ( /turf/open/floor/carpet, /area/centcom/holding/cafe) +"ikj" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/line{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "ikl" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 6 @@ -8134,6 +8353,9 @@ /obj/effect/turf_decal/trimline/dark_green/filled/warning{ dir = 1 }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /turf/open/floor/iron, /area/centcom/interlink) "iov" = ( @@ -8317,6 +8539,25 @@ /obj/structure/fireplace, /turf/open/floor/iron/dark, /area/centcom/interlink) +"iEh" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/blue/filled/line, +/obj/structure/disposalpipe/junction{ + dir = 1 + }, +/turf/open/indestructible/hoteltile{ + icon_state = "floor" + }, +/area/centcom/holding/cafe) "iFq" = ( /obj/effect/turf_decal/bot, /obj/structure/table, @@ -8353,6 +8594,15 @@ }, /turf/open/floor/iron, /area/centcom/interlink) +"iJk" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/warning{ + dir = 1 + }, +/obj/structure/disposalpipe/junction/yjunction{ + dir = 1 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "iJK" = ( /obj/structure/flora/bush/jungle/a, /turf/open/misc/grass/planet, @@ -8437,6 +8687,9 @@ /obj/effect/turf_decal/siding/wood{ dir = 4 }, +/obj/structure/disposalpipe/segment{ + dir = 6 + }, /turf/open/indestructible/hotelwood, /area/centcom/holding/cafepark) "iUg" = ( @@ -8598,6 +8851,13 @@ }, /turf/open/indestructible/plating, /area/centcom/holding/cafepark) +"jfB" = ( +/obj/machinery/conveyor_switch/oneway{ + id = "cargodisposals"; + name = "disposals conveyor switch" + }, +/turf/open/floor/plating, +/area/centcom/interlink) "jgg" = ( /obj/machinery/light/directional/east, /turf/open/floor/iron, @@ -8694,10 +8954,21 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron/dark, /area/centcom/interlink) +"joj" = ( +/obj/structure/disposalpipe/segment, +/turf/open/misc/dirt/planet, +/area/centcom/holding/cafepark) "joE" = ( /obj/structure/chair/sofa/corp/left, /turf/open/floor/iron/cafeteria, /area/centcom/interlink) +"jpm" = ( +/obj/effect/turf_decal/loading_area{ + dir = 1 + }, +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron/dark, +/area/centcom/interlink) "jqm" = ( /obj/structure/closet/crate/freezer/blood, /obj/effect/turf_decal/bot_blue, @@ -8715,11 +8986,14 @@ /area/centcom/interlink) "jsN" = ( /obj/machinery/light/directional/east, -/obj/structure/closet/crate/bin, /obj/effect/turf_decal/delivery, /obj/effect/turf_decal/trimline/dark_green/filled/line{ dir = 4 }, +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, /turf/open/floor/iron, /area/centcom/interlink) "jsY" = ( @@ -8828,6 +9102,24 @@ }, /turf/open/floor/wood, /area/centcom/holding/cafedorms) +"jCs" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/turf/open/indestructible/hoteltile{ + icon_state = "floor" + }, +/area/centcom/holding/cafe) "jDf" = ( /obj/structure/table/bronze, /obj/structure/stone_tile/block/burnt, @@ -8906,6 +9198,15 @@ /obj/structure/bed/pod, /turf/open/floor/iron, /area/centcom/interlink) +"jMh" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/warning{ + dir = 9 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "jNB" = ( /obj/machinery/light/floor{ alpha = 0; @@ -9046,6 +9347,14 @@ /obj/machinery/light/small/directional/east, /turf/open/indestructible/hotelwood, /area/centcom/holding/cafepark) +"kam" = ( +/obj/effect/turf_decal/delivery, +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 2 + }, +/turf/open/floor/iron/dark, +/area/centcom/interlink) "kdo" = ( /obj/structure/hedge/opaque, /obj/structure/curtain/cloth/fancy/mechanical{ @@ -9372,6 +9681,15 @@ icon_state = "white" }, /area/centcom/holding/cafepark) +"kJA" = ( +/obj/effect/turf_decal/tile/blue{ + dir = 8 + }, +/obj/structure/disposalpipe/segment, +/turf/open/indestructible/hoteltile{ + icon_state = "floor" + }, +/area/centcom/holding/cafe) "kJL" = ( /obj/item/flashlight/flare/candle/infinite{ pixel_x = 9; @@ -9398,6 +9716,9 @@ /obj/machinery/computer/records/security{ dir = 8 }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /turf/open/floor/iron/dark/textured_large, /area/centcom/interlink) "kKs" = ( @@ -9447,6 +9768,12 @@ }, /turf/open/misc/grass/planet, /area/centcom/holding/cafepark) +"kNb" = ( +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "kNd" = ( /obj/effect/mapping_helpers/airlock/access/all/service/kitchen, /obj/machinery/door/airlock/service{ @@ -9515,6 +9842,12 @@ /obj/machinery/light/warm/directional/north, /turf/open/floor/iron/dark, /area/centcom/interlink) +"kTY" = ( +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "kWb" = ( /obj/effect/turf_decal/siding/wood{ dir = 10 @@ -9535,6 +9868,9 @@ /turf/open/floor/iron/dark, /area/centcom/interlink) "kWH" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /turf/open/floor/iron/grimy, /area/centcom/interlink) "kWI" = ( @@ -9791,6 +10127,10 @@ /obj/machinery/vending/boozeomat/cafe, /turf/open/indestructible/hotelwood, /area/centcom/holding/cafe) +"lnY" = ( +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron, +/area/centcom/interlink) "loR" = ( /obj/structure/railing/corner{ dir = 4 @@ -9865,6 +10205,24 @@ }, /turf/open/floor/iron/white, /area/centcom/interlink) +"lyP" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/turf/open/indestructible/hoteltile{ + icon_state = "floor" + }, +/area/centcom/holding/cafepark) "lzk" = ( /obj/effect/turf_decal/siding/wood/corner{ dir = 8 @@ -9897,6 +10255,15 @@ }, /turf/open/misc/dirt/planet, /area/centcom/holding/cafepark) +"lBC" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/line{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "lCi" = ( /obj/structure/window/reinforced/spawner/directional/east, /obj/structure/window/reinforced/spawner/directional/north{ @@ -9971,6 +10338,13 @@ /obj/machinery/light/small/directional/north, /turf/open/floor/iron/dark, /area/centcom/interlink) +"lIt" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/corner, +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "lIy" = ( /obj/structure/chair/sofa/right/brown{ dir = 1 @@ -10195,6 +10569,7 @@ /obj/effect/turf_decal/weather/dirt{ dir = 9 }, +/obj/structure/disposalpipe/segment, /turf/open/indestructible/plating, /area/centcom/holding/cafepark) "mfN" = ( @@ -10228,6 +10603,9 @@ }, /obj/effect/mapping_helpers/airlock/access/all/security/general, /obj/effect/turf_decal/delivery/white, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /turf/open/floor/iron/dark/textured_large, /area/centcom/interlink) "mju" = ( @@ -10254,6 +10632,7 @@ /obj/effect/turf_decal/trimline/dark_green/filled/warning{ dir = 5 }, +/obj/structure/disposalpipe/segment, /turf/open/floor/iron, /area/centcom/interlink) "mnj" = ( @@ -10391,6 +10770,9 @@ /obj/effect/turf_decal/tile/neutral{ dir = 1 }, +/obj/structure/disposalpipe/segment{ + dir = 1 + }, /turf/open/indestructible/hoteltile{ icon_state = "floor" }, @@ -10418,10 +10800,14 @@ /turf/open/indestructible/hotelwood, /area/centcom/holding/cafe) "mza" = ( -/obj/structure/closet/crate/bin, /obj/effect/turf_decal/siding/wood{ dir = 4 }, +/obj/effect/turf_decal/delivery, +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, /turf/open/indestructible/hotelwood, /area/centcom/holding/cafepark) "mzf" = ( @@ -10779,6 +11165,12 @@ /obj/machinery/light/warm/directional/south, /turf/open/floor/iron/cafeteria, /area/centcom/interlink) +"nbG" = ( +/obj/structure/disposalpipe/junction{ + dir = 4 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "ncr" = ( /obj/machinery/deepfryer, /turf/open/floor/wood, @@ -10801,10 +11193,27 @@ }, /turf/open/floor/iron, /area/centcom/holding/cafe) +"nfi" = ( +/obj/machinery/door/airlock/multi_tile/public/glass{ + name = "Interlink" + }, +/obj/effect/turf_decal/siding/dark, +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron/dark, +/area/centcom/interlink) "ngg" = ( /obj/structure/chair/stool/bar/directional/west, /turf/open/indestructible/hotelwood, /area/centcom/holding/cafe) +"ngU" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/warning{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "nhZ" = ( /obj/structure/chair/sofa/corp/left{ dir = 8 @@ -11114,6 +11523,9 @@ /obj/effect/turf_decal/arrows{ dir = 8 }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /turf/open/floor/iron/dark, /area/centcom/interlink) "nKt" = ( @@ -11201,6 +11613,13 @@ /obj/item/reagent_containers/cup/glass/mug/coco, /turf/open/misc/grass/planet, /area/centcom/holding/cafepark) +"nPs" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/warning{ + dir = 6 + }, +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron, +/area/centcom/interlink) "nQm" = ( /obj/effect/turf_decal/weather/dirt{ dir = 1 @@ -11292,6 +11711,9 @@ dir = 9 }, /obj/effect/landmark/latejoin, +/obj/structure/disposalpipe/segment{ + dir = 5 + }, /turf/open/floor/iron, /area/centcom/interlink) "nYF" = ( @@ -11358,6 +11780,12 @@ dir = 6 }, /area/centcom/holding/cafepark) +"ogd" = ( +/obj/effect/turf_decal/delivery, +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk, +/turf/open/indestructible/hotelwood, +/area/centcom/holding/cafe) "ogq" = ( /obj/structure/chair/comfy/brown{ dir = 4 @@ -11493,6 +11921,21 @@ }, /turf/open/floor/wood, /area/centcom/interlink/dorm_rooms) +"oso" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/line{ + dir = 1 + }, +/obj/structure/disposalpipe/junction/flip{ + dir = 8 + }, +/turf/open/floor/iron, +/area/centcom/interlink) +"osF" = ( +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/turf/open/indestructible/hotelwood, +/area/centcom/holding/cafe) "ouF" = ( /obj/item/toy/plush/moth{ name = "Buzz Buzz" @@ -11901,6 +12344,12 @@ /obj/effect/turf_decal/siding/wood, /turf/closed/indestructible/weeb, /area/centcom/holding/cafe) +"oZK" = ( +/obj/structure/disposalpipe/segment{ + dir = 1 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "paj" = ( /obj/structure/chair/sofa/corp/right{ dir = 4 @@ -12006,6 +12455,24 @@ }, /turf/open/indestructible/hotelwood, /area/centcom/holding/cafe) +"pgJ" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/structure/disposalpipe/junction/flip{ + dir = 4 + }, +/turf/open/indestructible/hoteltile{ + icon_state = "floor" + }, +/area/centcom/holding/cafe) "pgL" = ( /obj/structure/chair/sofa/bench/right, /obj/effect/turf_decal/trimline/dark_green/filled/line{ @@ -12034,6 +12501,25 @@ }, /turf/open/misc/dirt/planet, /area/centcom/holding/cafepark) +"pit" = ( +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/structure/disposalpipe/segment, +/turf/open/indestructible/hoteltile{ + icon_state = "floor" + }, +/area/centcom/holding/cafepark) "pkJ" = ( /obj/structure/fans/tiny/invisible, /obj/structure/fence{ @@ -12177,6 +12663,20 @@ icon_state = "white" }, /area/centcom/holding/cafepark) +"pxG" = ( +/obj/effect/turf_decal/tile/blue{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/turf/open/indestructible/hoteltile{ + icon_state = "floor" + }, +/area/centcom/holding/cafe) "pxW" = ( /obj/effect/turf_decal/siding/wood{ dir = 8 @@ -12237,6 +12737,11 @@ /obj/structure/table, /turf/open/floor/iron/white, /area/centcom/interlink/dorm_rooms) +"pEH" = ( +/obj/machinery/light/directional/west, +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron/dark, +/area/centcom/interlink) "pET" = ( /obj/machinery/light/directional/south, /obj/effect/turf_decal/tile/blue/half/contrasted, @@ -12363,6 +12868,19 @@ }, /turf/open/indestructible/hotelwood, /area/centcom/holding/cafe) +"pLK" = ( +/obj/effect/turf_decal/box, +/obj/effect/turf_decal/caution/stand_clear, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/wood/glass{ + name = "Lounge" + }, +/obj/structure/fans/tiny/invisible, +/obj/structure/disposalpipe/segment, +/turf/open/indestructible/hoteltile{ + icon_state = "darkfull" + }, +/area/centcom/holding/cafe) "pMg" = ( /obj/machinery/door/airlock{ id_tag = "room1"; @@ -12690,11 +13208,24 @@ /obj/effect/landmark/latejoin, /turf/open/floor/iron, /area/centcom/interlink) +"qjL" = ( +/obj/effect/turf_decal/delivery, +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/centcom/interlink) "qkZ" = ( /obj/effect/turf_decal/tile/dark_blue/opposingcorners, /obj/effect/turf_decal/siding/wood/corner, /turf/open/floor/iron, /area/centcom/interlink) +"qmB" = ( +/obj/machinery/light/directional/south, +/obj/structure/disposalpipe/segment, +/turf/open/indestructible/hotelwood, +/area/centcom/holding/cafe) "qmG" = ( /obj/machinery/light/directional/south, /obj/structure/chair/stool/directional/south{ @@ -13067,6 +13598,9 @@ /obj/effect/turf_decal/tile/red/opposingcorners, /turf/open/floor/iron/dark, /area/centcom/interlink) +"qQv" = ( +/turf/open/indestructible/plating, +/area/centcom/holding/cafe) "qRd" = ( /obj/machinery/light/small/directional/north, /turf/open/floor/iron/showroomfloor, @@ -13254,6 +13788,24 @@ /obj/structure/fake_stairs/wood/directional/east, /turf/closed/indestructible/wood, /area/centcom/holding/cafepark) +"rku" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 1 + }, +/turf/open/indestructible/hoteltile{ + icon_state = "floor" + }, +/area/centcom/holding/cafepark) "rkW" = ( /obj/effect/turf_decal/trimline/blue/filled/line, /obj/structure/closet/crate/bin, @@ -13413,6 +13965,13 @@ icon_state = "darkfull" }, /area/centcom/holding/cafepark) +"rCG" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/centcom/interlink) "rDg" = ( /obj/effect/light_emitter/interlink, /obj/effect/turf_decal/weather/dirt{ @@ -13426,6 +13985,27 @@ }, /turf/open/floor/iron, /area/centcom/interlink) +"rEG" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/indestructible/hoteltile{ + icon_state = "floor" + }, +/area/centcom/holding/cafe) "rFa" = ( /obj/effect/turf_decal/siding/white/corner{ dir = 8 @@ -13568,6 +14148,9 @@ /obj/effect/turf_decal/tile/neutral{ dir = 1 }, +/obj/structure/disposalpipe/junction/flip{ + dir = 1 + }, /turf/open/indestructible/hoteltile{ icon_state = "floor" }, @@ -13954,6 +14537,10 @@ /obj/structure/chair/sofa/bench/left, /turf/open/floor/iron/cafeteria, /area/centcom/interlink) +"srf" = ( +/obj/structure/disposalpipe/segment, +/turf/closed/indestructible/fakeglass, +/area/centcom/holding/cafe) "srA" = ( /obj/structure/chair/wood{ dir = 8 @@ -14028,12 +14615,19 @@ /obj/effect/turf_decal/siding/white, /turf/open/floor/iron/white, /area/centcom/interlink) +"svq" = ( +/obj/structure/disposalpipe/segment, +/turf/open/indestructible/hotelwood, +/area/centcom/holding/cafe) "sxE" = ( -/obj/structure/closet/crate/bin, /obj/effect/turf_decal/delivery, /obj/effect/turf_decal/trimline/dark_green/filled/line{ dir = 8 }, +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, /turf/open/floor/iron, /area/centcom/interlink) "syc" = ( @@ -14054,6 +14648,9 @@ name = "Lounge" }, /obj/structure/fans/tiny/invisible, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /turf/open/indestructible/hoteltile{ icon_state = "darkfull" }, @@ -14440,7 +15037,6 @@ /turf/open/indestructible/hotelwood, /area/centcom/holding/cafe) "tct" = ( -/obj/structure/closet/crate/bin, /obj/effect/turf_decal/delivery, /obj/effect/turf_decal/trimline/blue/filled/line, /obj/effect/turf_decal/tile/neutral{ @@ -14453,6 +15049,10 @@ /obj/effect/turf_decal/tile/neutral{ dir = 1 }, +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, /turf/open/indestructible/hoteltile{ icon_state = "floor" }, @@ -14572,6 +15172,7 @@ /obj/effect/turf_decal/weather/dirt{ dir = 8 }, +/obj/structure/disposalpipe/segment, /turf/open/indestructible/plating, /area/centcom/holding/cafepark) "ttx" = ( @@ -14610,6 +15211,27 @@ icon_state = "white" }, /area/centcom/holding/cafepark) +"tuX" = ( +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/indestructible/hoteltile{ + icon_state = "floor" + }, +/area/centcom/holding/cafepark) "tvh" = ( /obj/structure/fence{ dir = 4 @@ -14733,6 +15355,17 @@ }, /turf/open/floor/wood, /area/centcom/holding/cafe) +"tIy" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/turf/open/indestructible/hoteltile{ + icon_state = "floor" + }, +/area/centcom/holding/cafe) "tIM" = ( /obj/structure/flora/bush/jungle/b, /obj/structure/fans/tiny/invisible, @@ -14747,6 +15380,12 @@ "tKt" = ( /turf/open/floor/plating/abductor, /area/centcom/holding/cafepark) +"tKS" = ( +/obj/machinery/door/airlock/wood{ + name = "Disposals" + }, +/turf/open/indestructible/plating, +/area/centcom/holding/cafe) "tLu" = ( /obj/item/toy/plush/lizard_plushie/green{ name = "Soaks-The-Rays" @@ -14817,6 +15456,7 @@ /obj/effect/turf_decal/trimline/dark_green/filled/line{ dir = 4 }, +/obj/structure/disposalpipe/segment, /turf/open/floor/iron, /area/centcom/interlink) "tXa" = ( @@ -15031,6 +15671,34 @@ }, /turf/open/floor/carpet/cyan, /area/centcom/holding/cafe) +"ufE" = ( +/obj/structure/railing/corner, +/obj/effect/turf_decal/trimline/blue/filled/corner, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/turf/open/indestructible/hoteltile{ + icon_state = "floor" + }, +/area/centcom/holding/cafepark) +"ugp" = ( +/obj/machinery/conveyor_switch/oneway{ + dir = 8; + id = "cafesposals"; + name = "disposal conveyor" + }, +/turf/open/indestructible/plating, +/area/centcom/holding/cafe) "uhO" = ( /obj/structure/table/reinforced, /obj/item/folder/blue, @@ -15100,6 +15768,15 @@ /obj/effect/turf_decal/trimline/dark_green/filled/line{ dir = 1 }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron, +/area/centcom/interlink) +"uks" = ( +/obj/structure/disposalpipe/segment{ + dir = 9 + }, /turf/open/floor/iron, /area/centcom/interlink) "umm" = ( @@ -15121,6 +15798,14 @@ /obj/effect/landmark/latejoin, /turf/open/floor/iron, /area/centcom/interlink) +"uoo" = ( +/obj/effect/turf_decal/delivery, +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, +/turf/open/indestructible/hotelwood, +/area/centcom/holding/cafe) "uoM" = ( /obj/effect/spawner/liquids_spawner, /turf/open/floor/iron/pool/cobble, @@ -15161,6 +15846,10 @@ /obj/structure/chair/wood, /turf/open/misc/grass/planet, /area/centcom/holding/cafepark) +"uxo" = ( +/obj/structure/disposalpipe/segment, +/turf/open/floor/plating, +/area/centcom/interlink) "uxW" = ( /turf/open/misc/beach/coast{ dir = 4 @@ -15358,6 +16047,15 @@ dir = 8 }, /area/centcom/holding/cafe) +"uUo" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/corner{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "uVm" = ( /obj/structure/stone_tile/center, /obj/structure/stone_tile/surrounding_tile{ @@ -15469,6 +16167,24 @@ /obj/item/kirbyplants/organic/plant22, /turf/open/floor/iron/dark, /area/centcom/interlink) +"vdA" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/indestructible/hoteltile{ + icon_state = "floor" + }, +/area/centcom/holding/cafe) "vdW" = ( /obj/structure/flora/bush/jungle/b, /obj/effect/light_emitter/interlink, @@ -15519,6 +16235,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 1 }, +/obj/structure/disposalpipe/segment, /turf/open/indestructible/hoteltile{ icon_state = "floor" }, @@ -15657,6 +16374,9 @@ /obj/structure/fence{ dir = 4 }, +/obj/structure/disposalpipe/segment{ + dir = 10 + }, /turf/open/indestructible/plating, /area/centcom/holding/cafepark) "vzH" = ( @@ -15664,6 +16384,9 @@ /obj/effect/turf_decal/trimline/dark_green/filled/line{ dir = 1 }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /turf/open/floor/iron, /area/centcom/interlink) "vDr" = ( @@ -15813,6 +16536,13 @@ }, /turf/open/floor/wood, /area/centcom/interlink) +"vSV" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/line, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "vTT" = ( /turf/closed/indestructible/steel, /area/centcom/holding/cafe) @@ -15912,6 +16642,24 @@ }, /turf/open/floor/iron/dark, /area/centcom/interlink) +"wbI" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/indestructible/hoteltile{ + icon_state = "floor" + }, +/area/centcom/holding/cafepark) "wcd" = ( /obj/structure/flora/bush/flowers_pp, /obj/structure/flora/bush/flowers_br, @@ -15971,6 +16719,9 @@ /area/centcom/holding/cafe) "wfh" = ( /obj/effect/landmark/latejoin, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /turf/open/floor/iron, /area/centcom/interlink) "wft" = ( @@ -16111,6 +16862,11 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/centcom/holding/cafe) +"wwq" = ( +/obj/structure/table/wood, +/obj/structure/disposalpipe/segment, +/turf/open/indestructible/hotelwood, +/area/centcom/holding/cafe) "wwD" = ( /obj/effect/turf_decal/weather/dirt{ dir = 4 @@ -16118,6 +16874,15 @@ /obj/effect/light_emitter/interlink, /turf/open/floor/grass, /area/centcom/interlink) +"wwF" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/line{ + dir = 5 + }, +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "wyd" = ( /obj/structure/railing/wooden_fencing{ dir = 8 @@ -16213,11 +16978,14 @@ /area/centcom/holding/cafepark) "wFF" = ( /obj/machinery/light/directional/west, -/obj/structure/closet/crate/bin, /obj/effect/turf_decal/delivery, /obj/effect/turf_decal/trimline/dark_green/filled/line{ dir = 8 }, +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 4 + }, /turf/open/floor/iron, /area/centcom/interlink) "wGV" = ( @@ -16267,6 +17035,10 @@ }, /turf/open/floor/iron/cafeteria, /area/centcom/interlink) +"wIA" = ( +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron/dark, +/area/centcom/interlink) "wIO" = ( /obj/effect/turf_decal/sand, /obj/effect/turf_decal/trimline/yellow/filled/warning{ @@ -16432,6 +17204,15 @@ /obj/structure/chair/sofa/bench/corner, /turf/open/floor/wood/large, /area/centcom/holding/cafe) +"wZP" = ( +/obj/effect/turf_decal/trimline/dark_green/filled/corner{ + dir = 4 + }, +/obj/structure/disposalpipe/junction/yjunction{ + dir = 1 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "wZS" = ( /obj/item/storage/cans/sixbeer, /turf/open/floor/carpet/orange, @@ -16514,6 +17295,15 @@ /obj/machinery/duct, /turf/open/floor/wood/tile, /area/centcom/interlink) +"xkb" = ( +/obj/effect/turf_decal/siding/dark{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/iron, +/area/centcom/interlink) "xkO" = ( /obj/structure/railing{ dir = 4 @@ -23413,7 +24203,7 @@ tvw tvw qLQ aXG -xyz +kam nYB ePw tvw @@ -24442,7 +25232,7 @@ ekE wOQ hvQ hvQ -hvQ +bIG bck tvw aWb @@ -24699,7 +25489,7 @@ jaf hvQ hvQ aTS -hvQ +bIG hvQ tvw aWb @@ -24956,7 +25746,7 @@ eXg hvQ deD tvw -hvQ +bIG dPd tvw kdy @@ -25213,7 +26003,7 @@ hvQ hvQ hvQ kfb -lvR +jMh wHJ tvw hZk @@ -25470,7 +26260,7 @@ hvQ hvQ hvQ hvQ -dGD +ngU nJp tvw kdy @@ -25984,7 +26774,7 @@ iPs iPs iPs fOv -dGD +ngU uPd tvw tvw @@ -26241,7 +27031,7 @@ iPs iPs iPs rDL -dGD +ngU wck tvw uis @@ -26755,7 +27545,7 @@ xgz jzh sIH lPi -iMY +lBC wck tvw sNg @@ -27012,7 +27802,7 @@ xgz pST oQW lPi -iMY +lBC wck tvw fzV @@ -27526,7 +28316,7 @@ lVL olE olE wtI -dGD +ngU nJp tvw tvw @@ -27783,7 +28573,7 @@ cRs pST sIH lPi -iMY +lBC cGt pHe saE @@ -28040,7 +28830,7 @@ olE pST oQW lPi -iMY +lBC nJp xPZ aXG @@ -28297,7 +29087,7 @@ iwK lPi lPi jHw -iMY +lBC nJp rYy tvw @@ -28554,7 +29344,7 @@ oIK kOZ kOZ wFF -oOC +uUo pSt cWG exf @@ -28810,8 +29600,8 @@ eYX mqE hvQ hvQ -hvQ -hvQ +nbG +uks hvQ hvQ hvQ @@ -29067,7 +29857,7 @@ lPi aUh hvQ hvQ -hvQ +bIG hvQ hvQ hvQ @@ -29324,7 +30114,7 @@ lPi crf anv ybB -mqE +guN hvQ hvQ hvQ @@ -29581,7 +30371,7 @@ tvw lPi lPi tvw -iMY +lBC hvQ hvQ aBm @@ -29838,7 +30628,7 @@ xKN olE olE bwP -dGD +ngU hvQ hvQ hvQ @@ -30095,7 +30885,7 @@ fYY olE olE wtI -dGD +ngU hvQ hvQ bTH @@ -30609,7 +31399,7 @@ kOZ kOZ wHJ tGG -dGD +ngU hvQ hvQ hvQ @@ -30852,7 +31642,7 @@ rMF hES rDL hvQ -hvQ +bIG hvQ hvQ tGG @@ -30866,8 +31656,8 @@ hvQ hvQ cGt tGG -dGD -hvQ +bAX +kTY hvQ hvQ hvQ @@ -31109,23 +31899,23 @@ aXG jXO rDL hvQ -hvQ -hvQ -aTS -tGG -dGD -lrp -eYX +kNb +lnY +bpP +fkF +amA +bIs +eXw tWA -eYX -eYX -eYX -eYX -bod -tGG +eXw +eXw +eXw +eXw +nPs +fkF mjK -mqE -lrp +wZP +lIt jsN eYX eYX @@ -31370,7 +32160,7 @@ lPi lPi tvw hoS -iMY +lBC nJp tvw tvw @@ -31381,8 +32171,8 @@ tvw tvw tvw jHw -iMY -nJp +oso +vSV rYy tvw dHP @@ -31627,7 +32417,7 @@ vat vat cNw tvw -iMY +lBC nJp tvw iVr @@ -31884,7 +32674,7 @@ vat iov vat lPi -iMY +lBC nJp tvw tfe @@ -31895,7 +32685,7 @@ pry bsj chZ pMg -dGD +ngU nJp aDg mDR @@ -32141,7 +32931,7 @@ vat vat vat lPi -iMY +lBC nJp tvw tvw @@ -32152,7 +32942,7 @@ hVC bsj osk tvw -iMY +lBC nJp aDg fVr @@ -32398,7 +33188,7 @@ vat vat xmn lPi -iMY +lBC pSt kOZ sga @@ -32409,7 +33199,7 @@ bsj bsj bsj tvw -iMY +lBC nJp tvw jSW @@ -32655,7 +33445,7 @@ vat vat vat tvw -iMY +lBC lrp eYX aPe @@ -32923,7 +33713,7 @@ tvw tvw tvw tvw -iMY +lBC nJp aDg kLZ @@ -33048,128 +33838,128 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -"} -(63,1,1) = {" -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +"} +(63,1,1) = {" +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +tvw +cMd +uxo fov -hES -aXG -aXG -aXG -pmJ -aXG -aXG -aXG -pmJ -aXG -aXG -aXG -aXG -aXG -pPI -dGD +jpm +wIA +wIA +wIA +pEH +wIA +gWk +wIA +pEH +wIA +wIA +wIA +wIA +wIA +nfi +iJk nJp tvw iVr @@ -33180,7 +33970,7 @@ nsT bsj nYF tvw -iMY +lBC nJp aDg fVr @@ -33407,9 +34197,9 @@ aaa aaa aaa aaa -aaa -aaa -aaa +tvw +eXn +aqG tvw mtv eOx @@ -33417,7 +34207,7 @@ pZh pZh jtl aXG -aXG +huK xyz pHQ pZh @@ -33426,7 +34216,7 @@ eOx jtl aXG cVm -dGD +ngU nJp tvw tfe @@ -33437,7 +34227,7 @@ pry bsj chZ dVh -dGD +ngU nJp aDg fVr @@ -33664,9 +34454,9 @@ aaa aaa aaa aaa -aaa -aaa -aaa +tvw +eGs +aqG tvw bjh cAI @@ -33674,7 +34464,7 @@ mDs xqq tUz uYo -uYo +cHy uYo eNn xqq @@ -33683,7 +34473,7 @@ cAI phk aXG pPI -dGD +ngU nJp tvw tvw @@ -33694,7 +34484,7 @@ hVC bsj uDT tvw -iMY +lBC nJp tvw fVr @@ -33921,9 +34711,9 @@ aaa aaa aaa aaa -aaa -aaa -aaa +tvw +eXn +aqG tvw aXG aXG @@ -33931,7 +34721,7 @@ eHo hvQ hvQ hvQ -hvQ +bIG hvQ hvQ hvQ @@ -33940,7 +34730,7 @@ aXG aXG jXO cVm -dGD +ngU pSt kOZ ubH @@ -33951,7 +34741,7 @@ bsj bsj bsj tvw -iMY +lBC nJp tvw fVr @@ -34178,9 +34968,9 @@ aaa aaa aaa aaa -aaa -aaa -aaa +tvw +eXn +jfB tvw aDg uTg @@ -34208,7 +34998,7 @@ bsj bsj bUO tvw -iMY +lBC nJp aDg fVr @@ -34435,9 +35225,9 @@ aaa aaa aaa aaa -aaa -aaa -aaa +tvw +tvw +tvw tvw aXG bdI @@ -34454,7 +35244,7 @@ cal aXG tvw oAn -oOC +uUo nJp tvw tvw @@ -34465,7 +35255,7 @@ tvw tvw tvw tvw -iMY +lBC nJp aDg fVr @@ -34711,7 +35501,7 @@ dHD aXG tvw fGC -hvQ +bIG nJp tvw iVr @@ -34722,7 +35512,7 @@ nsT bsj nYF tvw -iMY +lBC nJp aDg rVQ @@ -34968,7 +35758,7 @@ wYH aXG tvw fGC -hvQ +bIG nJp tvw tfe @@ -34979,7 +35769,7 @@ pry bsj chZ wdB -dGD +ngU nJp tvw vLx @@ -35225,7 +36015,7 @@ aXG aXG tvw vsB -hvQ +bIG nJp tvw tvw @@ -35236,7 +36026,7 @@ hVC bsj mUC tvw -iMY +lBC nJp tvw vLx @@ -35473,7 +36263,7 @@ eHo amv tvw aDg -aDg +rCG aDg tvw amv @@ -35482,7 +36272,7 @@ aXG aXG tvw iMY -hvQ +bIG pSt kOZ sga @@ -35493,7 +36283,7 @@ bsj bsj bsj tvw -iMY +lBC nJp tvw vLx @@ -35730,7 +36520,7 @@ inr nrl rYR rYR -rYR +xkb rYR rYR ojv @@ -35738,8 +36528,8 @@ liU aXG gAj tvw -iIb -eYX +wwF +ikj eYX eYX aPe @@ -35995,7 +36785,7 @@ aXG aXG aXG tvw -xyz +qjL dAM dmR tvw @@ -36244,7 +37034,7 @@ aXG aXG aXG aXG -aXG +fLG aXG aXG aXG @@ -36264,7 +37054,7 @@ nsT bsj nYF tvw -iMY +lBC nJp tvw vLx @@ -36521,7 +37311,7 @@ pry bsj chZ yln -dGD +ngU nJp tvw vLx @@ -36778,7 +37568,7 @@ hVC bsj cbF tvw -iMY +lBC nJp tvw aaa @@ -37035,7 +37825,7 @@ bsj bsj bsj tvw -iMY +lBC nJp tvw aaa @@ -37292,7 +38082,7 @@ bsj bsj bUO tvw -iMY +lBC nJp tvw aaa @@ -37806,7 +38596,7 @@ qzE gIO mMu xwC -oOC +uUo nJp tvw aaa @@ -38056,14 +38846,14 @@ kOZ kOZ kOZ oOC -hvQ -hvQ -hvQ -hvQ -hvQ -hvQ -hvQ -hvQ +kNb +oZK +oZK +oZK +oZK +oZK +oZK +uks nJp tvw aaa @@ -61736,7 +62526,7 @@ ayo ahY aqf aUo -aUo +fmr aUo aqf bcb @@ -61993,7 +62783,7 @@ alR aQd aqf aqy -aUo +fmr agr aqf rTU @@ -62250,7 +63040,7 @@ axQ aRM aqf aPK -aUo +fmr awQ aqf sRt @@ -62507,7 +63297,7 @@ aUo aUz aqf aYj -aUo +fmr aKD aqf aqf @@ -62764,7 +63554,7 @@ aME gWT aqf aXd -aUo +fmr aQa aqf dyU @@ -63021,7 +63811,7 @@ aqf aqf aqf aqf -aUo +fmr aqf aPZ dDF @@ -63274,11 +64064,11 @@ asC jZb aqf afr -atf +uoo aOb aSn aIU -aUo +fmr bNi aqf bZt @@ -63514,28 +64304,28 @@ asp aqf lnP aPo -aUo -aUo -aUo -bwG -wDG -aUo -aUz -aTb +ogd +svq +svq +wwq +dkH +svq +qmB +srf aBH -avS -axO +kJA +pxG axO axO aGo enf aqf aHP +fmr aUo aUo aUo -aUo -aUo +fmr jeI aqf aqf @@ -63781,18 +64571,18 @@ aUo aTb ayQ aOI -aOI -aKB +vdA +tIy aWq aDA -sIb -ang -aUo -aUo +iEh +pLK +svq +aKp aWh ahG aGY -aUo +osF jeI aqf dbn @@ -64038,8 +64828,8 @@ aUo aTb apA aOI -aOI -aOI +jCs +pgJ aKB aGo ayk @@ -64296,7 +65086,7 @@ aqf aGT apx apx -apx +rEG apx apx aoR @@ -64553,7 +65343,7 @@ aqf aqf aqf aka -aka +ePa aka aqf aqf @@ -64563,7 +65353,7 @@ aqf agV aUo aUo -aUo +atf aqf aqf ajj @@ -64810,7 +65600,7 @@ aqf pwO wVd aYc -aYc +tuX aYc kZK bON @@ -65067,7 +65857,7 @@ aqf ayt qVU qVU -qVU +wbI qVU qVU aJP @@ -65305,14 +66095,14 @@ aPf aPf ayI aPf -aPf -aPf -aPf -ekp -ayI -ayI -ayI -ayI +vTT +ugp +bif +gLS +joj +joj +joj +joj mfu tsx tsx @@ -65322,11 +66112,11 @@ tsx tsx aBa aqX -qVU +lyP vhm rOn mxd -qVU +rku tct aqf aAX @@ -65562,10 +66352,10 @@ aPf aPf ayI ayI -aPf -aPf -aPf -ekp +vTT +qQv +abV +vTT ayI ayI hea @@ -65578,8 +66368,8 @@ wIO wIO wIO vzb -sUE -vhm +pit +ufE qdG vdW bUS @@ -65819,10 +66609,10 @@ aPf ayI ayI ayI -aPf -aPf -aFP -agU +vTT +qQv +gcJ +vTT mPR uIo aSt @@ -66076,10 +66866,10 @@ ayI ayI ayI aPf -aPf -asX -aFP -agU +vTT +qQv +abV +vTT nXw aSt aSt @@ -66333,10 +67123,10 @@ ayI ayI aPf aPf -aPf -aFP -aFP -agU +vTT +tKS +vTT +vTT nXw aIr aIr diff --git a/code/__DEFINES/construction/structures.dm b/code/__DEFINES/construction/structures.dm index 453de8ebf05..e52b82f248e 100644 --- a/code/__DEFINES/construction/structures.dm +++ b/code/__DEFINES/construction/structures.dm @@ -62,7 +62,7 @@ #define GEAR_SECURE 1 #define GEAR_LOOSE 2 -// Stationary gas tanks +//Stationary gas tanks #define TANK_FRAME 0 #define TANK_PLATING_UNSECURED 1 diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm index 5798fd29e82..0d2fb6b874d 100644 --- a/code/__DEFINES/hud.dm +++ b/code/__DEFINES/hud.dm @@ -77,6 +77,7 @@ #define ui_building "EAST-4:22,SOUTH:21" #define ui_language_menu "EAST-4:6,SOUTH:21" #define ui_navigate_menu "EAST-4:22,SOUTH:5" +#define ui_floor_menu "EAST-4:14,SOUTH:37" //Upper-middle right (alerts) #define ui_alert1 "EAST-1:28,CENTER+5:27" @@ -143,6 +144,7 @@ #define ui_borg_alerts "CENTER+4:21,SOUTH:5" #define ui_borg_language_menu "CENTER+4:19,SOUTH+1:6" #define ui_borg_navigate_menu "CENTER+4:19,SOUTH+1:6" +#define ui_borg_floor_menu "CENTER+4:-13,SOUTH+1:6" //Aliens #define ui_alien_health "EAST,CENTER-1:15" @@ -151,6 +153,7 @@ #define ui_alien_storage_r "CENTER+1:18,SOUTH:5" #define ui_alien_language_menu "EAST-4:20,SOUTH:5" #define ui_alien_navigate_menu "EAST-4:20,SOUTH:5" +#define ui_alien_floor_menu "EAST-4:-12,SOUTH:5" //AI #define ui_ai_core "BOTTOM:6,RIGHT-4" @@ -159,6 +162,7 @@ #define ui_ai_state_laws "BOTTOM:6,RIGHT-1" #define ui_ai_mod_int "BOTTOM:6,RIGHT" #define ui_ai_language_menu "BOTTOM+1:8,RIGHT-1:30" +#define ui_ai_floor_menu "BOTTOM+1:8,RIGHT-1:14" #define ui_ai_crew_monitor "BOTTOM:6,CENTER-1" #define ui_ai_crew_manifest "BOTTOM:6,CENTER" @@ -200,6 +204,7 @@ #define ui_ghost_pai "SOUTH: 6, CENTER+1:24" #define ui_ghost_minigames "SOUTH: 6, CENTER+2:24" #define ui_ghost_language_menu "SOUTH: 22, CENTER+3:8" +#define ui_ghost_floor_menu "SOUTH: 6, CENTER+3:8" //Blobbernauts #define ui_blobbernaut_overmind_health "EAST-1:28,CENTER+0:19" diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm index fdfec5e8ca0..a4fb6d40be7 100644 --- a/code/__DEFINES/tgs.dm +++ b/code/__DEFINES/tgs.dm @@ -1,6 +1,6 @@ // tgstation-server DMAPI -#define TGS_DMAPI_VERSION "7.0.2" +#define TGS_DMAPI_VERSION "7.1.1" // All functions and datums outside this document are subject to change with any version and should not be relied on. @@ -50,6 +50,13 @@ #endif +#ifndef TGS_FILE2TEXT_NATIVE +#ifdef file2text +#error Your codebase is re-defining the BYOND proc file2text. The DMAPI requires the native version to read the result of world.Export(). You can fix this by adding "#define TGS_FILE2TEXT_NATIVE file2text" before your override of file2text to allow the DMAPI to use the native version. This will only be used for world.Export(), not regular file accesses +#endif +#define TGS_FILE2TEXT_NATIVE file2text +#endif + // EVENT CODES /// Before a reboot mode change, extras parameters are the current and new reboot mode enums. @@ -490,6 +497,16 @@ /world/proc/TgsChatChannelInfo() return +/** + * Trigger an event in TGS. Requires TGS version >= 6.3.0. Returns [TRUE] if the event was triggered successfully, [FALSE] otherwise. This function may sleep! + * + * event_name - The name of the event to trigger + * parameters - Optional list of string parameters to pass as arguments to the event script. The first parameter passed to a script will always be the running game's directory followed by these parameters. + * wait_for_completion - If set, this function will not return until the event has run to completion. + */ +/world/proc/TgsTriggerEvent(event_name, list/parameters, wait_for_completion = FALSE) + return + /* The MIT License diff --git a/code/__DEFINES/~nova_defines/airlock.dm b/code/__DEFINES/~nova_defines/airlock.dm index 8f0a05e3e61..258da592d57 100644 --- a/code/__DEFINES/~nova_defines/airlock.dm +++ b/code/__DEFINES/~nova_defines/airlock.dm @@ -27,7 +27,10 @@ #define AIRLOCK_LIGHT_POWER 0.5 #define AIRLOCK_LIGHT_RANGE 2 #define AIRLOCK_LIGHT_ENGINEERING "engineering" +#define AIRLOCK_LIGHT_FIRE "fire" +#define AIRLOCK_LIGHT_POWERON "poweron" #define AIRLOCK_POWERON_LIGHT_COLOR "#3aa7c2" +#define AIRLOCK_FIRE_LIGHT_COLOR "#eaeaea" #define AIRLOCK_BOLTS_LIGHT_COLOR "#c22323" #define AIRLOCK_ACCESS_LIGHT_COLOR "#57e69c" #define AIRLOCK_EMERGENCY_LIGHT_COLOR "#d1d11d" diff --git a/code/__DEFINES/~nova_defines/jobs.dm b/code/__DEFINES/~nova_defines/jobs.dm index 7aa6486c9d5..a8cc61a9cf7 100644 --- a/code/__DEFINES/~nova_defines/jobs.dm +++ b/code/__DEFINES/~nova_defines/jobs.dm @@ -6,9 +6,11 @@ #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, "No Guns" = TRUE, "Illiterate" = TRUE, "Nerve Stapled" = TRUE -#define HEAD_RESTRICTED_QUIRKS "Blind" = TRUE, "Deaf" = TRUE, "Mute" = TRUE, "Foreigner" = TRUE, "Brain Tumor" = TRUE, "Illiterate" = TRUE +#define SEC_RESTRICTED_QUIRKS "Blind" = TRUE, "Brain Tumor" = TRUE, "Deaf" = TRUE, "Paraplegic" = TRUE, "Hemiplegic" = TRUE, "Mute" = TRUE, "Foreigner" = TRUE, "Pacifist" = TRUE, "No Guns" = TRUE, "Illiterate" = TRUE, "Nerve Stapled" = TRUE, "Underworld Connections" = TRUE +#define HEAD_RESTRICTED_QUIRKS "Blind" = TRUE, "Deaf" = TRUE, "Mute" = TRUE, "Foreigner" = TRUE, "Brain Tumor" = TRUE, "Illiterate" = TRUE, "Underworld Connections" = TRUE +#define HEAD_RESTRICTED_QUIRKS_QM "Blind" = TRUE, "Deaf" = TRUE, "Mute" = TRUE, "Foreigner" = TRUE, "Brain Tumor" = TRUE, "Illiterate" = TRUE #define GUARD_RESTRICTED_QUIRKS "Blind" = TRUE, "Deaf" = TRUE, "Foreigner" = TRUE, "Pacifist" = TRUE, "Nerve Stapled" = TRUE +#define PRISONER_RESTRICTED_QUIRKS "Underworld Connections" = TRUE #define RESTRICTED_QUIRKS_EXCEPTIONS list("Mute" = "Signer") diff --git a/code/__DEFINES/~nova_defines/keybindings.dm b/code/__DEFINES/~nova_defines/keybindings.dm index 5a205f4f0f8..8d99a7a0278 100644 --- a/code/__DEFINES/~nova_defines/keybindings.dm +++ b/code/__DEFINES/~nova_defines/keybindings.dm @@ -4,3 +4,5 @@ #define COMSIG_KB_CLIENT_WHISPER_DOWN "keybinding_client_whisper_down" #define COMSIG_KB_LIVING_COMBAT_INDICATOR "keybinding_living_combat_indicator" #define COMSIG_KB_CARBON_TOGGLE_SAFETY "keybinding_carbon_toggle_safety" +#define COMSIG_KB_CLIENT_DO_DOWN "keybinding_client_do_down" +#define COMSIG_KB_CLIENT_DO_LONGER_DOWN "keybinding_client_do_longer_down" diff --git a/code/__DEFINES/~nova_defines/say.dm b/code/__DEFINES/~nova_defines/say.dm index 2126621afb4..ca8ad9d3ad7 100644 --- a/code/__DEFINES/~nova_defines/say.dm +++ b/code/__DEFINES/~nova_defines/say.dm @@ -1,3 +1,4 @@ #define MAX_FLAVOR_LEN 4096 //double the maximum message length. #define LOOC_CHANNEL "LOOC" // LOOC #define WHIS_CHANNEL "Whis" // Whisper +#define DO_CHANNEL "Do" // Do diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm index 5f687d19642..1d26c4916b0 100644 --- a/code/_onclick/hud/ai.dm +++ b/code/_onclick/hud/ai.dm @@ -186,6 +186,11 @@ using.screen_loc = ui_ai_language_menu static_inventory += using +// Z-level floor change + using = new /atom/movable/screen/floor_menu(null, src) + using.screen_loc = ui_ai_floor_menu + static_inventory += using + //AI core using = new /atom/movable/screen/ai/aicore(null, src) using.screen_loc = ui_ai_core diff --git a/code/_onclick/hud/alien.dm b/code/_onclick/hud/alien.dm index 3c1b1029a3e..c3b91173a45 100644 --- a/code/_onclick/hud/alien.dm +++ b/code/_onclick/hud/alien.dm @@ -63,6 +63,10 @@ using.screen_loc = ui_alien_language_menu static_inventory += using + using = new /atom/movable/screen/floor_menu(null, src) + using.screen_loc = ui_alien_floor_menu + static_inventory += using + using = new /atom/movable/screen/navigate(null, src) using.screen_loc = ui_alien_navigate_menu static_inventory += using @@ -87,7 +91,7 @@ pull_icon.update_appearance() pull_icon.screen_loc = ui_above_movement static_inventory += pull_icon - + rest_icon = new /atom/movable/screen/rest(null, src) rest_icon.icon = ui_style rest_icon.screen_loc = ui_above_intent diff --git a/code/_onclick/hud/alien_larva.dm b/code/_onclick/hud/alien_larva.dm index d9ebb3611b6..77d135ce2c6 100644 --- a/code/_onclick/hud/alien_larva.dm +++ b/code/_onclick/hud/alien_larva.dm @@ -32,6 +32,10 @@ using.screen_loc = ui_alien_language_menu static_inventory += using + using = new /atom/movable/screen/floor_menu(null, src) + using.screen_loc = ui_alien_floor_menu + static_inventory += using + using = new /atom/movable/screen/navigate(null, src) using.screen_loc = ui_alien_navigate_menu static_inventory += using diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm index 99b04df9068..e20c1ede2f6 100644 --- a/code/_onclick/hud/ghost.dm +++ b/code/_onclick/hud/ghost.dm @@ -86,6 +86,16 @@ using.icon = ui_style static_inventory += using + using = new /atom/movable/screen/language_menu(null, src) + using.screen_loc = ui_ghost_language_menu + using.icon = ui_style + static_inventory += using + + using = new /atom/movable/screen/floor_menu(null, src) + using.screen_loc = ui_ghost_floor_menu + using.icon = ui_style + static_inventory += using + /datum/hud/ghost/show_hud(version = 0, mob/viewmob) // don't show this HUD if observing; show the HUD of the observee var/mob/dead/observer/O = mymob diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 410f6c07a45..ca2068b9a50 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -70,6 +70,10 @@ using.icon = ui_style static_inventory += using + using = new /atom/movable/screen/floor_menu(null, src) + using.icon = ui_style + static_inventory += using + action_intent = new /atom/movable/screen/combattoggle/flashy(null, src) action_intent.icon = ui_style action_intent.screen_loc = ui_combat_toggle diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index fdc03364e3f..ae7ac6fee91 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -77,6 +77,7 @@ var/mob/living/silicon/robot/robit = mymob var/atom/movable/screen/using +// Language using = new/atom/movable/screen/language_menu(null, src) using.screen_loc = ui_borg_language_menu static_inventory += using @@ -86,6 +87,11 @@ using.screen_loc = ui_borg_navigate_menu static_inventory += using +// Z-level floor change + using = new /atom/movable/screen/floor_menu(null, src) + using.screen_loc = ui_borg_floor_menu + static_inventory += using + //Radio using = new /atom/movable/screen/robot/radio(null, src) using.screen_loc = ui_borg_radio diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index ce5c97a63c7..31a9426489f 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -127,6 +127,33 @@ /atom/movable/screen/language_menu/Click() usr.get_language_holder().open_language_menu(usr) +/atom/movable/screen/floor_menu + name = "change floor" + icon = 'icons/hud/screen_midnight.dmi' + icon_state = "floor_change" + screen_loc = ui_floor_menu + +/atom/movable/screen/floor_menu/Initialize(mapload) + . = ..() + register_context() + +/atom/movable/screen/floor_menu/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + + context[SCREENTIP_CONTEXT_LMB] = "Go up a floor" + context[SCREENTIP_CONTEXT_RMB] = "Go down a floor" + return CONTEXTUAL_SCREENTIP_SET + +/atom/movable/screen/floor_menu/Click(location,control,params) + var/list/modifiers = params2list(params) + + if(LAZYACCESS(modifiers, RIGHT_CLICK) || LAZYACCESS(modifiers, ALT_CLICK)) + usr.down() + return + + usr.up() + return + /atom/movable/screen/inventory /// The identifier for the slot. It has nothing to do with ID cards. var/slot_id 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 0f7fe6ef142..144de535d5a 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 @@ -8,7 +8,8 @@ . = ..() if(!controller.blackboard[targeting_strategy_key]) CRASH("No targeting strategy was supplied in the blackboard for [controller.pawn]") - + if(HAS_TRAIT(controller.pawn, TRAIT_HANDS_BLOCKED)) + return FALSE //Hiding location is priority var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key] if(QDELETED(target)) @@ -67,6 +68,8 @@ /datum/ai_behavior/basic_ranged_attack/setup(datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) . = ..() + if(HAS_TRAIT(controller.pawn, TRAIT_HANDS_BLOCKED)) + return FALSE var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key] if(QDELETED(target)) return FALSE diff --git a/code/datums/ai_laws/laws_neutral.dm b/code/datums/ai_laws/laws_neutral.dm index 2fe19dafbc5..7adef14d95b 100644 --- a/code/datums/ai_laws/laws_neutral.dm +++ b/code/datums/ai_laws/laws_neutral.dm @@ -60,6 +60,7 @@ "You are a universally renowned artist.", "The station is your canvas.", "Make something beautiful out of your canvas. It will be admired as an artistic wonder of this sector.", + "Art requires appreciation. Cultivate an audience aboard the station to ensure as many as possible see your works.", ) /datum/ai_laws/tyrant diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm index 7a65524788a..de42ae64cfd 100644 --- a/code/datums/components/tackle.dm +++ b/code/datums/components/tackle.dm @@ -164,8 +164,6 @@ neutral_outcome(user, target, tackle_word) //Forces a neutral outcome so you're not screwed too much from being blocked while tackling return COMPONENT_MOVABLE_IMPACT_FLIP_HITPUSH - - switch(roll) if(-INFINITY to -1) negative_outcome(user, target, roll, tackle_word) //OOF @@ -178,6 +176,15 @@ return COMPONENT_MOVABLE_IMPACT_FLIP_HITPUSH +/// Helper to do a grab and then adjust the grab state if necessary +/datum/component/tackler/proc/do_grab(mob/living/carbon/tackler, mob/living/carbon/tackled, skip_to_state = GRAB_PASSIVE) + set waitfor = FALSE + + if(!tackler.grab(tackled) || tackler.pulling != tackled) + return + if(tackler.grab_state != skip_to_state) + tackler.setGrabState(skip_to_state) + /** * Our positive tackling outcomes. * @@ -198,15 +205,10 @@ var/potential_outcome = (roll * 10) if(ishuman(target)) - var/mob/living/carbon/human/human_target = target - var/target_armor = human_target.run_armor_check(BODY_ZONE_CHEST, MELEE) - potential_outcome *= ((100 - target_armor) /100) + potential_outcome *= ((100 - target.run_armor_check(BODY_ZONE_CHEST, MELEE)) /100) else potential_outcome *= 0.9 - var/mob/living/carbon/human/human_target = target - var/mob/living/carbon/human/human_sacker = user - switch(potential_outcome) if(-INFINITY to 0) //I don't want to know how this has happened, okay? neutral_outcome(user, target, roll, tackle_word) //Default to neutral @@ -233,9 +235,7 @@ target.Paralyze(0.5 SECONDS) target.Knockdown(3 SECONDS) target.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 2, 10 SECONDS) - if(ishuman(target) && ishuman(user)) - INVOKE_ASYNC(human_sacker, TYPE_PROC_REF(/mob/living, grab), human_sacker, human_target) - human_sacker.setGrabState(GRAB_PASSIVE) + do_grab(user, target) if(50 to INFINITY) // absolutely BODIED var/stamcritted_user = HAS_TRAIT_FROM(user, TRAIT_INCAPACITATED, STAMINA) @@ -259,9 +259,7 @@ target.Paralyze(0.5 SECONDS) target.Knockdown(3 SECONDS) target.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 3, 10 SECONDS) - if(ishuman(target) && ishuman(user)) - INVOKE_ASYNC(human_sacker, TYPE_PROC_REF(/mob/living, grab), human_sacker, human_target) - human_sacker.setGrabState(GRAB_AGGRESSIVE) + do_grab(user, target, GRAB_AGGRESSIVE) /** * Our neutral tackling outcome. @@ -300,9 +298,7 @@ var/potential_roll_outcome = (roll * -10) if(ishuman(user)) - var/mob/living/carbon/human/human_sacker = target - var/attacker_armor = human_sacker.run_armor_check(BODY_ZONE_CHEST, MELEE) - potential_roll_outcome *= ((100 - attacker_armor) /100) + potential_roll_outcome *= ((100 - target.run_armor_check(BODY_ZONE_CHEST, MELEE)) /100) else potential_roll_outcome *= 0.9 diff --git a/code/datums/elements/decals/blood.dm b/code/datums/elements/decals/blood.dm index ec09caed73d..7984939cddc 100644 --- a/code/datums/elements/decals/blood.dm +++ b/code/datums/elements/decals/blood.dm @@ -9,10 +9,14 @@ /datum/element/decal/blood/Detach(atom/source) UnregisterSignal(source, COMSIG_ATOM_GET_EXAMINE_NAME) + if(isitem(source)) + var/obj/item/source_item = source + REMOVE_KEEP_TOGETHER(source_item, type) return ..() /datum/element/decal/blood/generate_appearance(_icon, _icon_state, _dir, _plane, _layer, _color, _alpha, _smoothing, source) var/obj/item/I = source + ADD_KEEP_TOGETHER(I, type) var/icon = I.icon var/icon_state = I.icon_state if(!icon || !icon_state) diff --git a/code/datums/elements/window_smash.dm b/code/datums/elements/window_smash.dm index fbe2674b86c..32896d096bf 100644 --- a/code/datums/elements/window_smash.dm +++ b/code/datums/elements/window_smash.dm @@ -24,6 +24,9 @@ for(var/obj/structure/window/window in target_turf) window.smash_and_injure(flying_mob, old_loc, direction) + for(var/obj/structure/grille/grille in target_turf) + grille.smash_and_injure(flying_mob, old_loc, direction) + /datum/element/window_smashing/Detach(datum/source) UnregisterSignal(source, COMSIG_MOVABLE_MOVED) passwindow_off(source, TRAM_PASSENGER_TRAIT) diff --git a/code/datums/records/manifest.dm b/code/datums/records/manifest.dm index 1ba59b72d86..4b1aaeda9a5 100644 --- a/code/datums/records/manifest.dm +++ b/code/datums/records/manifest.dm @@ -38,7 +38,7 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new) misc_list[++misc_list.len] = list( "name" = name, "rank" = rank, - "trim" = trim, // NOVA EDIT ADDITION - Alt Titles + "trim" = trim, ) continue for(var/department_type as anything in job.departments_list) @@ -52,7 +52,7 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new) var/list/entry = list( "name" = name, "rank" = rank, - "trim" = trim, // NOVA EDIT ADDITION - Alt Titles + "trim" = trim, ) var/list/department_list = manifest_out[department.department_name] if(istype(job, department.department_head)) diff --git a/code/game/machinery/computer/arena.dm b/code/game/machinery/computer/arena.dm deleted file mode 100644 index 97d89c24140..00000000000 --- a/code/game/machinery/computer/arena.dm +++ /dev/null @@ -1,411 +0,0 @@ -#define ARENA_RED_TEAM "red" -#define ARENA_GREEN_TEAM "green" -#define ARENA_DEFAULT_ID "arena_default" -#define ARENA_CORNER_A "cornerA" -#define ARENA_CORNER_B "cornerB" - -/// Arena related landmarks -/obj/effect/landmark/arena - name = "arena landmark" - var/landmark_tag - var/arena_id = ARENA_DEFAULT_ID - -/obj/effect/landmark/arena/start - name = "arena corner A" - landmark_tag = ARENA_CORNER_A - -/obj/effect/landmark/arena/end - name = "arena corner B" - landmark_tag = ARENA_CORNER_B - -/// Controller for admin event arenas -/obj/machinery/computer/arena - name = "arena controller" - - interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_SET_MACHINE|INTERACT_MACHINE_REQUIRES_LITERACY - - /// Arena ID - var/arena_id = ARENA_DEFAULT_ID - /// Enables/disables spawning - var/ready_to_spawn = FALSE - /// Assoc list of map templates indexed by user friendly names - var/static/list/arena_templates = list() - /// Were the config directory arenas loaded - var/static/default_arenas_loaded = FALSE - /// Name of currently loaded template - var/current_arena_template = "None" - // What turf arena clears to - var/empty_turf_type = /turf/open/indestructible - // List of team ids - var/list/teams = list(ARENA_RED_TEAM,ARENA_GREEN_TEAM) - /// List of hud instances indedxed by team id - var/static/list/team_huds = list() - /// List of hud colors indexed by team id - var/static/list/team_colors = list(ARENA_RED_TEAM = "red", ARENA_GREEN_TEAM = "green") - // Team hud index in GLOB.huds indexed by team id - var/static/list/team_hud_index = list() - - /// List of ckeys indexed by team id - var/list/team_keys = list() - /// List of outfit datums/types indexed by team id, can be empty - var/list/outfits = list() - /// Default team outfit if `outfits[team]` is empty - var/default_outfit = /datum/outfit/job/assistant - - /// Is the arena template loading in - var/loading = FALSE - - //How long between admin pressing start and doors opening - var/start_delay = 30 SECONDS - //Value for the countdown - var/start_time - var/list/countdowns = list() //List of countdown effects ticking down to start - - //Sound played when the fight starts. - var/start_sound = 'sound/items/airhorn2.ogg' - var/start_sound_volume = 50 - -/obj/machinery/computer/arena/Initialize(mapload, obj/item/circuitboard/C) - . = ..() - LoadDefaultArenas() - -/** - * Loads the arenas from config directory. - * THESE ARE FULLY CACHED FOR QUICK SWITCHING SO KEEP TRACK OF THE AMOUNT - */ -/obj/machinery/computer/arena/proc/LoadDefaultArenas() - if(default_arenas_loaded) - return - var/arena_dir = "[global.config.directory]/arenas/" - var/list/default_arenas = flist(arena_dir) - for(var/arena_file in default_arenas) - var/simple_name = replacetext(replacetext(arena_file,arena_dir,""),".dmm","") - INVOKE_ASYNC(src, PROC_REF(add_new_arena_template), null, arena_dir + arena_file, simple_name) - -/obj/machinery/computer/arena/proc/get_landmark_turf(landmark_tag) - for(var/obj/effect/landmark/arena/L in GLOB.landmarks_list) - if(L.arena_id == arena_id && L.landmark_tag == landmark_tag && isturf(L.loc)) - return L.loc - -/obj/machinery/computer/arena/proc/get_load_point() - var/turf/A = get_landmark_turf(ARENA_CORNER_A) - var/turf/B = get_landmark_turf(ARENA_CORNER_B) - return locate(min(A.x,B.x),min(A.y,B.y),A.z) - -/obj/machinery/computer/arena/proc/get_arena_turfs() - var/lp = get_load_point() - var/turf/A = get_landmark_turf(ARENA_CORNER_A) - var/turf/B = get_landmark_turf(ARENA_CORNER_B) - var/turf/hp = locate(max(A.x,B.x),max(A.y,B.y),A.z) - return block(lp,hp) - -/obj/machinery/computer/arena/proc/clear_arena() - for(var/turf/T in get_arena_turfs()) - T.empty(turf_type = /turf/open/indestructible) - current_arena_template = "None" - -/obj/machinery/computer/arena/proc/load_arena(arena_template,mob/user) - if(loading) - return - var/datum/map_template/M = arena_templates[arena_template] - if(!M) - to_chat(user,span_warning("No such arena")) - return - clear_arena() //Clear current arena - var/turf/A = get_landmark_turf(ARENA_CORNER_A) - var/turf/B = get_landmark_turf(ARENA_CORNER_B) - var/wh = abs(A.x - B.x) + 1 - var/hz = abs(A.y - B.y) + 1 - if(M.width > wh || M.height > hz) - to_chat(user,span_warning("Arena template is too big for the current arena!")) - return - loading = TRUE - var/bd = M.load(get_load_point()) - if(bd) - current_arena_template = arena_template - loading = FALSE - - message_admins("[key_name_admin(user)] loaded [arena_template] event arena for [arena_id] arena.") - log_admin("[key_name(user)] loaded [arena_template] event arena for [arena_id] arena.") - - - -/obj/machinery/computer/arena/proc/add_new_arena_template(user,fname,friendly_name) - if(!fname) - fname = input(user, "Upload dmm file to use as arena template","Upload Map Template") as null|file - if(!fname) - return - if(!friendly_name) - friendly_name = "[fname]" //Could ask the user for friendly name here - - var/datum/map_template/T = new(fname,friendly_name,TRUE) - if(!T.cached_map || T.cached_map.check_for_errors()) - to_chat(user,"Map failed to parse check for errors.") - return - - arena_templates[T.name] = T - message_admins("[key_name_admin(user)] uploaded new event arena: [friendly_name].") - log_admin("[key_name(user)] uploaded new event arena: [friendly_name].") - -/obj/machinery/computer/arena/proc/load_team(user,team) - var/rawteam = tgui_input_text(user, "Enter team member list (ckeys separated by comma)", "Team List", multiline = TRUE) - if(isnull(rawteam)) - return - for(var/i in splittext(rawteam, ",")) - var/key = ckey(i) - if(!i) - continue - add_team_member(user,team,key) - -/obj/machinery/computer/arena/proc/add_team_member(mob/user,team,key) - if(!key) - var/list/keys = list() - for(var/mob/M in GLOB.player_list) - keys += M.client - var/client/selection = tgui_input_list(user, "Select a player", "Team member", sort_key(keys)) - //Could be freeform if you want to add disconnected i guess - if(isnull(selection)) - return - key = selection.ckey - if(!team_keys[team]) - team_keys[team] = list(key) - else - team_keys[team] |= key - to_chat(user,"[key] added to [team] team.") - -/obj/machinery/computer/arena/proc/remove_member(mob/user,ckey,team) - team_keys[team] -= ckey - to_chat(user,"[ckey] removed from [team] team.") - -/obj/machinery/computer/arena/proc/spawn_member(obj/machinery/arena_spawn/spawnpoint,ckey,team) - var/mob/oldbody = get_mob_by_key(ckey) - if(!isobserver(oldbody)) - return - var/mob/living/carbon/human/M = new/mob/living/carbon/human(get_turf(spawnpoint)) - oldbody.client.prefs.safe_transfer_prefs_to(M, is_antag = TRUE) - M.set_species(/datum/species/human) // Could use setting per team - M.equipOutfit(outfits[team] ? outfits[team] : default_outfit) - M.faction += team //In case anyone wants to add team based stuff to arena special effects - M.key = ckey - -/obj/machinery/computer/arena/proc/change_outfit(mob/user,team) - outfits[team] = user.client.robust_dress_shop() - -/obj/machinery/computer/arena/proc/toggle_spawn(mob/user) - ready_to_spawn = !ready_to_spawn - to_chat(user,"You [ready_to_spawn ? "enable" : "disable"] the spawners.") - log_admin("[key_name(user)] toggled event arena spawning for [arena_id] arena.") - // Could use update_appearance on spawnpoints here to show they're on - if(ready_to_spawn) - for(var/mob/M in all_contestants()) - to_chat(M,span_userdanger("Arena you're signed up for is ready!")) - -/obj/machinery/computer/arena/proc/all_contestants() - . = list() - for(var/team in team_keys) - for(var/key in team_keys[team]) - var/mob/M = get_mob_by_key(key) - if(M) - . += M - -/obj/machinery/computer/arena/proc/reset_arena() - clear_arena() - set_doors(closed = TRUE) - -/obj/machinery/computer/arena/proc/get_spawn(team) - for(var/obj/machinery/arena_spawn/A as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/arena_spawn)) - if(A.arena_id == arena_id && A.team == team) - return A - -/obj/machinery/computer/arena/proc/start_match(mob/user) - //TODO: Check if everyone is spawned in, if not ask for confirmation. - var/timetext = DisplayTimeText(start_delay) - to_chat(user,span_notice("The match will start in [timetext].")) - for(var/mob/M in all_contestants()) - to_chat(M,span_userdanger("The gates will open in [timetext]!")) - start_time = world.time + start_delay - addtimer(CALLBACK(src, PROC_REF(begin)),start_delay) - for(var/team in teams) - var/obj/machinery/arena_spawn/team_spawn = get_spawn(team) - var/obj/effect/countdown/arena/A = new(team_spawn) - A.start() - countdowns += A - -/obj/machinery/computer/arena/proc/begin() - ready_to_spawn = FALSE - set_doors(closed = FALSE) - if(start_sound) - for(var/team in teams) - var/obj/machinery/arena_spawn/A = get_spawn(team) - playsound(A,start_sound, start_sound_volume) - for(var/mob/M in all_contestants()) - to_chat(M,span_userdanger("START!")) - //Clean up the countdowns - QDEL_LIST(countdowns) - start_time = null - updateUsrDialog() - - -/obj/machinery/computer/arena/proc/set_doors(closed = FALSE) - for(var/obj/machinery/door/poddoor/D as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/door/poddoor)) - if(D.id != arena_id) - continue - if(closed) - INVOKE_ASYNC(D, TYPE_PROC_REF(/obj/machinery/door/poddoor, close)) - else - INVOKE_ASYNC(D, TYPE_PROC_REF(/obj/machinery/door/poddoor, open)) - -/obj/machinery/computer/arena/Topic(href, href_list) - if(..()) - return - var/mob/user = usr - - if(!user.client.holder) // Should it require specific perm ? - return - - if(href_list["upload"]) - add_new_arena_template(user) - if(href_list["change_arena"]) - load_arena(href_list["change_arena"],user) - if(href_list["toggle_spawn"]) - toggle_spawn(user) - if(href_list["start"]) - start_match(user) - if(href_list["follow"]) - var/mob/observed_team_member = locate(href_list["follow"]) in GLOB.mob_list - if(observed_team_member) - user.client?.admin_follow(observed_team_member) - if(href_list["team_action"]) - var/team = href_list["team"] - switch(href_list["team_action"]) - if("addmember") - add_team_member(user,team) - if("loadteam") - load_team(user,team) - if("outfit") - change_outfit(user,team) - if(href_list["special"]) - switch(href_list["special"]) - if("reset") - reset_arena() - //Just example in case you want to add more - if("randomarena") - load_random_arena(user) - if("spawntrophy") - trophy_for_last_man_standing(user) - if(href_list["member_action"]) - var/ckey = href_list["ckey"] - var/team = href_list["team"] - switch(href_list["member_action"]) - if("remove") - remove_member(user,ckey,team) - updateUsrDialog() - -// Special functions - -/obj/machinery/computer/arena/proc/load_random_arena(mob/user) - if(!length(arena_templates)) - to_chat(user,span_warning("No arenas present")) - return - var/picked = pick(arena_templates) - load_arena(picked,user) - -/obj/machinery/computer/arena/proc/trophy_for_last_man_standing() - var/arena_turfs = get_arena_turfs() - for(var/mob/living/L in GLOB.mob_living_list) - if(L.stat != DEAD && (get_turf(L) in arena_turfs)) - var/obj/item/reagent_containers/cup/glass/trophy/gold_cup/G = new(get_turf(L)) - G.name = "[L.real_name]'s Trophy" - -/obj/machinery/computer/arena/ui_interact(mob/user) - . = ..() - var/list/dat = list() - dat += "
Spawning is currently [ready_to_spawn ? "enabled" : "disabled"] Toggle
" - dat += "
[start_time ? "Stop countdown" : "Start!"]
" - for(var/team in teams) - dat += "

[capitalize(team)] team:

" - dat += "" - dat += "
Team Outfit : [outfits[team] ? outfits[team] : default_outfit]
" - dat += "Load team" - dat += "Add member" - dat += "Change Outfit" - //Add more per team features here - - dat += "Current arena: [current_arena_template]" - dat += "

Arena List:

" - for(var/A in arena_templates) - dat += "[A]
" - dat += "
" - dat += "Upload new arena
" - dat += "
" - //Special actions - dat += "Reset Arena.
" - dat += "Load random arena.
" - dat += "Spawn trophies for survivors.
" - - var/datum/browser/popup = new(user, "arena controller", "Arena Controller", 500, 600) - popup.set_content(dat.Join()) - popup.open() - -/// Arena spawnpoint -/obj/machinery/arena_spawn - name = "Arena Spawnpoint" - icon = 'icons/obj/machines/beacon.dmi' - icon_state = "syndbeacon" - resistance_flags = INDESTRUCTIBLE - /// In case we have multiple arena controllers at once. - var/arena_id = ARENA_DEFAULT_ID - /// Team ID - var/team = "default" - /// only exist to cut down on glob.machines lookups, do not modify - var/obj/machinery/computer/arena/_controller - -/obj/machinery/arena_spawn/red - name = "Red Team Spawnpoint" - color = "red" - team = ARENA_RED_TEAM - -/obj/machinery/arena_spawn/green - name = "Green Team Spawnpoint" - color = "green" - team = ARENA_GREEN_TEAM - -/obj/machinery/arena_spawn/proc/get_controller() - if(_controller && !QDELETED(_controller) && _controller.arena_id == arena_id) - return _controller - for(var/obj/machinery/computer/arena/A as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/computer/arena)) - if(A.arena_id == arena_id) - _controller = A - return _controller - -/obj/machinery/arena_spawn/attack_ghost(mob/user) - var/obj/machinery/computer/arena/C = get_controller() - if(!C) //Unlinked spawn - return - if(C.ready_to_spawn) - var/list/allowed_keys = C.team_keys[team] - if(!(user.ckey in allowed_keys)) - to_chat(user,span_warning("You're not on the team list.")) - return - C.spawn_member(src,user.ckey,team) - -#undef ARENA_GREEN_TEAM -#undef ARENA_RED_TEAM -#undef ARENA_DEFAULT_ID -#undef ARENA_CORNER_A -#undef ARENA_CORNER_B diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index 8446fb4a9d9..1274a6796eb 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -9,6 +9,92 @@ /obj/structure/frame/computer/Initialize(mapload) . = ..() AddComponent(/datum/component/simple_rotation) + register_context() + update_appearance(UPDATE_ICON_STATE) + +/obj/structure/frame/computer/deconstruct(disassembled = TRUE) + if(!(obj_flags & NO_DECONSTRUCTION)) + var/atom/drop_loc = drop_location() + if(state == FRAME_COMPUTER_STATE_GLASSED) + if(disassembled) + new /obj/item/stack/sheet/glass(drop_loc, 2) + else + new /obj/item/shard(drop_loc) + new /obj/item/shard(drop_loc) + if(state >= FRAME_COMPUTER_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_loc, 5) + + return ..() + +/obj/structure/frame/computer/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = NONE + if(isnull(held_item)) + return + + switch(state) + if(FRAME_COMPUTER_STATE_EMPTY) + if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Un" : ""]anchor" + return CONTEXTUAL_SCREENTIP_SET + else if(anchored && istype(held_item, /obj/item/circuitboard/computer)) + context[SCREENTIP_CONTEXT_LMB] = "Install board" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_WELDER) + context[SCREENTIP_CONTEXT_LMB] = "Unweld frame" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Disassemble frame" + return CONTEXTUAL_SCREENTIP_SET + if(FRAME_COMPUTER_STATE_BOARD_INSTALLED) + if(held_item.tool_behaviour == TOOL_CROWBAR) + context[SCREENTIP_CONTEXT_LMB] = "Pry out board" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Secure board" + return CONTEXTUAL_SCREENTIP_SET + if(FRAME_COMPUTER_STATE_BOARD_SECURED) + if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Unsecure board" + return CONTEXTUAL_SCREENTIP_SET + else if(istype(held_item, /obj/item/stack/cable_coil)) + context[SCREENTIP_CONTEXT_LMB] = "Install cable" + return CONTEXTUAL_SCREENTIP_SET + if(FRAME_COMPUTER_STATE_WIRED) + if(held_item.tool_behaviour == TOOL_WIRECUTTER) + context[SCREENTIP_CONTEXT_LMB] = "Cut out cable" + return CONTEXTUAL_SCREENTIP_SET + else if(istype(held_item, /obj/item/stack/sheet/glass)) + context[SCREENTIP_CONTEXT_LMB] = "Install panel" + return CONTEXTUAL_SCREENTIP_SET + if(FRAME_COMPUTER_STATE_GLASSED) + if(held_item.tool_behaviour == TOOL_CROWBAR) + context[SCREENTIP_CONTEXT_LMB] = "Pry out glass" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Complete frame" + return CONTEXTUAL_SCREENTIP_SET + +/obj/structure/frame/computer/examine(user) + . = ..() + + switch(state) + if(FRAME_STATE_EMPTY) + . += span_notice("It can be [EXAMINE_HINT("wrenched")] [anchored ? "loose" : "in place"].") + if(anchored) + . += span_warning("It's missing a circuit board.") + . += span_notice("It can be [EXAMINE_HINT("welded")] or [EXAMINE_HINT("screwed")] apart.") + if(FRAME_COMPUTER_STATE_BOARD_INSTALLED) + . += span_warning("An [circuit.name] is installed and should be [EXAMINE_HINT("screwed")] in place.") + . += span_notice("The circuit board can be [EXAMINE_HINT("pried")] out.") + if(FRAME_COMPUTER_STATE_BOARD_SECURED) + . += span_warning("Its requires [EXAMINE_HINT("5 cable")] pieces to wire it.") + . += span_notice("The circuit board can be [EXAMINE_HINT("screwed")] loose.") + if(FRAME_COMPUTER_STATE_WIRED) + . += span_notice("The wires can be cut out with [EXAMINE_HINT("wire cutters")].") + . += span_warning("Its requires [EXAMINE_HINT("2 glass")] sheets to complete the screen.") + if(FRAME_COMPUTER_STATE_GLASSED) + . += span_notice("The screen can be [EXAMINE_HINT("pried")] out.") + . += span_notice("The moniter can be [EXAMINE_HINT("screwed")] to complete it") /obj/structure/frame/computer/circuit_added(obj/item/circuitboard/added) state = FRAME_COMPUTER_STATE_BOARD_INSTALLED @@ -22,7 +108,45 @@ if(state != FRAME_COMPUTER_STATE_EMPTY) balloon_alert(user, "circuit already installed!") return FALSE - return ..() + if(!anchored && istype(board)) + balloon_alert(user, "frame must be anchored!") + return FALSE + . = ..() + if(. && !by_hand) // Installing via RPED auto-secures it + state = FRAME_COMPUTER_STATE_BOARD_SECURED + update_appearance(UPDATE_ICON_STATE) + return . + +/obj/structure/frame/computer/install_parts_from_part_replacer(mob/living/user, obj/item/storage/part_replacer/replacer, no_sound = FALSE) + switch(state) + if(FRAME_COMPUTER_STATE_BOARD_SECURED) + var/obj/item/stack/cable_coil/cable = locate() in replacer + if(isnull(cable)) + return FALSE + + if(add_cabling(user, cable, time = 0)) + if(!no_sound) + replacer.play_rped_sound() + if(replacer.works_from_distance) + user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) + no_sound = TRUE + return install_parts_from_part_replacer(user, replacer, no_sound = no_sound) // Recursive call to handle the next part + + return FALSE + + if(FRAME_COMPUTER_STATE_WIRED) + var/obj/item/stack/sheet/glass/glass_sheets = locate() in replacer + if(isnull(glass_sheets)) + return FALSE + + if(add_glass(user, glass_sheets, time = 0)) + if(!no_sound) + replacer.play_rped_sound() + if(replacer.works_from_distance) + user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) + return TRUE + + return FALSE /obj/structure/frame/computer/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) . = ..() @@ -48,11 +172,9 @@ if(istype(tool, /obj/item/storage/part_replacer)) return install_parts_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING - return . - /obj/structure/frame/computer/screwdriver_act(mob/living/user, obj/item/tool) . = ..() - if(. != NONE) + if(. & ITEM_INTERACT_ANY_BLOCKER) return . switch(state) @@ -83,6 +205,9 @@ return ITEM_INTERACT_BLOCKING /obj/structure/frame/computer/crowbar_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + switch(state) if(FRAME_COMPUTER_STATE_BOARD_INSTALLED) tool.play_tool_sound(src) @@ -92,14 +217,12 @@ return ITEM_INTERACT_SUCCESS if(FRAME_COMPUTER_STATE_BOARD_SECURED) - if(!user.combat_mode) - balloon_alert(user, "unsecure the circuit!") - return ITEM_INTERACT_BLOCKING + balloon_alert(user, "unsecure the circuit!") + return ITEM_INTERACT_BLOCKING if(FRAME_COMPUTER_STATE_WIRED) - if(!user.combat_mode) - balloon_alert(user, "remove the wiring!") - return ITEM_INTERACT_BLOCKING + balloon_alert(user, "remove the wiring!") + return ITEM_INTERACT_BLOCKING if(FRAME_COMPUTER_STATE_GLASSED) tool.play_tool_sound(src) @@ -111,38 +234,34 @@ dropped_glass.add_fingerprint(user) return ITEM_INTERACT_SUCCESS -/obj/structure/frame/computer/install_parts_from_part_replacer(mob/living/user, obj/item/storage/part_replacer/replacer, no_sound = FALSE) - switch(state) - if(FRAME_COMPUTER_STATE_BOARD_SECURED) - var/obj/item/stack/cable_coil/cable = locate() in replacer - if(isnull(cable)) - return FALSE - - if(add_cabling(user, cable, time = 0)) - if(!no_sound) - replacer.play_rped_sound() - if(replacer.works_from_distance) - user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) - no_sound = TRUE - return install_parts_from_part_replacer(user, replacer, no_sound = no_sound) // Recursive call to handle the next part - - return FALSE +/obj/structure/frame/computer/wirecutter_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE - if(FRAME_COMPUTER_STATE_WIRED) - var/obj/item/stack/sheet/glass/glass_sheets = locate() in replacer - if(isnull(glass_sheets)) - return FALSE + if(state != FRAME_COMPUTER_STATE_WIRED) + return ITEM_INTERACT_BLOCKING - if(add_glass(user, glass_sheets, time = 0)) - if(!no_sound) - replacer.play_rped_sound() - if(replacer.works_from_distance) - user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) - return TRUE + tool.play_tool_sound(src) + balloon_alert(user, "cables removed") + state = FRAME_COMPUTER_STATE_BOARD_SECURED + update_appearance(UPDATE_ICON_STATE) - return FALSE + var/obj/item/stack/cable_coil/dropped_cables = new (drop_location(), 5) + if (!QDELETED(dropped_cables)) + dropped_cables.add_fingerprint(user) + return ITEM_INTERACT_SUCCESS +/** + * Adds cable to the computer to wire it + * Arguments + * + * * mob/living/user - the player who is adding the cable + * * obj/item/stack/cable_coil/cable - the cable we are trying to add + * * time - time taken to complete the operation + */ /obj/structure/frame/computer/proc/add_cabling(mob/living/user, obj/item/stack/cable_coil/cable, time = 2 SECONDS) + PRIVATE_PROC(TRUE) + if(state != FRAME_COMPUTER_STATE_BOARD_SECURED) return FALSE if(!cable.tool_start_check(user, amount = 5)) @@ -156,7 +275,17 @@ update_appearance(UPDATE_ICON_STATE) return TRUE +/** + * Adds glass sheets to the computer to complete the screen + * Arguments + * + * * mob/living/user - the player who is adding the glass + * * obj/item/stack/sheet/glass/glass - the glass we are trying to add + * * time - time taken to complete the operation + */ /obj/structure/frame/computer/proc/add_glass(mob/living/user, obj/item/stack/sheet/glass/glass, time = 2 SECONDS) + PRIVATE_PROC(TRUE) + if(state != FRAME_COMPUTER_STATE_WIRED) return FALSE if(!glass.tool_start_check(user, amount = 2)) @@ -171,22 +300,6 @@ update_appearance(UPDATE_ICON_STATE) return TRUE -/obj/structure/frame/computer/wirecutter_act(mob/living/user, obj/item/tool) - if(state != FRAME_COMPUTER_STATE_WIRED) - return NONE - - tool.play_tool_sound(src) - balloon_alert(user, "cables removed") - state = FRAME_COMPUTER_STATE_BOARD_SECURED - update_appearance(UPDATE_ICON_STATE) - var/obj/item/stack/cable_coil/dropped_cables = new (drop_location(), 5) - if (!QDELETED(dropped_cables)) - dropped_cables.add_fingerprint(user) - return ITEM_INTERACT_SUCCESS - -/obj/structure/frame/computer/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation - /obj/structure/frame/computer/finalize_construction(mob/living/user, obj/item/tool) tool.play_tool_sound(src) var/obj/machinery/new_machine = new circuit.build_path(loc) @@ -221,20 +334,6 @@ qdel(src) return TRUE -/obj/structure/frame/computer/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/atom/drop_loc = drop_location() - if(state == FRAME_COMPUTER_STATE_GLASSED) - if(disassembled) - new /obj/item/stack/sheet/glass(drop_loc, 2) - else - new /obj/item/shard(drop_loc) - new /obj/item/shard(drop_loc) - if(state >= FRAME_COMPUTER_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_loc, 5) - - return ..() - /// Helpers for rcd /obj/structure/frame/computer/rcd icon = 'icons/hud/radial.dmi' diff --git a/code/game/machinery/computer/records/medical.dm b/code/game/machinery/computer/records/medical.dm index 71eab88c113..b98117975d6 100644 --- a/code/game/machinery/computer/records/medical.dm +++ b/code/game/machinery/computer/records/medical.dm @@ -65,6 +65,7 @@ quirk_notes = target.quirk_notes, rank = target.rank, species = target.species, + trim = target.trim, // NOVA EDIT ADDITION START - Expanded records! past_medical_records = target.past_medical_records, past_general_records = target.past_general_records, diff --git a/code/game/machinery/computer/records/security.dm b/code/game/machinery/computer/records/security.dm index e30814f231a..6980e764fa8 100644 --- a/code/game/machinery/computer/records/security.dm +++ b/code/game/machinery/computer/records/security.dm @@ -128,6 +128,7 @@ note = target.security_note, rank = target.rank, species = target.species, + trim = target.trim, wanted_status = target.wanted_status, // NOVA EDIT ADDITION - RP Records past_general_records = target.past_general_records, diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index 497babd2e42..e624e3f33d7 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -24,7 +24,7 @@ new /obj/item/stack/sheet/iron(drop_loc, 5) circuit?.forceMove(drop_loc) - qdel(src) + return ..() /// Called when circuit has been set to a new board /obj/structure/frame/proc/circuit_added(obj/item/circuitboard/added) @@ -97,13 +97,13 @@ return FALSE /obj/structure/frame/wrench_act(mob/living/user, obj/item/tool) + . = NONE switch(default_unfasten_wrench(user, tool, 4 SECONDS)) if(SUCCESSFUL_UNFASTEN) return ITEM_INTERACT_SUCCESS if(FAILED_UNFASTEN) return ITEM_INTERACT_BLOCKING - - return NONE + return . /obj/structure/frame/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) . = ..() @@ -201,421 +201,3 @@ */ /obj/structure/frame/proc/install_parts_from_part_replacer(mob/living/user, obj/item/storage/part_replacer/replacer, no_sound = FALSE) return FALSE - -/obj/structure/frame/machine - name = "machine frame" - desc = "The standard frame for most station appliances. Its appearance and function is controlled by the inserted board." - board_type = /obj/item/circuitboard/machine - /// List of all compnents inside the frame contributing to its construction - var/list/components - /// List of all components required to construct the frame - var/list/req_components - /// User-friendly list of names of required components - var/list/req_component_names - -/obj/structure/frame/machine/examine(user) - . = ..() - if(state != FRAME_STATE_BOARD_INSTALLED) - return . - - if(!length(req_components)) - . += span_info("It requires no components.") - return . - - if(!req_component_names) - stack_trace("[src]'s req_components list has items but its req_component_names list is null!") - return . - - var/list/nice_list = list() - for(var/component in req_components) - if(!ispath(component)) - stack_trace("An item in [src]'s req_components list is not a path!") - continue - if(!req_components[component]) - continue - - nice_list += list("[req_components[component]] [req_component_names[component]]\s") - . += span_info("It requires [english_list(nice_list, "no more components")].") - return . - -/** - * Collates the displayed names of the machine's components - * - * Arguments: - * * specific_parts - If true, the component should not use base name, but a specific tier - */ -/obj/structure/frame/machine/proc/update_namelist(specific_parts) - if(!req_components) - return - - req_component_names = list() - for(var/component_path in req_components) - if(!ispath(component_path)) - continue - - if(ispath(component_path, /obj/item/stack)) - var/obj/item/stack/stack_path = component_path - if(initial(stack_path.singular_name)) - req_component_names[component_path] = initial(stack_path.singular_name) - else - req_component_names[component_path] = initial(stack_path.name) - else if(ispath(component_path, /datum/stock_part)) - var/datum/stock_part/stock_part = component_path - var/obj/item/physical_object_type = initial(stock_part.physical_object_type) - - req_component_names[component_path] = initial(physical_object_type.name) - else if(ispath(component_path, /obj/item/stock_parts)) - var/obj/item/stock_parts/stock_part = component_path - - if(!specific_parts && initial(stock_part.base_name)) - req_component_names[component_path] = initial(stock_part.base_name) - else - req_component_names[component_path] = initial(stock_part.name) - else if(ispath(component_path, /obj/item)) - var/obj/item/part = component_path - - req_component_names[component_path] = initial(part.name) - else - stack_trace("Invalid component part [component_path] in [type], couldn't get its name") - req_component_names[component_path] = "[component_path] (this is a bug)" - -/obj/structure/frame/machine/proc/get_req_components_amt() - var/amt = 0 - for(var/path in req_components) - amt += req_components[path] - return amt - -/obj/structure/frame/machine/try_dissassemble(mob/living/user, obj/item/tool, disassemble_time) - if(anchored) - balloon_alert(user, "must be unsecured first!") - return FALSE - return ..() - -/obj/structure/frame/machine/install_board(mob/living/user, obj/item/circuitboard/machine/board, by_hand = TRUE) - if(state == FRAME_STATE_EMPTY) - balloon_alert(user, "needs wiring!") - return FALSE - if(state == FRAME_STATE_BOARD_INSTALLED) - balloon_alert(user, "circuit already installed!") - return FALSE - if(!anchored && istype(board) && board.needs_anchored) - balloon_alert(user, "frame must be anchored!") - return FALSE - - return ..() - -/obj/structure/frame/machine/circuit_added(obj/item/circuitboard/machine/added) - state = FRAME_STATE_BOARD_INSTALLED - update_appearance(UPDATE_ICON_STATE) - //add circuit board as the first component to the list of components - //required for part_replacer to locate it while exchanging parts - //so it does not early return in /obj/machinery/proc/exchange_parts - components = list(circuit) - req_components = added.req_components.Copy() - update_namelist(added.specific_parts) - -/obj/structure/frame/machine/circuit_removed(obj/item/circuitboard/machine/removed) - state = FRAME_STATE_WIRED - update_appearance(UPDATE_ICON_STATE) - -/obj/structure/frame/machine/install_parts_from_part_replacer(mob/living/user, obj/item/storage/part_replacer/replacer, no_sound = FALSE) - if(!length(replacer.contents) || !get_req_components_amt()) - return FALSE - - var/play_sound = FALSE - var/list/part_list = replacer.get_sorted_parts() //parts sorted in order of tier - for(var/path in req_components) - var/target_path - if(ispath(path, /datum/stock_part)) - var/datum/stock_part/datum_part = path - target_path = initial(datum_part.physical_object_base_type) - else - target_path = path - - var/obj/item/part - while(req_components[path] > 0 && (part = look_for(part_list, target_path, ispath(path, /obj/item/stack/ore/bluespace_crystal) ? /obj/item/stack/sheet/bluespace_crystal : null))) - part_list -= part - if(istype(part, /obj/item/stack)) - var/obj/item/stack/S = part - var/used_amt = min(round(S.get_amount()), req_components[path]) - var/stack_name = S.singular_name - if(!used_amt || !S.use(used_amt)) - continue - req_components[path] -= used_amt - // No balloon alert here so they can look back and see what they added - to_chat(user, span_notice("You add [used_amt] [stack_name] to [src].")) - play_sound = TRUE - else if(replacer.atom_storage.attempt_remove(part, src)) - var/stock_part_datum = GLOB.stock_part_datums_per_object[part.type] - if (!isnull(stock_part_datum)) - components += stock_part_datum - qdel(part) - else - components += part - part.forceMove(src) - req_components[path]-- - // No balloon alert here so they can look back and see what they added - to_chat(user, span_notice("You add [part] to [src].")) - play_sound = TRUE - - if(play_sound && !no_sound) - replacer.play_rped_sound() - if(replacer.works_from_distance) - user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) - return TRUE - -/** - * Attempts to add the passed part to the frame - * - * Requires no sanity check that the passed part is a stock part - * - * Arguments - * * user - the player - * * tool - the part to add - */ -/obj/structure/frame/machine/proc/add_part(mob/living/user, obj/item/tool) - for(var/stock_part_base in req_components) - if (req_components[stock_part_base] == 0) - continue - - var/stock_part_path - - if(ispath(stock_part_base, /obj/item)) - stock_part_path = stock_part_base - else if(ispath(stock_part_base, /datum/stock_part)) - var/datum/stock_part/stock_part_datum_type = stock_part_base - stock_part_path = initial(stock_part_datum_type.physical_object_type) - else - stack_trace("Bad stock part in req_components: [stock_part_base]") - continue - - //if we require an bluespace crystall and we have an full sheet of them we can allow that - if(ispath(stock_part_path, /obj/item/stack/ore/bluespace_crystal) && istype(tool, /obj/item/stack/sheet/bluespace_crystal)) - //allow it - pass() - else if(!istype(tool, stock_part_path)) - continue - - if(isstack(tool)) - var/obj/item/stack/S = tool - var/used_amt = min(round(S.get_amount()), req_components[stock_part_path]) - if(used_amt && S.use(used_amt)) - req_components[stock_part_path] -= used_amt - // No balloon alert here so they can look back and see what they added - to_chat(user, span_notice("You add [tool] to [src].")) - return - - // We might end up qdel'ing the part if it's a stock part datum. - // In practice, this doesn't have side effects to the name, - // but academically we should not be using an object after it's deleted. - var/part_name = "[tool]" - - if (ispath(stock_part_base, /datum/stock_part)) - // We can't just reuse stock_part_path here or its singleton, - // or else putting in a tier 2 part will deconstruct to a tier 1 part. - var/stock_part_datum = GLOB.stock_part_datums_per_object[tool.type] - if (isnull(stock_part_datum)) - stack_trace("tool.type] does not have an associated stock part datum!") - continue - - components += stock_part_datum - - // We regenerate the stock parts on deconstruct. - // This technically means we lose unique qualities of the stock part, but - // it's worth it for how dramatically this simplifies the code. - // The only place I can see it affecting anything is like...RPG qualities. :P - qdel(tool) - else if(user.transferItemToLoc(tool, src)) - components += tool - else - break - - // No balloon alert here so they can look back and see what they added - to_chat(user, span_notice("You add [part_name] to [src].")) - req_components[stock_part_base]-- - return TRUE - - balloon_alert(user, "can't add that!") - return FALSE - -/** - * Attempt to finalize the construction of the frame into a machine - * as according to our circuit and parts - * - * If successful, results in qdel'ing the frame and newing of a machine - * - * Arguments - * * user - the player - * * tool - the tool used to finalize the construction - */ -/obj/structure/frame/machine/finalize_construction(mob/living/user, obj/item/tool) - for(var/component in req_components) - if(req_components[component] > 0) - user.balloon_alert(user, "missing components!") - return FALSE - - tool.play_tool_sound(src) - var/obj/machinery/new_machine = new circuit.build_path(loc) - if(istype(new_machine)) - new_machine.clear_components() - // Set anchor state - new_machine.set_anchored(anchored) - // Prevent us from dropping stuff thanks to /Exited - var/obj/item/circuitboard/machine/leaving_circuit = circuit - circuit = null - // Assign the circuit & parts & move them all at once into the machine - // no need to seperatly move circuit board as its already part of the components list - new_machine.circuit = leaving_circuit - new_machine.component_parts = components - for (var/obj/new_part in components) - new_part.forceMove(new_machine) - //Inform machine that its finished & cleanup - new_machine.RefreshParts() - new_machine.on_construction(user) - components = null - qdel(src) - return TRUE - -/obj/structure/frame/machine/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) - . = ..() - if(. & ITEM_INTERACT_ANY_BLOCKER) - return . - - switch(state) - if(FRAME_STATE_EMPTY) - if(istype(tool, /obj/item/stack/cable_coil)) - if(!tool.tool_start_check(user, amount = 5)) - return ITEM_INTERACT_BLOCKING - - balloon_alert(user, "adding cables...") - if(!tool.use_tool(src, user, 2 SECONDS, volume = 50, amount = 5) || state != FRAME_STATE_EMPTY) - return ITEM_INTERACT_BLOCKING - - state = FRAME_STATE_WIRED - update_appearance(UPDATE_ICON_STATE) - return ITEM_INTERACT_SUCCESS - - if(FRAME_STATE_WIRED) - if(isnull(circuit) && istype(tool, /obj/item/storage/part_replacer)) - return install_circuit_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING - - if(FRAME_STATE_BOARD_INSTALLED) - if(istype(tool, /obj/item/storage/part_replacer)) - return install_parts_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING - - if(!user.combat_mode) - return add_part(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING - - return . - -/obj/structure/frame/machine/screwdriver_act(mob/living/user, obj/item/tool) - . = ..() - if(. & ITEM_INTERACT_ANY_BLOCKER) - return . - if(state != FRAME_STATE_BOARD_INSTALLED) - return . - - if(finalize_construction(user, tool)) - return ITEM_INTERACT_SUCCESS - - return ITEM_INTERACT_BLOCKING - -/obj/structure/frame/machine/can_be_unfasten_wrench(mob/user, silent) - . = ..() - if(. != SUCCESSFUL_UNFASTEN) - return . - - if(circuit?.needs_anchored) - balloon_alert(user, "circuit must be anchored!") - return FAILED_UNFASTEN - - return . - -/obj/structure/frame/machine/wirecutter_act(mob/living/user, obj/item/tool) - if(state != FRAME_STATE_WIRED) - return NONE - - balloon_alert(user, "removing cables...") - if(!tool.use_tool(src, user, 2 SECONDS, volume = 50) || state != FRAME_STATE_WIRED) - return ITEM_INTERACT_BLOCKING - - state = FRAME_STATE_EMPTY - update_appearance(UPDATE_ICON_STATE) - new /obj/item/stack/cable_coil(drop_location(), 5) - return ITEM_INTERACT_SUCCESS - -/obj/structure/frame/machine/crowbar_act(mob/living/user, obj/item/tool) - if(state != FRAME_STATE_BOARD_INSTALLED) - return NONE - - tool.play_tool_sound(src) - var/list/leftover_components = components.Copy() - circuit - dump_contents() - balloon_alert(user, "circuit board[length(leftover_components) ? " and components" : ""] removed") - // Circuit exited handles updating state - return ITEM_INTERACT_SUCCESS - -/obj/structure/frame/machine/Exited(atom/movable/gone, direction) - if(gone == circuit) - components -= circuit - return ..() - -/obj/structure/frame/machine/Destroy() - QDEL_LIST(components) - return ..() - -/** - * Returns the instance of path1 in list, else path2 in list - * - * Arguments - * * parts - the list of parts to search - * * path1 - the first path to search for - * * path2 - the second path to search for, if path1 is not found - */ -/obj/structure/frame/machine/proc/look_for(list/parts, path1, path2) - return (locate(path1) in parts) || (path2 ? (locate(path2) in parts) : null) - -/obj/structure/frame/machine/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(state >= FRAME_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_location(), 5) - dump_contents() - return ..() - -/obj/structure/frame/machine/dump_contents() - var/atom/drop_loc = drop_location() - - // We need a snowflake check for stack items since they don't exist anymore - for(var/component in circuit?.req_components) - if(!ispath(component, /obj/item/stack)) - continue - var/obj/item/stack/stack_path = component - var/stack_amount = circuit.req_components[component] - req_components[component] - if(stack_amount > 0) - new stack_path(drop_loc, stack_amount) - - // Rest of the stuff can just be spat out (this includes the circuitboard0) - for(var/component in components) - if(ismovable(component)) - var/atom/movable/atom_component = component - atom_component.forceMove(drop_loc) - - else if(istype(component, /datum/stock_part)) - var/datum/stock_part/stock_part_datum = component - var/physical_object_type = initial(stock_part_datum.physical_object_type) - new physical_object_type(drop_loc) - - else - stack_trace("Invalid component [component] was found in constructable frame") - - components = null - req_components = null - req_component_names = null - -/obj/structure/frame/machine/secured - state = FRAME_STATE_WIRED - anchored = TRUE - -/obj/structure/frame/machine/secured/Initialize(mapload) - . = ..() - update_appearance(UPDATE_ICON_STATE) diff --git a/code/game/machinery/machine_frame.dm b/code/game/machinery/machine_frame.dm new file mode 100644 index 00000000000..a3c074937f0 --- /dev/null +++ b/code/game/machinery/machine_frame.dm @@ -0,0 +1,474 @@ +/obj/structure/frame/machine + name = "machine frame" + desc = "The standard frame for most station appliances. Its appearance and function is controlled by the inserted board." + board_type = /obj/item/circuitboard/machine + /// List of all compnents inside the frame contributing to its construction + var/list/components + /// List of all components required to construct the frame + var/list/req_components + /// User-friendly list of names of required components + var/list/req_component_names + +/obj/structure/frame/machine/Initialize(mapload) + . = ..() + register_context() + update_appearance(UPDATE_ICON_STATE) + +/obj/structure/frame/machine/Destroy() + QDEL_LIST(components) + return ..() + +/obj/structure/frame/machine/deconstruct(disassembled = TRUE) + if(!(obj_flags & NO_DECONSTRUCTION)) + if(state >= FRAME_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_location(), 5) + dump_contents() + return ..() + +/obj/structure/frame/machine/try_dissassemble(mob/living/user, obj/item/tool, disassemble_time) + if(anchored) + balloon_alert(user, "must be unsecured first!") + return FALSE + return ..() + +/obj/structure/frame/machine/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = NONE + if(isnull(held_item)) + return + + switch(state) + if(FRAME_STATE_EMPTY) + if(istype(held_item, /obj/item/stack/cable_coil)) + context[SCREENTIP_CONTEXT_LMB] = "Wire Frame" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Un" : ""]anchor" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_WELDER) + context[SCREENTIP_CONTEXT_LMB] = "Unweld frame" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Disassemble frame" + return CONTEXTUAL_SCREENTIP_SET + if(FRAME_STATE_WIRED) + if(held_item.tool_behaviour == TOOL_WIRECUTTER) + context[SCREENTIP_CONTEXT_LMB] = "Cut wires" + return CONTEXTUAL_SCREENTIP_SET + else if(istype(held_item, board_type)) + context[SCREENTIP_CONTEXT_LMB] = "Insert board" + return CONTEXTUAL_SCREENTIP_SET + if(FRAME_STATE_BOARD_INSTALLED) + if(held_item.tool_behaviour == TOOL_CROWBAR) + context[SCREENTIP_CONTEXT_LMB] = "Pry out components" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_WRENCH) + if(!circuit.needs_anchored) + context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Un" : ""]anchor" + return CONTEXTUAL_SCREENTIP_SET + return NONE + else if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + var/needs_components = FALSE + for(var/component in req_components) + if(!req_components[component]) + continue + needs_components = TRUE + break + if(!needs_components) + context[SCREENTIP_CONTEXT_LMB] = "Complete frame" + return CONTEXTUAL_SCREENTIP_SET + else if(!istype(held_item, /obj/item/storage/part_replacer)) + for(var/component in req_components) + if(!req_components[component]) + continue + var/stock_part_path + if(ispath(component, /obj/item)) + stock_part_path = component + else if(ispath(component, /datum/stock_part)) + var/datum/stock_part/stock_part_datum_type = component + stock_part_path = initial(stock_part_datum_type.physical_object_type) + if(istype(held_item, stock_part_path)) + context[SCREENTIP_CONTEXT_LMB] = "Insert part" + return CONTEXTUAL_SCREENTIP_SET + +/obj/structure/frame/machine/examine(user) + . = ..() + if(!circuit?.needs_anchored) + . += span_notice("It can be [EXAMINE_HINT("anchored")] [anchored ? "loose" : "in place"]") + if(state == FRAME_STATE_EMPTY) + . += span_warning("It needs [EXAMINE_HINT("5 cable")] pieces to wire it.") + return + if(state == FRAME_STATE_WIRED) + . += span_info("Its wires can be cut with a [EXAMINE_HINT("wirecutter")].") + if(state != FRAME_STATE_BOARD_INSTALLED) + . += span_warning("Its missing a circuit board..") + return + if(!length(req_components)) + . += span_info("It requires no components.") + return + + var/list/nice_list = list() + for(var/component in req_components) + if(!req_components[component]) + continue + nice_list += list("[req_components[component]] [req_component_names[component]]\s") + . += span_info("It requires [english_list(nice_list, "no more components")].") + + . += span_info("All the components can be [EXAMINE_HINT("pried")] out.") + if(!length(nice_list)) + . += span_info("The frame can be [EXAMINE_HINT("screwed")] to complete it.") + +/obj/structure/frame/machine/dump_contents() + var/atom/drop_loc = drop_location() + + // We need a snowflake check for stack items since they don't exist anymore + for(var/component in circuit?.req_components) + if(!ispath(component, /obj/item/stack)) + continue + var/obj/item/stack/stack_path = component + var/stack_amount = circuit.req_components[component] - req_components[component] + if(stack_amount > 0) + new stack_path(drop_loc, stack_amount) + + // Rest of the stuff can just be spat out (this includes the circuitboard0) + for(var/component in components) + if(ismovable(component)) + var/atom/movable/atom_component = component + atom_component.forceMove(drop_loc) + + else if(istype(component, /datum/stock_part)) + var/datum/stock_part/stock_part_datum = component + var/physical_object_type = initial(stock_part_datum.physical_object_type) + new physical_object_type(drop_loc) + + else + stack_trace("Invalid component [component] was found in constructable frame") + + components = null + req_components = null + req_component_names = null + +/obj/structure/frame/machine/install_board(mob/living/user, obj/item/circuitboard/machine/board, by_hand = TRUE) + if(state == FRAME_STATE_EMPTY) + balloon_alert(user, "needs wiring!") + return FALSE + if(state == FRAME_STATE_BOARD_INSTALLED) + balloon_alert(user, "circuit already installed!") + return FALSE + if(!anchored && istype(board) && board.needs_anchored) + balloon_alert(user, "frame must be anchored!") + return FALSE + + return ..() + +/obj/structure/frame/machine/circuit_added(obj/item/circuitboard/machine/added) + state = FRAME_STATE_BOARD_INSTALLED + update_appearance(UPDATE_ICON_STATE) + + //add circuit board as the first component to the list of components + //required for part_replacer to locate it while exchanging parts + //so it does not early return in /obj/machinery/proc/exchange_parts + components = list(circuit) + req_components = added.req_components.Copy() + if(!req_components) + return + + //creates a list of names from all the required parts + req_component_names = list() + for(var/component_path in req_components) + if(!ispath(component_path)) + continue + + if(ispath(component_path, /obj/item/stack)) + var/obj/item/stack/stack_path = component_path + if(initial(stack_path.singular_name)) + req_component_names[component_path] = initial(stack_path.singular_name) + else + req_component_names[component_path] = initial(stack_path.name) + else if(ispath(component_path, /datum/stock_part)) + var/datum/stock_part/stock_part = component_path + var/obj/item/physical_object_type = initial(stock_part.physical_object_type) + + req_component_names[component_path] = initial(physical_object_type.name) + else if(ispath(component_path, /obj/item/stock_parts)) + var/obj/item/stock_parts/stock_part = component_path + + if(!added.specific_parts && initial(stock_part.base_name)) + req_component_names[component_path] = initial(stock_part.base_name) + else + req_component_names[component_path] = initial(stock_part.name) + else if(ispath(component_path, /obj/item)) + var/obj/item/part = component_path + + req_component_names[component_path] = initial(part.name) + else + stack_trace("Invalid component part [component_path] in [type], couldn't get its name") + req_component_names[component_path] = "[component_path] (this is a bug)" + +/obj/structure/frame/machine/circuit_removed(obj/item/circuitboard/machine/removed) + components -= removed + state = FRAME_STATE_WIRED + update_appearance(UPDATE_ICON_STATE) + +/** + * Returns the instance of path1 in list, else path2 in list + * + * Arguments + * * parts - the list of parts to search + * * path1 - the first path to search for + * * path2 - the second path to search for, if path1 is not found + */ +/obj/structure/frame/machine/proc/look_for(list/parts, path1, path2) + PRIVATE_PROC(TRUE) + + return (locate(path1) in parts) || (path2 ? (locate(path2) in parts) : null) + +/obj/structure/frame/machine/install_parts_from_part_replacer(mob/living/user, obj/item/storage/part_replacer/replacer, no_sound = FALSE) + if(!length(replacer.contents)) + return FALSE + var/amt = 0 + for(var/path in req_components) + amt += req_components[path] + if(!amt) + return FALSE + + var/play_sound = FALSE + var/list/part_list = replacer.get_sorted_parts() //parts sorted in order of tier + for(var/path in req_components) + var/target_path + if(ispath(path, /datum/stock_part)) + var/datum/stock_part/datum_part = path + target_path = initial(datum_part.physical_object_base_type) + else + target_path = path + + var/obj/item/part + while(req_components[path] > 0 && (part = look_for(part_list, target_path, ispath(path, /obj/item/stack/ore/bluespace_crystal) ? /obj/item/stack/sheet/bluespace_crystal : null))) + part_list -= part + if(istype(part, /obj/item/stack)) + var/obj/item/stack/S = part + var/used_amt = min(round(S.get_amount()), req_components[path]) + var/stack_name = S.singular_name + if(!used_amt || !S.use(used_amt)) + continue + req_components[path] -= used_amt + // No balloon alert here so they can look back and see what they added + to_chat(user, span_notice("You add [used_amt] [stack_name] to [src].")) + play_sound = TRUE + else if(replacer.atom_storage.attempt_remove(part, src)) + var/stock_part_datum = GLOB.stock_part_datums_per_object[part.type] + if (!isnull(stock_part_datum)) + components += stock_part_datum + qdel(part) + else + components += part + part.forceMove(src) + req_components[path]-- + // No balloon alert here so they can look back and see what they added + to_chat(user, span_notice("You add [part] to [src].")) + play_sound = TRUE + + if(play_sound && !no_sound) + replacer.play_rped_sound() + if(replacer.works_from_distance) + user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) + return TRUE + +/obj/structure/frame/machine/can_be_unfasten_wrench(mob/user, silent) + . = ..() + if(. != SUCCESSFUL_UNFASTEN) + return . + + if(circuit?.needs_anchored) + balloon_alert(user, "frame must be anchored!") + return FAILED_UNFASTEN + + return . + +/obj/structure/frame/machine/screwdriver_act(mob/living/user, obj/item/tool) + . = ..() + if(. & ITEM_INTERACT_ANY_BLOCKER) + return . + if(state != FRAME_STATE_BOARD_INSTALLED) + return . + + if(finalize_construction(user, tool)) + return ITEM_INTERACT_SUCCESS + + return ITEM_INTERACT_BLOCKING + +/obj/structure/frame/machine/wirecutter_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + if(state != FRAME_STATE_WIRED) + return ITEM_INTERACT_BLOCKING + + balloon_alert(user, "removing cables...") + if(!tool.use_tool(src, user, 2 SECONDS, volume = 50) || state != FRAME_STATE_WIRED) + return ITEM_INTERACT_BLOCKING + + state = FRAME_STATE_EMPTY + update_appearance(UPDATE_ICON_STATE) + new /obj/item/stack/cable_coil(drop_location(), 5) + return ITEM_INTERACT_SUCCESS + +/obj/structure/frame/machine/crowbar_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + if(state != FRAME_STATE_BOARD_INSTALLED) + return ITEM_INTERACT_BLOCKING + + tool.play_tool_sound(src) + var/list/leftover_components = components.Copy() - circuit + dump_contents() + balloon_alert(user, "circuit board[length(leftover_components) ? " and components" : ""] removed") + // Circuit exited handles updating state + return ITEM_INTERACT_SUCCESS + +/** + * Attempts to add the passed part to the frame + * + * Requires no sanity check that the passed part is a stock part + * + * Arguments + * * user - the player + * * tool - the part to add + */ +/obj/structure/frame/machine/proc/add_part(mob/living/user, obj/item/tool) + PRIVATE_PROC(TRUE) + + for(var/stock_part_base in req_components) + if (req_components[stock_part_base] == 0) + continue + + var/stock_part_path + + if(ispath(stock_part_base, /obj/item)) + stock_part_path = stock_part_base + else if(ispath(stock_part_base, /datum/stock_part)) + var/datum/stock_part/stock_part_datum_type = stock_part_base + stock_part_path = initial(stock_part_datum_type.physical_object_type) + else + stack_trace("Bad stock part in req_components: [stock_part_base]") + continue + + //if we require an bluespace crystall and we have an full sheet of them we can allow that + if(ispath(stock_part_path, /obj/item/stack/ore/bluespace_crystal) && istype(tool, /obj/item/stack/sheet/bluespace_crystal)) + pass() //allow it + else if(!istype(tool, stock_part_path)) + continue + + if(isstack(tool)) + var/obj/item/stack/S = tool + var/used_amt = min(round(S.get_amount()), req_components[stock_part_path]) + if(used_amt && S.use(used_amt)) + req_components[stock_part_path] -= used_amt + // No balloon alert here so they can look back and see what they added + to_chat(user, span_notice("You add [tool] to [src].")) + return + + // We might end up qdel'ing the part if it's a stock part datum. + // In practice, this doesn't have side effects to the name, + // but academically we should not be using an object after it's deleted. + var/part_name = "[tool]" + + if (ispath(stock_part_base, /datum/stock_part)) + // We can't just reuse stock_part_path here or its singleton, + // or else putting in a tier 2 part will deconstruct to a tier 1 part. + var/stock_part_datum = GLOB.stock_part_datums_per_object[tool.type] + if (isnull(stock_part_datum)) + stack_trace("tool.type] does not have an associated stock part datum!") + continue + + components += stock_part_datum + + // We regenerate the stock parts on deconstruct. + // This technically means we lose unique qualities of the stock part, but + // it's worth it for how dramatically this simplifies the code. + // The only place I can see it affecting anything is like...RPG qualities. :P + qdel(tool) + else if(user.transferItemToLoc(tool, src)) + components += tool + else + break + + // No balloon alert here so they can look back and see what they added + to_chat(user, span_notice("You add [part_name] to [src].")) + req_components[stock_part_base]-- + return TRUE + + balloon_alert(user, "can't add that!") + return FALSE + +/obj/structure/frame/machine/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) + . = ..() + if(. & ITEM_INTERACT_ANY_BLOCKER) + return . + + switch(state) + if(FRAME_STATE_EMPTY) + if(istype(tool, /obj/item/stack/cable_coil)) + if(!tool.tool_start_check(user, amount = 5)) + return ITEM_INTERACT_BLOCKING + + balloon_alert(user, "adding cables...") + if(!tool.use_tool(src, user, 2 SECONDS, volume = 50, amount = 5) || state != FRAME_STATE_EMPTY) + return ITEM_INTERACT_BLOCKING + + state = FRAME_STATE_WIRED + update_appearance(UPDATE_ICON_STATE) + return ITEM_INTERACT_SUCCESS + + if(FRAME_STATE_WIRED) + if(isnull(circuit) && istype(tool, /obj/item/storage/part_replacer)) + return install_circuit_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING + + if(FRAME_STATE_BOARD_INSTALLED) + if(istype(tool, /obj/item/storage/part_replacer)) + return install_parts_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING + + if(!user.combat_mode) + return add_part(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING + + return . + +/** + * Attempt to finalize the construction of the frame into a machine + * as according to our circuit and parts + * + * If successful, results in qdel'ing the frame and newing of a machine + * + * Arguments + * * user - the player + * * tool - the tool used to finalize the construction + */ +/obj/structure/frame/machine/finalize_construction(mob/living/user, obj/item/tool) + for(var/component in req_components) + if(req_components[component] > 0) + user.balloon_alert(user, "missing components!") + return FALSE + + tool.play_tool_sound(src) + var/obj/machinery/new_machine = new circuit.build_path(loc) + if(istype(new_machine)) + new_machine.clear_components() + // Set anchor state + new_machine.set_anchored(anchored) + // Prevent us from dropping stuff thanks to /Exited + var/obj/item/circuitboard/machine/leaving_circuit = circuit + circuit = null + // Assign the circuit & parts & move them all at once into the machine + // no need to seperatly move circuit board as its already part of the components list + new_machine.circuit = leaving_circuit + new_machine.component_parts = components + for (var/obj/new_part in components) + new_part.forceMove(new_machine) + //Inform machine that its finished & cleanup + new_machine.RefreshParts() + new_machine.on_construction(user) + components = null + qdel(src) + return TRUE + +/obj/structure/frame/machine/secured + state = FRAME_STATE_WIRED + anchored = TRUE diff --git a/code/game/objects/effects/countdown.dm b/code/game/objects/effects/countdown.dm index ab422dda3d1..d83440ee9bd 100644 --- a/code/game/objects/effects/countdown.dm +++ b/code/game/objects/effects/countdown.dm @@ -162,19 +162,6 @@ var/time_left = max(0, (H.finish_time - world.time) / 10) return round(time_left) -/obj/effect/countdown/arena - invisibility = INVISIBILITY_NONE - name = "arena countdown" - -/obj/effect/countdown/arena/get_value() - var/obj/machinery/arena_spawn/A = attached_to - if(!istype(A)) - return - else - var/obj/machinery/computer/arena/C = A.get_controller() - var/time_left = max(0, (C.start_time - world.time) / 10) - return round(time_left) - /obj/effect/countdown/flower_bud name = "flower bud countdown" diff --git a/code/game/objects/items/food/misc.dm b/code/game/objects/items/food/misc.dm index da07843dec3..8cebf7e05aa 100644 --- a/code/game/objects/items/food/misc.dm +++ b/code/game/objects/items/food/misc.dm @@ -246,6 +246,7 @@ w_class = WEIGHT_CLASS_BULKY tastes = list("cherry" = 1, "crepe" = 1) foodtypes = GRAIN | FRUIT | SUGAR + food_flags = FOOD_FINGER_FOOD crafting_complexity = FOOD_COMPLEXITY_5 /obj/item/food/branrequests diff --git a/code/game/objects/items/food/pie.dm b/code/game/objects/items/food/pie.dm index 46674fb735e..e5775991520 100644 --- a/code/game/objects/items/food/pie.dm +++ b/code/game/objects/items/food/pie.dm @@ -484,3 +484,30 @@ tastes = list("pie" = 1, "the far off year of 2010" = 1) foodtypes = GRAIN crafting_complexity = FOOD_COMPLEXITY_2 + +/obj/item/food/pie/bacid_pie + name = "battery acid pie" + desc = "Ooh it's a pie made of... battery acid? You suppose an ethereal could find some enjoyement in eating this." + icon_state = "bacid_pie" + food_reagents = list( + /datum/reagent/consumable/nutriment = 18, + /datum/reagent/consumable/liquidelectricity/enriched = 18 + ) + tastes = list("battery acid" = 2, "electricity" = 2, "a cyber world" = 2) + foodtypes = TOXIC + slice_type = /obj/item/food/pieslice/bacid_pie + yield = 4 + crafting_complexity = FOOD_COMPLEXITY_3 + + +/obj/item/food/pieslice/bacid_pie + name = "battery acid pie slice" + desc = "The battery acid filling has a concerningly appealing bright green color" + icon_state = "bacid_pie_slice" + food_reagents = list( + /datum/reagent/consumable/nutriment = 4.5, + /datum/reagent/consumable/liquidelectricity/enriched = 4.5 + ) + tastes = list("battery acid" = 1, "electricity" = 1, "a cyber world" = 1) + foodtypes = TOXIC + crafting_complexity = FOOD_COMPLEXITY_3 diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index de996015e59..f110cd8b43e 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -325,6 +325,7 @@ door.update_appearance() qdel(src) + return door /obj/structure/door_assembly/update_overlays() . = ..() diff --git a/code/game/objects/structures/door_assembly_types.dm b/code/game/objects/structures/door_assembly_types.dm index 36b41fbc326..589cad42bca 100644 --- a/code/game/objects/structures/door_assembly_types.dm +++ b/code/game/objects/structures/door_assembly_types.dm @@ -293,4 +293,5 @@ /obj/structure/door_assembly/door_assembly_material/finish_door() var/obj/machinery/door/airlock/door = ..() door.set_custom_materials(custom_materials) + door.update_appearance() return door diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index fba9d5cecc4..da023942518 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -339,19 +339,19 @@ var/turf/T = get_turf(src) if(T.overfloor_placed)//cant be a floor in the way! return FALSE - // Shocking hurts the grille (to weaken monkey powersinks) - if(prob(50)) + + var/obj/structure/cable/cable_node = T.get_cable_node() + if(isnull(cable_node)) + return FALSE + if(!electrocute_mob(user, cable_node, src, 1, TRUE)) + return FALSE + if(prob(50)) // Shocking hurts the grille (to weaken monkey powersinks) take_damage(1, BURN, FIRE, sound_effect = FALSE) - var/obj/structure/cable/C = T.get_cable_node() - if(C) - if(electrocute_mob(user, C, src, 1, TRUE)) - var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread - s.set_up(3, 1, src) - s.start() - return TRUE - else - return FALSE - return FALSE + var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread + sparks.set_up(3, 1, src) + sparks.start() + + return TRUE /obj/structure/grille/should_atmos_process(datum/gas_mixture/air, exposed_temperature) return exposed_temperature > T0C + 1500 && !broken diff --git a/code/game/turfs/open/floor.dm b/code/game/turfs/open/floor.dm index 28a60c83ddb..17d9a41b58a 100644 --- a/code/game/turfs/open/floor.dm +++ b/code/game/turfs/open/floor.dm @@ -201,7 +201,6 @@ /turf/open/floor/acid_melt() ScrapeAway(flags = CHANGETURF_INHERIT_AIR) -/// if you are updating this make to to update /turf/open/misc/rcd_vals() too /turf/open/floor/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) switch(the_rcd.mode) if(RCD_TURF) diff --git a/code/game/turfs/open/misc.dm b/code/game/turfs/open/misc.dm index a704c7f12b1..02de7489786 100644 --- a/code/game/turfs/open/misc.dm +++ b/code/game/turfs/open/misc.dm @@ -76,153 +76,18 @@ return /turf/open/misc/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) - switch(the_rcd.mode) - if(RCD_TURF) - if(the_rcd.rcd_design_path != /turf/open/floor/plating/rcd) - return FALSE - - var/obj/structure/girder/girder = locate() in src - if(girder) - return girder.rcd_vals(user, the_rcd) - - return rcd_result_with_memory( - list("delay" = 2 SECONDS, "cost" = 16), - src, RCD_MEMORY_WALL, - ) - if(RCD_WINDOWGRILLE) - //default cost for building a grill for fulltile windows - var/cost = 4 - var/delay = 1 SECONDS - if(the_rcd.rcd_design_path == /obj/structure/window) - cost = 4 - delay = 2 SECONDS - else if(the_rcd.rcd_design_path == /obj/structure/window/reinforced) - cost = 6 - delay = 2.5 SECONDS - return rcd_result_with_memory( - list("delay" = delay, "cost" = cost), - src, RCD_MEMORY_WINDOWGRILLE, - ) - if(RCD_AIRLOCK) - if(ispath(the_rcd.rcd_design_path, /obj/machinery/door/airlock/glass)) - return list("delay" = 5 SECONDS, "cost" = 20) - else - return list("delay" = 5 SECONDS, "cost" = 16) - if(RCD_STRUCTURE) - var/static/list/structure_costs = list( - /obj/structure/reflector = list("delay" = 2 SECONDS, "cost" = 20), - /obj/structure/girder = list("delay" = 1.3 SECONDS, "cost" = 8), - /obj/structure/frame/machine/secured = list("delay" = 2 SECONDS, "cost" = 20), - /obj/structure/frame/computer/rcd = list("delay" = 2 SECONDS, "cost" = 20), - /obj/structure/floodlight_frame = list("delay" = 3 SECONDS, "cost" = 20), - /obj/structure/chair = list("delay" = 1 SECONDS, "cost" = 4), - /obj/structure/chair/stool/bar = list("delay" = 0.5 SECONDS, "cost" = 4), - /obj/structure/table = list("delay" = 2 SECONDS, "cost" = 8), - /obj/structure/bed = list("delay" = 2.5 SECONDS, "cost" = 8), - /obj/structure/rack = list("delay" = 2.5 SECONDS, "cost" = 4), - ) - - var/list/design_data = structure_costs[the_rcd.rcd_design_path] - if(!isnull(design_data)) - return design_data - - for(var/structure in structure_costs) - if(ispath(the_rcd.rcd_design_path, structure)) - return structure_costs[structure] - + if(the_rcd.mode == RCD_TURF) + if(the_rcd.rcd_design_path != /turf/open/floor/plating/rcd) return FALSE + return list("delay" = 0, "cost" = 3) return FALSE /turf/open/misc/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, list/rcd_data) - switch(rcd_data["[RCD_DESIGN_MODE]"]) - if(RCD_TURF) - if(rcd_data["[RCD_DESIGN_PATH]"] != /turf/open/floor/plating/rcd) - return FALSE - - var/obj/structure/girder/girder = locate() in src - if(girder) - return girder.rcd_act(user, the_rcd, rcd_data) - - place_on_top(/turf/closed/wall) - return TRUE - if(RCD_WINDOWGRILLE) - //check if we are building a window - var/obj/structure/window/window_path = rcd_data["[RCD_DESIGN_PATH]"] - if(!ispath(window_path)) - CRASH("Invalid window path type in RCD: [window_path]") - - //allow directional windows to be built without grills - if(!initial(window_path.fulltile)) - if(!valid_build_direction(src, user.dir, is_fulltile = FALSE)) - balloon_alert(user, "window already here!") - return FALSE - var/obj/structure/window/WD = new window_path(src, user.dir) - WD.set_anchored(TRUE) - return TRUE - - //build grills to deal with full tile windows - if(locate(/obj/structure/grille) in src) - return FALSE - var/obj/structure/grille/new_grille = new(src) - new_grille.set_anchored(TRUE) - return TRUE - if(RCD_AIRLOCK) - var/obj/machinery/door/airlock_type = rcd_data["[RCD_DESIGN_PATH]"] - - if(ispath(airlock_type, /obj/machinery/door/window)) - if(!valid_build_direction(src, user.dir, is_fulltile = FALSE)) - balloon_alert(user, "there's already a windoor!") - return FALSE - for(var/obj/machinery/door/door in src) - if(istype(door, /obj/machinery/door/window)) - continue - balloon_alert(user, "there's already a door!") - return FALSE - //create the assembly and let it finish itself - var/obj/structure/windoor_assembly/assembly = new (src, user.dir) - assembly.secure = ispath(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) - if(door.sub_door) - continue - balloon_alert(user, "there's already a door!") - return FALSE - //create the assembly and let it finish itself - var/obj/structure/door_assembly/assembly = new (src) - if(initial(airlock_type.glass)) - assembly.glass = TRUE - assembly.glass_type = airlock_type - else - assembly.airlock_type = airlock_type - assembly.electronics = the_rcd.airlock_electronics.create_copy(assembly) - assembly.finish_door() - return TRUE - if(RCD_STRUCTURE) - var/atom/movable/design_type = rcd_data["[RCD_DESIGN_PATH]"] - - //map absolute types to basic subtypes - var/atom/movable/locate_type = design_type - if(ispath(locate_type, /obj/structure/frame/machine/secured)) - locate_type = /obj/structure/frame/machine - if(ispath(locate_type, /obj/structure/frame/computer/rcd)) - locate_type = /obj/structure/frame/computer - if(ispath(locate_type, /obj/structure/floodlight_frame/completed)) - locate_type = /obj/structure/floodlight_frame - if(locate(locate_type) in src) - return FALSE - - var/atom/movable/design = new design_type(src) - var/static/list/dir_types = list( - /obj/structure/chair, - /obj/structure/table, - /obj/structure/rack, - /obj/structure/bed, - ) - if(is_path_in_list(locate_type, dir_types)) - design.setDir(user.dir) - return TRUE + if(rcd_data["[RCD_DESIGN_MODE]"] == RCD_TURF) + if(rcd_data["[RCD_DESIGN_PATH]"] != /turf/open/floor/plating/rcd) + return FALSE + + place_on_top(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR) + return TRUE return FALSE diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm index 20f65281f96..5d4c6c9deee 100644 --- a/code/modules/antagonists/wizard/equipment/soulstone.dm +++ b/code/modules/antagonists/wizard/equipment/soulstone.dm @@ -456,42 +456,42 @@ switch(construct_class) if(CONSTRUCT_JUGGERNAUT) if(IS_CULTIST(creator)) - makeNewConstruct(/mob/living/basic/construct/juggernaut, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the makeNewConstruct proc + make_new_construct(/mob/living/basic/construct/juggernaut, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the make_new_construct proc return switch(theme) if(THEME_WIZARD) - makeNewConstruct(/mob/living/basic/construct/juggernaut/mystic, target, creator, cultoverride, loc_override) + make_new_construct(/mob/living/basic/construct/juggernaut/mystic, target, creator, cultoverride, loc_override) if(THEME_HOLY) - makeNewConstruct(/mob/living/basic/construct/juggernaut/angelic, target, creator, cultoverride, loc_override) + make_new_construct(/mob/living/basic/construct/juggernaut/angelic, target, creator, cultoverride, loc_override) if(THEME_CULT) - makeNewConstruct(/mob/living/basic/construct/juggernaut, target, creator, cultoverride, loc_override) + make_new_construct(/mob/living/basic/construct/juggernaut, target, creator, cultoverride, loc_override) if(CONSTRUCT_WRAITH) if(IS_CULTIST(creator)) - makeNewConstruct(/mob/living/basic/construct/wraith, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the makeNewConstruct proc + make_new_construct(/mob/living/basic/construct/wraith, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the make_new_construct proc return switch(theme) if(THEME_WIZARD) - makeNewConstruct(/mob/living/basic/construct/wraith/mystic, target, creator, cultoverride, loc_override) + make_new_construct(/mob/living/basic/construct/wraith/mystic, target, creator, cultoverride, loc_override) if(THEME_HOLY) - makeNewConstruct(/mob/living/basic/construct/wraith/angelic, target, creator, cultoverride, loc_override) + make_new_construct(/mob/living/basic/construct/wraith/angelic, target, creator, cultoverride, loc_override) if(THEME_CULT) - makeNewConstruct(/mob/living/basic/construct/wraith, target, creator, cultoverride, loc_override) + make_new_construct(/mob/living/basic/construct/wraith, target, creator, cultoverride, loc_override) if(CONSTRUCT_ARTIFICER) if(IS_CULTIST(creator)) - makeNewConstruct(/mob/living/basic/construct/artificer, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the makeNewConstruct proc + make_new_construct(/mob/living/basic/construct/artificer, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the make_new_construct proc return switch(theme) if(THEME_WIZARD) - makeNewConstruct(/mob/living/basic/construct/artificer/mystic, target, creator, cultoverride, loc_override) + make_new_construct(/mob/living/basic/construct/artificer/mystic, target, creator, cultoverride, loc_override) if(THEME_HOLY) - makeNewConstruct(/mob/living/basic/construct/artificer/angelic, target, creator, cultoverride, loc_override) + make_new_construct(/mob/living/basic/construct/artificer/angelic, target, creator, cultoverride, loc_override) if(THEME_CULT) - makeNewConstruct(/mob/living/basic/construct/artificer/noncult, target, creator, cultoverride, loc_override) + make_new_construct(/mob/living/basic/construct/artificer/noncult, target, creator, cultoverride, loc_override) -/proc/makeNewConstruct(mob/living/basic/construct/ctype, mob/target, mob/stoner = null, cultoverride = FALSE, loc_override = null) +/proc/make_new_construct(mob/living/basic/construct/ctype, mob/target, mob/stoner = null, cultoverride = FALSE, loc_override = null) if(QDELETED(target)) return - var/mob/living/basic/construct/newstruct = new ctype((loc_override) ? (loc_override) : (get_turf(target))) + var/mob/living/basic/construct/newstruct = new ctype(loc_override || get_turf(target)) var/makeicon = newstruct.icon_state var/theme = newstruct.theme flick("make_[makeicon][theme]", newstruct) @@ -499,20 +499,20 @@ if(stoner) newstruct.faction |= "[REF(stoner)]" newstruct.master = stoner - var/datum/action/innate/seek_master/SM = new() - SM.Grant(newstruct) - newstruct.key = target.key - var/atom/movable/screen/alert/bloodsense/BS - if(newstruct.mind && ((stoner && IS_CULTIST(stoner)) || cultoverride) && SSticker.HasRoundStarted()) + var/datum/action/innate/seek_master/seek_master = new + seek_master.Grant(newstruct) + target.mind?.transfer_to(newstruct, force_key_move = TRUE) + var/atom/movable/screen/alert/bloodsense/sense_alert + if(newstruct.mind && !IS_CULTIST(newstruct) && ((stoner && IS_CULTIST(stoner)) || cultoverride) && SSticker.HasRoundStarted()) newstruct.mind.add_antag_datum(/datum/antagonist/cult/construct) if(IS_CULTIST(stoner) || cultoverride) - to_chat(newstruct, "You are still bound to serve the cult[stoner ? " and [stoner]":""], follow [stoner ? stoner.p_their() : "their"] orders and help [stoner ? stoner.p_them() : "them"] complete [stoner ? stoner.p_their() : "their"] goals at all costs.") + to_chat(newstruct, span_cultbold("You are still bound to serve the cult[stoner ? " and [stoner]" : ""], follow [stoner?.p_their() || "their"] orders and help [stoner?.p_them() || "them"] complete [stoner?.p_their() || "their"] goals at all costs.")) else if(stoner) - to_chat(newstruct, "You are still bound to serve your creator, [stoner], follow [stoner.p_their()] orders and help [stoner.p_them()] complete [stoner.p_their()] goals at all costs.") + to_chat(newstruct, span_boldwarning("You are still bound to serve your creator, [stoner], follow [stoner.p_their()] orders and help [stoner.p_them()] complete [stoner.p_their()] goals at all costs.")) newstruct.clear_alert("bloodsense") - BS = newstruct.throw_alert("bloodsense", /atom/movable/screen/alert/bloodsense) - if(BS) - BS.Cviewer = newstruct + sense_alert = newstruct.throw_alert("bloodsense", /atom/movable/screen/alert/bloodsense) + if(sense_alert) + sense_alert.Cviewer = newstruct newstruct.cancel_camera() /obj/item/soulstone/anybody diff --git a/code/modules/cargo/goodies.dm b/code/modules/cargo/goodies.dm index 337dca218ea..fd30973d241 100644 --- a/code/modules/cargo/goodies.dm +++ b/code/modules/cargo/goodies.dm @@ -249,6 +249,12 @@ cost = PAYCHECK_CREW contains = list(/obj/item/bait_can/worm/premium) +/datum/supply_pack/goody/naturalbait + name = "Freshness Jars full of Natural Bait" + desc = "Homemade in the Spinward Sector." + cost = PAYCHECK_CREW * 4 //rock on + contains = list(/obj/item/storage/pill_bottle/naturalbait) + /datum/supply_pack/goody/telescopic_fishing_rod name = "Telescopic Fishing Rod" desc = "A collapsible fishing rod that can fit within a backpack." diff --git a/code/modules/cargo/packs/imports.dm b/code/modules/cargo/packs/imports.dm index 7edfe9e2a9c..fae1e405d3f 100644 --- a/code/modules/cargo/packs/imports.dm +++ b/code/modules/cargo/packs/imports.dm @@ -71,13 +71,6 @@ crate_name = "bananium sheet crate" discountable = SUPPLY_PACK_RARE_DISCOUNTABLE -/datum/supply_pack/imports/naturalbait - name = "Freshness Jars full of Natural Bait" - desc = "Homemade in the Spinward Sector." - cost = 2000 //rock on - contains = list(/obj/item/storage/pill_bottle/naturalbait) - crate_name = "fishing bait crate" - /datum/supply_pack/imports/dumpstercorpse name = "A....Dumpster?" desc = "Why does it smell so bad...." diff --git a/code/modules/deathmatch/deathmatch_loadouts.dm b/code/modules/deathmatch/deathmatch_loadouts.dm index 480e1975fb9..f994987427e 100644 --- a/code/modules/deathmatch/deathmatch_loadouts.dm +++ b/code/modules/deathmatch/deathmatch_loadouts.dm @@ -17,6 +17,8 @@ if(!isnull(species_override)) user.set_species(species_override) + else if (istype(user.dna.species.outfit_important_for_life)) //plasmamen get lit on fire and die + user.set_species(/datum/species/human) for(var/datum/action/act as anything in granted_spells) var/datum/action/new_ability = new act(user) new_ability.Grant(user) @@ -31,7 +33,7 @@ name = "Deathmatch: Assistant loadout" display_name = "Assistant" desc = "A simple assistant loadout: greyshirt and a toolbox" - + l_hand = /obj/item/storage/toolbox/mechanical uniform = /obj/item/clothing/under/color/grey back = /obj/item/storage/backpack @@ -48,7 +50,7 @@ name = "Deathmatch: Operative" display_name = "Operative" desc = "A syndicate operative." - + uniform = /obj/item/clothing/under/syndicate shoes = /obj/item/clothing/shoes/combat gloves = /obj/item/clothing/gloves/combat @@ -59,7 +61,7 @@ name = "Deathmatch: Ranged Operative" display_name = "Ranged Operative" desc = "A syndicate operative with a gun and a knife." - + l_hand = /obj/item/gun/ballistic/automatic/pistol l_pocket = /obj/item/knife/combat backpack_contents = list(/obj/item/ammo_box/magazine/m9mm = 5) @@ -68,7 +70,7 @@ name = "Deathmatch: Melee Operative" display_name = "Melee Operative" desc = "A syndicate operative with multiple knives." - + gloves = /obj/item/clothing/gloves/tackler/combat/insulated suit = /obj/item/clothing/suit/armor/vest head = /obj/item/clothing/head/helmet @@ -80,7 +82,7 @@ name = "Deathmatch: Security Officer" display_name = "Security Officer" desc = "A security officer." - + uniform = /datum/outfit/job/security::uniform suit = /datum/outfit/job/security::suit suit_store = /datum/outfit/job/security::suit_store @@ -100,7 +102,7 @@ name = "DM: Instagib" display_name = "Instagib" desc = "Assistant with an instakill rifle." - + l_hand = /obj/item/gun/energy/laser/instakill /datum/outfit/deathmatch_loadout/operative/sniper @@ -143,7 +145,7 @@ name = "Deathmatch: Battler Base" display_name = "Battler" desc = "What is a battler whith out weapone?." - + shoes = /obj/item/clothing/shoes/combat uniform = /obj/item/clothing/under/syndicate gloves = /obj/item/clothing/gloves/combat @@ -154,14 +156,14 @@ name = "Deathmatch: Soldier" display_name = "Soldier" desc = "Ready for combat." - + l_hand = /obj/item/gun/ballistic/rifle/boltaction l_pocket = /obj/item/knife/combat uniform = /obj/item/clothing/under/syndicate/rus_army suit = /obj/item/clothing/suit/armor/vest head = /obj/item/clothing/head/helmet/rus_helmet gloves = /obj/item/clothing/gloves/tackler/combat/insulated - + backpack_contents = list( /obj/item/grenade/smokebomb = 2, /obj/item/ammo_box/strilka310 = 2, @@ -199,7 +201,7 @@ name = "Deathmatch: North Star" display_name = "North Star" desc = "flip flip flip" - + uniform = /obj/item/clothing/under/suit/carpskin head = /obj/item/clothing/head/fedora/carpskin gloves = /obj/item/clothing/gloves/rapid @@ -212,7 +214,7 @@ name = "Deathmatch: Janitor" display_name = "Janitor" desc = "Regular work" - + uniform = /obj/item/clothing/under/rank/civilian/janitor suit = /obj/item/clothing/suit/caution head = /obj/item/reagent_containers/cup/bucket @@ -229,7 +231,7 @@ name = "Deathmatch: Surgeon" display_name = "Surgeon" desc = "Treatment has come" - + uniform = /obj/item/clothing/under/rank/medical/scrubs/blue suit = /obj/item/clothing/suit/apron/surgical head = /obj/item/clothing/head/utility/surgerycap @@ -238,7 +240,7 @@ l_pocket = /obj/item/reagent_containers/hypospray/combat r_pocket = /obj/item/reagent_containers/hypospray/medipen/penthrite l_hand = /obj/item/chainsaw - + backpack_contents = list( /obj/item/storage/medkit/tactical, /obj/item/reagent_containers/hypospray/medipen/stimulants, @@ -248,7 +250,7 @@ name = "Deathmatch: Raider" display_name = "Raider" desc = "Not from Shadow Legends" - + l_hand = /obj/item/nullrod/claymore/chainsaw_sword r_pocket = /obj/item/switchblade uniform = /obj/item/clothing/under/costume/jabroni @@ -260,7 +262,7 @@ name = "DM: Clown" display_name = "Clown (Man Of Honk)" desc = "Who called this honking clown" - + uniform = /datum/outfit/job/clown::uniform belt = /datum/outfit/job/clown::belt shoes = /datum/outfit/job/clown::shoes @@ -285,7 +287,7 @@ name = "Deathmatch: Coder" display_name = "Coder" desc = "What" - + l_hand = /obj/item/toy/katana uniform = /obj/item/clothing/under/costume/schoolgirl suit = /obj/item/clothing/suit/costume/joker @@ -299,7 +301,7 @@ name = "Deathmatch: Engineer" display_name = "Engineer" desc = "Meet the engineer" - + l_hand = /obj/item/storage/toolbox/emergency/turret uniform = /obj/item/clothing/under/rank/engineering/engineer shoes = /obj/item/clothing/shoes/magboots @@ -311,7 +313,7 @@ name = "Deathmatch: Scientist" display_name = "Scientist" desc = "What a nerd" - + uniform = /obj/item/clothing/under/rank/rnd/scientist suit = /obj/item/clothing/suit/armor/reactive/stealth mask = /obj/item/clothing/mask/gas @@ -353,7 +355,7 @@ name = "Deathmatch: Ripper" display_name = "Ripper" desc = "Die die die!!!" - + l_hand = /obj/item/gun/ballistic/shotgun/hook r_hand = /obj/item/gun/ballistic/shotgun/hook uniform = /obj/item/clothing/under/costume/skeleton @@ -366,7 +368,7 @@ name = "Deathmatch: Cowboy" display_name = "Cowboy" desc = "Yeehaw partner" - + r_hand = /obj/item/clothing/mask/cigarette/cigar l_hand = /obj/item/melee/curator_whip l_pocket = /obj/item/lighter diff --git a/code/modules/deathmatch/deathmatch_lobby.dm b/code/modules/deathmatch/deathmatch_lobby.dm index 138f639a0a6..e498f662b5e 100644 --- a/code/modules/deathmatch/deathmatch_lobby.dm +++ b/code/modules/deathmatch/deathmatch_lobby.dm @@ -295,6 +295,11 @@ /datum/deathmatch_lobby/ui_state(mob/user) return GLOB.observer_state +/// fills the lobby with fake players for the sake of UI debug, can only be called via VV +/datum/deathmatch_lobby/proc/fakefill(count) + for(var/i = 1 to count) + players["[rand(1,999)]"] = list("mob" = usr, "host" = FALSE, "ready" = FALSE, "loadout" = pick(loadouts)) + /datum/deathmatch_lobby/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, null) if(!ui) @@ -314,7 +319,7 @@ .["admin"] = check_rights_for(user.client, R_ADMIN) .["global_chat"] = global_chat .["playing"] = playing - .["loadouts"] = list() + .["loadouts"] = list("Randomize") for (var/datum/outfit/deathmatch_loadout/loadout as anything in loadouts) .["loadouts"] += initial(loadout.display_name) .["map"] = list() @@ -371,6 +376,9 @@ return FALSE if (params["player"] != usr.ckey && host != usr.ckey) return FALSE + if (params["loadout"] == "Randomize") + players[params["player"]]["loadout"] = pick(loadouts) + return TRUE for (var/datum/outfit/deathmatch_loadout/possible_loadout as anything in loadouts) if (params["loadout"] != initial(possible_loadout.display_name)) continue diff --git a/code/modules/deathmatch/deathmatch_maps.dm b/code/modules/deathmatch/deathmatch_maps.dm index 60594d903bb..d437bffbb3c 100644 --- a/code/modules/deathmatch/deathmatch_maps.dm +++ b/code/modules/deathmatch/deathmatch_maps.dm @@ -107,6 +107,7 @@ desc = "Choose your battler!" max_players = 10 allowed_loadouts = list( + /datum/outfit/deathmatch_loadout/battler/soldier, // First because its a good and easy loadout and is picked by default /datum/outfit/deathmatch_loadout/battler/bloodminer, /datum/outfit/deathmatch_loadout/battler/clown, /datum/outfit/deathmatch_loadout/battler/cowboy, @@ -117,7 +118,6 @@ /datum/outfit/deathmatch_loadout/battler/raider, /datum/outfit/deathmatch_loadout/battler/ripper, /datum/outfit/deathmatch_loadout/battler/scientist, - /datum/outfit/deathmatch_loadout/battler/soldier, /datum/outfit/deathmatch_loadout/battler/surgeon, /datum/outfit/deathmatch_loadout/battler/tgcoder, /datum/outfit/deathmatch_loadout/naked, diff --git a/code/modules/events/ghost_role/fugitive_event.dm b/code/modules/events/ghost_role/fugitive_event.dm index 1556eb04558..4b86e751c0b 100644 --- a/code/modules/events/ghost_role/fugitive_event.dm +++ b/code/modules/events/ghost_role/fugitive_event.dm @@ -62,7 +62,7 @@ HUNTER_PACK_BOUNTY, HUNTER_PACK_PSYKER, ) - addtimer(CALLBACK(src, PROC_REF(spawn_hunters), hunter_backstory), 10 MINUTES) + addtimer(CALLBACK(src, PROC_REF(check_spawn_hunters), hunter_backstory, 10 MINUTES), 1 MINUTES) role_name = "fugitive hunter" return SUCCESSFUL_SPAWN @@ -103,7 +103,13 @@ S.put_in_hands(A) new /obj/item/autosurgeon(landing_turf) -//security team gets called in after 10 minutes of prep to find the refugees +/datum/round_event/ghost_role/fugitives/proc/check_spawn_hunters(backstory, remaining_time) + //if the emergency shuttle has been called, spawn hunters now to give them a chance + if(remaining_time == 0 || SSshuttle.emergency.mode != EMERGENCY_IDLE_OR_RECALLED) + spawn_hunters(backstory) + return + addtimer(CALLBACK(src, PROC_REF(check_spawn_hunters), backstory, remaining_time - 1 MINUTES), 1 MINUTES) + /datum/round_event/ghost_role/fugitives/proc/spawn_hunters(backstory) var/list/candidates = SSpolling.poll_ghost_candidates("Do you wish to be considered for a group of [backstory]?", check_jobban = ROLE_FUGITIVE_HUNTER, pic_source = /obj/machinery/sleeper, role_name_text = backstory) shuffle_inplace(candidates) diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm index 93851558cff..a9f1ad23d8e 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm @@ -237,3 +237,11 @@ ) result = /obj/item/food/pie/asdfpie category = CAT_PIE + +/datum/crafting_recipe/food/bacid_pie + reqs = list( + /obj/item/food/pie/plain = 1, + /obj/item/stock_parts/cell = 2, + ) + result = /obj/item/food/pie/bacid_pie + category = CAT_PIE diff --git a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm index 64cff6780df..e9dc43837ff 100644 --- a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm +++ b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm @@ -16,18 +16,19 @@ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID maxHealth = 220 health = 220 + initial_language_holder = /datum/language_holder/monkey response_help_continuous = "prods" response_help_simple = "prod" response_disarm_continuous = "challenges" response_disarm_simple = "challenge" response_harm_continuous = "thumps" response_harm_simple = "thump" - speed = 0.5 + speed = -0.1 melee_attack_cooldown = CLICK_CD_MELEE - melee_damage_lower = 15 - melee_damage_upper = 18 + melee_damage_lower = 25 + melee_damage_upper = 30 damage_coeff = list(BRUTE = 1, BURN = 1.5, TOX = 1.5, STAMINA = 0, OXY = 1.5) - obj_damage = 20 + obj_damage = 40 attack_verb_continuous = "pummels" attack_verb_simple = "pummel" attack_sound = 'sound/weapons/punch1.ogg' @@ -123,7 +124,7 @@ /// Gorillas are slower when carrying something /datum/movespeed_modifier/gorilla_standing blacklisted_movetypes = (FLYING|FLOATING) - multiplicative_slowdown = 0.5 + multiplicative_slowdown = 1.2 /// A smaller gorilla summoned via magic /mob/living/basic/gorilla/lesser diff --git a/code/modules/mob/living/carbon/alien/organs.dm b/code/modules/mob/living/carbon/alien/organs.dm index 66f555b639a..a73926b18ae 100644 --- a/code/modules/mob/living/carbon/alien/organs.dm +++ b/code/modules/mob/living/carbon/alien/organs.dm @@ -197,13 +197,7 @@ for(var/atom/movable/thing as anything in stomach_contents) if(!digestable_cache[thing.type]) continue - thing.reagents.trans_to(src, 4) - - if(isliving(thing)) - var/mob/living/lad = thing - lad.adjustBruteLoss(6) - else if(!thing.reagents.total_volume) // Mobs can't get dusted like this, too important - qdel(thing) + thing.acid_act(75, 10) /obj/item/organ/internal/stomach/alien/proc/consume_thing(atom/movable/thing) RegisterSignal(thing, COMSIG_MOVABLE_MOVED, PROC_REF(content_moved)) @@ -211,9 +205,6 @@ if(isliving(thing)) var/mob/living/lad = thing RegisterSignal(thing, COMSIG_LIVING_DEATH, PROC_REF(content_died)) - if(lad.stat == DEAD) - qdel(lad) - return stomach_contents += thing thing.forceMove(owner || src) // We assert that if we have no owner, we will not be nullspaced diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 27742552e93..147419272a5 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -85,7 +85,7 @@ span_userdanger("You violently crash into [victim][extra_speed ? " extra hard" : ""], but [victim] managed to block the worst of it!")) log_combat(src, victim, "crashed into and was blocked by") return - else if(HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) + else if(HAS_TRAIT(victim, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) victim.take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5) victim.apply_damage(10 + 10 * extra_speed, STAMINA) victim.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 2, 10 SECONDS) 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 4de716fe953..1f371d575ac 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -42,9 +42,7 @@ ai_controlled_species = TRUE /datum/species/monkey/random_name(gender,unique,lastname) - var/randname = "monkey ([rand(1,999)])" - - return randname + return "monkey ([rand(1, 999)])" /datum/species/monkey/on_species_gain(mob/living/carbon/human/H, datum/species/old_species) . = ..() @@ -170,7 +168,7 @@ /obj/item/organ/internal/brain/primate/on_mob_insert(mob/living/carbon/primate) . = ..() - RegisterSignal(primate, COMSIG_MOVABLE_CROSS, PROC_REF(on_crossed), TRUE) + RegisterSignal(primate, COMSIG_MOVABLE_CROSS, PROC_REF(on_crossed)) /obj/item/organ/internal/brain/primate/on_mob_remove(mob/living/carbon/primate) . = ..() @@ -185,11 +183,13 @@ var/mob/living/in_the_way_mob = crossed if(iscarbon(in_the_way_mob) && !in_the_way_mob.combat_mode) return - if(in_the_way_mob.pass_flags & PASSTABLE) + if(in_the_way_mob.pass_flags & PASSMOB) return in_the_way_mob.knockOver(owner) /obj/item/organ/internal/brain/primate/get_attacking_limb(mob/living/carbon/human/target) - return owner.get_bodypart(BODY_ZONE_HEAD) + if(!HAS_TRAIT(owner, TRAIT_ADVANCEDTOOLUSER)) + return owner.get_bodypart(BODY_ZONE_HEAD) + return ..() #undef MONKEY_SPEC_ATTACK_BITE_MISS_CHANCE diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 10f9a79ca00..ca61dfda7b0 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -559,7 +559,7 @@ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cult_ending_helper), CULT_VICTORY_MASS_CONVERSION), 120) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(ending_helper)), 270) if(client) - makeNewConstruct(/mob/living/basic/construct/harvester, src, cultoverride = TRUE) + make_new_construct(/mob/living/basic/construct/harvester, src, cultoverride = TRUE) else switch(rand(1, 4)) if(1) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 86465dca120..424f2bbcd1c 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -699,7 +699,7 @@ if("Station Member") var/list/personnel_list = list() - for(var/datum/record/crew/record in GLOB.manifest.locked)//Look in data core locked. + for(var/datum/record/locked/record in GLOB.manifest.locked)//Look in data core locked. personnel_list["[record.name]: [record.rank]"] = record.character_appearance//Pull names, rank, and image. if(!length(personnel_list)) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 8c6ebe11496..d2b8ce0f3c3 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -391,7 +391,7 @@ ///Can the mob hear /mob/proc/can_hear() - . = TRUE + return !HAS_TRAIT(src, TRAIT_DEAF) /** * Examine text for traits shared by multiple types. diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm index a2485d5a2f3..0e2a25576d5 100644 --- a/code/modules/power/singularity/narsie.dm +++ b/code/modules/power/singularity/narsie.dm @@ -147,7 +147,7 @@ start_ending_the_round() /obj/narsie/attack_ghost(mob/user) - makeNewConstruct(/mob/living/basic/construct/harvester, user, cultoverride = TRUE, loc_override = loc) + make_new_construct(/mob/living/basic/construct/harvester, user, cultoverride = TRUE, loc_override = loc) /obj/narsie/process() var/datum/component/singularity/singularity_component = singularity.resolve() diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index e6ec977fd55..1209ede446b 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -2430,7 +2430,8 @@ /datum/reagent/magillitis/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() if((ishuman(affected_mob)) && current_cycle > 10) - affected_mob.gorillize() + var/mob/living/basic/gorilla/new_gorilla = affected_mob.gorillize() + new_gorilla.AddComponent(/datum/component/regenerator, regeneration_delay = 12 SECONDS, brute_per_second = 1.5, outline_colour = COLOR_PALE_GREEN) /datum/reagent/growthserum name = "Growth Serum" diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index 8e74b0ad6f8..901041b25d7 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -419,7 +419,7 @@ determin_ph_range = 6 temp_exponent_factor = 0.5 ph_exponent_factor = 1 - thermic_constant = -7.5 + thermic_constant = -1.5 H_ion_release = 0 rate_up_lim = 10 purity_min = 0.2 diff --git a/code/modules/research/xenobiology/crossbreeding/_misc.dm b/code/modules/research/xenobiology/crossbreeding/_misc.dm index 8eb166bf820..7b85a878ec3 100644 --- a/code/modules/research/xenobiology/crossbreeding/_misc.dm +++ b/code/modules/research/xenobiology/crossbreeding/_misc.dm @@ -175,6 +175,12 @@ Slimecrossing Items w_class = WEIGHT_CLASS_SMALL icon = 'icons/obj/science/slimecrossing.dmi' icon_state = "capturedevice" + ///traits we give and remove from the mob on exit and entry + var/static/list/traits_on_transfer = list( + TRAIT_IMMOBILIZED, + TRAIT_HANDS_BLOCKED, + TRAIT_AI_PAUSED, + ) /obj/item/capturedevice/attack(mob/living/pokemon, mob/user) if(length(contents)) @@ -211,11 +217,11 @@ Slimecrossing Items /obj/item/capturedevice/proc/store(mob/living/pokemon) pokemon.forceMove(src) - pokemon.add_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED), ABSTRACT_ITEM_TRAIT) + pokemon.add_traits(traits_on_transfer, ABSTRACT_ITEM_TRAIT) pokemon.cancel_camera() /obj/item/capturedevice/proc/release() 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.remove_traits(traits_on_transfer, ABSTRACT_ITEM_TRAIT) pokemon.cancel_camera() diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index be1a7828c2e..e13fef576ec 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -250,9 +250,9 @@ px_x = -5 px_y = -3 dmg_overlay_type = SPECIES_MONKEY - unarmed_damage_low = 1 /// monkey punches must be really weak, considering they bite people instead and their bites are weak as hell. - unarmed_damage_high = 2 - unarmed_effectiveness = 0 + unarmed_damage_low = 3 + unarmed_damage_high = 8 + unarmed_effectiveness = 5 appendage_noun = "paw" /obj/item/bodypart/arm/left/alien @@ -347,8 +347,8 @@ px_x = 5 px_y = -3 dmg_overlay_type = SPECIES_MONKEY - unarmed_damage_low = 1 - unarmed_damage_high = 2 + unarmed_damage_low = 3 + unarmed_damage_high = 8 unarmed_effectiveness = 0 appendage_noun = "paw" @@ -463,8 +463,8 @@ dmg_overlay_type = SPECIES_MONKEY unarmed_damage_low = 2 unarmed_damage_high = 3 - unarmed_effectiveness = 0 - footprint_sprite = FOOTPRINT_SPRITE_PAWS + unarmed_effectiveness = 5 + footprint_sprite = FOOTPRINT_SPRITE_PAWS /obj/item/bodypart/leg/left/alien icon = 'icons/mob/human/species/alien/bodyparts.dmi' @@ -553,8 +553,8 @@ dmg_overlay_type = SPECIES_MONKEY unarmed_damage_low = 2 unarmed_damage_high = 3 - unarmed_effectiveness = 0 - footprint_sprite = FOOTPRINT_SPRITE_PAWS + unarmed_effectiveness = 5 + footprint_sprite = FOOTPRINT_SPRITE_PAWS /obj/item/bodypart/leg/right/alien icon = 'icons/mob/human/species/alien/bodyparts.dmi' diff --git a/code/modules/tgs/core/core.dm b/code/modules/tgs/core/core.dm index 8be96f27404..15622228e91 100644 --- a/code/modules/tgs/core/core.dm +++ b/code/modules/tgs/core/core.dm @@ -166,3 +166,11 @@ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) if(api) return api.Visibility() + +/world/TgsTriggerEvent(event_name, list/parameters, wait_for_completion = FALSE) + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + if(!istype(parameters, /list)) + parameters = list() + + return api.TriggerEvent(event_name, parameters, wait_for_completion) diff --git a/code/modules/tgs/core/datum.dm b/code/modules/tgs/core/datum.dm index 07ce3b68458..898516f1248 100644 --- a/code/modules/tgs/core/datum.dm +++ b/code/modules/tgs/core/datum.dm @@ -17,7 +17,7 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null) world.sleep_offline = FALSE // https://www.byond.com/forum/post/2894866 del(world) world.sleep_offline = FALSE // just in case, this is BYOND after all... - sleep(1) + sleep(world.tick_lag) TGS_DEBUG_LOG("BYOND DIDN'T TERMINATE THE WORLD!!! TICK IS: [world.time], sleep_offline: [world.sleep_offline]") /datum/tgs_api/latest @@ -69,3 +69,6 @@ TGS_PROTECT_DATUM(/datum/tgs_api) /datum/tgs_api/proc/Visibility() return TGS_UNIMPLEMENTED + +/datum/tgs_api/proc/TriggerEvent(event_name, list/parameters, wait_for_completion) + return FALSE diff --git a/code/modules/tgs/v4/api.dm b/code/modules/tgs/v4/api.dm index 945e2e41176..7c87922750b 100644 --- a/code/modules/tgs/v4/api.dm +++ b/code/modules/tgs/v4/api.dm @@ -181,7 +181,7 @@ var/json = json_encode(data) while(requesting_new_port && !override_requesting_new_port) - sleep(1) + sleep(world.tick_lag) //we need some port open at this point to facilitate return communication if(!world.port) @@ -209,7 +209,7 @@ requesting_new_port = FALSE while(export_lock) - sleep(1) + sleep(world.tick_lag) export_lock = TRUE last_interop_response = null @@ -217,7 +217,7 @@ text2file(json, server_commands_json_path) for(var/I = 0; I < EXPORT_TIMEOUT_DS && !last_interop_response; ++I) - sleep(1) + sleep(world.tick_lag) if(!last_interop_response) TGS_ERROR_LOG("Failed to get export result for: [json]") diff --git a/code/modules/tgs/v5/__interop_version.dm b/code/modules/tgs/v5/__interop_version.dm index 616263098fd..f4806f7adb9 100644 --- a/code/modules/tgs/v5/__interop_version.dm +++ b/code/modules/tgs/v5/__interop_version.dm @@ -1 +1 @@ -"5.8.0" +"5.9.0" diff --git a/code/modules/tgs/v5/_defines.dm b/code/modules/tgs/v5/_defines.dm index 1c7d67d20cd..92c7a8388a7 100644 --- a/code/modules/tgs/v5/_defines.dm +++ b/code/modules/tgs/v5/_defines.dm @@ -14,6 +14,7 @@ #define DMAPI5_BRIDGE_COMMAND_KILL 4 #define DMAPI5_BRIDGE_COMMAND_CHAT_SEND 5 #define DMAPI5_BRIDGE_COMMAND_CHUNK 6 +#define DMAPI5_BRIDGE_COMMAND_EVENT 7 #define DMAPI5_PARAMETER_ACCESS_IDENTIFIER "accessIdentifier" #define DMAPI5_PARAMETER_CUSTOM_COMMANDS "customCommands" @@ -34,6 +35,7 @@ #define DMAPI5_BRIDGE_PARAMETER_VERSION "version" #define DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE "chatMessage" #define DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL "minimumSecurityLevel" +#define DMAPI5_BRIDGE_PARAMETER_EVENT_INVOCATION "eventInvocation" #define DMAPI5_BRIDGE_RESPONSE_NEW_PORT "newPort" #define DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION "runtimeInformation" @@ -81,6 +83,7 @@ #define DMAPI5_TOPIC_COMMAND_SEND_CHUNK 9 #define DMAPI5_TOPIC_COMMAND_RECEIVE_CHUNK 10 #define DMAPI5_TOPIC_COMMAND_RECEIVE_BROADCAST 11 +#define DMAPI5_TOPIC_COMMAND_COMPLETE_EVENT 12 #define DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE "commandType" #define DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND "chatCommand" @@ -116,3 +119,9 @@ #define DMAPI5_CUSTOM_CHAT_COMMAND_NAME "name" #define DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT "helpText" #define DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY "adminOnly" + +#define DMAPI5_EVENT_ID "eventId" + +#define DMAPI5_EVENT_INVOCATION_NAME "eventName" +#define DMAPI5_EVENT_INVOCATION_PARAMETERS "parameters" +#define DMAPI5_EVENT_INVOCATION_NOTIFY_COMPLETION "notifyCompletion" diff --git a/code/modules/tgs/v5/api.dm b/code/modules/tgs/v5/api.dm index a5c064a8eaf..95b8edd3ee5 100644 --- a/code/modules/tgs/v5/api.dm +++ b/code/modules/tgs/v5/api.dm @@ -27,6 +27,8 @@ var/chunked_requests = 0 var/list/chunked_topics = list() + var/list/pending_events = list() + var/detached = FALSE /datum/tgs_api/v5/New() @@ -46,6 +48,10 @@ var/datum/tgs_version/api_version = ApiVersion() version = null // we want this to be the TGS version, not the interop version + + // sleep once to prevent an issue where world.Export on the first tick can hang indefinitely + sleep(world.tick_lag) + var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands(), DMAPI5_PARAMETER_TOPIC_PORT = GetTopicPort())) if(!istype(bridge_response)) TGS_ERROR_LOG("Failed initial bridge request!") @@ -125,7 +131,7 @@ TGS_DEBUG_LOG("RequireInitialBridgeResponse: Starting sleep") logged = TRUE - sleep(1) + sleep(world.tick_lag) TGS_DEBUG_LOG("RequireInitialBridgeResponse: Passed") @@ -249,6 +255,40 @@ WaitForReattach(TRUE) return chat_channels.Copy() +/datum/tgs_api/v5/TriggerEvent(event_name, list/parameters, wait_for_completion) + RequireInitialBridgeResponse() + WaitForReattach(TRUE) + + if(interop_version.minor < 9) + TGS_WARNING_LOG("Interop version too low for custom events!") + return FALSE + + var/str_parameters = list() + for(var/i in parameters) + str_parameters += "[i]" + + var/list/response = Bridge(DMAPI5_BRIDGE_COMMAND_EVENT, list(DMAPI5_BRIDGE_PARAMETER_EVENT_INVOCATION = list(DMAPI5_EVENT_INVOCATION_NAME = event_name, DMAPI5_EVENT_INVOCATION_PARAMETERS = str_parameters, DMAPI5_EVENT_INVOCATION_NOTIFY_COMPLETION = wait_for_completion))) + if(!response) + return FALSE + + var/event_id = response[DMAPI5_EVENT_ID] + if(!event_id) + return FALSE + + TGS_DEBUG_LOG("Created event ID: [event_id]") + if(!wait_for_completion) + return TRUE + + TGS_DEBUG_LOG("Waiting for completion of event ID: [event_id]") + + while(!pending_events[event_id]) + sleep(world.tick_lag) + + TGS_DEBUG_LOG("Completed wait on event ID: [event_id]") + pending_events -= event_id + + return TRUE + /datum/tgs_api/v5/proc/DecodeChannels(chat_update_json) TGS_DEBUG_LOG("DecodeChannels()") var/list/chat_channels_json = chat_update_json[DMAPI5_CHAT_UPDATE_CHANNELS] diff --git a/code/modules/tgs/v5/bridge.dm b/code/modules/tgs/v5/bridge.dm index a0ab3598767..0c5e701a32b 100644 --- a/code/modules/tgs/v5/bridge.dm +++ b/code/modules/tgs/v5/bridge.dm @@ -65,7 +65,7 @@ if(detached) // Wait up to one minute for(var/i in 1 to 600) - sleep(1) + sleep(world.tick_lag) if(!detached && (!require_channels || length(chat_channels))) break @@ -77,8 +77,11 @@ /datum/tgs_api/v5/proc/PerformBridgeRequest(bridge_request) WaitForReattach(FALSE) + TGS_DEBUG_LOG("Bridge request start") // This is an infinite sleep until we get a response var/export_response = world.Export(bridge_request) + TGS_DEBUG_LOG("Bridge request complete") + if(!export_response) TGS_ERROR_LOG("Failed bridge request: [bridge_request]") return @@ -88,7 +91,7 @@ TGS_ERROR_LOG("Failed bridge request, missing content!") return - var/response_json = file2text(content) + var/response_json = TGS_FILE2TEXT_NATIVE(content) if(!response_json) TGS_ERROR_LOG("Failed bridge request, failed to load content!") return diff --git a/code/modules/tgs/v5/topic.dm b/code/modules/tgs/v5/topic.dm index 05e6c4e1b21..e1f2cb63857 100644 --- a/code/modules/tgs/v5/topic.dm +++ b/code/modules/tgs/v5/topic.dm @@ -176,6 +176,10 @@ var/list/reattach_response = TopicResponse(error_message) reattach_response[DMAPI5_PARAMETER_CUSTOM_COMMANDS] = ListCustomCommands() reattach_response[DMAPI5_PARAMETER_TOPIC_PORT] = GetTopicPort() + + for(var/eventId in pending_events) + pending_events[eventId] = TRUE + return reattach_response if(DMAPI5_TOPIC_COMMAND_SEND_CHUNK) @@ -276,6 +280,15 @@ TGS_WORLD_ANNOUNCE(message) return TopicResponse() + if(DMAPI5_TOPIC_COMMAND_COMPLETE_EVENT) + var/event_id = topic_parameters[DMAPI5_EVENT_ID] + if (!istext(event_id)) + return TopicResponse("Invalid or missing [DMAPI5_EVENT_ID]") + + TGS_DEBUG_LOG("Completing event ID [event_id]...") + pending_events[event_id] = TRUE + return TopicResponse() + return TopicResponse("Unknown command: [command]") /datum/tgs_api/v5/proc/WorldBroadcast(message) diff --git a/code/modules/tgs/v5/undefs.dm b/code/modules/tgs/v5/undefs.dm index d531d4b7b9d..237207fdfd0 100644 --- a/code/modules/tgs/v5/undefs.dm +++ b/code/modules/tgs/v5/undefs.dm @@ -14,6 +14,7 @@ #undef DMAPI5_BRIDGE_COMMAND_KILL #undef DMAPI5_BRIDGE_COMMAND_CHAT_SEND #undef DMAPI5_BRIDGE_COMMAND_CHUNK +#undef DMAPI5_BRIDGE_COMMAND_EVENT #undef DMAPI5_PARAMETER_ACCESS_IDENTIFIER #undef DMAPI5_PARAMETER_CUSTOM_COMMANDS @@ -34,6 +35,7 @@ #undef DMAPI5_BRIDGE_PARAMETER_VERSION #undef DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE #undef DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL +#undef DMAPI5_BRIDGE_PARAMETER_EVENT_INVOCATION #undef DMAPI5_BRIDGE_RESPONSE_NEW_PORT #undef DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION @@ -81,6 +83,7 @@ #undef DMAPI5_TOPIC_COMMAND_SEND_CHUNK #undef DMAPI5_TOPIC_COMMAND_RECEIVE_CHUNK #undef DMAPI5_TOPIC_COMMAND_RECEIVE_BROADCAST +#undef DMAPI5_TOPIC_COMMAND_COMPLETE_EVENT #undef DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE #undef DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND @@ -116,3 +119,9 @@ #undef DMAPI5_CUSTOM_CHAT_COMMAND_NAME #undef DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT #undef DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY + +#undef DMAPI5_EVENT_ID + +#undef DMAPI5_EVENT_INVOCATION_NAME +#undef DMAPI5_EVENT_INVOCATION_PARAMETERS +#undef DMAPI5_EVENT_INVOCATION_NOTIFY_COMPLETION diff --git a/code/modules/tgui_input/say_modal/speech.dm b/code/modules/tgui_input/say_modal/speech.dm index e4c5032e2b3..7797e44afb1 100644 --- a/code/modules/tgui_input/say_modal/speech.dm +++ b/code/modules/tgui_input/say_modal/speech.dm @@ -54,6 +54,8 @@ if(WHIS_CHANNEL) client.mob.whisper_verb(entry) return TRUE + if(DO_CHANNEL) + client.mob.do_verb(entry) // NOVA EDIT ADDITION END return FALSE diff --git a/code/modules/transport/linear_controller.dm b/code/modules/transport/linear_controller.dm index dd90562deb6..80c161c3291 100644 --- a/code/modules/transport/linear_controller.dm +++ b/code/modules/transport/linear_controller.dm @@ -35,6 +35,9 @@ ///if true, the platform cannot be manually moved. var/controls_locked = FALSE + /// probability of being thrown hard during an emergency stop + var/throw_chance = 17.5 + /datum/transport_controller/linear/New(obj/structure/transport/linear/transport_module) transport_id = transport_module.transport_id create_modular_set = transport_module.create_modular_set diff --git a/code/modules/transport/tram/tram_controller.dm b/code/modules/transport/tram/tram_controller.dm index c7fc895184f..4dceecbfc4c 100644 --- a/code/modules/transport/tram/tram_controller.dm +++ b/code/modules/transport/tram/tram_controller.dm @@ -17,17 +17,15 @@ var/travel_remaining = 0 ///how far in total we'll be travelling var/travel_trip_length = 0 - ///multiplier on how much damage/force the tram imparts on things it hits var/collision_lethality = 1 - var/obj/effect/landmark/transport/nav_beacon/tram/nav/nav_beacon - /// reference to the destination landmarks we consider ourselves "at" or travelling towards. since we potentially span multiple z levels we dont actually + /// reference to the navigation landmark associated with this tram. since we potentially span multiple z levels we dont actually /// know where on us this platform is. as long as we know THAT its on us we can just move the distance and direction between this /// and the destination landmark. + var/obj/effect/landmark/transport/nav_beacon/tram/nav/nav_beacon + /// reference to the landmark we consider ourself stationary at. var/obj/effect/landmark/transport/nav_beacon/tram/platform/idle_platform - /// reference to the destination landmarks we consider ourselves travelling towards. since we potentially span multiple z levels we dont actually - /// know where on us this platform is. as long as we know THAT its on us we can just move the distance and direction between this - /// and the destination landmark. + /// reference to the destination landmark we consider ourselves travelling towards. var/obj/effect/landmark/transport/nav_beacon/tram/platform/destination_platform var/current_speed = 0 @@ -284,7 +282,11 @@ degraded_stop() return PROCESS_KILL - normal_stop() + if((controller_status & COMM_ERROR) && prob(5)) // malfunctioning tram has a small chance to e-stop + degraded_stop() + else + normal_stop() + return PROCESS_KILL else if(world.time >= scheduled_move) @@ -538,7 +540,8 @@ set_status_code(COMM_ERROR, TRUE) SEND_TRANSPORT_SIGNAL(COMSIG_COMMS_STATUS, src, FALSE) paired_cabinet.generate_repair_signals() - collision_lethality = 1.25 + collision_lethality *= 1.25 + throw_chance *= 1.25 log_transport("TC: [specific_transport_id] starting Tram Malfunction event.") /** @@ -553,6 +556,7 @@ set_status_code(COMM_ERROR, FALSE) paired_cabinet.clear_repair_signals() collision_lethality = initial(collision_lethality) + throw_chance = initial(throw_chance) SEND_TRANSPORT_SIGNAL(COMSIG_COMMS_STATUS, src, TRUE) log_transport("TC: [specific_transport_id] ending Tram Malfunction event.") diff --git a/code/modules/transport/transport_module.dm b/code/modules/transport/transport_module.dm index c33d729e75c..9fdfefc835c 100644 --- a/code/modules/transport/transport_module.dm +++ b/code/modules/transport/transport_module.dm @@ -934,7 +934,8 @@ /obj/structure/transport/linear/tram/proc/estop_throw(throw_direction) for(var/mob/living/passenger in transport_contents) to_chat(passenger, span_userdanger("The tram comes to a sudden, grinding stop!")) - if(prob(17.5)) // sometimes you go through a window + var/mob_throw_chance = transport_controller_datum.throw_chance + if(prob(mob_throw_chance || 17.5) || HAS_TRAIT(passenger, TRAIT_CURSED)) // sometimes you go through a window, especially with bad luck passenger.AddElement(/datum/element/window_smashing, duration = 1.5 SECONDS) var/throw_target = get_edge_target_turf(src, throw_direction) passenger.throw_at(throw_target, 30, 7, force = MOVE_FORCE_OVERPOWERING) diff --git a/code/modules/uplink/uplink_items/job.dm b/code/modules/uplink/uplink_items/job.dm index eaf83e8fabc..4ecf06a129a 100644 --- a/code/modules/uplink/uplink_items/job.dm +++ b/code/modules/uplink/uplink_items/job.dm @@ -156,16 +156,17 @@ /datum/uplink_item/role_restricted/magillitis_serum name = "Magillitis Serum Autoinjector" desc = "A single-use autoinjector which contains an experimental serum that causes rapid muscular growth in Hominidae. \ - Side-affects may include hypertrichosis, violent outbursts, and an unending affinity for bananas." + Side-affects may include hypertrichosis, violent outbursts, and an unending affinity for bananas. \ + Now also contains regenerative chemicals to keep users healthy as they exercise their newfound muscles." item = /obj/item/reagent_containers/hypospray/medipen/magillitis cost = 15 restricted_roles = list(JOB_GENETICIST, JOB_RESEARCH_DIRECTOR) -/datum/uplink_item/role_restricted/gorillacubes - name = "Box of Gorilla Cubes" - desc = "A box with three Waffle Co. brand gorilla cubes. Eat big to get big. \ +/datum/uplink_item/role_restricted/gorillacube + name = "Gorilla Cube" + desc = "A Waffle Co. brand gorilla cube. Eat big to get big. \ Caution: Product may rehydrate when exposed to water." - item = /obj/item/storage/box/gorillacubes + item = /obj/item/food/monkeycube/gorilla cost = 6 restricted_roles = list(JOB_GENETICIST, JOB_RESEARCH_DIRECTOR) diff --git a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm index 335e8bc5a3e..c0047eb91d7 100644 --- a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm +++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm @@ -552,6 +552,7 @@ range = MECHA_MELEE toolspeed = 0.8 mech_flags = EXOSUIT_MODULE_PADDY + projectiles_per_shot = 0 ///Chassis but typed for the cargo_hold var var/obj/vehicle/sealed/mecha/ripley/secmech ///Audio for using the hydraulic clamp @@ -570,10 +571,13 @@ secmech = null return ..() -/obj/item/mecha_parts/mecha_equipment/weapon/paddy_claw/action(mob/living/source, atom/target, list/modifiers) +/obj/item/mecha_parts/mecha_equipment/weapon/paddy_claw/action(mob/source, atom/target, list/modifiers) if(!secmech.cargo_hold) //We did try CRASH("Mech [chassis] has a claw device, but no internal storage. This should be impossible.") - if(ismob(target)) + if(!action_checks(target)) + return + if(isliving(target)) + . = ..() var/mob/living/mobtarget = target if(mobtarget.move_resist == MOVE_FORCE_OVERPOWERING) //No megafauna or bolted AIs, please. to_chat(source, "[span_warning("[src] is unable to lift [mobtarget].")]") @@ -596,11 +600,12 @@ carbontarget.update_handcuffed() return - if(!istype(target, /obj/machinery/door)) + if(istype(target, /obj/machinery/door)) + . = ..() + var/obj/machinery/door/target_door = target + playsound(chassis, clampsound, 50, FALSE, -6) + target_door.try_to_crowbar(src, source) return - var/obj/machinery/door/target_door = target - playsound(chassis, clampsound, 50, FALSE, -6) - target_door.try_to_crowbar(src, source) /obj/item/mecha_parts/mecha_equipment/weapon/paddy_claw/get_snowflake_data() return list( diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index 6d269a7ca22..15f95f66a13 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -821,7 +821,7 @@ post_crush_living(living_target, was_alive) flags_to_return |= (SUCCESSFULLY_CRUSHED_MOB|SUCCESSFULLY_CRUSHED_ATOM) - else if (atom_target.uses_integrity && !(atom_target.invisibility > SEE_INVISIBLE_LIVING) && !(is_type_in_typecache(atom_target, GLOB.WALLITEMS_INTERIOR) || is_type_in_typecache(atom_target, GLOB.WALLITEMS_EXTERIOR))) + else if(check_atom_crushable(atom_target)) atom_target.take_damage(adjusted_damage, damage_type, damage_flag, FALSE, crush_dir) crushed = TRUE flags_to_return |= SUCCESSFULLY_CRUSHED_ATOM @@ -861,6 +861,21 @@ /atom/movable/proc/post_tilt() return +/proc/check_atom_crushable(atom/atom_target) + /// Contains structures and items that vendors shouldn't crush when we land on them. + var/static/list/vendor_uncrushable_objects = list( + /obj/structure/chair, + /obj/machinery/conveyor, + ) + GLOB.WALLITEMS_INTERIOR + GLOB.WALLITEMS_EXTERIOR + + if(is_type_in_list(atom_target, vendor_uncrushable_objects)) //make sure its not in the list of "uncrushable" stuff + return FALSE + + if (atom_target.uses_integrity && !(atom_target.invisibility > SEE_INVISIBLE_LIVING)) //check if it has integrity + allow ninjas, etc to be crushed in cloak + return TRUE //SMUSH IT + + return FALSE + /obj/machinery/vending/post_crush_living(mob/living/crushed, was_alive) if(was_alive && crushed.stat == DEAD && crushed.client) diff --git a/config/arenas/README.md b/config/arenas/README.md deleted file mode 100644 index 9f31ce2349a..00000000000 --- a/config/arenas/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Add admin arena dmms here. - -**These are fully cached so keep this directory empty by default.** \ No newline at end of file diff --git a/config/lavaruinblacklist.txt b/config/lavaruinblacklist.txt index 29154fe011b..dc1749973eb 100644 --- a/config/lavaruinblacklist.txt +++ b/config/lavaruinblacklist.txt @@ -42,3 +42,6 @@ _maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm #_maps/RandomRuins/LavaRuins/lavaland_surface_ww_vault.dmm #_maps/RandomRuins/LavaRuins/lavaland_surface_wwiioutpost.dmm #_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm + +##MEGAFAUNA +#_maps/RandomRuins/LavaRuins/nova/lavaland_surface_arena.dmm diff --git a/config/spaceruinblacklist.txt b/config/spaceruinblacklist.txt index bf149ca5640..e42b0d918e7 100644 --- a/config/spaceruinblacklist.txt +++ b/config/spaceruinblacklist.txt @@ -72,7 +72,7 @@ #_maps/RandomRuins/SpaceRuins/space_billboard.dmm #_maps/RandomRuins/SpaceRuins/space_billboard.dmm #_maps/RandomRuins/SpaceRuins/space_ghost_restaurant.dmm -#_maps/RandomRuins/SpaceRuins/spacehotel.dmm +_maps/RandomRuins/SpaceRuins/spacehotel.dmm #_maps/RandomRuins/SpaceRuins/spinwardsmoothies.dmm #_maps/RandomRuins/SpaceRuins/spinwardsmoothies.dmm #_maps/RandomRuins/SpaceRuins/the_faceoff.dmm @@ -88,5 +88,33 @@ #_maps/RandomRuins/SpaceRuins/waystation.dmm #_maps/RandomRuins/SpaceRuins/whiteshipdock.dmm #_maps/RandomRuins/SpaceRuins/whiteshipruin_box.dmm + +##Custom Ruins +#_maps/RandomRuins/SpaceRuins/nova/alientoollab.dmm +#_maps/RandomRuins/SpaceRuins/nova/blackmarket.dmm +#_maps/RandomRuins/SpaceRuins/nova/cargodiselost.dmm +#_maps/RandomRuins/SpaceRuins/nova/clothing_facility.dmm +#_maps/RandomRuins/SpaceRuins/nova/codealpha.dmm +#_maps/RandomRuins/SpaceRuins/nova/crash.dmm +#_maps/RandomRuins/SpaceRuins/nova/derelictferry.dmm +#_maps/RandomRuins/SpaceRuins/nova/des_two.dmm #_maps/RandomRuins/SpaceRuins/nova/drones_derelict.dmm -#_maps/RandomRuins/SpaceRuins/shuttle8532.dmm +#_maps/RandomRuins/SpaceRuins/nova/ghostship.dmm +#_maps/RandomRuins/SpaceRuins/nova/luna.dmm +#_maps/RandomRuins/SpaceRuins/nova/piratefort.dmm +#_maps/RandomRuins/SpaceRuins/nova/port_tarkon.dmm +#_maps/RandomRuins/SpaceRuins/nova/posterpandamonium.dmm +#_maps/RandomRuins/SpaceRuins/nova/prisonshuttle.dmm +#_maps/RandomRuins/SpaceRuins/nova/salvagepost.dmm +#_maps/RandomRuins/SpaceRuins/nova/scrapeheap.dmm +#_maps/RandomRuins/SpaceRuins/nova/shuttle8532.dmm +#_maps/RandomRuins/SpaceRuins/nova/shuttlescrap.dmm +#_maps/RandomRuins/SpaceRuins/nova/smugglies.dmm +#_maps/RandomRuins/SpaceRuins/nova/spacehotel.dmm +#_maps/RandomRuins/SpaceRuins/nova/syndibase.dmm +#_maps/RandomRuins/SpaceRuins/nova/toystore.dmm +#_maps/RandomRuins/SpaceRuins/nova/vaulttango.dmm +#_maps/RandomRuins/SpaceRuins/nova/waypointstation.dmm +#_maps/RandomRuins/SpaceRuins/nova/whiteshipruin_box.dmm +#_maps/RandomRuins/SpaceRuins/nova/wreckedfriendship.dmm +#_maps/RandomRuins/SpaceRuins/nova/wreckedhomestead.dmm diff --git a/html/changelogs/archive/2024-03.yml b/html/changelogs/archive/2024-03.yml new file mode 100644 index 00000000000..1a02199135c --- /dev/null +++ b/html/changelogs/archive/2024-03.yml @@ -0,0 +1,112 @@ +2024-03-01: + 00-Steven: + - bugfix: Medical/security records now show an icon based on the registered trim, + rather than showing a question mark for records with customized titles. + - bugfix: Newscasters no longer say "No wanted issue posted. Have a secure day." + when there is, in fact, an active wanted issue currently posted. + 13spacemen: + - bugfix: You can build material airlocks again + - bugfix: Blood overlays on items no longer leak onto other objects + A.C.M.O.: + - bugfix: Fixed the AI hologram's ability to copy the appearance of crew members. + Absolucy: + - qol: Constructs now reuse the victim's mind instead of just moving their client + ArcaneMusic: + - image: New sprites for plant grafts! + Ben10Omintrix: + - bugfix: fixes pokemon ai still being active when inside the pokeball + Ghommie: + - balance: '"Freshness Jars full of Natural Bait" is now a goodie and costs 200 + credits instead of 2000' + Iamgoofball: + - balance: xenomorph stomachs will no longer destroy items directly, refactored + it to use acid_act() + - bugfix: fixes xenomorph vore accidentally destroying mobs it wasn't supposed to + destroy, im thinking this was modified list in place shenanigans + IndieanaJones: + - balance: Gorillas are faster, stronger, but not bigger too. Note while holding + an item, they are the same speed as they were prior. + - balance: Gorillas now have the understanding of languages as monkeys do. + - balance: The Gorilla Cube Box for traitors has been replaced with a singular gorilla + cube. Due to the aforementioned changes, this singular gorilla should be as + scary if not scarier than 3 gorillas were prior. + - balance: ' Magillitis Serum Autoinjector now grants the resulting gorilla a slow + passive regeneration effect which kicks in after not taking damage for 12 seconds.' + JohnFulpWillard: + - qol: Intelligent monkeys now punch people instead of biting them. + KingkumaArt: + - rscadd: a list of items called vendor_nocrush that vendors dont deal integrity + damage to upon hitting them. + - bugfix: Makes vending machines no longer crush chairs and conveyors. + Knouli: + - balance: DeForest brand Civil Defense Medical Kits may now be repurposed to carry + a limited selection of field-portable cheese rations. + LT3: + - code_imp: Tram throwing now breaks grilles consistently + - code_imp: Tram malfunction lethality/throw chance are now a multiplier instead + of flat value + - code_imp: Tram throw chance can be adjusted + - code_imp: Unlucky trait is now used in tram throw calculation + - qol: Airlocks don't flash constantly on engineering override, override/overlay + added for fire alarm + - bugfix: Airlock lighting should no longer render on top of player characters + - bugfix: Airlock emissives no longer overlap firedoors + - bugfix: Fixed missing overlays on various airlock types + Melbert: + - bugfix: The Paddy's Claw should be properly unusable in situations which it should + be properly unusable. + - bugfix: Fixes grabbing yourself when you tackle someone. + PapaMichael: + - balance: Fugitive hunters will spawn early if the emergency shuttle is called. + SyncIt21: + - qol: adds examines & screentips for building & deconstructing both machine & computer + frames. + - qol: Adding a circuitboard from a rped to n computer frame will automatically + screw it in place like before. + - code_imp: merged procs for computer & machine frames. autodocs them where possible. + - code_imp: moved code for machine frame into its own file. + - bugfix: RCD converts miscellaneous turfs like basalt, sand, beach etc to plating + first & not put a wall directly on top of them + - bugfix: Cryostylane reaction now has a moderate & not extreme cooling effect. + Helps you achieve more pure amounts of Cryostylane + TJatPBnJ: + - balance: Power crepes are now finger food + TheSmallBlue: + - qol: added an HUD button to go up and down floors + TheVekter: + - rscadd: Added a new law to the Artist lawset in order to encourage Artist AIs + to build an audience. + mc-oofert: + - rscadd: Added an option to deathmatch loadout dropdown that allows you to pick + a random loadout + - bugfix: In deathmatch, plasmamen are made humans and the UI supports more players + - bugfix: Grilles dont break by just walking into them under any circumstances + necromanceranne: + - bugfix: Being in a Swat Suit appropriately protects you from collisions with a + body, rather than the body thrown at you having these protections protecting + YOU, the victim of the collision. + softcerv: + - code_imp: TRAIT_DEAF now works on non-carbon mobs + yooriss: + - qol: 'The telepathy genetics mutation has had significant usability improvements: + it is now point-targeting based, and right-clicking the power allows for quick + resending to the same target, a feature mirrored by the new *treply emote. Telepathy + now also shows runechat messages.' + - rscadd: The Telepathic quirk has been added, allowing characters to start with + an unremovable (or activated) telepathy mutation. + - rscadd: A new form of emoting is available called 'Do', accessible via the K and + Ctrl-K keybinds by default (as well as the 'Do' verb). Do doesn't put your character + name first and instead includes it in brackets at the end, so you can use it + to write better prose and even narrate things in the environment around you + with less clunkiness! Try it out today. + - rscadd: The Underworld Connections quirk has been added, allowing dodgy characters + (including silicons!) to gain access to exploitable information at roundstart. + Non-silicons also receive a fully customizable black market uplink, too. + - qol: Prices at the galactic Black Market have now fallen drastically to be more + in line with general cargo costs, give or take, and should now be vastly more + affordable for most people. Pick up one and order some spuriously legal things + for you and your friends today! + - rscadd: The Entombed quirk has been added, allowing characters to start off with + a permanently unremovable low-end MODsuit stuck to their back slot. Letting + the suit's charge run low will eventually kill you, and the quirk has special + interactions with both Ethereals and Plasmamen! diff --git a/icons/hud/screen_clockwork.dmi b/icons/hud/screen_clockwork.dmi index aa815e957e4..0923e42e7e4 100644 Binary files a/icons/hud/screen_clockwork.dmi and b/icons/hud/screen_clockwork.dmi differ diff --git a/icons/hud/screen_detective.dmi b/icons/hud/screen_detective.dmi index d1d7e49a832..aed6e0d6572 100644 Binary files a/icons/hud/screen_detective.dmi and b/icons/hud/screen_detective.dmi differ diff --git a/icons/hud/screen_glass.dmi b/icons/hud/screen_glass.dmi index 29f8cb47bfd..63ad3293921 100644 Binary files a/icons/hud/screen_glass.dmi and b/icons/hud/screen_glass.dmi differ diff --git a/icons/hud/screen_midnight.dmi b/icons/hud/screen_midnight.dmi index 9cfe8db9727..5483ddf4564 100644 Binary files a/icons/hud/screen_midnight.dmi and b/icons/hud/screen_midnight.dmi differ diff --git a/icons/hud/screen_operative.dmi b/icons/hud/screen_operative.dmi index b4b38782fe1..f2d60d394ac 100644 Binary files a/icons/hud/screen_operative.dmi and b/icons/hud/screen_operative.dmi differ diff --git a/icons/hud/screen_plasmafire.dmi b/icons/hud/screen_plasmafire.dmi index 8225adbda60..5423d3855b2 100644 Binary files a/icons/hud/screen_plasmafire.dmi and b/icons/hud/screen_plasmafire.dmi differ diff --git a/icons/hud/screen_retro.dmi b/icons/hud/screen_retro.dmi index a00d16cac5e..b4252109d68 100644 Binary files a/icons/hud/screen_retro.dmi and b/icons/hud/screen_retro.dmi differ diff --git a/icons/hud/screen_slimecore.dmi b/icons/hud/screen_slimecore.dmi index b7e3a87e07a..a75fe55c378 100644 Binary files a/icons/hud/screen_slimecore.dmi and b/icons/hud/screen_slimecore.dmi differ diff --git a/icons/hud/screen_trasenknox.dmi b/icons/hud/screen_trasenknox.dmi index 58c28d83e4b..2569d2a635e 100644 Binary files a/icons/hud/screen_trasenknox.dmi and b/icons/hud/screen_trasenknox.dmi differ diff --git a/icons/mob/huds/antag_hud.dmi b/icons/mob/huds/antag_hud.dmi index aa96f2338b2..bb44e3de956 100644 Binary files a/icons/mob/huds/antag_hud.dmi and b/icons/mob/huds/antag_hud.dmi differ diff --git a/icons/obj/food/piecake.dmi b/icons/obj/food/piecake.dmi index 8474ba29fe9..e6c0a71022d 100644 Binary files a/icons/obj/food/piecake.dmi and b/icons/obj/food/piecake.dmi differ diff --git a/icons/obj/service/hydroponics/equipment.dmi b/icons/obj/service/hydroponics/equipment.dmi index ed339a8a420..0fcebb3c519 100644 Binary files a/icons/obj/service/hydroponics/equipment.dmi and b/icons/obj/service/hydroponics/equipment.dmi differ diff --git a/modular_nova/master_files/code/datums/quirks/neutral_quirks/equipping.dm b/modular_nova/master_files/code/datums/quirks/neutral_quirks/equipping.dm index 4f48ddd4610..cb68d141684 100644 --- a/modular_nova/master_files/code/datums/quirks/neutral_quirks/equipping.dm +++ b/modular_nova/master_files/code/datums/quirks/neutral_quirks/equipping.dm @@ -6,6 +6,8 @@ var/list/items = list() /// the items that will be forcefully equipped, formatted in the way of [item_path = list of slots it can be equipped to], will equip over nodrop items var/list/forced_items = list() + /// did we force drop any items? if so, they're in this list. useful for transferring any applicable contents into new items on roundstart + var/list/force_dropped_items = list() /datum/quirk/equipping/add_unique(client/client_source) var/mob/living/carbon/carbon_holder = quirk_holder @@ -45,7 +47,15 @@ if (check_nodrop && HAS_TRAIT(item_in_slot, TRAIT_NODROP)) return FALSE target.dropItemToGround(item_in_slot, force = TRUE) + force_dropped_items += item_in_slot + RegisterSignal(item_in_slot, COMSIG_QDELETING, PROC_REF(dropped_items_cleanup)) + return target.equip_to_slot_if_possible(item, slot, disable_warning = TRUE) // this should never not work tbh +/datum/quirk/equipping/proc/dropped_items_cleanup(obj/item/source) + SIGNAL_HANDLER + + force_dropped_items -= source + /datum/quirk/equipping/proc/on_equip_item(obj/item/equipped, success) return diff --git a/modular_nova/master_files/code/modules/clothing/neck/_neck.dm b/modular_nova/master_files/code/modules/clothing/neck/_neck.dm new file mode 100644 index 00000000000..c062f7597c3 --- /dev/null +++ b/modular_nova/master_files/code/modules/clothing/neck/_neck.dm @@ -0,0 +1,3 @@ +//DEFAULT NECK ITEMS OVERRIDE// +/obj/item/clothing/neck + w_class = WEIGHT_CLASS_SMALL diff --git a/modular_nova/master_files/code/modules/entombed_quirk/code/entombed.dm b/modular_nova/master_files/code/modules/entombed_quirk/code/entombed.dm new file mode 100644 index 00000000000..cec2af9d52c --- /dev/null +++ b/modular_nova/master_files/code/modules/entombed_quirk/code/entombed.dm @@ -0,0 +1,273 @@ +/// How much damage should we be taking when the suit's been disabled a while? +#define ENTOMBED_TICK_DAMAGE 1.5 + +/datum/quirk/equipping/entombed + name = "Entombed" + desc = "You are permanently fused to (or otherwise reliant on) a single MOD unit that can never be removed from your person. If it runs out of charge or is turned off, you'll start to die!" + gain_text = span_warning("Your exosuit is both prison and home.") + lose_text = span_notice("At last, you're finally free from that horrible exosuit.") + medical_record_text = "Patient is physiologically reliant on a MOD unit for homeostasis. Do not attempt removal." + value = 0 + icon = FA_ICON_ARROW_CIRCLE_DOWN + forced_items = list(/obj/item/mod/control/pre_equipped/entombed = list(ITEM_SLOT_BACK)) + quirk_flags = QUIRK_HUMAN_ONLY | QUIRK_PROCESSES + /// The modsuit we're stuck in + var/obj/item/mod/control/pre_equipped/entombed/modsuit + /// Has the player chosen to deploy-lock? + var/deploy_locked = FALSE + /// How long before they start taking damage when the suit's not active? + var/life_support_failure_threshold = 1.5 MINUTES + /// TimerID for our timeframe tracker + var/life_support_timer + /// Are we taking damage? + var/life_support_failed = FALSE + +/datum/quirk/equipping/entombed/process(seconds_per_tick) + var/mob/living/carbon/human/human_holder = quirk_holder + if (!modsuit || life_support_failed) + // we've got no modsuit or life support. take damage ow + human_holder.adjustToxLoss(ENTOMBED_TICK_DAMAGE * seconds_per_tick, updating_health = TRUE, forced = TRUE) + human_holder.set_jitter_if_lower(10 SECONDS) + + if (!modsuit.active) + if (!life_support_timer) + //start the timer and let the player know + life_support_timer = addtimer(CALLBACK(src, PROC_REF(life_support_failure), human_holder), life_support_failure_threshold, TIMER_STOPPABLE | TIMER_DELETE_ME) + + to_chat(human_holder, span_danger("Your physiology begins to erratically seize and twitch, bereft of your MODsuit's vital support. Turn it back on as soon as you can!")) + human_holder.balloon_alert(human_holder, "suit life support warning!") + human_holder.set_jitter_if_lower(life_support_failure_threshold) //give us some foley jitter + return + else + if (life_support_timer) + // clear our timer and let the player know everything's back to normal + deltimer(life_support_timer) + life_support_timer = null + life_support_failed = FALSE + + to_chat(human_holder, span_notice("Relief floods your frame as your suit begins sustaining your life once more.")) + human_holder.balloon_alert(human_holder, "suit life support restored!") + human_holder.adjust_jitter(-(life_support_failure_threshold / 2)) // clear half of it, wow, that was unpleasant + +/datum/quirk/equipping/entombed/proc/life_support_failure() + // Warn the player and begin the gradual dying process. + var/mob/living/carbon/human/human_holder = quirk_holder + + human_holder.visible_message(span_danger("[human_holder] suddenly staggers, a dire pallor overtaking [human_holder.p_their()] features as a feeble 'breep' emanates from their suit..."), span_userdanger("Terror descends as your suit's life support system breeps feebly, and then goes horrifyingly silent.")) + human_holder.balloon_alert(human_holder, "SUIT LIFE SUPPORT FAILING!") + playsound(human_holder, 'sound/effects/alert.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) // OH GOD THE STRESS NOISE + life_support_failed = TRUE + +/datum/quirk/equipping/entombed/add_unique(client/client_source) + . = ..() + var/mob/living/carbon/human/human_holder = quirk_holder + if (istype(human_holder.back, /obj/item/mod/control/pre_equipped/entombed)) + modsuit = human_holder.back // link this up to the quirk for easy access + + if (isnull(modsuit)) + stack_trace("Entombed quirk couldn't create a fused MODsuit on [quirk_holder] and was force-removed.") + qdel(src) + return + + var/lock_deploy = client_source?.prefs.read_preference(/datum/preference/toggle/entombed_deploy_lock) + if (!isnull(lock_deploy)) + deploy_locked = lock_deploy + + // set no dismember trait for deploy-locked dudes, i'm sorry, there's basically no better way to do this. + // it's a pretty ample buff but i dunno what else to do... + if (deploy_locked) + ADD_TRAIT(human_holder, TRAIT_NODISMEMBER, QUIRK_TRAIT) + + // set all of our customization stuff from prefs, if we have it + var/modsuit_skin = client_source?.prefs.read_preference(/datum/preference/choiced/entombed_skin) + + if (modsuit_skin == NONE) + modsuit_skin = "civilian" + + modsuit.skin = lowertext(modsuit_skin) + + var/modsuit_name = client_source?.prefs.read_preference(/datum/preference/text/entombed_mod_name) + if (modsuit_name) + modsuit.name = modsuit_name + + var/modsuit_desc = client_source?.prefs.read_preference(/datum/preference/text/entombed_mod_desc) + if (modsuit_desc) + modsuit.desc = modsuit_desc + + var/modsuit_skin_prefix = client_source?.prefs.read_preference(/datum/preference/text/entombed_mod_prefix) + if (modsuit_skin_prefix) + modsuit.theme.name = lowertext(modsuit_skin_prefix) + + // ensure we're applying our config theme changes, just in case + for(var/obj/item/part as anything in modsuit.mod_parts) + part.name = "[modsuit.theme.name] [initial(part.name)]" + part.desc = "[initial(part.desc)] [modsuit.theme.desc]" + + install_racial_features() + + //transfer as many items across from our dropped backslot as we can. do this last incase something breaks + if (force_dropped_items) + var/obj/item/old_bag = locate() in force_dropped_items + if (old_bag.atom_storage) + old_bag.atom_storage.dump_content_at(modsuit, human_holder) + +/datum/quirk/equipping/entombed/post_add() + . = ..() + // quickly deploy it on roundstart. we can't do this in add_unique because that gets called in the preview screen, which overwrites people's loadout stuff in suit/shoes/gloves slot. very unfun for them + modsuit.quick_activation() + +/datum/quirk/equipping/entombed/remove() + var/mob/living/carbon/human/human_holder = quirk_holder + if (deploy_locked && HAS_TRAIT_FROM(human_holder, TRAIT_NODISMEMBER, QUIRK_TRAIT)) + REMOVE_TRAIT(human_holder, TRAIT_NODISMEMBER, QUIRK_TRAIT) + QDEL_NULL(modsuit) + +/datum/quirk/equipping/entombed/proc/install_racial_features() + // deploy specific racial features - ethereals get ethereal cores, plasmamen get free plasma stabilizer module + if (!modsuit) // really don't know how this could ever happen but it's better than runtimes + return + var/mob/living/carbon/human/human_holder = quirk_holder + if (isethereal(human_holder)) + var/obj/item/mod/core/ethereal/eth_core = new + eth_core.install(modsuit) + else if (isplasmaman(human_holder)) + var/obj/item/mod/module/plasma_stabilizer/entombed/plasma_stab = new + modsuit.install(plasma_stab, human_holder) + +/datum/quirk_constant_data/entombed + associated_typepath = /datum/quirk/equipping/entombed + customization_options = list( + /datum/preference/choiced/entombed_skin, + /datum/preference/text/entombed_mod_desc, + /datum/preference/text/entombed_mod_name, + /datum/preference/text/entombed_mod_prefix, + /datum/preference/toggle/entombed_deploy_lock, + ) + +/datum/preference/choiced/entombed_skin + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "entombed_skin" + savefile_identifier = PREFERENCE_CHARACTER + can_randomize = FALSE + +/datum/preference/choiced/entombed_skin/init_possible_values() + return list( + "Standard", + "Civilian", + "Advanced", + "Atmospheric", + "Corpsman", + "Cosmohonk", + "Engineering", + "Infiltrator", + "Interdyne", + "Loader", + "Medical", + "Mining", + "Prototype", + "Security", + ) + +/datum/preference/choiced/entombed_skin/create_default_value() + return "Civilian" + +/datum/preference/choiced/entombed_skin/is_accessible(datum/preferences/preferences) + if (!..()) + return FALSE + + return "Entombed" in preferences.all_quirks + +/datum/preference/choiced/entombed_skin/apply_to_human(mob/living/carbon/human/target, value) + return + +/datum/preference/text/entombed_mod_name + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "entombed_mod_name" + savefile_identifier = PREFERENCE_CHARACTER + can_randomize = FALSE + maximum_value_length = 48 + +/datum/preference/text/entombed_mod_name/is_accessible(datum/preferences/preferences) + if (!..()) + return FALSE + + return "Entombed" in preferences.all_quirks + +/datum/preference/text/entombed_mod_name/serialize(input) + return htmlrendertext(input) + +/datum/preference/text/entombed_mod_name/deserialize(input, datum/preferences/preferences) + var/sanitized_input = htmlrendertext(input) + if(!isnull(sanitized_input)) + return sanitized_input + else + return "" + +/datum/preference/text/entombed_mod_name/apply_to_human(mob/living/carbon/human/target, value) + return + +/datum/preference/text/entombed_mod_desc + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "entombed_mod_desc" + savefile_identifier = PREFERENCE_CHARACTER + can_randomize = FALSE + +/datum/preference/text/entombed_mod_desc/is_accessible(datum/preferences/preferences) + if (!..()) + return FALSE + + return "Entombed" in preferences.all_quirks + +/datum/preference/text/entombed_mod_desc/serialize(input) + return htmlrendertext(input) + +/datum/preference/text/entombed_mod_desc/deserialize(input, datum/preferences/preferences) + var/sanitized_input = htmlrendertext(input) + if(!isnull(sanitized_input)) + return sanitized_input + else + return "" + +/datum/preference/text/entombed_mod_desc/apply_to_human(mob/living/carbon/human/target, value) + return + +/datum/preference/text/entombed_mod_prefix + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "entombed_mod_prefix" + savefile_identifier = PREFERENCE_CHARACTER + can_randomize = FALSE + maximum_value_length = 16 + +/datum/preference/text/entombed_mod_prefix/is_accessible(datum/preferences/preferences) + if (!..()) + return FALSE + + return "Entombed" in preferences.all_quirks + +/datum/preference/text/entombed_mod_prefix/serialize(input) + return htmlrendertext(input) + +/datum/preference/text/entombed_mod_prefix/deserialize(input, datum/preferences/preferences) + return htmlrendertext(input) + +/datum/preference/text/entombed_mod_prefix/create_default_value() + return "Fused" + +/datum/preference/text/entombed_mod_prefix/apply_to_human(mob/living/carbon/human/target, value) + return + +/datum/preference/toggle/entombed_deploy_lock + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "entombed_deploy_lock" + savefile_identifier = PREFERENCE_CHARACTER + +/datum/preference/toggle/entombed_deploy_lock/is_accessible(datum/preferences/preferences) + if (!..(preferences)) + return FALSE + + return "Entombed" in preferences.all_quirks + +/datum/preference/toggle/entombed_deploy_lock/apply_to_human(mob/living/carbon/human/target, value) + return + +#undef ENTOMBED_TICK_DAMAGE diff --git a/modular_nova/master_files/code/modules/entombed_quirk/code/entombed_mod.dm b/modular_nova/master_files/code/modules/entombed_quirk/code/entombed_mod.dm new file mode 100644 index 00000000000..68f489e34d0 --- /dev/null +++ b/modular_nova/master_files/code/modules/entombed_quirk/code/entombed_mod.dm @@ -0,0 +1,95 @@ +/datum/mod_theme/entombed + name = "fused" + desc = "Circumstances have rendered this protective suit into someone's second skin. Literally." + extended_desc = "Some great aspect of someone's past has permanently bound them to this device, for better or worse." + + default_skin = "civilian" + armor_type = /datum/armor/mod_entombed + resistance_flags = FIRE_PROOF | ACID_PROOF // It is better to die for the Emperor than live for yourself. + max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT + siemens_coefficient = 0 + complexity_max = DEFAULT_MAX_COMPLEXITY - 5 + charge_drain = DEFAULT_CHARGE_DRAIN + slowdown_inactive = 2.5 // very slow because the quirk infers you rely on this to move/exist + slowdown_active = 0.95 + inbuilt_modules = list( + /obj/item/mod/module/joint_torsion/entombed, + /obj/item/mod/module/storage, + ) + allowed_suit_storage = list( + /obj/item/tank/internals, + /obj/item/flashlight, + ) + +/datum/armor/mod_entombed + melee = ARMOR_LEVEL_WEAK + bullet = ARMOR_LEVEL_WEAK + laser = ARMOR_LEVEL_WEAK + energy = ARMOR_LEVEL_WEAK + bomb = ARMOR_LEVEL_WEAK + bio = ARMOR_LEVEL_WEAK + fire = ARMOR_LEVEL_WEAK + acid = ARMOR_LEVEL_WEAK + wound = WOUND_ARMOR_WEAK + +/obj/item/mod/module/joint_torsion/entombed + name = "internal joint torsion adaptation" + desc = "Your adaptation to life in this MODsuit shell allows you to ambulate in such a way that your movements recharge the suit's internal batteries slightly, but only while under the effect of gravity." + removable = FALSE + complexity = 0 + power_per_step = DEFAULT_CHARGE_DRAIN * 0.4 + +/obj/item/mod/module/plasma_stabilizer/entombed + name = "colony-stabilized interior seal" + desc = "Your colony has fully integrated the internal segments of your suit's plate into your skeleton, forming a hermetic seal between you and the outside world from which none of your atmosphere can escape. This is enough to allow your head to view the world with your helmet retracted." + complexity = 0 + idle_power_cost = 0 + removable = FALSE + +/obj/item/mod/control/pre_equipped/entombed + theme = /datum/mod_theme/entombed + applied_cell = /obj/item/stock_parts/cell/high + +/obj/item/mod/control/pre_equipped/entombed/canStrip(mob/who) + return TRUE //you can always try, and it'll hit doStrip below + +/obj/item/mod/control/pre_equipped/entombed/doStrip(mob/who) + // attempt to handle custom stripping behavior - if we have a storage module of some kind + var/obj/item/mod/module/storage/inventory = locate() in src.modules + if (!isnull(inventory)) + src.atom_storage.remove_all() + to_chat(who, span_notice("You empty out all the items from the MODsuit's storage module!")) + who.balloon_alert(who, "emptied out MOD storage items!") + return TRUE + + to_chat(who, span_warning("The suit seems permanently fused to their frame - you can't remove it!")) + who.balloon_alert(who, "can't strip a fused MODsuit!") + return ..() + +/obj/item/mod/control/pre_equipped/entombed/retract(mob/user, obj/item/part) + if (ishuman(user)) + var/mob/living/carbon/human/human_user = user + var/datum/quirk/equipping/entombed/tomb_quirk = human_user.get_quirk(/datum/quirk/equipping/entombed) + //check to make sure we're not retracting something we shouldn't be able to + if (tomb_quirk && tomb_quirk.deploy_locked) + if (istype(part, /obj/item/clothing)) // make sure it's a modsuit piece and not a module, we retract those too + if (!istype(part, /obj/item/clothing/head/mod)) // they can only retract the helmet, them's the sticks + human_user.balloon_alert(human_user, "part is fused to you - can't retract!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return + return ..() + +/obj/item/mod/control/pre_equipped/entombed/quick_deploy(mob/user) + if (ishuman(user)) + var/mob/living/carbon/human/human_user = user + var/datum/quirk/equipping/entombed/tomb_quirk = human_user.get_quirk(/datum/quirk/equipping/entombed) + //if we're deploy_locked, just disable this functionality entirely + if (tomb_quirk && tomb_quirk.deploy_locked) + human_user.balloon_alert(human_user, "you can only retract your helmet, and only manually!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return + return ..() + +/obj/item/mod/control/pre_equipped/entombed/Initialize(mapload, new_theme, new_skin, new_core) + . = ..() + ADD_TRAIT(src, TRAIT_NODROP, QUIRK_TRAIT) diff --git a/modular_nova/modules/aesthetics/airlock/code/airlock.dm b/modular_nova/modules/aesthetics/airlock/code/airlock.dm index 97f043dc3c1..28399c6fe6d 100644 --- a/modular_nova/modules/aesthetics/airlock/code/airlock.dm +++ b/modular_nova/modules/aesthetics/airlock/code/airlock.dm @@ -3,28 +3,17 @@ doorClose = 'modular_nova/modules/aesthetics/airlock/sound/close.ogg' boltUp = 'modular_nova/modules/aesthetics/airlock/sound/bolts_up.ogg' boltDown = 'modular_nova/modules/aesthetics/airlock/sound/bolts_down.ogg' - //noPower = 'sound/machines/doorclick.ogg' var/forcedOpen = 'modular_nova/modules/aesthetics/airlock/sound/open_force.ogg' //Come on guys, why aren't all the sound files like this. var/forcedClosed = 'modular_nova/modules/aesthetics/airlock/sound/close_force.ogg' /// For those airlocks you might want to have varying "fillings" for, without having to /// have an icon file per door with a different filling. var/fill_state_suffix = null - /// For the airlocks that use greyscale lights, set this to the color you want your lights to be. - var/greyscale_lights_color = null /// For the airlocks that use a greyscale accent door color, set this color to the accent color you want it to be. var/greyscale_accent_color = null - - var/has_environment_lights = TRUE //Does this airlock emit a light? - var/light_color_poweron = AIRLOCK_POWERON_LIGHT_COLOR - var/light_color_bolts = AIRLOCK_BOLTS_LIGHT_COLOR - var/light_color_access = AIRLOCK_ACCESS_LIGHT_COLOR - var/light_color_emergency = AIRLOCK_EMERGENCY_LIGHT_COLOR - var/light_color_engineering = AIRLOCK_ENGINEERING_LIGHT_COLOR - var/light_color_deny = AIRLOCK_DENY_LIGHT_COLOR - var/door_light_range = AIRLOCK_LIGHT_RANGE - var/door_light_power = AIRLOCK_LIGHT_POWER - ///Is this door external? E.g. does it lead to space? Shuttle docking systems bolt doors with this flag. + /// Does this airlock emit a light? + var/has_environment_lights = TRUE + /// Is this door external? E.g. does it lead to space? Shuttle docking systems bolt doors with this flag. var/external = FALSE /obj/machinery/door/airlock/external @@ -39,59 +28,57 @@ /obj/machinery/door/airlock/update_overlays() . = ..() - var/pre_light_range = 0 - var/pre_light_power = 0 - var/pre_light_color = initial(light_color) - var/lights_overlay = "" - var/frame_state - var/light_state + var/light_state = AIRLOCK_LIGHT_POWERON + var/pre_light_color switch(airlock_state) if(AIRLOCK_CLOSED) frame_state = AIRLOCK_FRAME_CLOSED if(locked) light_state = AIRLOCK_LIGHT_BOLTS - lights_overlay = "lights_bolts" - pre_light_color = light_color_bolts + pre_light_color = AIRLOCK_BOLTS_LIGHT_COLOR else if(emergency) light_state = AIRLOCK_LIGHT_EMERGENCY - lights_overlay = "lights_emergency" - pre_light_color = light_color_emergency + pre_light_color = AIRLOCK_EMERGENCY_LIGHT_COLOR + else if(fire_active) + light_state = AIRLOCK_LIGHT_FIRE + pre_light_color = AIRLOCK_FIRE_LIGHT_COLOR else if(engineering_override) light_state = AIRLOCK_LIGHT_ENGINEERING - lights_overlay = "lights_engineering" - pre_light_color = light_color_engineering + pre_light_color = AIRLOCK_ENGINEERING_LIGHT_COLOR else - lights_overlay = "lights_poweron" - pre_light_color = light_color_poweron + pre_light_color = AIRLOCK_POWERON_LIGHT_COLOR if(AIRLOCK_DENY) frame_state = AIRLOCK_FRAME_CLOSED light_state = AIRLOCK_LIGHT_DENIED - lights_overlay = "lights_denied" - pre_light_color = light_color_deny + pre_light_color = AIRLOCK_DENY_LIGHT_COLOR if(AIRLOCK_EMAG) frame_state = AIRLOCK_FRAME_CLOSED if(AIRLOCK_CLOSING) frame_state = AIRLOCK_FRAME_CLOSING light_state = AIRLOCK_LIGHT_CLOSING - lights_overlay = "lights_closing" - pre_light_color = light_color_access + pre_light_color = AIRLOCK_ACCESS_LIGHT_COLOR if(AIRLOCK_OPEN) frame_state = AIRLOCK_FRAME_OPEN if(locked) - lights_overlay = "lights_bolts_open" - pre_light_color = light_color_bolts + light_state = AIRLOCK_LIGHT_BOLTS + pre_light_color = AIRLOCK_BOLTS_LIGHT_COLOR else if(emergency) - lights_overlay = "lights_emergency_open" - pre_light_color = light_color_emergency + light_state = AIRLOCK_LIGHT_EMERGENCY + pre_light_color = AIRLOCK_EMERGENCY_LIGHT_COLOR + else if(fire_active) + light_state = AIRLOCK_LIGHT_FIRE + pre_light_color = AIRLOCK_FIRE_LIGHT_COLOR + else if(engineering_override) + light_state = AIRLOCK_LIGHT_ENGINEERING + pre_light_color = AIRLOCK_ENGINEERING_LIGHT_COLOR else - lights_overlay = "lights_poweron_open" - pre_light_color = light_color_poweron + pre_light_color = AIRLOCK_POWERON_LIGHT_COLOR + light_state += "_open" if(AIRLOCK_OPENING) frame_state = AIRLOCK_FRAME_OPENING light_state = AIRLOCK_LIGHT_OPENING - lights_overlay = "lights_opening" - pre_light_color = light_color_access + pre_light_color = AIRLOCK_ACCESS_LIGHT_COLOR . += get_airlock_overlay(frame_state, icon, src, em_block = TRUE) if(airlock_material) @@ -99,30 +86,16 @@ else . += get_airlock_overlay("fill_[frame_state + fill_state_suffix]", icon, src, em_block = TRUE) - if(greyscale_lights_color && !light_state) - lights_overlay += "_greyscale" - - if(lights && hasPower()) + if(lights && hasPower() && has_environment_lights) . += get_airlock_overlay("lights_[light_state]", overlays_file, src, em_block = FALSE) - pre_light_range = door_light_range - pre_light_power = door_light_power - if(has_environment_lights) - set_light(l_range = pre_light_range, l_power = pre_light_power, l_color = pre_light_color, l_on = TRUE) - if(multi_tile) - filler.set_light(l_range = pre_light_range, l_power = pre_light_power, l_color = pre_light_color, l_on = TRUE) - else - lights_overlay = "" - set_light(l_on = FALSE) + . += emissive_appearance(overlays_file, "lights_[light_state]", src, alpha = src.alpha) - var/mutable_appearance/lights_appearance = mutable_appearance(overlays_file, lights_overlay, FLOAT_LAYER, src, ABOVE_LIGHTING_PLANE) + if(multi_tile) + filler.set_light(l_range = AIRLOCK_LIGHT_RANGE, l_power = AIRLOCK_LIGHT_POWER, l_color = pre_light_color, l_on = TRUE) - if(greyscale_lights_color && !light_state) - lights_appearance.color = greyscale_lights_color - - if(multi_tile) - lights_appearance.dir = dir - - . += lights_appearance + set_light(l_range = AIRLOCK_LIGHT_RANGE, l_power = AIRLOCK_LIGHT_POWER, l_color = pre_light_color, l_on = TRUE) + else + set_light(l_on = FALSE) if(greyscale_accent_color) . += get_airlock_overlay("[frame_state]_accent", overlays_file, src, em_block = TRUE, state_color = greyscale_accent_color) @@ -359,6 +332,43 @@ icon = 'modular_nova/modules/aesthetics/airlock/icons/airlocks/highsec/highsec.dmi' overlays_file = 'modular_nova/modules/aesthetics/airlock/icons/airlocks/highsec/overlays.dmi' +//TITANIUM / SHUTTLE +/obj/machinery/door/airlock/titanium + icon = 'modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle/shuttle.dmi' + overlays_file = 'modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle/overlays.dmi' + +/obj/machinery/door/airlock/shuttle + icon = 'modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle/shuttle.dmi' + overlays_file = 'modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle/overlays.dmi' + +//SHUTTLE2 +/obj/machinery/door/airlock/shuttle/ferry + icon = 'modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle2/erokez.dmi' + overlays_file = 'modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle2/overlays.dmi' + +/obj/machinery/door/airlock/external/wagon + icon = 'modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle2/wagon.dmi' + overlays_file = 'modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle2/overlays.dmi' + +//SURVIVAL +/obj/machinery/door/airlock/survival_pod + overlays_file = 'modular_nova/modules/aesthetics/airlock/icons/airlocks/survival/overlays.dmi' + +//ABDUCTOR +/obj/machinery/door/airlock/abductor + overlays_file = 'modular_nova/modules/aesthetics/airlock/icons/airlocks/abductor/overlays.dmi' + +//CULT +/obj/machinery/door/airlock/cult + overlays_file = 'modular_nova/modules/aesthetics/airlock/icons/airlocks/cult/runed/overlays.dmi' + +/obj/machinery/door/airlock/cult/unruned + overlays_file = 'modular_nova/modules/aesthetics/airlock/icons/airlocks/cult/unruned/overlays.dmi' + +//CLOCKWORK +/obj/machinery/door/airlock/bronze + overlays_file = 'modular_nova/modules/aesthetics/airlock/icons/airlocks/clockwork/overlays.dmi' + //MULTI-TILE /obj/machinery/door/airlock/multi_tile diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/abductor/overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/abductor/overlays.dmi new file mode 100644 index 00000000000..b93c50ad2e4 Binary files /dev/null and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/abductor/overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/centcom/overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/centcom/overlays.dmi index f47a46ad003..cb01199b9d2 100644 Binary files a/modular_nova/modules/aesthetics/airlock/icons/airlocks/centcom/overlays.dmi and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/centcom/overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/clockwork/overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/clockwork/overlays.dmi new file mode 100644 index 00000000000..f8eba778357 Binary files /dev/null and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/clockwork/overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/cult/runed/overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/cult/runed/overlays.dmi new file mode 100644 index 00000000000..d1c20063f3a Binary files /dev/null and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/cult/runed/overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/cult/unruned/overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/cult/unruned/overlays.dmi new file mode 100644 index 00000000000..3bc7295350e Binary files /dev/null and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/cult/unruned/overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/external/overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/external/overlays.dmi index 7e0080f78c8..85fd009b43a 100644 Binary files a/modular_nova/modules/aesthetics/airlock/icons/airlocks/external/overlays.dmi and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/external/overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/hatch/overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/hatch/overlays.dmi index 662f12813da..61af0a0abc3 100644 Binary files a/modular_nova/modules/aesthetics/airlock/icons/airlocks/hatch/overlays.dmi and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/hatch/overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/highsec/overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/highsec/overlays.dmi index 580ca671550..1c6bbc12fdd 100644 Binary files a/modular_nova/modules/aesthetics/airlock/icons/airlocks/highsec/overlays.dmi and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/highsec/overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/multi_tile/glass_overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/multi_tile/glass_overlays.dmi index a6a2b020138..c464c9316e0 100644 Binary files a/modular_nova/modules/aesthetics/airlock/icons/airlocks/multi_tile/glass_overlays.dmi and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/multi_tile/glass_overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/multi_tile/metal_overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/multi_tile/metal_overlays.dmi index 7de2b627a45..7903886dd5b 100644 Binary files a/modular_nova/modules/aesthetics/airlock/icons/airlocks/multi_tile/metal_overlays.dmi and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/multi_tile/metal_overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle/overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle/overlays.dmi index d418e45f603..a885f4ac74a 100644 Binary files a/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle/overlays.dmi and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle/overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle/shuttle.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle/shuttle.dmi new file mode 100644 index 00000000000..b4b998e4bcb Binary files /dev/null and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle/shuttle.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle2/erokez.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle2/erokez.dmi new file mode 100644 index 00000000000..da8d47bd152 Binary files /dev/null and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle2/erokez.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle2/overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle2/overlays.dmi new file mode 100644 index 00000000000..6d5a316cf3f Binary files /dev/null and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle2/overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle2/wagon.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle2/wagon.dmi new file mode 100644 index 00000000000..c92e9f9199c Binary files /dev/null and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/shuttle2/wagon.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/station/overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/station/overlays.dmi index 8530f0753db..d851d4df630 100644 Binary files a/modular_nova/modules/aesthetics/airlock/icons/airlocks/station/overlays.dmi and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/station/overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/station2/overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/station2/overlays.dmi index 1342376d98c..74d98718119 100644 Binary files a/modular_nova/modules/aesthetics/airlock/icons/airlocks/station2/overlays.dmi and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/station2/overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/survival/overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/survival/overlays.dmi new file mode 100644 index 00000000000..a98ceafb5ab Binary files /dev/null and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/survival/overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/tram/tram_overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/tram/tram_overlays.dmi index e30dbeb2b98..65df94c91a0 100644 Binary files a/modular_nova/modules/aesthetics/airlock/icons/airlocks/tram/tram_overlays.dmi and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/tram/tram_overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/airlock/icons/airlocks/vault/overlays.dmi b/modular_nova/modules/aesthetics/airlock/icons/airlocks/vault/overlays.dmi index 992e678d010..a0408ef8ee2 100644 Binary files a/modular_nova/modules/aesthetics/airlock/icons/airlocks/vault/overlays.dmi and b/modular_nova/modules/aesthetics/airlock/icons/airlocks/vault/overlays.dmi differ diff --git a/modular_nova/modules/aesthetics/firealarm/icons/firealarm.dmi b/modular_nova/modules/aesthetics/firealarm/icons/firealarm.dmi index ce8c37b6004..1bcd033b9cf 100644 Binary files a/modular_nova/modules/aesthetics/firealarm/icons/firealarm.dmi and b/modular_nova/modules/aesthetics/firealarm/icons/firealarm.dmi differ diff --git a/modular_nova/modules/aesthetics/firedoor/code/firedoor.dm b/modular_nova/modules/aesthetics/firedoor/code/firedoor.dm index 8ed0be1c749..c3747c73944 100644 --- a/modular_nova/modules/aesthetics/firedoor/code/firedoor.dm +++ b/modular_nova/modules/aesthetics/firedoor/code/firedoor.dm @@ -10,7 +10,8 @@ if(istype(src, /obj/machinery/door/firedoor/border_only)) return if(density) // if the door is closed, add the bottom blinking overlay -- and only if it's closed - . += "firelock_alarm_type_bottom" + . += mutable_appearance(icon, "firelock_alarm_type_bottom") + . += emissive_appearance(icon, "firelock_alarm_type_bottom", src, alpha = src.alpha) /obj/machinery/door/firedoor/open() playsound(loc, door_open_sound, 100, TRUE) diff --git a/modular_nova/modules/aesthetics/firedoor/icons/firedoor.dmi b/modular_nova/modules/aesthetics/firedoor/icons/firedoor.dmi index c7ab9ab729e..5996d310aac 100644 Binary files a/modular_nova/modules/aesthetics/firedoor/icons/firedoor.dmi and b/modular_nova/modules/aesthetics/firedoor/icons/firedoor.dmi differ diff --git a/modular_nova/modules/aesthetics/firedoor/icons/firedoor_glass.dmi b/modular_nova/modules/aesthetics/firedoor/icons/firedoor_glass.dmi index 69eb711fa2e..934891a09f8 100644 Binary files a/modular_nova/modules/aesthetics/firedoor/icons/firedoor_glass.dmi and b/modular_nova/modules/aesthetics/firedoor/icons/firedoor_glass.dmi differ diff --git a/modular_nova/modules/airlock_override/code/airlock_override.dm b/modular_nova/modules/airlock_override/code/airlock_override.dm index cad26123ce5..e2008c131e0 100644 --- a/modular_nova/modules/airlock_override/code/airlock_override.dm +++ b/modular_nova/modules/airlock_override/code/airlock_override.dm @@ -70,9 +70,15 @@ /obj/machinery/door/airlock /// Determines if engineers get access to this door on orange alert var/engineering_override = FALSE + /// If there is an active fire alarm in the door's area + var/fire_active = FALSE + /// Area the door is located in + var/area/door_area /obj/machinery/door/airlock/Initialize(mapload) . = ..() + door_area = get_area(src) + RegisterSignal(door_area, COMSIG_AREA_FIRE_CHANGED, PROC_REF(update_fire_status)) RegisterSignal(SSdcs, COMSIG_GLOB_FORCE_ENG_OVERRIDE, PROC_REF(force_eng_override)) ///Check for the three states of open access. Emergency, Unrestricted, and Engineering Override @@ -83,7 +89,7 @@ if(unrestricted_side(user)) return TRUE - if(engineering_override) + if(engineering_override || fire_active) var/mob/living/carbon/human/interacting_human = user if(!istype(interacting_human)) return ..() @@ -101,6 +107,9 @@ if(!source_area.engineering_override_eligible) return + if(isnull(req_access) && isnull(req_one_access)) // no restrictions, no problem + return + if(level != SEC_LEVEL_ORANGE && GLOB.force_eng_override) return @@ -111,7 +120,9 @@ return engineering_override = FALSE - normalspeed = TRUE + if(!fire_active) + normalspeed = TRUE + update_appearance() return @@ -150,17 +161,45 @@ GLOBAL_VAR_INIT(force_eng_override, FALSE) /obj/machinery/door/airlock/proc/force_eng_override(datum/source, status) SIGNAL_HANDLER - if(!status) - engineering_override = FALSE + if(isnull(req_access) && isnull(req_one_access)) // no restrictions, no problem + return + + engineering_override = status + if(!engineering_override && !fire_active) normalspeed = TRUE update_appearance() return - var/area/source_area = get_area(src) - if(!source_area.engineering_override_eligible) + if(!door_area.engineering_override_eligible) + return + + normalspeed = FALSE + update_appearance() + +/** + * Change the airlock's fire_active status, triggered by COMSIG_AREA_FIRE_CHANGED + * Activates fire status overlay and increases door speed. + * + * Arguments: + * * source - The /area with changed fire status + * * fire - the new fire status (TRUE/FALSE) + * +*/ +/obj/machinery/door/airlock/proc/update_fire_status(datum/source, fire) + SIGNAL_HANDLER + + if(isnull(req_access) && isnull(req_one_access)) // no restrictions, no problem + return + + fire_active = fire + if(!fire_active && !engineering_override) + normalspeed = TRUE + update_appearance() + return + + if(!door_area.engineering_override_eligible) return - engineering_override = TRUE normalspeed = FALSE update_appearance() diff --git a/modular_nova/modules/ashwalkers/code/effects/ash_rituals.dm b/modular_nova/modules/ashwalkers/code/effects/ash_rituals.dm index 59a52c87335..4f621b656e6 100644 --- a/modular_nova/modules/ashwalkers/code/effects/ash_rituals.dm +++ b/modular_nova/modules/ashwalkers/code/effects/ash_rituals.dm @@ -28,7 +28,7 @@ /obj/item/stack/sheet/sinew, ) ritual_success_items = list( - /obj/item/clothing/neck/necklace/ashwalker, + /obj/item/clothing/neck/necklace/translator, ) /datum/ash_ritual/summon_key diff --git a/modular_nova/modules/customization/datums/keybinding/communication.dm b/modular_nova/modules/customization/datums/keybinding/communication.dm index 335e256e588..1ac9a6da963 100644 --- a/modular_nova/modules/customization/datums/keybinding/communication.dm +++ b/modular_nova/modules/customization/datums/keybinding/communication.dm @@ -23,3 +23,33 @@ return winset(user, null, "command=[user.tgui_say_create_open_command(WHIS_CHANNEL)]") return TRUE + +/datum/keybinding/client/communication/Do + hotkey_keys = list("K") + name = DO_CHANNEL + full_name = "Do" + keybind_signal = COMSIG_KB_CLIENT_DO_DOWN + +/datum/keybinding/client/communication/Do/down(client/user) + . = ..() + if(.) + return + winset(user, null, "command=[user.tgui_say_create_open_command(DO_CHANNEL)]") + return TRUE + +/datum/keybinding/client/communication/Do_longer + hotkey_keys = list("CtrlK") + name = "do_longer" + full_name = "Do (Longer)" + keybind_signal = COMSIG_KB_CLIENT_DO_LONGER_DOWN + +/datum/keybinding/client/communication/Do_longer/down(client/user) + . = ..() + if(.) + return + var/message_text = tgui_input_text(user, "Write out your Do action:", "Do (Longer)", null, MAX_MESSAGE_LEN, TRUE) + if (!message_text) + return + + user.mob.do_verb(message_text) + return TRUE diff --git a/modular_nova/modules/customization/modules/jobs/_job.dm b/modular_nova/modules/customization/modules/jobs/_job.dm index 189e643e2ff..f053abc3390 100644 --- a/modular_nova/modules/customization/modules/jobs/_job.dm +++ b/modular_nova/modules/customization/modules/jobs/_job.dm @@ -117,7 +117,7 @@ banned_augments = list(HEAD_RESTRICTED_AUGMENTS) /datum/job/quartermaster - banned_quirks = list(HEAD_RESTRICTED_QUIRKS) + banned_quirks = list(HEAD_RESTRICTED_QUIRKS_QM) banned_augments = list(HEAD_RESTRICTED_AUGMENTS) //Silicon @@ -142,6 +142,7 @@ /datum/job/prisoner required_languages = null + banned_quirks = list(PRISONER_RESTRICTED_QUIRKS) /datum/job/orderly banned_quirks = list(GUARD_RESTRICTED_QUIRKS) diff --git a/modular_nova/modules/deforest_medical_items/code/storage_items.dm b/modular_nova/modules/deforest_medical_items/code/storage_items.dm index f66aa7d8bdb..012ba6b32f1 100644 --- a/modular_nova/modules/deforest_medical_items/code/storage_items.dm +++ b/modular_nova/modules/deforest_medical_items/code/storage_items.dm @@ -70,6 +70,8 @@ atom_storage.set_holdable(list( /obj/item/reagent_containers/hypospray/medipen, /obj/item/storage/pill_bottle/prescription_stimulant, + /obj/item/food/cheese/firm_cheese_slice, //It's not called a cheese kit for nothing. + /obj/item/food/cheese/wedge, )) /obj/item/storage/medkit/civil_defense/stocked diff --git a/modular_nova/modules/gladiator/code/datums/ruins/lavaland.dm b/modular_nova/modules/gladiator/code/datums/ruins/lavaland.dm deleted file mode 100644 index 0703d375fee..00000000000 --- a/modular_nova/modules/gladiator/code/datums/ruins/lavaland.dm +++ /dev/null @@ -1,9 +0,0 @@ -/datum/map_template/ruin/lavaland/arena - name = "Grand Arena" - id = "arena" - description = "An ancient gladitorial arena containing a deadly warrior within." - prefix = "_maps/RandomRuins/LavaRuins/nova/" - suffix = "lavaland_surface_arena.dmm" - cost = 0 - always_place = TRUE //WOULD BE UNFAIR IF SOMETHING THAT IS ALWAYS PLACED HAD A COST... - allow_duplicates = FALSE diff --git a/modular_nova/modules/mapping/code/icemoon.dm b/modular_nova/modules/mapping/code/icemoon.dm index bf39280cc9d..d00ce32aed8 100644 --- a/modular_nova/modules/mapping/code/icemoon.dm +++ b/modular_nova/modules/mapping/code/icemoon.dm @@ -4,7 +4,7 @@ /*------*/ /datum/map_template/ruin/icemoon/underground/nova/mining_site_below - name = "Mining Site Underground" + name = "Ice-ruin Mining Site Underground" id = "miningsite-underground" description = "The Iceminer arena." prefix = "_maps/RandomRuins/IceRuins/nova/" @@ -12,7 +12,7 @@ always_place = TRUE /datum/map_template/ruin/icemoon/underground/nova/interdyne_base - name = "Interdyne Pharmaceuticals Nova Sector Base 8817238" + name = "Ice-ruin Interdyne Pharmaceuticals Nova Sector Base 8817238" id = "ice-base" description = "A planetside Interdyne research facility developing biological weapons; it is closely guarded by an elite team of agents." prefix = "_maps/RandomRuins/IceRuins/nova/" diff --git a/modular_nova/modules/mapping/code/lavaland.dm b/modular_nova/modules/mapping/code/lavaland.dm index 3863e2283ff..f99824e0d9f 100644 --- a/modular_nova/modules/mapping/code/lavaland.dm +++ b/modular_nova/modules/mapping/code/lavaland.dm @@ -4,7 +4,7 @@ /*------*/ /datum/map_template/ruin/lavaland/ash_walker - name = "Ash Walker Nest" + name = "Lava-Ruin Ash Walker Nest" id = "ash-walker" description = "A race of unbreathing lizards live here, that run faster than a human can, worship a broken dead city, and are capable of reproducing by something involving tentacles? \ Probably best to stay clear." @@ -14,7 +14,7 @@ allow_duplicates = FALSE /datum/map_template/ruin/lavaland/nova/interdyne_base - name = "Interdyne Pharmaceutics Nova Sector Base 3c76928" + name = "Lava-Ruin Interdyne Pharmaceutics Nova Sector Base 3c76928" id = "lava-base" description = "A planetside Interdyne research facility developing biological weapons; it is closely guarded by an elite team of agents." prefix = "_maps/RandomRuins/LavaRuins/nova/" @@ -23,3 +23,12 @@ never_spawn_with = list(/datum/map_template/ruin/icemoon/underground/nova/interdyne_base) unpickable = TRUE //FF REMOVAL - INTERDYNE-REMAP. ORIGINAL always_place = TRUE +/datum/map_template/ruin/lavaland/arena + name = "Lava-Ruin Grand Arena" + id = "arena" + description = "An ancient gladitorial arena containing a deadly warrior within." + prefix = "_maps/RandomRuins/LavaRuins/nova/" + suffix = "lavaland_surface_arena.dmm" + cost = 0 + always_place = TRUE //WOULD BE UNFAIR IF SOMETHING THAT IS ALWAYS PLACED HAD A COST... + allow_duplicates = FALSE diff --git a/modular_nova/modules/mapping/code/mob_spawns.dm b/modular_nova/modules/mapping/code/mob_spawns.dm index 9fd74f012d5..ce6eef78ac0 100644 --- a/modular_nova/modules/mapping/code/mob_spawns.dm +++ b/modular_nova/modules/mapping/code/mob_spawns.dm @@ -532,6 +532,7 @@ /datum/id_trim/away/hotel/security assignment = "Hotel Security" + access = list(ACCESS_TWIN_NEXUS_STAFF, ACCESS_TWIN_NEXUS_MANAGER) //CRYO CONSOLES diff --git a/modular_nova/modules/mapping/code/space.dm b/modular_nova/modules/mapping/code/space.dm index f6e4f135e42..1bb749b8a77 100644 --- a/modular_nova/modules/mapping/code/space.dm +++ b/modular_nova/modules/mapping/code/space.dm @@ -5,9 +5,8 @@ /datum/map_template/ruin/space/whiteshipruin_box_nova/ id = "whiteshipruin_box_nova" - prefix = "_maps/RandomRuins/SpaceRuins/nova/" suffix = "whiteshipruin_box.dmm" - name = "NT Medical Ship" + name = "Space-Ruin NT Medical Ship" description = "An ancient ship, said to be among the first discovered derelicts near Space Station 13 that was still in working order. \ Aged and deprecated by time, this relic of a vessel is now broken beyond repair." @@ -15,164 +14,158 @@ id = "spacehotel" prefix = "_maps/RandomRuins/SpaceRuins/nova/" suffix = "spacehotel.dmm" - name = "The Twin-Nexus Hotel" + name = "Space-Ruin The Twin-Nexus Hotel" description = "An interstellar hotel, where the weary spaceman can rest their head and relax, assured that the residental staff will not murder them in their sleep. Probably." /datum/map_template/ruin/space/nova/des_two - name = "DS-2" id = "des_two" - description = "If DS-1 was so good..." suffix = "des_two.dmm" + name = "Space-Ruin DS-2" + description = "If DS-1 was so good..." always_place = TRUE /datum/map_template/ruin/space/nova/derelictferry id = "derelictferry" suffix = "derelictferry.dmm" - name = "Derelict Ferry" + name = "Space-Ruin Derelict Ferry" description = "Clearly once a ferry fielded by Central Command to send their staff to nearby stations, this ship's seen better days." /datum/map_template/ruin/space/nova/posterpandamonium id = "posterpandamonium" suffix = "posterpandamonium.dmm" - name = "Abandoned Outpost" + name = "Space-Ruin Abandoned Outpost" description = "Whilst nicely furnished and filled with all sorts of posters, whoever once lived here seems long gone." /datum/map_template/ruin/space/nova/prisonshuttle id = "prisonshuttle" suffix = "prisonshuttle.dmm" - name = "Partisan Shuttle" + name = "Space-Ruin Partisan Shuttle" description = "You can faintly hear hardbass." /datum/map_template/ruin/space/nova/toystore id = "toystore" suffix = "toystore.dmm" - name = "Toy Store" + name = "Space-Ruin Toy Store" description = "A once state-of-the-art store, now left derelict after the company behind it went bankrupt. Maybe they shouldn't have picked such a remote location." /datum/map_template/ruin/space/nova/waypointstation id = "waypointstation" suffix = "waypointstation.dmm" - name = "Waypoint Station" + name = "Space-Ruin Waypoint Station" description = "Previously used as a refueling stop for larger ships, unintentional syndicate intervention has turned this station into a combat zone." /datum/map_template/ruin/space/nova/alientoollab id = "alientoollab" suffix = "alientoollab.dmm" - name = "Abductor Replication Facility" + name = "Space-Ruin Abductor Replication Facility" description = "A mad doctor's dreams were dashed when he finally disclosed to both his funders that each other existed, leaving behind his work for the looters." /datum/map_template/ruin/space/nova/codealpha id = "codealpha" suffix = "codealpha.dmm" - name = "Code Alpha Supplementary Station" + name = "Space-Ruin Code Alpha Supplementary Station" description = "The mess hall of a once bustling supplementary station, to be deployed alongside SS13." /datum/map_template/ruin/space/nova/smugglies //Excuse me sir, do you have money printers in here? id = "smugglies" suffix = "smugglies.dmm" - name = "Suspicious Cargo Installation" + name = "Space-Ruin Suspicious Cargo Installation" description = "*SCREECH* RDM RDM RDM" /datum/map_template/ruin/space/nova/clothing_facility id = "clothing_facility" suffix = "clothing_facility.dmm" - name = "Abandoned Clothing Facility" + name = "Space-Ruin Abandoned Clothing Facility" description = "A den of bad ideas. Secborgs were made here!" /datum/map_template/ruin/space/nova/luna id = "luna" suffix = "luna.dmm" - name = "Luna" + name = "Space-Ruin Luna" description = "Please note for ethical concerns all experimentation regarding writing artificial intelligence units to beleive they are A, A fictional character and B, human have been suspended. Have a pleasant shift." /datum/map_template/ruin/space/nova/blackmarket id = "blackmarket" suffix = "blackmarket.dmm" - name = "Shady Market" + name = "Space-Ruin Shady Market" description = "Whaddya buyin'?" /datum/map_template/ruin/space/nova/shuttle8532 id = "shuttle8532" suffix = "shuttle8532.dmm" - name = "Shuttle 8532" + name = "Space-Ruin Shuttle 8532" description = "While nobody can predict what space has to offer for the sailors that ride its waves, nobody is quite expecting a meteroid half the size of your shuttle to split it in half." /datum/map_template/ruin/space/nova/ghostship id = "ghostship" suffix = "ghostship.dmm" - name = "Ghost Ship" + name = "Space-Ruin Ghost Ship" description = "An ancient ship, seemingly pre-bluespace in design yet retrofitted with newer systems. Seemingly just up-and-abandoned in the middle of space..." /datum/map_template/ruin/space/nova/salvagepost id = "salvagepost" suffix = "salvagepost.dmm" - name = "Pre-Bluespace Salvage Post" + name = "Space-Ruin Pre-Bluespace Salvage Post" description = "An extremely old, long forgotten post used to salvage damaged or decommissioned ships before bluespace transportation. Surprising its stayed intact so long." /datum/map_template/ruin/space/nova/vaulttango id = "vaulttango" suffix = "vaulttango.dmm" - name = "ARBORLINK Vault Tango" + name = "Space-Ruin ARBORLINK Vault Tango" description = "Nanotrasen isn't the only corporation experimenting in advanced bluespace technology." /datum/map_template/ruin/space/nova/friendship id = "friendship" suffix = "wreckedfriendship.dmm" - name = "NTSS Friendship" + name = "Space-Ruin NTSS Friendship" description = "120 people.. one ship. It's unsurprising." /datum/map_template/ruin/space/nova/homestead id = "homestead" suffix = "wreckedhomestead.dmm" - name = "NTSS Homestead" + name = "Space-Ruin NTSS Homestead" description = "A wrecked ship." -/datum/map_template/ruin/space/nova/medieval1 - id = "medieval1" - suffix = "medieval1.dmm" - name = "Medieval 1" - description = "A forgotten peice of history left overrun with a reminder of what brought its destruction" - /datum/map_template/ruin/space/nova/cargodiselost id = "CargodiseLost" suffix = "cargodiselost.dmm" - name = "Cargodise Lost" + name = "Space-Ruin Cargodise Lost" description = "A small crew of freight-haulers are marooned in space after pirates knock out their engines. They must survive off of the cargo on board their ship and fend off the pirate boarders on their ship." /datum/map_template/ruin/space/nova/infestedntship + id = "scrapheap" suffix = "scrapheap.dmm" - name = "NT Research Vessel" + name = "Space-Ruin NT Research Vessel" description = "A zombie-infested NT ship, seemingly dedicated to medical research." /datum/map_template/ruin/space/nova/piratefort + id = "piratefort" suffix = "piratefort.dmm" - name = "Pirate Fort" + name = "Space-Ruin Pirate Fort" description = "A pirate hideout in deep space." /datum/map_template/ruin/space/nova/syndibase + id = "syndibase" suffix = "syndibase.dmm" - name = "Syndicate Outpost" + name = "Space-Ruin Syndicate Outpost" description = "A Syndicate research outpost in deep space." /datum/map_template/ruin/space/nova/crash + id = "crash" suffix = "crash.dmm" - name = "Crashed Boat" + name = "Space-Ruin Crashed Boat" description = "A small ferry crashed into an asteroid." /datum/map_template/ruin/space/nova/shuttlescrap + id = "shuttlescrap" suffix = "shuttlescrap.dmm" - name = "Broken Shuttle" + name = "Space-Ruin Broken Shuttle" description = "A small shuttle that clearly got clipped by something." -/datum/map_template/ruin/space/nova/gorilla - suffix = "gorilla.dmm" - name = "Gorilla" - description = "There is no need to be upset." - /datum/map_template/ruin/space/nova/escapefromtarkon - suffix = "port_tarkon.dmm" - name = "Port Tarkon" id = "escapefromtarkon" + suffix = "port_tarkon.dmm" + name = "Space-Ruin Port Tarkon" description = "An ambitious goal, A step forward, A trial run for the Tarkon drill, ment to implant mining stations within meteors. Decades of disaster have, however, left this one... Unattended for far too long." always_place = TRUE diff --git a/modular_nova/modules/modular_items/code/necklace.dm b/modular_nova/modules/modular_items/code/necklace.dm index 4e87508dd4f..b64cbcceed2 100644 --- a/modular_nova/modules/modular_items/code/necklace.dm +++ b/modular_nova/modules/modular_items/code/necklace.dm @@ -1,10 +1,6 @@ -//DEFAULT NECK ITEMS OVERRIDE// -/obj/item/clothing/neck - w_class = WEIGHT_CLASS_SMALL - -//ASHWALKER TRANSLATOR NECKLACE// +//TRANSLATOR NECKLACE// #define LANGUAGE_TRANSLATOR "translator" -/obj/item/clothing/neck/necklace/ashwalker +/obj/item/clothing/neck/necklace/translator/ name = "ashen necklace" desc = "A necklace crafted from ash, connected to the Necropolis through the core of a Legion. This imbues overdwellers with an unnatural understanding of Ashtongue, the native language of Lavaland, while worn." icon = 'modular_nova/master_files/icons/obj/clothing/neck.dmi' @@ -12,23 +8,49 @@ worn_icon = 'modular_nova/master_files/icons/mob/clothing/neck.dmi' icon_state = "ashnecklace" w_class = WEIGHT_CLASS_SMALL //allows this to fit inside of pockets. + /// The language granted by this necklace + var/datum/language/language_granted = /datum/language/ashtongue + /// Where the power comes from + var/power_source = "the Necropolis" + /// Whether or not to display the message upon equipping/unequipping + var/silent -//uses code from the pirate hat. -/obj/item/clothing/neck/necklace/ashwalker/equipped(mob/user, slot) +/obj/item/clothing/neck/necklace/translator/Initialize(mapload) . = ..() - if(!ishuman(user)) + RegisterSignal(src, COMSIG_ITEM_EQUIPPED, PROC_REF(on_necklace_equip)) + +/obj/item/clothing/neck/necklace/translator/proc/on_necklace_equip(datum/source, mob/living/carbon/human/equipper, slot) + SIGNAL_HANDLER + + if(!(slot & ITEM_SLOT_NECK)) return - if(slot & ITEM_SLOT_NECK) - user.grant_language(/datum/language/ashtongue/, source = LANGUAGE_TRANSLATOR) - to_chat(user, span_boldnotice("Slipping the necklace on, you feel the insidious creep of the Necropolis enter your bones, and your very shadow. You find yourself with an unnatural knowledge of Ashtongue; but the amulet's eye stares at you.")) -/obj/item/clothing/neck/necklace/ashwalker/dropped(mob/user) - . = ..() - if(!ishuman(user)) + if(!istype(equipper)) return - var/mob/living/carbon/human/H = user - if(H.get_item_by_slot(ITEM_SLOT_NECK) == src && !QDELETED(src)) //This can be called as a part of destroy - user.remove_language(/datum/language/ashtongue/, source = LANGUAGE_TRANSLATOR) - to_chat(user, span_boldnotice("You feel the alien mind of the Necropolis lose its interest in you as you remove the necklace. The eye closes, and your mind does as well, losing its grasp of Ashtongue.")) -//ASHWALKER TRANSLATOR NECKLACE END// + equipper.grant_language(language_granted, source = LANGUAGE_TRANSLATOR) + RegisterSignal(src, COMSIG_ITEM_DROPPED, PROC_REF(on_necklace_unequip)) + + if(!silent) + to_chat(equipper, span_boldnotice("Slipping the necklace on, you feel the insidious creep of [power_source] enter your bones, your very shadow and soul. You find yourself with an unnatural knowledge of the [initial(language_granted.name)]; but the amulet's eye stares back at you with a gleeful intent. Causing you to shiver with unease, you don't want to keep this on forever.")) + +/obj/item/clothing/neck/necklace/translator/proc/on_necklace_unequip(obj/item/source, mob/living/carbon/human/unequipper) + SIGNAL_HANDLER + + if(!istype(unequipper)) + return + + if(unequipper.wear_neck != source) + return + + unequipper.remove_language(language_granted, source = LANGUAGE_TRANSLATOR) + UnregisterSignal(source, COMSIG_ITEM_DROPPED) + + if(!silent) + to_chat(unequipper, span_boldnotice("You feel the alien mind of [power_source] lose its interest in you as you remove the necklace. The eye closes, and your mind does as well, losing its grasp of [initial(language_granted.name)]")) + +/obj/item/clothing/neck/necklace/translator/hearthkin + name = "gemmed necklace" + desc = "A necklace crafted from a gem found in the frozen wastes. This imbues overdwellers with an unnatural understanding of the Hearthkin while worn." + language_granted = /datum/language/siiktajr + power_source = "a dark nature" diff --git a/modular_nova/modules/roleplay_do/code/do_checks.dm b/modular_nova/modules/roleplay_do/code/do_checks.dm new file mode 100644 index 00000000000..cab5717df4c --- /dev/null +++ b/modular_nova/modules/roleplay_do/code/do_checks.dm @@ -0,0 +1,20 @@ +/mob/living/proc/doverb_checks(message) + if(!length(message)) + return FALSE + + if(GLOB.say_disabled) //This is here to try to identify lag problems + to_chat(usr, span_danger("Speech is currently admin-disabled.")) + return FALSE + + //quickly calc our name stub again: duplicate this in say.dm override + var/name_stub = " ([usr])" + if(length(message) > (MAX_MESSAGE_LEN - length(name_stub))) + to_chat(usr, message) + to_chat(usr, span_warning("^^^----- The preceding message has been DISCARDED for being over the maximum length of [MAX_MESSAGE_LEN]. It has NOT been sent! -----^^^")) + return FALSE + + if(usr.stat != CONSCIOUS) + to_chat(usr, span_notice("You cannot send a Do in your current condition.")) + return FALSE + + return TRUE diff --git a/modular_nova/modules/roleplay_do/code/do_verbs.dm b/modular_nova/modules/roleplay_do/code/do_verbs.dm new file mode 100644 index 00000000000..9af9dd974b8 --- /dev/null +++ b/modular_nova/modules/roleplay_do/code/do_verbs.dm @@ -0,0 +1,48 @@ +/mob/verb/do_verb(message as message) + set name = "Do" + set category = "IC" + set instant = TRUE + + if(GLOB.say_disabled) + to_chat(usr, span_danger("Speech is currently admin-disabled.")) + return + + if(message) + QUEUE_OR_CALL_VERB_FOR(VERB_CALLBACK(src, TYPE_VERB_REF(/mob/living, do_actual_verb), message), SSspeech_controller) + +/mob/living/verb/do_actual_verb(message as message) + if (!message || !doverb_checks(message)) + return + + if (!try_speak(message)) // ensure we pass the vibe check (filters, etc) + return + + var/name_stub = " ([usr])" + message = usr.say_emphasis(message) + message = trim(copytext_char(message, 1, (MAX_MESSAGE_LEN - length(name_stub)))) + var/message_with_name = message + name_stub + + usr.log_message(message, LOG_EMOTE) + + var/list/viewers = get_hearers_in_view(DEFAULT_MESSAGE_RANGE, usr) + + if(istype(usr, /mob/living/silicon/ai)) + var/mob/living/silicon/ai/ai = usr + viewers = get_hearers_in_view(DEFAULT_MESSAGE_RANGE, ai.eyeobj) + + var/obj/effect/overlay/holo_pad_hologram/hologram = GLOB.hologram_impersonators[usr] + if(hologram) + viewers |= get_hearers_in_view(1, hologram) + + for(var/mob/living/silicon/ai/ai as anything in GLOB.ai_list) + if(ai.client && !(ai in viewers) && (ai.eyeobj in viewers)) + viewers += ai + + for(var/mob/ghost as anything in GLOB.dead_mob_list) + if((ghost.client?.prefs.chat_toggles & CHAT_GHOSTSIGHT) && !(ghost in viewers)) + ghost.show_message(span_emote(message_with_name)) + + for(var/mob/reciever in viewers) + reciever.show_message(span_emote(message_with_name), alt_msg = span_emote(message_with_name)) + if (reciever.client?.prefs.read_preference(/datum/preference/toggle/enable_runechat)) + create_chat_message(usr, null, message, null, EMOTE_MESSAGE) diff --git a/modular_nova/modules/telepathy_quirk/code/telepathy_action.dm b/modular_nova/modules/telepathy_quirk/code/telepathy_action.dm new file mode 100644 index 00000000000..e2ab3ef5e32 --- /dev/null +++ b/modular_nova/modules/telepathy_quirk/code/telepathy_action.dm @@ -0,0 +1,125 @@ +/datum/mutation/human/telepathy + power_path = /datum/action/cooldown/spell/pointed/telepathy + +/datum/action/cooldown/spell/pointed/telepathy + name = "Telepathic Communication" + desc = "Left click: point target to project a thought to them. Right click: project to your last thought target, if in range." + button_icon = 'icons/mob/actions/actions_revenant.dmi' + button_icon_state = "r_transmit" + spell_requirements = SPELL_REQUIRES_NO_ANTIMAGIC + antimagic_flags = MAGIC_RESISTANCE_MIND + cooldown_time = 1 SECONDS + cast_range = 7 + /// What's the last mob we point-targeted with this ability? + var/datum/weakref/last_target_ref + /// The message we send + var/message + /// Are we blocking casts? + var/blocked = FALSE + +/datum/action/cooldown/spell/pointed/telepathy/is_valid_target(atom/cast_on) + . = ..() + if (!.) + return FALSE + + if (!isliving(cast_on)) + to_chat(owner, span_warning("Inanimate objects can't hear your thoughts.")) + owner.balloon_alert(owner, "not a thing with thoughts!") + return FALSE + + var/mob/living/living_target = cast_on + if (living_target.stat == DEAD) + to_chat(owner, span_warning("The disruptive noise of departed resonance inhibits your ability to communicate with the dead.")) + owner.balloon_alert(owner, "can't transmit to the dead!") + return FALSE + + if (get_dist(living_target, owner) > cast_range) + owner.balloon_alert(owner, "too far away!") + return FALSE + + return TRUE + +/datum/action/cooldown/spell/pointed/telepathy/before_cast(atom/cast_on) + . = ..() + if(. & SPELL_CANCEL_CAST || blocked) + return + + message = autopunct_bare(capitalize(tgui_input_text(owner, "What do you wish to whisper to [cast_on]?", "[src]"))) + if(QDELETED(src) || QDELETED(owner) || QDELETED(cast_on) || !can_cast_spell()) + return . | SPELL_CANCEL_CAST + + if(get_dist(cast_on, owner) > cast_range) + owner.balloon_alert(owner, "they're too far!") + return . | SPELL_CANCEL_CAST + + if(!message) + reset_spell_cooldown() + return . | SPELL_CANCEL_CAST + +/datum/action/cooldown/spell/pointed/telepathy/Trigger(trigger_flags, atom/target) + if (trigger_flags & TRIGGER_SECONDARY_ACTION) + var/mob/living/last_target = last_target_ref?.resolve() + + if(isnull(last_target)) + last_target_ref = null + owner.balloon_alert(owner, "last target is not available!") + return + else if(get_dist(last_target, owner) > cast_range) + owner.balloon_alert(owner, "[last_target] is too far away!") + return + + blocked = TRUE + + message = autopunct_bare(capitalize(tgui_input_text(owner, "What do you wish to whisper to [last_target]?", "[src]"))) + if(QDELETED(src) || QDELETED(owner) || QDELETED(last_target) || !can_cast_spell()) + blocked = FALSE + return + send_thought(owner, last_target, message) + src.StartCooldown() + blocked = FALSE + return + + . = ..() + +/datum/action/cooldown/spell/pointed/telepathy/cast(mob/living/cast_on) + . = ..() + send_thought(owner, cast_on, message) + +/datum/action/cooldown/spell/pointed/telepathy/proc/send_thought(mob/living/caster, mob/living/target, message) + log_directed_talk(caster, target, message, LOG_SAY, tag = "telepathy") + + last_target_ref = WEAKREF(target) + + to_chat(owner, span_boldnotice("You reach out and convey to [target]: \"[span_purple(message)]\"")) + // flub a runechat chat message, do something with the language later + if(owner.client?.prefs.read_preference(/datum/preference/toggle/enable_runechat)) + owner.create_chat_message(owner, owner.get_selected_language(), message, list("italics")) + if(!target.can_block_magic(antimagic_flags, charge_cost = 0) && target.client) //make sure we've got a client before we bother sending anything + //different messaging if the target has the telepathy mutation themselves themselves + if (ishuman(target)) + var/mob/living/carbon/human/human_target = target + var/datum/mutation/human/telepathy/tele_mut = human_target.dna.get_mutation(/datum/mutation/human/telepathy) + + if (tele_mut) + to_chat(target, span_boldnotice("[caster]'s psychic presence resounds in your mind: \"[span_purple(message)]\"")) + else + to_chat(target, span_boldnotice("A voice echoes in your head: \"[span_purple(message)]\"")) + + if(target.client?.prefs.read_preference(/datum/preference/toggle/enable_runechat)) + target.create_chat_message(target, target.get_selected_language(), message, list("italics")) // it appears over them since they hear it in their head + else + owner.balloon_alert(owner, "something blocks your thoughts!") + to_chat(owner, span_warning("Your mind encounters impassable resistance: the thought was blocked!")) + return + + // send to ghosts as well i guess + for(var/mob/dead/ghost as anything in GLOB.dead_mob_list) + if(!isobserver(ghost)) + continue + + var/from_link = FOLLOW_LINK(ghost, owner) + var/from_mob_name = span_boldnotice("[owner]") + var/to_link = FOLLOW_LINK(ghost, target) + var/to_mob_name = span_name("[target]") + + to_chat(ghost, "[from_link] " + span_purple("\[Telepathy\] [from_mob_name] transmits, \"[message]\"") + " to [to_mob_name] [to_link]") diff --git a/modular_nova/modules/telepathy_quirk/code/telepathy_quirk.dm b/modular_nova/modules/telepathy_quirk/code/telepathy_quirk.dm new file mode 100644 index 00000000000..5cbcfb275f6 --- /dev/null +++ b/modular_nova/modules/telepathy_quirk/code/telepathy_quirk.dm @@ -0,0 +1,34 @@ +/datum/quirk/telepathic + name = "Telepathic" + desc = "You are able to transmit your thoughts to other living creatures." + gain_text = span_purple("Your mind roils with psychic energy.") + lose_text = span_notice("Mundanity encroaches upon your thoughts once again.") + medical_record_text = "Patient has an unusually enlarged Broca's area visible in cerebral biology, and appears to be able to communicate via extrasensory means." + value = 0 + icon = FA_ICON_HEAD_SIDE_COUGH + /// Ref used to easily retrieve the action used when removing the quirk from silicons + var/datum/weakref/tele_action_ref + +/datum/quirk/telepathic/add(client/client_source) + if (iscarbon(quirk_holder)) + var/mob/living/carbon/human/human_holder = quirk_holder + + if (!human_holder.dna.activate_mutation(/datum/mutation/human/telepathy)) + human_holder.dna.add_mutation(/datum/mutation/human/telepathy, MUT_OTHER) + else if (issilicon(quirk_holder)) + var/mob/living/silicon/robot_holder = quirk_holder + var/datum/action/cooldown/spell/pointed/telepathy/tele_action = new + + tele_action.Grant(robot_holder) + tele_action_ref = WEAKREF(tele_action) + +/datum/quirk/telepathic/remove() + var/datum/action/cooldown/spell/pointed/telepathy/tele_action = tele_action_ref?.resolve() + if (isnull(tele_action)) + tele_action_ref = null + if (iscarbon(quirk_holder)) + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.dna.remove_mutation(/datum/mutation/human/telepathy) + else if (issilicon(quirk_holder) && !isnull(tele_action)) + QDEL_NULL(tele_action) + tele_action_ref = null diff --git a/modular_nova/modules/telepathy_quirk/code/telepathy_reply_emote.dm b/modular_nova/modules/telepathy_quirk/code/telepathy_reply_emote.dm new file mode 100644 index 00000000000..adf5e672599 --- /dev/null +++ b/modular_nova/modules/telepathy_quirk/code/telepathy_reply_emote.dm @@ -0,0 +1,17 @@ +/datum/emote/living/telepathy_reply + key = "treply" + key_third_person = "treply" + cooldown = 4 SECONDS + +/datum/emote/living/telepathy_reply/run_emote(mob/living/user, params, type_override, intentional) + if (ishuman(user) && intentional) + var/mob/living/carbon/human/human_user = user + var/datum/mutation/human/telepathy/mutation = human_user.dna.get_mutation(/datum/mutation/human/telepathy) + if (mutation) + var/datum/action/cooldown/spell/pointed/telepathy/tele_action = locate() in user.actions + // just straight up call the right-click action as is + if (tele_action) + tele_action.Trigger(TRIGGER_SECONDARY_ACTION) + tele_action.blocked = FALSE + + return ..() diff --git a/modular_nova/modules/underworld_connections/code/black_market_uplink.dm b/modular_nova/modules/underworld_connections/code/black_market_uplink.dm new file mode 100644 index 00000000000..42a060cca60 --- /dev/null +++ b/modular_nova/modules/underworld_connections/code/black_market_uplink.dm @@ -0,0 +1,2 @@ +/obj/item/market_uplink + w_class = WEIGHT_CLASS_SMALL diff --git a/modular_nova/modules/underworld_connections/code/markets/base_black_market.dm b/modular_nova/modules/underworld_connections/code/markets/base_black_market.dm new file mode 100644 index 00000000000..9b13c31b9bf --- /dev/null +++ b/modular_nova/modules/underworld_connections/code/markets/base_black_market.dm @@ -0,0 +1,222 @@ +// This file contains a WHOLE BUNCH of cost defuckulations to bring the ancient black market stuff back into line with our current cargo pricing. +// I've also taken the liberty of redoing a few descs because man they kinda suck. +// Some availability_probs have been upped considerably for items that I think should be core to the "dodgy" character archetype, like switchblades, science goggles and the various maintenance pills. + +// CLOTHING + +/datum/market_item/clothing/ninja_mask + price_min = PAYCHECK_CREW + price_max = PAYCHECK_CREW * 3 + +/datum/market_item/clothing/durathread_vest + desc = "Concerns about high asbestos content are completely unfounded. Note: may contain asbestos." + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW * 1.5 + +/datum/market_item/clothing/durathread_helmet + desc = "Smells faintly like an icewalker. Weird. Goes on your head and is vaguely armoured. Note: may contain asbestos." + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW * 1.5 + +/datum/market_item/clothing/full_spacesuit_set + desc = "Decommissioned thirty years ago, boxes of these ancient spaceproof relics keep showing up in warehouses somewhere. They're \"old style\"." + price_min = PAYCHECK_CREW * 6 + price_max = PAYCHECK_CREW * 12 + +/datum/market_item/clothing/chameleon_hat + desc = "Emulate the appearance of any hat in the sector! Warning: device not quality tested. \[REDACTED\] assumes no risk for malfunction or mortal injury." + price_min = PAYCHECK_CREW + price_max = PAYCHECK_CREW * 3 + +/datum/market_item/clothing/rocket_boots + price_min = PAYCHECK_CREW * 6 + price_max = PAYCHECK_CREW * 12 + +/datum/market_item/clothing/anti_sec_pin + price_min = PAYCHECK_CREW + price_max = PAYCHECK_CREW * 3 + availability_prob = 100 //it's funny so why not + +// CONSUMABLES +/datum/market_item/consumable/clown_tears + desc = "Wrung by force from ethically-sourced clowns by your local jester. 100% guaranteed baton free." + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW * 1.5 + +/datum/market_item/consumable/donk_pocket_box + price_min = PAYCHECK_CREW * 0.3 + price_max = PAYCHECK_CREW * 1 + availability_prob = 100 //you can always afford some (illegal) donkpockets. Donk Co loves you. + +/datum/market_item/consumable/suspicious_pills + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW * 1.5 + +/datum/market_item/consumable/floor_pill + desc = "Harvested daily by responsibly-paid assistants, this pill is guaranteed to a) have been on the floor, and b) is a pill. Good luck!" + price_min = PAYCHECK_CREW * 0.1 + price_max = PAYCHECK_CREW * 0.3 + availability_prob = 100 // no shortage of unmarked pills babyyyy + +/datum/market_item/consumable/pumpup + desc = "Clean-up crews sell off these things by the dozen after every shift - get your hands on some today! What could possibly go wrong with maintenance drugs?" + price_min = PAYCHECK_CREW * 0.2 + price_max = PAYCHECK_CREW * 0.4 + +// MISCELLANEOUS + +/datum/market_item/misc/Clear_PDA + desc = "Clearly show your appreciation for style with this limited edition clear PDA!" + price_min = PAYCHECK_CREW + price_max = PAYCHECK_CREW * 2 + +/datum/market_item/misc/jade_Lantern + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW + +/datum/market_item/misc/cap_gun + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW + +/datum/market_item/misc/shoulder_holster + name = "Shoulder Holster" + //why in great googly moogly were these so expensive? what the fuck? + price_min = PAYCHECK_CREW * 0.2 + price_max = PAYCHECK_CREW * 0.6 + +/datum/market_item/misc/donk_recycler + price_min = PAYCHECK_CREW * 2 + price_max = PAYCHECK_CREW * 4 + +/datum/market_item/misc/shove_blocker + // ok this is a seriously fucking good module so we'll make it cost a bit + price_min = PAYCHECK_CREW * 8 + price_max = PAYCHECK_CREW * 14 + +/datum/market_item/misc/holywater + desc = "The Spinward Independent Magicians assume no responsibility for the holy (or unholiness) of this magical reagent." + price_min = PAYCHECK_CREW + price_max = PAYCHECK_CREW * 3 + +/datum/market_item/misc/strange_seed + desc = "Exotic varieties of seed outlawed in most sectors, including this one. What's the worst that could happen?" + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW + +/datum/market_item/misc/smugglers_satchel + //inventory gamers... + price_min = PAYCHECK_CREW * 3 + price_max = PAYCHECK_CREW * 6 + +/datum/market_item/misc/roulette + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW * 6 // it's how the chips fall babyyy + +/datum/market_item/misc/jawed_hook + desc = "If you're struggling with the fishes, give 'em the jaws, see?" + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW * 1.5 + +/datum/market_item/misc/v8_engine + name = "Genuine V8 Engine (Preserved)" + price_min = PAYCHECK_CREW * 6 + price_max = PAYCHECK_CREW * 12 + +/datum/market_item/misc/fish + name = "Case of Smuggled Fish" + desc = "What makes these fish such hot products? We'd have to kill you if we told you." + +/datum/market_item/misc/giant_wrench_parts + name = "Comically-Large Wrench Parts" + desc = "They're searching every broadband transmission for the name of this wrench, alright? You're mad if you assemble this thing. Mad, we tell you." + price_min = PAYCHECK_CREW * 4 + price_max = PAYCHECK_CREW * 8 + +// TOOLS +/datum/market_item/tool/caravan_wrench + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW * 2 + availability_prob = 100 // let's have all the experimental tools be always available, because why not? + +/datum/market_item/tool/caravan_wirecutters + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW * 2 + availability_prob = 100 + +/datum/market_item/tool/caravan_screwdriver + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW * 2 + availability_prob = 100 + +/datum/market_item/tool/caravan_crowbar + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW * 2 + availability_prob = 100 + +/datum/market_item/tool/binoculars + //we can roundstart with these so let's tone them way down + desc = "Offworld military surplus. They'll never see you coming." + price_min = PAYCHECK_CREW * 0.2 + price_max = PAYCHECK_CREW * 0.5 + +/datum/market_item/tool/riot_shield + desc = "Bloodstains not included." + price_min = PAYCHECK_CREW * 4 + price_max = PAYCHECK_CREW * 8 + +/datum/market_item/tool/thermite_bottle + desc = "Thirty galactic units of an incendiary compound that will burn through just about anything." + price_min = PAYCHECK_CREW * 2 + price_max = PAYCHECK_CREW * 6 + +/datum/market_item/tool/science_goggles + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW * 2 + availability_prob = 100 // for people who want to make illicit drugs in maint + +/datum/market_item/tool/fake_scanner + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW * 2 + +/datum/market_item/tool/program_disk + name = "Bootleg PDA Data Disk" + desc = "Contains a random selection of limited PDA programs purloined by bitrunners from the FTU. Wait, we're not supposed to tell you that." + price_min = PAYCHECK_CREW * 1.5 + price_max = PAYCHECK_CREW * 3 + availability_prob = 100 // not every program is useful but some of these are and they're fun and hackery, so why not? + +// WEAPONS + +/datum/market_item/weapon/bear_trap + price_min = PAYCHECK_CREW * 2 + price_max = PAYCHECK_CREW * 4 + +/datum/market_item/weapon/shotgun_dart + price_min = PAYCHECK_CREW * 0.1 + price_max = PAYCHECK_CREW * 0.3 + +/datum/market_item/weapon/bone_spear + price_min = PAYCHECK_CREW * 0.5 + price_max = PAYCHECK_CREW * 2 + +/datum/market_item/weapon/chainsaw + desc = "Once used to fell trees on Gaia worlds, the humble chainsaw has come into its own as the premiere anti-mold device of the sector. And you can have one right now for one easy payment!" + price_min = PAYCHECK_CREW * 2 + price_max = PAYCHECK_CREW * 4 + availability_prob = 75 // USE CHAINSAWS FOR MOLDS MORE OH MY GOD + +/datum/market_item/weapon/switchblade + // This is force 20 like the sabre/shamshir so price it similarly. Also, make it always available so you can shank people in maints. + desc = "Standard-issue hardware for shifty goons sector-wide. Pointy and sharp." + price_min = PAYCHECK_CREW * 4.25 + price_max = PAYCHECK_CREW * 8 + availability_prob = 100 + +/datum/market_item/weapon/emp_grenade + desc = "The bane of synthetics and station-engineers everywhere." + price_min = PAYCHECK_CREW * 1.5 + price_max = PAYCHECK_CREW * 5 + +/datum/market_item/weapon/fisher + price_min = PAYCHECK_CREW * 4 + price_max = PAYCHECK_CREW * 8 diff --git a/modular_nova/modules/underworld_connections/code/underworld_connections_quirk.dm b/modular_nova/modules/underworld_connections/code/underworld_connections_quirk.dm new file mode 100644 index 00000000000..f3d78d7df45 --- /dev/null +++ b/modular_nova/modules/underworld_connections/code/underworld_connections_quirk.dm @@ -0,0 +1,147 @@ +/datum/quirk/item_quirk/underworld_connections + name = "Underworld Connections" + desc = "You're in with the seedier elements of the galactic underworld, and can start with a customizable black market uplink, and access to information brokers with exploitable information about the crew. Security has suspicions about you, and you may struggle to obtain a weapons permit." + icon = FA_ICON_SUITCASE + value = 0 + gain_text = span_notice("Your contacts to the underworld are close at hand.") + lose_text = span_notice("Your contacts to the underworld have gone quiet.") + medical_record_text = "Patient records may have been tampered with in the past." + quirk_flags = QUIRK_HIDE_FROM_SCAN + mail_goodies = list(/obj/item/storage/briefcase/secure) + +/datum/quirk/item_quirk/underworld_connections/add_unique(client/client_source) + if (ishuman(quirk_holder)) + var/obj/item/market_uplink/blackmarket/roundstart_uplink = new + + //customize the goddamn uplink + var/uplink_skin = client_source?.prefs.read_preference(/datum/preference/choiced/uplink_skin) + var/list/uplink_skin_val = GLOB.possible_uplink_skins[uplink_skin] + if (uplink_skin_val) + roundstart_uplink.icon = uplink_skin_val[1] + roundstart_uplink.icon_state = uplink_skin_val[2] + + var/uplink_name = client_source?.prefs.read_preference(/datum/preference/text/uplink_name) + if (uplink_name) + roundstart_uplink.name = uplink_name + + var/uplink_desc = client_source?.prefs.read_preference(/datum/preference/text/uplink_desc) + if (uplink_desc) + roundstart_uplink.desc = uplink_desc + + give_item_to_holder( + roundstart_uplink, + 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/underworld_connections/post_add() + . = ..() + + // Make sure we've got a client/mind first (hence, post_add), then give us exploitables access + quirk_holder.mind.has_exploitables_override = TRUE + quirk_holder.mind.handle_exploitables() + + // Also let the user know that they need to OPFOR if they want to do heavy antagonism. Policy request. + to_chat(quirk_holder, span_boldwarning("REMEMBER: The Underworld Connections quirk does NOT make you an antagonist. Please make an OPFOR request if you intend to do serious criminal activity.")) + + // Set us as 'suspected' on HUDs at roundstart and leave a note about our dark and mysterious past. No permits for us! If we're human. + if (ishuman(quirk_holder)) + var/mob/living/carbon/human/human_holder = quirk_holder + var/datum/record/crew/our_record = find_record(human_holder.name) + if (our_record) + our_record.wanted_status = WANTED_SUSPECT + our_record.security_note += "DO NOT ISSUE WEAPON PERMITS. Subject has suspected links to covert criminal elements." + +/datum/quirk/item_quirk/underworld_connections/remove() + if (ishuman(quirk_holder)) + var/mob/living/carbon/human/human_holder = quirk_holder + var/datum/record/crew/our_record = find_record(human_holder.name) + if (our_record.security_note) + our_record.security_note = replacetext(our_record.security_note, "DO NOT ISSUE WEAPON PERMITS. Subject has suspected links to covert criminal elements.", "") + if (!length(our_record.security_note)) // that was the only thing in the notes + our_record.security_note = null + if (isnull(our_record.security_note) && our_record.wanted_status == WANTED_SUSPECT) // only clear this if the security notes contain nothing but the quirk-generated note, just to be certain we are not accidentally resetting the wanted status for an unrelated crime + our_record.wanted_status = WANTED_NONE + + quirk_holder.mind.has_exploitables_override = FALSE + quirk_holder.mind.handle_exploitables() + +/datum/quirk_constant_data/underworld_connections + associated_typepath = /datum/quirk/item_quirk/underworld_connections + customization_options = list(/datum/preference/choiced/uplink_skin, /datum/preference/text/uplink_name, /datum/preference/text/uplink_desc) + +/datum/preference/choiced/uplink_skin + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "underworld_uplink_skin" + savefile_identifier = PREFERENCE_CHARACTER + can_randomize = FALSE + +/// List of uplink skins, associated list where the value is a list containing icon dmi and then icon_state +GLOBAL_LIST_INIT(possible_uplink_skins, list( + "Brick Phone" = list('icons/obj/antags/gang/cell_phone.dmi', "phone_off"), + "Default Black Market Uplink" = list('icons/obj/blackmarket.dmi', "uplink"), + "Generic Radio" = list('icons/obj/devices/voice.dmi', "radio"), + "Green Walkie Talkie" = list('icons/obj/devices/voice.dmi', "walkietalkie"), + "Inconspicious PDA" = list('icons/obj/modular_pda.dmi', "pda"), + "Mining Radio" = list('icons/obj/miningradio.dmi', "miningradio"), + "Red Analogue Phone" = list('icons/obj/devices/voice.dmi', "red_phone"), + "Red Walkie Talkie" = list('icons/obj/devices/voice.dmi', "nukietalkie"), + "Syndicate Suspicious Phone" = list('icons/obj/antags/syndicate_tools.dmi', "suspiciousphone"), + "Syndicate Tablet (Silicon)" = list('icons/obj/modular_pda.dmi', "tablet-silicon-syndicate"), +)) + +/datum/preference/choiced/uplink_skin/init_possible_values() + return assoc_to_keys(GLOB.possible_uplink_skins) + +/datum/preference/choiced/uplink_skin/create_default_value() + return "Default Black Market Uplink" + +/datum/preference/choiced/uplink_skin/is_accessible(datum/preferences/preferences) + if (!..()) + return FALSE + + return "Underworld Connections" in preferences.all_quirks + +/datum/preference/choiced/uplink_skin/apply_to_human(mob/living/carbon/human/target, value) + return + +/datum/preference/text/uplink_name + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "underworld_uplink_name" + savefile_identifier = PREFERENCE_CHARACTER + can_randomize = FALSE + maximum_value_length = 32 + +/datum/preference/text/uplink_name/is_accessible(datum/preferences/preferences) + if (!..()) + return FALSE + + return "Underworld Connections" in preferences.all_quirks + +/datum/preference/text/uplink_name/serialize(input) + return htmlrendertext(input) + +/datum/preference/text/uplink_name/apply_to_human(mob/living/carbon/human/target, value) + return + +/datum/preference/text/uplink_desc + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "underworld_uplink_desc" + savefile_identifier = PREFERENCE_CHARACTER + can_randomize = FALSE + +/datum/preference/text/uplink_desc/is_accessible(datum/preferences/preferences) + if (!..()) + return FALSE + + return "Underworld Connections" in preferences.all_quirks + +/datum/preference/text/uplink_desc/serialize(input) + return htmlrendertext(input) + +/datum/preference/text/uplink_desc/apply_to_human(mob/living/carbon/human/target, value) + return diff --git a/modular_nova/modules/xenoarch/code/modules/research/xenoarch/xenoarch_reward.dm b/modular_nova/modules/xenoarch/code/modules/research/xenoarch/xenoarch_reward.dm index 037d1949327..2bfb3102c66 100644 --- a/modular_nova/modules/xenoarch/code/modules/research/xenoarch/xenoarch_reward.dm +++ b/modular_nova/modules/xenoarch/code/modules/research/xenoarch/xenoarch_reward.dm @@ -67,7 +67,8 @@ GLOBAL_LIST_INIT(clothing_reward, list( /obj/item/clothing/under/costume/gladiator/ash_walker/robe = 1, /obj/item/clothing/under/costume/gladiator/ash_walker/tribal = 1, /obj/item/clothing/under/costume/gladiator/ash_walker/white = 1, - /obj/item/clothing/neck/necklace/ashwalker = 1, + /obj/item/clothing/neck/necklace/translator = 1, + /obj/item/clothing/neck/necklace/translator/hearthkin = 1, /obj/item/clothing/head/helmet/gladiator = 1, /obj/item/clothing/under/costume/gladiator/ash_walker = 1, )) diff --git a/tgstation.dme b/tgstation.dme index 1c340f63dac..8e80cbb8e44 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2056,6 +2056,7 @@ #include "code\game\machinery\launch_pad.dm" #include "code\game\machinery\lightswitch.dm" #include "code\game\machinery\limbgrower.dm" +#include "code\game\machinery\machine_frame.dm" #include "code\game\machinery\mass_driver.dm" #include "code\game\machinery\mechlaunchpad.dm" #include "code\game\machinery\medical_kiosk.dm" @@ -2098,7 +2099,6 @@ #include "code\game\machinery\computer\accounting.dm" #include "code\game\machinery\computer\aifixer.dm" #include "code\game\machinery\computer\apc_control.dm" -#include "code\game\machinery\computer\arena.dm" #include "code\game\machinery\computer\atmos_alert.dm" #include "code\game\machinery\computer\buildandrepair.dm" #include "code\game\machinery\computer\camera.dm" @@ -6393,6 +6393,7 @@ #include "modular_nova\master_files\code\modules\clothing\head\cowboy.dm" #include "modular_nova\master_files\code\modules\clothing\head\monkey_magnification_helmet.dm" #include "modular_nova\master_files\code\modules\clothing\masks\_masks.dm" +#include "modular_nova\master_files\code\modules\clothing\neck\_neck.dm" #include "modular_nova\master_files\code\modules\clothing\outfits\ert.dm" #include "modular_nova\master_files\code\modules\clothing\outfits\standard.dm" #include "modular_nova\master_files\code\modules\clothing\shoes\bananashoes.dm" @@ -6422,6 +6423,8 @@ #include "modular_nova\master_files\code\modules\clothing\under\jobs\security.dm" #include "modular_nova\master_files\code\modules\clothing\under\jobs\civilian\civilian.dm" #include "modular_nova\master_files\code\modules\clothing\under\jobs\civilian\suits.dm" +#include "modular_nova\master_files\code\modules\entombed_quirk\code\entombed.dm" +#include "modular_nova\master_files\code\modules\entombed_quirk\code\entombed_mod.dm" #include "modular_nova\master_files\code\modules\events\_event.dm" #include "modular_nova\master_files\code\modules\experisci\experiment.dm" #include "modular_nova\master_files\code\modules\food_and_drinks\recipes\food_mixtures.dm" @@ -7285,7 +7288,6 @@ #include "modular_nova\modules\ghostcafe\code\ghostcafeturf.dm" #include "modular_nova\modules\ghostcafe\code\hilbertshotel_ghost.dm" #include "modular_nova\modules\ghostcafe\code\robot_ghostcafe.dm" -#include "modular_nova\modules\gladiator\code\datums\ruins\lavaland.dm" #include "modular_nova\modules\gladiator\code\game\objects\items\gladiator_items.dm" #include "modular_nova\modules\gladiator\code\modules\mob\living\simple_animal\hostile\megafauna\markedone.dm" #include "modular_nova\modules\goofsec\code\cellphone.dm" @@ -7947,6 +7949,8 @@ #include "modular_nova\modules\robot_limb_detach\code\robot_limb_detach_quirk.dm" #include "modular_nova\modules\rod-stopper\code\immovable_nova.dm" #include "modular_nova\modules\rod-stopper\code\rodstopper.dm" +#include "modular_nova\modules\roleplay_do\code\do_checks.dm" +#include "modular_nova\modules\roleplay_do\code\do_verbs.dm" #include "modular_nova\modules\roundstart_implants\code\loadout_implants.dm" #include "modular_nova\modules\roundstart_implants\code\loadout_subtypes.dm" #include "modular_nova\modules\roundstart_implants\code\tool_subtypes.dm" @@ -8065,6 +8069,9 @@ #include "modular_nova\modules\tarkon\code\misc_fluff\research.dm" #include "modular_nova\modules\tarkon\code\misc_fluff\spawner.dm" #include "modular_nova\modules\tarkon\code\misc_fluff\tools.dm" +#include "modular_nova\modules\telepathy_quirk\code\telepathy_action.dm" +#include "modular_nova\modules\telepathy_quirk\code\telepathy_quirk.dm" +#include "modular_nova\modules\telepathy_quirk\code\telepathy_reply_emote.dm" #include "modular_nova\modules\tesh_augments\code\all_nodes.dm" #include "modular_nova\modules\tesh_augments\code\limbs.dm" #include "modular_nova\modules\tesh_augments\code\mechfabricator_designs.dm" @@ -8102,6 +8109,9 @@ #include "modular_nova\modules\trim_tokens\code\cards_ids.dm" #include "modular_nova\modules\trim_tokens\code\trim_tokens.dm" #include "modular_nova\modules\turretid\code\turret_id_system.dm" +#include "modular_nova\modules\underworld_connections\code\black_market_uplink.dm" +#include "modular_nova\modules\underworld_connections\code\underworld_connections_quirk.dm" +#include "modular_nova\modules\underworld_connections\code\markets\base_black_market.dm" #include "modular_nova\modules\verbs\code\looc.dm" #include "modular_nova\modules\verbs\code\say.dm" #include "modular_nova\modules\verbs\code\subtle.dm" diff --git a/tgui/packages/tgui-say/ChannelIterator.test.ts b/tgui/packages/tgui-say/ChannelIterator.test.ts index 62743dc6e99..1f0621297ab 100644 --- a/tgui/packages/tgui-say/ChannelIterator.test.ts +++ b/tgui/packages/tgui-say/ChannelIterator.test.ts @@ -14,6 +14,7 @@ describe('ChannelIterator', () => { // NOVA EDIT ADDITION START expect(channelIterator.next()).toBe('Whis'); expect(channelIterator.next()).toBe('LOOC'); + expect(channelIterator.next()).toBe('Do'); // NOVA EDIT ADDITION END expect(channelIterator.next()).toBe('OOC'); expect(channelIterator.next()).toBe('Say'); // Admin is blacklisted so it should be skipped diff --git a/tgui/packages/tgui-say/ChannelIterator.ts b/tgui/packages/tgui-say/ChannelIterator.ts index c8ee2e1ed1a..57866808609 100644 --- a/tgui/packages/tgui-say/ChannelIterator.ts +++ b/tgui/packages/tgui-say/ChannelIterator.ts @@ -5,6 +5,7 @@ export type Channel = // NOVA EDIT ADDITION START | 'Whis' | 'LOOC' + | 'Do' // NOVA EDIT ADDITION END | 'OOC' | 'Admin'; @@ -24,6 +25,7 @@ export class ChannelIterator { // NOVA EDIT ADDITION 'Whis', 'LOOC', + 'Do', // NOVA EDIT ADDITION 'OOC', 'Admin', diff --git a/tgui/packages/tgui-say/constants/index.tsx b/tgui/packages/tgui-say/constants/index.tsx index 8502f1dba47..8095aa98583 100644 --- a/tgui/packages/tgui-say/constants/index.tsx +++ b/tgui/packages/tgui-say/constants/index.tsx @@ -5,6 +5,7 @@ export const CHANNELS = [ 'Me', 'Whis', // NOVA EDIT ADDITION - CUSTOMIZATION 'LOOC', // NOVA EDIT ADDITION - CUSTOMIZATION + 'Do', // NOVA EDIT ADDITION - Do roleplay addition 'OOC', 'Admin', ] as const; diff --git a/tgui/packages/tgui-say/styles/colors.scss b/tgui/packages/tgui-say/styles/colors.scss index 52e6153fd60..7c44da982f4 100644 --- a/tgui/packages/tgui-say/styles/colors.scss +++ b/tgui/packages/tgui-say/styles/colors.scss @@ -29,6 +29,7 @@ $_channel_map: ( 'Synd': #8f4a4b, // NOVA EDIT ADDITION 'Whis': #7c7fd9, + 'Do': #59da7e, ); $channel_keys: map.keys($_channel_map) !default; diff --git a/tgui/packages/tgui/interfaces/ChemRecipeDebug.tsx b/tgui/packages/tgui/interfaces/ChemRecipeDebug.tsx index c108966bbb7..a1c53ffb879 100644 --- a/tgui/packages/tgui/interfaces/ChemRecipeDebug.tsx +++ b/tgui/packages/tgui/interfaces/ChemRecipeDebug.tsx @@ -368,7 +368,7 @@ export const ChemRecipeDebug = (props) => { step={0.1} stepPixelSize={3} value={editReaction?.editValue || 0} - minValue={0} + minValue={-1000} maxValue={1000} disabled={editReaction === null} onDrag={(e, value) => diff --git a/tgui/packages/tgui/interfaces/CrewManifest.jsx b/tgui/packages/tgui/interfaces/CrewManifest.jsx index 0241ef5e70b..01ddb4e544f 100644 --- a/tgui/packages/tgui/interfaces/CrewManifest.jsx +++ b/tgui/packages/tgui/interfaces/CrewManifest.jsx @@ -10,12 +10,10 @@ const commandJobs = [ 'Chief Engineer', 'Research Director', 'Chief Medical Officer', - 'Quartermaster', // NOVA EDIT - 'Nanotrasen Consultant', // NOVA EDIT + 'Quartermaster', + 'Nanotrasen Consultant', // NOVA EDIT ADDITION ]; -// NOVA EDIT CHANGE BEGIN - ALTERNATIVE_JOB_TITLES -// Any instance of crewMember.trim was originally crewMember.rank export const CrewManifest = (props) => { const { data: { manifest, positions }, @@ -105,4 +103,3 @@ export const CrewManifest = (props) => { ); }; -// NOVA EDIT CHANGE END - ALTERNATIVE_JOB_TITLES diff --git a/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx b/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx index 6c1a2221a4d..2e9b8018187 100644 --- a/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx +++ b/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx @@ -44,11 +44,11 @@ type Data = { export const DeathmatchLobby = (props) => { const { act, data } = useBackend(); return ( - + - -
+ +
@@ -148,6 +148,7 @@ export const DeathmatchLobby = (props) => { {data.map.desc} + Maximum Play Time: {`${data.map.time / 600}min`}
diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/RecordTabs.tsx b/tgui/packages/tgui/interfaces/MedicalRecords/RecordTabs.tsx index 4d08c84ba0b..7aee1f276a8 100644 --- a/tgui/packages/tgui/interfaces/MedicalRecords/RecordTabs.tsx +++ b/tgui/packages/tgui/interfaces/MedicalRecords/RecordTabs.tsx @@ -89,7 +89,7 @@ const CrewTab = (props: { record: MedicalRecord }) => { const { act, data } = useBackend(); const { assigned_view } = data; const { record } = props; - const { crew_ref, name, rank } = record; + const { crew_ref, name, trim } = record; /** Sets the record to preview */ const selectRecord = (record: MedicalRecord) => { @@ -108,7 +108,7 @@ const CrewTab = (props: { record: MedicalRecord }) => { selected={selectedRecord?.crew_ref === crew_ref} > - {name} + {name} ); diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/types.ts b/tgui/packages/tgui/interfaces/MedicalRecords/types.ts index 34fc55ceb61..a80952d2525 100644 --- a/tgui/packages/tgui/interfaces/MedicalRecords/types.ts +++ b/tgui/packages/tgui/interfaces/MedicalRecords/types.ts @@ -26,6 +26,7 @@ export type MedicalRecord = { quirk_notes: string; rank: string; species: string; + trim: string; // NOVA EDIT START - RP Records past_general_records: string; past_medical_records: string; diff --git a/tgui/packages/tgui/interfaces/Newscaster.jsx b/tgui/packages/tgui/interfaces/Newscaster.jsx index 431e7d606e6..b3a30eb2bdd 100644 --- a/tgui/packages/tgui/interfaces/Newscaster.jsx +++ b/tgui/packages/tgui/interfaces/Newscaster.jsx @@ -326,9 +326,11 @@ const NewscasterWantedScreen = (props) => { ) : ( - {wanted.active - ? 'Please contact your local security officer if spotted.' - : 'No wanted issue posted. Have a secure day.'} + {wanted.map((activeWanted) => + activeWanted.active + ? 'Please contact your local security officer if spotted.' + : 'No wanted issue posted. Have a secure day.', + )} )} diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/nova/entombed.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/nova/entombed.tsx new file mode 100644 index 00000000000..48c6c63fab2 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/nova/entombed.tsx @@ -0,0 +1,38 @@ +// THIS IS A NOVA SECTOR UI FILE +import { + CheckboxInput, + Feature, + FeatureChoiced, + FeatureDropdownInput, + FeatureShortTextInput, + FeatureToggle, +} from '../../base'; + +export const entombed_skin: FeatureChoiced = { + name: 'MODsuit Skin', + component: FeatureDropdownInput, +}; + +export const entombed_mod_name: Feature = { + name: 'MODsuit Control Unit Name', + component: FeatureShortTextInput, +}; + +export const entombed_mod_desc: Feature = { + name: 'MODsuit Control Unit Description', + component: FeatureShortTextInput, +}; + +export const entombed_mod_prefix: Feature = { + name: 'MODsuit Deployed Prefix', + description: + "This is appended to any deployed pieces of MODsuit gear, like the chest, helmet, etc. The default is 'fused' - try to use an adjective, if you can.", + component: FeatureShortTextInput, +}; + +export const entombed_deploy_lock: FeatureToggle = { + name: 'MODsuit Stays Deployed (Soft DNR)', + description: + 'Prevents anyone from retracting any of your MODsuit, except your helmet. Even you. WARNING: this may make you extremely difficult to revive, and can be considered a soft DNR. Choose wisely.', + component: CheckboxInput, +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/nova/underworld_connections.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/nova/underworld_connections.tsx new file mode 100644 index 00000000000..ce2d7763ffe --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/nova/underworld_connections.tsx @@ -0,0 +1,22 @@ +// THIS IS A NOVA SECTOR UI FILE +import { + Feature, + FeatureChoiced, + FeatureDropdownInput, + FeatureShortTextInput, +} from '../../base'; + +export const underworld_uplink_skin: FeatureChoiced = { + name: 'Uplink Skin', + component: FeatureDropdownInput, +}; + +export const underworld_uplink_name: Feature = { + name: 'Uplink Name', + component: FeatureShortTextInput, +}; + +export const underworld_uplink_desc: Feature = { + name: 'Uplink Description', + component: FeatureShortTextInput, +}; diff --git a/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx b/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx index 4670d9b06b1..8132027e3e6 100644 --- a/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx +++ b/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx @@ -91,7 +91,7 @@ const CrewTab = (props: { record: SecurityRecord }) => { const { act, data } = useBackend(); const { assigned_view } = data; const { record } = props; - const { crew_ref, name, rank, wanted_status } = record; + const { crew_ref, name, trim, wanted_status } = record; /** Chooses a record */ const selectRecord = (record: SecurityRecord) => { @@ -112,7 +112,7 @@ const CrewTab = (props: { record: SecurityRecord }) => { selected={isSelected} > - {name} + {name} ); diff --git a/tgui/packages/tgui/interfaces/SecurityRecords/types.ts b/tgui/packages/tgui/interfaces/SecurityRecords/types.ts index 08f21324b50..580cbe85b71 100644 --- a/tgui/packages/tgui/interfaces/SecurityRecords/types.ts +++ b/tgui/packages/tgui/interfaces/SecurityRecords/types.ts @@ -22,6 +22,7 @@ export type SecurityRecord = { note: string; rank: string; species: string; + trim: string; wanted_status: string; voice: string; // NOVA EDIT START - RP Records