diff --git a/_maps/RandomRuins/StationRuins/Box/Engine/engine_singulo.dmm b/_maps/RandomRuins/StationRuins/Box/Engine/engine_singulo.dmm index 76cb8bb9db..402cfc73cf 100644 --- a/_maps/RandomRuins/StationRuins/Box/Engine/engine_singulo.dmm +++ b/_maps/RandomRuins/StationRuins/Box/Engine/engine_singulo.dmm @@ -735,7 +735,7 @@ /obj/machinery/atmospherics/components/unary/outlet_injector{ dir = 1 }, -/turf/open/space/basic, +/turf/open/floor/plating/airless, /area/engine/engineering) "Si" = ( /obj/structure/cable/yellow{ diff --git a/_maps/RandomRuins/StationRuins/Box/Engine/engine_tesla.dmm b/_maps/RandomRuins/StationRuins/Box/Engine/engine_tesla.dmm index 7f55d69b17..af2ba1ffd7 100644 --- a/_maps/RandomRuins/StationRuins/Box/Engine/engine_tesla.dmm +++ b/_maps/RandomRuins/StationRuins/Box/Engine/engine_tesla.dmm @@ -240,7 +240,7 @@ /obj/machinery/atmospherics/components/unary/outlet_injector{ dir = 1 }, -/turf/open/space/basic, +/turf/open/floor/plating/airless, /area/engine/engineering) "nR" = ( /obj/structure/cable{ @@ -905,14 +905,6 @@ }, /turf/open/space/basic, /area/space/nearstation) -"VR" = ( -/obj/structure/lattice/catwalk, -/obj/machinery/camera/emp_proof{ - c_tag = "Tesla Engine Northeast"; - network = list("ss13","engine") - }, -/turf/open/space/basic, -/area/space/nearstation) "Wf" = ( /obj/effect/turf_decal/stripes/line{ dir = 9 @@ -1728,7 +1720,7 @@ dz dz FP FP -VR +FP dz dz Yl diff --git a/_maps/RandomRuins/StationRuins/Lavaland/Mining_Station/Mining_Station_Public_01.dmm b/_maps/RandomRuins/StationRuins/Lavaland/Mining_Station/Mining_Station_Public_01.dmm index fec45c7310..3118ad3f5f 100644 --- a/_maps/RandomRuins/StationRuins/Lavaland/Mining_Station/Mining_Station_Public_01.dmm +++ b/_maps/RandomRuins/StationRuins/Lavaland/Mining_Station/Mining_Station_Public_01.dmm @@ -64,6 +64,9 @@ /turf/open/floor/plating, /area/mine/living_quarters) "aN" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, /turf/open/floor/plasteel/white, /area/mine/laborcamp) "aW" = ( @@ -82,24 +85,10 @@ "bg" = ( /turf/closed/wall, /area/mine/eva) -"bH" = ( -/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/atmos_waste{ - dir = 4; - piping_layer = 3 - }, -/obj/structure/lattice/catwalk, -/turf/open/floor/plating/asteroid/basalt/lava_land_surface, -/area/mine/living_quarters) -"bI" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3, -/obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/structure/cable{ - icon_state = "2-8" - }, -/turf/open/floor/plasteel, +"bn" = ( +/obj/structure/cable, +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/plating, /area/mine/living_quarters) "bX" = ( /obj/machinery/door/window/southleft, @@ -174,13 +163,6 @@ }, /turf/open/floor/plasteel, /area/mine/living_quarters) -"di" = ( -/obj/machinery/light{ - dir = 4 - }, -/obj/effect/turf_decal/tile/brown, -/turf/open/floor/plasteel, -/area/mine/living_quarters) "dk" = ( /obj/structure/table, /obj/item/stack/packageWrap, @@ -192,12 +174,6 @@ }, /turf/open/floor/plasteel, /area/mine/eva) -"dC" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, -/turf/open/floor/plasteel, -/area/mine/living_quarters) "dL" = ( /obj/machinery/atmospherics/components/binary/pump/on, /obj/structure/cable{ @@ -220,6 +196,15 @@ }, /turf/open/floor/plasteel, /area/mine/production) +"dU" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/sign/warning/electricshock{ + pixel_y = -32 + }, +/turf/open/floor/plating, +/area/mine/laborcamp/security) "dZ" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 @@ -301,6 +286,21 @@ }, /turf/open/floor/plasteel, /area/mine/laborcamp) +"fx" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/turf/open/floor/plating, +/area/mine/laborcamp/security) +"fA" = ( +/obj/machinery/power/terminal{ + dir = 4 + }, +/obj/machinery/power/port_gen/pacman{ + anchored = 1 + }, +/turf/open/floor/plating, +/area/mine/laborcamp/security) "fN" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 5 @@ -308,6 +308,12 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{ dir = 5 }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, /turf/open/floor/plasteel, /area/mine/laborcamp/security) "fO" = ( @@ -349,9 +355,18 @@ /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, /area/mine/production) +"gn" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/open/floor/plasteel, +/area/mine/laborcamp) "gs" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3, +/obj/structure/cable{ + icon_state = "1-2" + }, /turf/open/floor/plasteel, /area/mine/laborcamp) "gP" = ( @@ -376,6 +391,15 @@ }, /turf/open/floor/plasteel/white, /area/mine/laborcamp) +"hb" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/power/smes{ + charge = 5e+006 + }, +/turf/open/floor/plating, +/area/mine/laborcamp/security) "hf" = ( /obj/item/twohanded/required/kirbyplants/random, /turf/open/floor/plasteel, @@ -387,14 +411,6 @@ }, /turf/open/floor/plasteel, /area/mine/living_quarters) -"hv" = ( -/obj/machinery/camera{ - c_tag = "Crew Area Hallway West"; - dir = 1; - network = list("mine") - }, -/turf/open/floor/plasteel, -/area/mine/living_quarters) "hy" = ( /obj/machinery/camera{ c_tag = "Labor Camp External"; @@ -415,25 +431,21 @@ /turf/open/floor/plasteel, /area/mine/living_quarters) "hP" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{ - dir = 4 +/obj/structure/lattice/catwalk, +/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/atmos_waste{ + dir = 4; + piping_layer = 3 }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/obj/structure/cable{ - icon_state = "4-8" - }, -/turf/open/floor/plasteel, +/turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/mine/living_quarters) "hQ" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3, -/obj/structure/cable{ - icon_state = "1-2" +/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/atmos_waste{ + dir = 1; + piping_layer = 3 }, -/turf/open/floor/plasteel, -/area/mine/living_quarters) +/obj/structure/lattice/catwalk, +/turf/open/floor/plating/asteroid/basalt/lava_land_surface, +/area/mine/laborcamp/security) "ia" = ( /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, @@ -582,6 +594,14 @@ }, /turf/open/floor/plasteel, /area/mine/living_quarters) +"kP" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/open/floor/plating, +/area/mine/laborcamp) "kR" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 4 @@ -630,6 +650,9 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{ dir = 6 }, +/obj/structure/cable{ + icon_state = "2-4" + }, /turf/open/floor/plasteel, /area/mine/laborcamp) "lI" = ( @@ -715,6 +738,9 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{ dir = 4 }, +/obj/structure/cable{ + icon_state = "4-8" + }, /turf/open/floor/plasteel, /area/mine/laborcamp/security) "mN" = ( @@ -733,13 +759,11 @@ }, /turf/open/floor/plasteel, /area/mine/laborcamp/security) -"nv" = ( +"nx" = ( /obj/effect/spawner/structure/window/reinforced, -/obj/structure/cable{ - icon_state = "0-2" - }, +/obj/structure/cable, /turf/open/floor/plating, -/area/mine/living_quarters) +/area/mine/laborcamp/security) "ny" = ( /obj/machinery/computer/prisoner, /obj/effect/turf_decal/tile/red{ @@ -772,11 +796,17 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{ dir = 10 }, -/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ - dir = 1 +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 }, /obj/structure/cable{ - icon_state = "1-2" + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "4-8" }, /turf/open/floor/plasteel, /area/mine/laborcamp/security) @@ -790,6 +820,14 @@ }, /turf/open/floor/plasteel, /area/mine/production) +"nL" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/open/floor/plating, +/area/mine/laborcamp/security) "nN" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 @@ -805,6 +843,19 @@ /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, /area/mine/production) +"nX" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/open/floor/plating, +/area/mine/laborcamp/security) "oo" = ( /obj/machinery/conveyor{ id = "mining_internal" @@ -828,6 +879,9 @@ /obj/machinery/door/airlock/medical/glass{ name = "Infirmary" }, +/obj/structure/cable{ + icon_state = "1-2" + }, /turf/open/floor/plasteel/white, /area/mine/laborcamp) "oy" = ( @@ -886,6 +940,22 @@ }, /turf/open/floor/plasteel, /area/mine/eva) +"pu" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/plating, +/area/mine/living_quarters) "pK" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3, @@ -947,6 +1017,15 @@ }, /turf/open/floor/plating, /area/mine/living_quarters) +"qx" = ( +/obj/effect/turf_decal/tile/purple{ + dir = 4 + }, +/obj/structure/sign/poster/official/random{ + pixel_y = 32 + }, +/turf/open/floor/plasteel, +/area/mine/living_quarters) "qH" = ( /obj/structure/extinguisher_cabinet{ pixel_x = 30 @@ -1071,6 +1150,12 @@ "si" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, /turf/open/floor/plasteel, /area/mine/laborcamp/security) "sj" = ( @@ -1151,15 +1236,25 @@ }, /turf/open/floor/plasteel, /area/mine/laborcamp) +"td" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/structure/cable, +/turf/open/floor/plating, +/area/mine/laborcamp) "tk" = ( /obj/machinery/atmospherics/pipe/manifold4w/scrubbers/hidden/layer3, -/obj/machinery/atmospherics/pipe/manifold4w/supply/hidden, /obj/structure/cable{ icon_state = "4-8" }, /obj/structure/cable{ icon_state = "1-4" }, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 8 + }, /turf/open/floor/plasteel, /area/mine/living_quarters) "tr" = ( @@ -1183,16 +1278,6 @@ }, /turf/open/floor/plasteel, /area/mine/production) -"uh" = ( -/obj/effect/turf_decal/tile/brown{ - dir = 8 - }, -/obj/effect/turf_decal/tile/brown, -/obj/effect/turf_decal/tile/brown{ - dir = 1 - }, -/turf/open/floor/plasteel, -/area/mine/living_quarters) "uG" = ( /obj/structure/table, /obj/item/clothing/glasses/meson, @@ -1258,6 +1343,13 @@ }, /turf/open/floor/plasteel, /area/mine/laborcamp) +"vA" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plasteel, +/area/mine/laborcamp) "vE" = ( /obj/effect/turf_decal/tile/brown{ dir = 1 @@ -1285,6 +1377,16 @@ }, /turf/open/floor/plasteel, /area/mine/eva) +"vM" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/chair, +/turf/open/floor/plasteel, +/area/mine/living_quarters) "wd" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 @@ -1356,6 +1458,9 @@ /area/mine/production) "xd" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3, +/obj/structure/cable{ + icon_state = "2-8" + }, /turf/open/floor/plasteel, /area/mine/laborcamp) "xh" = ( @@ -1399,6 +1504,9 @@ /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer3{ dir = 1 }, +/obj/structure/cable{ + icon_state = "4-8" + }, /turf/open/floor/plasteel, /area/mine/laborcamp/security) "yt" = ( @@ -1416,6 +1524,13 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel, /area/mine/production) +"yQ" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/open/floor/plating, +/area/mine/laborcamp/security) "yR" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on, /turf/open/floor/plasteel, @@ -1435,12 +1550,26 @@ }, /turf/open/floor/plating, /area/mine/living_quarters) +"zk" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/structure/cable, +/turf/open/floor/plating, +/area/mine/laborcamp/security) "zo" = ( /obj/structure/table, /turf/open/floor/carpet, /area/mine/living_quarters) "zx" = ( /obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/structure/cable{ + icon_state = "0-4" + }, /turf/open/floor/plating, /area/mine/laborcamp) "zy" = ( @@ -1502,14 +1631,10 @@ /turf/open/floor/plasteel, /area/mine/living_quarters) "Ah" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3, /obj/structure/cable{ icon_state = "1-2" }, -/obj/structure/cable{ - icon_state = "2-8" - }, /turf/open/floor/plasteel, /area/mine/laborcamp/security) "Aj" = ( @@ -1602,6 +1727,16 @@ /obj/structure/reagent_dispensers/fueltank, /turf/open/floor/plating, /area/mine/living_quarters) +"BD" = ( +/obj/machinery/door/airlock/maintenance{ + name = "Mining Station Maintenance"; + req_access_txt = "48" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/open/floor/plating, +/area/mine/laborcamp/security) "BO" = ( /obj/machinery/door/airlock{ name = "Labor Camp Storage" @@ -1638,6 +1773,12 @@ }, /turf/open/floor/plasteel, /area/mine/production) +"Cl" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plasteel, +/area/mine/laborcamp) "Cm" = ( /obj/machinery/vending/snack, /obj/effect/turf_decal/tile/bar, @@ -1646,6 +1787,13 @@ }, /turf/open/floor/plasteel, /area/mine/living_quarters) +"Cw" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/open/floor/plating, +/area/mine/laborcamp) "Cy" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 @@ -1748,18 +1896,6 @@ }, /turf/open/floor/plasteel, /area/mine/production) -"Em" = ( -/obj/effect/turf_decal/tile/brown{ - dir = 1 - }, -/obj/effect/turf_decal/tile/brown{ - dir = 8 - }, -/obj/structure/cable{ - icon_state = "4-8" - }, -/turf/open/floor/plasteel, -/area/mine/living_quarters) "Ev" = ( /obj/machinery/light/small{ dir = 4 @@ -1792,7 +1928,9 @@ /obj/effect/turf_decal/tile/red{ dir = 8 }, -/obj/machinery/vending/security, +/obj/structure/cable{ + icon_state = "4-8" + }, /turf/open/floor/plasteel, /area/mine/laborcamp/security) "EH" = ( @@ -1805,6 +1943,9 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{ dir = 9 }, +/obj/structure/cable{ + icon_state = "1-8" + }, /turf/open/floor/plasteel, /area/mine/laborcamp) "FC" = ( @@ -1825,19 +1966,6 @@ }, /turf/open/floor/plasteel, /area/mine/laborcamp) -"Ge" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/structure/cable{ - icon_state = "2-4" - }, -/obj/structure/cable{ - icon_state = "1-4" - }, -/obj/structure/cable{ - icon_state = "0-4" - }, -/turf/open/floor/plating, -/area/mine/living_quarters) "Gt" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer3{ dir = 1 @@ -1845,9 +1973,6 @@ /obj/effect/turf_decal/tile/red{ dir = 8 }, -/obj/structure/cable{ - icon_state = "4-8" - }, /turf/open/floor/plasteel, /area/mine/laborcamp/security) "GM" = ( @@ -1891,6 +2016,9 @@ dir = 10 }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3, +/obj/structure/cable{ + icon_state = "1-2" + }, /turf/open/floor/plasteel, /area/mine/laborcamp) "Hh" = ( @@ -1964,11 +2092,6 @@ }, /turf/open/floor/plasteel, /area/mine/laborcamp) -"HR" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/structure/cable, -/turf/open/floor/plating, -/area/mine/living_quarters) "HS" = ( /obj/machinery/conveyor{ dir = 10; @@ -2038,6 +2161,9 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 8 }, +/obj/structure/cable{ + icon_state = "4-8" + }, /turf/open/floor/plasteel, /area/mine/laborcamp/security) "II" = ( @@ -2053,6 +2179,9 @@ /obj/structure/table, /obj/effect/turf_decal/tile/red, /obj/machinery/recharger, +/obj/structure/cable{ + icon_state = "4-8" + }, /turf/open/floor/plasteel, /area/mine/laborcamp/security) "IS" = ( @@ -2073,19 +2202,6 @@ }, /turf/open/floor/carpet, /area/mine/living_quarters) -"Jc" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{ - dir = 4 - }, -/obj/effect/spawner/structure/window/reinforced, -/obj/structure/cable{ - icon_state = "2-4" - }, -/obj/structure/cable{ - icon_state = "0-4" - }, -/turf/open/floor/plating, -/area/mine/living_quarters) "Jl" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer3, /obj/effect/turf_decal/tile/purple{ @@ -2267,12 +2383,6 @@ }, /turf/open/floor/plasteel, /area/mine/production) -"KR" = ( -/obj/effect/turf_decal/tile/brown{ - dir = 4 - }, -/turf/open/floor/plasteel, -/area/mine/living_quarters) "KS" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 @@ -2347,10 +2457,11 @@ /turf/open/floor/plasteel, /area/mine/laborcamp/security) "LG" = ( -/obj/effect/turf_decal/tile/brown{ - dir = 1 +/obj/structure/cable{ + icon_state = "0-2" }, -/turf/open/floor/plasteel, +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/plating, /area/mine/living_quarters) "LL" = ( /obj/effect/turf_decal/tile/red{ @@ -2392,6 +2503,13 @@ }, /turf/open/floor/plasteel, /area/mine/production) +"Mh" = ( +/obj/structure/table, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/open/floor/plasteel/white, +/area/mine/laborcamp) "Mj" = ( /obj/structure/sink{ dir = 4; @@ -2492,12 +2610,6 @@ }, /turf/open/floor/plating, /area/mine/living_quarters) -"ML" = ( -/obj/structure/chair{ - dir = 8 - }, -/turf/open/floor/plasteel, -/area/mine/living_quarters) "MM" = ( /obj/machinery/light{ dir = 8 @@ -2702,16 +2814,16 @@ /turf/open/floor/plasteel, /area/mine/living_quarters) "Qr" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3, -/obj/machinery/door/airlock/security/glass{ - name = "Labor Camp Monitoring"; - req_access_txt = "2" +/obj/structure/cable, +/obj/structure/cable{ + icon_state = "1-8" }, /obj/structure/cable{ - icon_state = "1-2" + icon_state = "1-4" }, -/turf/open/floor/plasteel, +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/plating, /area/mine/laborcamp/security) "Qx" = ( /obj/structure/chair{ @@ -2738,6 +2850,12 @@ }, /turf/open/floor/plasteel, /area/mine/eva) +"QL" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/open/floor/plasteel, +/area/mine/laborcamp/security) "Rf" = ( /obj/machinery/mineral/unloading_machine{ dir = 1; @@ -2755,6 +2873,9 @@ req_access_txt = "2"; security_level = 6 }, +/obj/structure/cable{ + icon_state = "1-2" + }, /turf/open/floor/plasteel, /area/mine/laborcamp) "Ru" = ( @@ -2837,6 +2958,12 @@ /area/mine/living_quarters) "Sp" = ( /obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/structure/cable{ + icon_state = "0-8" + }, /turf/open/floor/plating, /area/mine/laborcamp/security) "Sq" = ( @@ -2904,7 +3031,7 @@ dir = 8 }, /obj/structure/cable{ - icon_state = "4-8" + icon_state = "1-8" }, /turf/open/floor/plasteel, /area/mine/laborcamp/security) @@ -2951,6 +3078,9 @@ desc = "Powered by the tears and sweat of laborers."; name = "Prison Ofitser" }, +/obj/structure/cable{ + icon_state = "1-2" + }, /turf/open/floor/plasteel, /area/mine/laborcamp/security) "Un" = ( @@ -3099,19 +3229,6 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on, /turf/open/floor/plasteel/dark, /area/mine/maintenance) -"WX" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer3, -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/structure/cable{ - icon_state = "1-4" - }, -/turf/open/floor/plasteel, -/area/mine/living_quarters) "WY" = ( /obj/machinery/door/airlock{ id_tag = "miningdorm1"; @@ -3170,12 +3287,6 @@ }, /turf/open/floor/plasteel, /area/mine/living_quarters) -"XR" = ( -/obj/structure/sign/poster/official/random{ - pixel_y = 32 - }, -/turf/open/floor/plasteel, -/area/mine/living_quarters) "XU" = ( /obj/machinery/power/smes{ charge = 5e+006 @@ -3211,9 +3322,6 @@ dir = 1; network = list("labor") }, -/obj/structure/cable{ - icon_state = "4-8" - }, /turf/open/floor/plasteel, /area/mine/laborcamp/security) "Yi" = ( @@ -3291,13 +3399,6 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer3, /turf/open/floor/plasteel, /area/mine/living_quarters) -"Zu" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{ - dir = 4 - }, -/obj/structure/lattice/catwalk, -/turf/open/floor/plating/asteroid/basalt/lava_land_surface, -/area/mine/living_quarters) "Zw" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 @@ -4329,9 +4430,9 @@ cd cd HO cd -zI -zI -VT +RF +RF +RF VT VT VT @@ -4386,9 +4487,9 @@ HU cd Jr cd -my -wV -VT +fA +fx +RF VT uJ VT @@ -4443,13 +4544,13 @@ at cd Op cd -wV -wV -wV +hb +dU +RF +VT VT VT VT -Lm Lm wz wz @@ -4486,8 +4587,8 @@ JY JY JY zx -zx -zx +kP +td cd cd cd @@ -4501,15 +4602,15 @@ NH NH Ya Mn -Mn +BD Mn Dv Mn -nv -Ge -HR -VN -Lm +wV +VT +VT +VT +wz Lm Lm Lm @@ -4542,9 +4643,9 @@ JY JY JY JY -zx -wB +Cw wB +Mh cd AH NH @@ -4562,11 +4663,11 @@ EB MM LC Mn -xH -dC -hf -VN -bH +wV +wV +VT +VT +Lm Lm Lm Lm @@ -4603,13 +4704,13 @@ cd eh aN ow -NH -NH -NH -NH +Cl +Cl +Cl +gn vo ly -xd +vA Hg gs gs @@ -4619,11 +4720,11 @@ si fN TC Mn -ML -dC -oy -VN -Zu +wV +my +VT +VT +VT Lm Lm Lm @@ -4664,7 +4765,7 @@ fs NH Wt xd -xd +vA Fx Yf uR @@ -4676,13 +4777,13 @@ Hx mL Yg Mn -XR -dC -Ag -VN -Jc -HR -VN +zI +VT +VT +VT +VT +wz +Lm Lm Lm Lm @@ -4732,14 +4833,14 @@ LL Hx xS Gt -Sp -FE -Em -cD -Ag -sm -uh -VN +Dv +my +VT +VT +VT +VT +wz +Lm Lm Lm Lm @@ -4791,12 +4892,12 @@ nJ Ah Qr hQ -bI -hQ -hQ -WX -hv -VN +VT +VT +VT +Lm +Lm +Lm Lm Lm Lm @@ -4846,13 +4947,13 @@ WL Hx IG UJ -Sp -Ag -Ag -di -KR +yQ +my +my +VT +Lm hP -Ag +Lm VN VN VN @@ -4901,15 +5002,15 @@ Ya Mn kB Oh -Hx +QL sR Al Al Al Al LG -hP -Ag +pu +bn VN zy If @@ -4955,7 +5056,7 @@ my my my zI -Sp +Dv ny ig IK @@ -4964,9 +5065,9 @@ Al wC wC Al -Ag -hP -Ag +hf +vM +xH VN Ru Ag @@ -5013,16 +5114,16 @@ my my zI Sp -Sp -Sp -Sp -Sp +zk +nL +nX +nx Al Uz Ue Al -EH -hP +qx +sm aW VN Dr diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index a630c54b6e..6c1642ca8b 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -21911,7 +21911,7 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/obj/machinery/computer/arcade/minesweeper, +/obj/machinery/vending/wardrobe/cap_wardrobe, /turf/open/floor/wood, /area/crew_quarters/heads/captain) "bdj" = ( @@ -55854,6 +55854,10 @@ }, /turf/open/floor/plasteel, /area/crew_quarters/dorms) +"nZL" = ( +/obj/machinery/computer/arcade/minesweeper, +/turf/open/floor/wood, +/area/crew_quarters/heads/captain) "oax" = ( /obj/structure/table/wood/fancy, /obj/machinery/light, @@ -90865,7 +90869,7 @@ aVv aXg aYF aZV -bbw +nZL bcn tgH ben diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index fd0f0a1742..1abdd85019 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -62353,7 +62353,7 @@ /turf/open/floor/wood, /area/crew_quarters/heads/captain/private) "cbd" = ( -/obj/effect/landmark/event_spawn, +/obj/machinery/vending/wardrobe/cap_wardrobe, /turf/open/floor/wood, /area/crew_quarters/heads/captain/private) "cbe" = ( @@ -127169,6 +127169,13 @@ dir = 9 }, /area/science/circuit) +"rjr" = ( +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 1 + }, +/obj/effect/landmark/event_spawn, +/turf/open/floor/wood, +/area/crew_quarters/heads/captain/private) "rqh" = ( /obj/structure/lattice, /turf/open/space/basic, @@ -169426,7 +169433,7 @@ bUO bXf bUQ cbe -ccP +rjr ceH cgu cij diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 3353d1b15b..1be18fdfeb 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -28355,6 +28355,7 @@ /obj/structure/disposalpipe/segment{ dir = 6 }, +/obj/machinery/vending/wardrobe/cap_wardrobe, /turf/open/floor/carpet, /area/crew_quarters/heads/captain/private) "bdL" = ( @@ -81645,6 +81646,19 @@ /obj/machinery/door/firedoor, /turf/open/floor/plating, /area/crew_quarters/cryopod) +"eQf" = ( +/obj/machinery/computer/shuttle/mining/common{ + dir = 1 + }, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/open/floor/plating, +/area/hallway/primary/port) "eZe" = ( /obj/structure/cable/yellow{ icon_state = "1-2" @@ -98511,7 +98525,7 @@ bgA biz bkb blZ -bnM +eQf bqf bqf bqf diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm index 22734b0979..b34da30300 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -9830,6 +9830,7 @@ /obj/structure/cable{ icon_state = "0-2" }, +/obj/item/twohanded/required/kirbyplants/random, /turf/open/floor/carpet, /area/crew_quarters/heads/captain) "axT" = ( @@ -11162,10 +11163,7 @@ /obj/structure/extinguisher_cabinet{ pixel_x = -24 }, -/obj/item/twohanded/required/kirbyplants{ - icon_state = "plant-20"; - pixel_y = 3 - }, +/obj/machinery/vending/wardrobe/cap_wardrobe, /turf/open/floor/plasteel/dark, /area/crew_quarters/heads/captain) "aBl" = ( @@ -28097,11 +28095,6 @@ }, /turf/open/floor/plasteel/dark, /area/science/robotics/lab) -"boY" = ( -/obj/effect/turf_decal/bot, -/obj/effect/landmark/start/cyborg, -/turf/open/floor/plasteel, -/area/science/robotics/lab) "boZ" = ( /obj/structure/table, /obj/machinery/cell_charger, @@ -98811,8 +98804,8 @@ beI bkt blH bmO -boY -boY +bnQ +bnQ bqi bry bsZ @@ -99068,8 +99061,8 @@ bju bkt blI bmO -boY -boY +bnQ +bnQ bqi brz bta diff --git a/code/__DEFINES/MC.dm b/code/__DEFINES/MC.dm index fe48edd266..65be8258a1 100644 --- a/code/__DEFINES/MC.dm +++ b/code/__DEFINES/MC.dm @@ -20,7 +20,7 @@ #define NEW_SS_GLOBAL(varname) if(varname != src){if(istype(varname)){Recover();qdel(varname);}varname = src;} #define START_PROCESSING(Processor, Datum) if (!(Datum.datum_flags & DF_ISPROCESSING)) {Datum.datum_flags |= DF_ISPROCESSING;Processor.processing += Datum} -#define STOP_PROCESSING(Processor, Datum) Datum.datum_flags &= ~DF_ISPROCESSING;Processor.processing -= Datum +#define STOP_PROCESSING(Processor, Datum) Datum.datum_flags &= ~DF_ISPROCESSING;Processor.processing -= Datum;Processor.currentrun -= Datum //SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier) diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index 2b19610040..56d5c63833 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -34,6 +34,7 @@ #define CAN_MASTURBATE_WITH (1<<5) #define MASTURBATE_LINKED_ORGAN (1<<6) //used to pass our mission to the linked organ #define CAN_CLIMAX_WITH (1<<7) +#define GENITAL_CAN_AROUSE (1<<8) #define COCK_SIZE_MIN 1 #define COCK_SIZE_MAX 20 diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm index ad93dd2d54..939f6698cb 100644 --- a/code/__DEFINES/maths.dm +++ b/code/__DEFINES/maths.dm @@ -199,4 +199,6 @@ #define LORENTZ_CUMULATIVE_DISTRIBUTION(x, y, s) ( (1/PI)*TORADIANS(arctan((x-y)/s)) + 1/2 ) #define RULE_OF_THREE(a, b, x) ((a*x)/b) -// ) \ No newline at end of file +// ) + +#define MANHATTAN_DISTANCE(a, b) (abs(a.x - b.x) + abs(a.y - b.y)) \ No newline at end of file diff --git a/code/__DEFINES/profile.dm b/code/__DEFINES/profile.dm index 28fc7782ce..8929e0f05e 100644 --- a/code/__DEFINES/profile.dm +++ b/code/__DEFINES/profile.dm @@ -1,5 +1,5 @@ -#define PROFILE_START ;PROFILE_STORE = list();PROFILE_SET; -#define PROFILE_STOP ;PROFILE_STORE = null; +#define LINE_PROFILE_START ;PROFILE_STORE = list();PROFILE_SET; +#define LINE_PROFILE_STOP ;PROFILE_STORE = null; #define PROFILE_SET ;PROFILE_TIME = TICK_USAGE_REAL; PROFILE_LINE = __LINE__; PROFILE_FILE = __FILE__; PROFILE_SLEEPCHECK = world.time; diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 5c54843df2..162c898917 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -47,6 +47,7 @@ // Subsystems shutdown in the reverse of the order they initialize in // The numbers just define the ordering, they are meaningless otherwise. +#define INIT_ORDER_PROFILER 101 #define INIT_ORDER_FAIL2TOPIC 22 #define INIT_ORDER_TITLE 20 #define INIT_ORDER_GARBAGE 19 diff --git a/code/__DEFINES/tgs.config.dm b/code/__DEFINES/tgs.config.dm index a40b5d4663..9f4f63a1fc 100644 --- a/code/__DEFINES/tgs.config.dm +++ b/code/__DEFINES/tgs.config.dm @@ -1,4 +1,5 @@ #define TGS_EXTERNAL_CONFIGURATION +#define TGS_V3_API #define TGS_DEFINE_AND_SET_GLOBAL(Name, Value) GLOBAL_VAR_INIT(##Name, ##Value); GLOBAL_PROTECT(##Name) #define TGS_READ_GLOBAL(Name) GLOB.##Name #define TGS_WRITE_GLOBAL(Name, Value) GLOB.##Name = ##Value diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm index db4f046ec3..dcccfc9295 100644 --- a/code/__DEFINES/tgs.dm +++ b/code/__DEFINES/tgs.dm @@ -107,6 +107,22 @@ var/commit //full sha of compiled commit var/origin_commit //full sha of last known remote commit. This may be null if the TGS repository is not currently tracking a remote branch +//represents a version of tgstation-server +/datum/tgs_version + var/suite //The suite version, can be >=3 + + //this group of variables can be null to represent a wild card + var/major //The major version + var/minor //The minor version + var/patch //The patch version + + var/raw_parameter //The unparsed parameter + var/deprefixed_parameter //The version only bit of raw_parameter + +//if the tgs_version is a wildcard version +/datum/tgs_version/proc/Wildcard() + return + //represents a merge of a GitHub pull request /datum/tgs_revision_information/test_merge var/number //pull request number @@ -155,22 +171,22 @@ //FUNCTIONS -//Returns the respective string version of the API +//Returns the respective supported /datum/tgs_version of the API /world/proc/TgsMaximumAPIVersion() return /world/proc/TgsMinimumAPIVersion() return -//Gets the current version of the server tools running the server -/world/proc/TgsVersion() - return - //Returns TRUE if the world was launched under the server tools and the API matches, FALSE otherwise //No function below this succeeds if it returns FALSE /world/proc/TgsAvailable() return +//Gets the current /datum/tgs_version of the server tools running the server +/world/proc/TgsVersion() + return + /world/proc/TgsInstanceName() return diff --git a/code/__HELPERS/_cit_helpers.dm b/code/__HELPERS/_cit_helpers.dm index c0acf4c5a5..1bde770045 100644 --- a/code/__HELPERS/_cit_helpers.dm +++ b/code/__HELPERS/_cit_helpers.dm @@ -57,14 +57,11 @@ GLOBAL_LIST_EMPTY(ipc_antennas_list) //Genitals and Arousal Lists GLOBAL_LIST_EMPTY(genitals_list) -GLOBAL_LIST_EMPTY(cock_shapes_list)//global_lists.dm for the list initializations //Now also _DATASTRUCTURES globals.dm -GLOBAL_LIST_EMPTY(cock_shapes_icons) //Associated list for names->icon_states for cockshapes. +GLOBAL_LIST_EMPTY(cock_shapes_list) GLOBAL_LIST_EMPTY(gentlemans_organ_names) GLOBAL_LIST_EMPTY(balls_shapes_list) -GLOBAL_LIST_EMPTY(balls_shapes_icons) GLOBAL_LIST_EMPTY(breasts_size_list) GLOBAL_LIST_EMPTY(breasts_shapes_list) -GLOBAL_LIST_EMPTY(breasts_shapes_icons) GLOBAL_LIST_EMPTY(vagina_shapes_list) GLOBAL_LIST_INIT(cum_into_containers_list, list(/obj/item/reagent_containers/food/snacks/pie)) //Yer fuggin snowflake name list jfc GLOBAL_LIST_INIT(dick_nouns, list("dick","cock","member","shaft")) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index ff9d1bec4c..7045767f98 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -51,26 +51,15 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/antenna, GLOB.ipc_antennas_list, roundstart = TRUE) //genitals init_sprite_accessory_subtypes(/datum/sprite_accessory/penis, GLOB.cock_shapes_list) - for(var/K in GLOB.cock_shapes_list) - var/datum/sprite_accessory/penis/value = GLOB.cock_shapes_list[K] - GLOB.cock_shapes_icons[K] = value.icon_state - init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts, GLOB.breasts_shapes_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/testicles, GLOB.balls_shapes_list) GLOB.breasts_size_list = list ("a", "b", "c", "d", "e") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing. GLOB.gentlemans_organ_names = list("phallus", "willy", "dick", "prick", "member", "tool", "gentleman's organ", "cock", "wang", "knob", "dong", "joystick", "pecker", "johnson", "weenie", "tadger", "schlong", "thirsty ferret", "baloney pony", "schlanger", "Mutton dagger", "old blind bob","Hanging Johnny", "fishing rod", "Tally whacker", "polly rocket", "One eyed trouser trout", "Ding dong", "ankle spanker", "Pork sword", "engine cranker", "Harry hot dog", "Davy Crockett", "Kidney cracker", "Heat seeking moisture missile", "Giggle stick", "love whistle", "Tube steak", "Uncle Dick", "Purple helmet warrior") - for(var/K in GLOB.breasts_shapes_list) - var/datum/sprite_accessory/breasts/value = GLOB.breasts_shapes_list[K] - GLOB.breasts_shapes_icons[K] = value.icon_state - - init_sprite_accessory_subtypes(/datum/sprite_accessory/testicles, GLOB.balls_shapes_list) - for(var/K in GLOB.balls_shapes_list) - var/datum/sprite_accessory/testicles/value = GLOB.balls_shapes_list[K] - GLOB.balls_shapes_icons[K] = value.icon_state for(var/gpath in subtypesof(/obj/item/organ/genital)) var/obj/item/organ/genital/G = gpath diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 9cced1fdc7..2cb088c654 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1543,3 +1543,25 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) for(var/each_item in items_list) for(var/i in 1 to items_list[each_item]) new each_item(where_to) + +//sends a message to chat +//config_setting should be one of the following +//null - noop +//empty string - use TgsTargetBroadcast with admin_only = FALSE +//other string - use TgsChatBroadcast with the tag that matches config_setting, only works with TGS4, if using TGS3 the above method is used +/proc/send2chat(message, config_setting) + if(config_setting == null || !world.TgsAvailable()) + return + var/datum/tgs_version/version = world.TgsVersion() + if(config_setting == "" || version.suite == 3) + world.TgsTargetedChatBroadcast(message, FALSE) + return + + var/list/channels_to_use = list() + for(var/I in world.TgsChatChannelInfo()) + var/datum/tgs_chat_channel/channel = I + if(channel.tag == config_setting) + channels_to_use += channel + + if(channels_to_use.len) + world.TgsChatBroadcast() \ No newline at end of file diff --git a/code/__HELPERS/vector.dm b/code/__HELPERS/vector.dm new file mode 100644 index 0000000000..80295bde0e --- /dev/null +++ b/code/__HELPERS/vector.dm @@ -0,0 +1,57 @@ +// Basic geometry things. + +/datum/vector/ + var/x = 0 + var/y = 0 + +/datum/vector/New(var/x, var/y) + src.x = x + src.y = y + +/datum/vector/proc/duplicate() + return new /datum/vector(x, y) + +/datum/vector/proc/euclidian_norm() + return sqrt(x*x + y*y) + +/datum/vector/proc/squared_norm() + return x*x + y*y + +/datum/vector/proc/normalize() + var/norm = euclidian_norm() + x = x/norm + y = y/norm + return src + +/datum/vector/proc/chebyshev_norm() + return max(abs(x), abs(y)) + +/datum/vector/proc/chebyshev_normalize() + var/norm = chebyshev_norm() + x = x/norm + y = y/norm + return src + +/datum/vector/proc/is_integer() + return ISINTEGER(x) && ISINTEGER(y) + +/atom/movable/proc/vector_translate(var/datum/vector/V, var/delay) + var/turf/T = get_turf(src) + var/turf/destination = locate(T.x + V.x, T.y + V.y, z) + var/datum/vector/V_norm = V.duplicate() + V_norm.chebyshev_normalize() + if (!V_norm.is_integer()) + return + var/turf/destination_temp + while (destination_temp != destination) + destination_temp = locate(T.x + V_norm.x, T.y + V_norm.y, z) + forceMove(destination_temp) + T = get_turf(src) + sleep(delay + world.tick_lag) // Shortest possible time to sleep + +/atom/proc/get_translated_turf(var/datum/vector/V) + var/turf/T = get_turf(src) + return locate(T.x + V.x, T.y + V.y, z) + +/proc/atoms2vector(var/atom/A, var/atom/B) + return new /datum/vector((B.x - A.x), (B.y - A.y)) // Vector from A -> B \ No newline at end of file diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index cda19dbaac..3f11c8a2f2 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -1,19 +1,22 @@ - +/** + *This is the proc that handles the order of an item_attack. + *The order of procs called is: + *tool_act on the target. If it returns TRUE, the chain will be stopped. + *pre_attack() on src. If this returns TRUE, the chain will be stopped. + *attackby on the target. If it returns TRUE, the chain will be stopped. + *and lastly + *afterattack. The return value does not matter. + */ /obj/item/proc/melee_attack_chain(mob/user, atom/target, params) - if(!tool_attack_chain(user, target) && pre_attack(target, user, params)) - // Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example) - var/resolved = target.attackby(src, user, params) - if(!resolved && target && !QDELETED(src)) - afterattack(target, user, 1, params) // 1: clicking something Adjacent - - -//Checks if the item can work as a tool, calling the appropriate tool behavior on the target -/obj/item/proc/tool_attack_chain(mob/user, atom/target) - if(!tool_behaviour) - return FALSE - - return target.tool_act(user, src, tool_behaviour) - + if(tool_behaviour && target.tool_act(user, src, tool_behaviour)) + return + if(pre_attack(target, user, params)) + return + if(target.attackby(src,user, params)) + return + if(QDELETED(src) || QDELETED(target)) + return + afterattack(target, user, TRUE, params) // Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown. /obj/item/proc/attack_self(mob/user) @@ -23,8 +26,8 @@ /obj/item/proc/pre_attack(atom/A, mob/living/user, params) //do stuff before attackby! if(SEND_SIGNAL(src, COMSIG_ITEM_PRE_ATTACK, A, user, params) & COMPONENT_NO_ATTACK) - return FALSE - return TRUE //return FALSE to avoid calling attackby after this proc does stuff + return TRUE + return FALSE //return TRUE to avoid calling attackby after this proc does stuff // No comment /atom/proc/attackby(obj/item/W, mob/user, params) @@ -112,7 +115,7 @@ send_item_attack_message(I, user) if(I.force) apply_damage(totitemdamage, I.damtype) //CIT CHANGE - replaces I.force with totitemdamage - if(I.damtype == BRUTE && !HAS_TRAIT(src, TRAIT_NOMARROW)) + if(I.damtype == BRUTE && !HAS_TRAIT(src, TRAIT_NOMARROW)) if(prob(33)) I.add_mob_blood(src) var/turf/location = get_turf(src) diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 2e5b8a1852..cb8c0fe966 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -1,3 +1,5 @@ +/datum/config_entry/flag/auto_profile // Automatically start profiler on server start + /datum/config_entry/flag/autoadmin // if autoadmin is enabled protection = CONFIG_ENTRY_LOCKED @@ -392,6 +394,13 @@ config_entry_value = 50 /datum/config_entry/flag/irc_announce_new_game + deprecated_by = /datum/config_entry/string/chat_announce_new_game + +/datum/config_entry/flag/irc_announce_new_game/DeprecationUpdate(value) + return "" //default broadcast + +/datum/config_entry/string/chat_announce_new_game + config_entry_value = null /datum/config_entry/flag/debug_admin_hrefs diff --git a/code/controllers/subsystem/weather.dm b/code/controllers/subsystem/processing/weather.dm similarity index 77% rename from code/controllers/subsystem/weather.dm rename to code/controllers/subsystem/processing/weather.dm index 5e44f2e4c3..0a1b4fc609 100644 --- a/code/controllers/subsystem/weather.dm +++ b/code/controllers/subsystem/processing/weather.dm @@ -4,25 +4,16 @@ #define END_STAGE 4 //Used for all kinds of weather, ex. lavaland ash storms. -SUBSYSTEM_DEF(weather) +PROCESSING_SUBSYSTEM_DEF(weather) name = "Weather" flags = SS_BACKGROUND wait = 10 runlevels = RUNLEVEL_GAME - var/list/processing = list() var/list/eligible_zlevels = list() var/list/next_hit_by_zlevel = list() //Used by barometers to know when the next storm is coming -/datum/controller/subsystem/weather/fire() - // process active weather - for(var/V in processing) - var/datum/weather/W = V - if(W.aesthetic || W.stage != MAIN_STAGE) - continue - for(var/i in GLOB.mob_living_list) - var/mob/living/L = i - if(W.can_weather_act(L)) - W.weather_act(L) +/datum/controller/subsystem/processing/weather/fire() + . = ..() //Active weather is handled by . = ..() processing subsystem base fire(). // start random weather on relevant levels for(var/z in eligible_zlevels) @@ -34,7 +25,7 @@ SUBSYSTEM_DEF(weather) addtimer(CALLBACK(src, .proc/make_eligible, z, possible_weather), randTime + initial(W.weather_duration_upper), TIMER_UNIQUE) //Around 5-10 minutes between weathers next_hit_by_zlevel["[z]"] = world.time + randTime + initial(W.telegraph_duration) -/datum/controller/subsystem/weather/Initialize(start_timeofday) +/datum/controller/subsystem/processing/weather/Initialize(start_timeofday) for(var/V in subtypesof(/datum/weather)) var/datum/weather/W = V var/probability = initial(W.probability) @@ -47,7 +38,7 @@ SUBSYSTEM_DEF(weather) eligible_zlevels["[z]"][W] = probability return ..() -/datum/controller/subsystem/weather/proc/run_weather(datum/weather/weather_datum_type, z_levels) +/datum/controller/subsystem/processing/weather/proc/run_weather(datum/weather/weather_datum_type, z_levels) if (istext(weather_datum_type)) for (var/V in subtypesof(/datum/weather)) var/datum/weather/W = V @@ -69,11 +60,11 @@ SUBSYSTEM_DEF(weather) var/datum/weather/W = new weather_datum_type(z_levels) W.telegraph() -/datum/controller/subsystem/weather/proc/make_eligible(z, possible_weather) +/datum/controller/subsystem/processing/weather/proc/make_eligible(z, possible_weather) eligible_zlevels[z] = possible_weather next_hit_by_zlevel["[z]"] = null -/datum/controller/subsystem/weather/proc/get_weather(z, area/active_area) +/datum/controller/subsystem/processing/weather/proc/get_weather(z, area/active_area) var/datum/weather/A for(var/V in processing) var/datum/weather/W = V diff --git a/code/controllers/subsystem/profiler.dm b/code/controllers/subsystem/profiler.dm new file mode 100644 index 0000000000..ec8b243073 --- /dev/null +++ b/code/controllers/subsystem/profiler.dm @@ -0,0 +1,63 @@ +#define PROFILER_FILENAME "profiler.json" + +SUBSYSTEM_DEF(profiler) + name = "Profiler" + init_order = INIT_ORDER_PROFILER + runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY + wait = 3000 + flags = SS_NO_TICK_CHECK + var/fetch_cost = 0 + var/write_cost = 0 + +/datum/controller/subsystem/profiler/stat_entry(msg) + msg += "F:[round(fetch_cost,1)]ms" + msg += "|W:[round(write_cost,1)]ms" + ..(msg) + +/datum/controller/subsystem/profiler/Initialize() + if(CONFIG_GET(flag/auto_profile)) + StartProfiling() + else + StopProfiling() //Stop the early start from world/New + return ..() + +/datum/controller/subsystem/profiler/fire() + if(CONFIG_GET(flag/auto_profile)) + DumpFile() + +/datum/controller/subsystem/profiler/Shutdown() + if(CONFIG_GET(flag/auto_profile)) + DumpFile() + return ..() + +/datum/controller/subsystem/profiler/proc/StartProfiling() +#if DM_BUILD < 1506 || DM_VERSION < 513 + stack_trace("Auto profiling unsupported on this byond version") + CONFIG_SET(flag/auto_profile, FALSE) +#else + world.Profile(PROFILE_START) +#endif + +/datum/controller/subsystem/profiler/proc/StopProfiling() +#if DM_BUILD >= 1506 && DM_VERSION >= 513 + world.Profile(PROFILE_STOP) +#endif + +/datum/controller/subsystem/profiler/proc/DumpFile() +#if DM_BUILD < 1506 || DM_VERSION < 513 + stack_trace("Auto profiling unsupported on this byond version") + CONFIG_SET(flag/auto_profile, FALSE) +#else + var/timer = TICK_USAGE_REAL + var/current_profile_data = world.Profile(PROFILE_REFRESH,format="json") + fetch_cost = MC_AVERAGE(fetch_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + CHECK_TICK + if(!length(current_profile_data)) //Would be nice to have explicit proc to check this + stack_trace("Warning, profiling stopped manually before dump.") + var/json_file = file("[GLOB.log_directory]/[PROFILER_FILENAME]") + if(fexists(json_file)) + fdel(json_file) + timer = TICK_USAGE_REAL + WRITE_FILE(json_file, current_profile_data) + write_cost = MC_AVERAGE(write_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) +#endif diff --git a/code/controllers/subsystem/server_maint.dm b/code/controllers/subsystem/server_maint.dm index 9e926b29a1..b77c78c4bb 100644 --- a/code/controllers/subsystem/server_maint.dm +++ b/code/controllers/subsystem/server_maint.dm @@ -81,8 +81,8 @@ SUBSYSTEM_DEF(server_maint) co.ehjax_send(data = "roundrestart") if(server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite C << link("byond://[server]") - var/tgsversion = world.TgsVersion() + var/datum/tgs_version/tgsversion = world.TgsVersion() if(tgsversion) - SSblackbox.record_feedback("text", "server_tools", 1, tgsversion) + SSblackbox.record_feedback("text", "server_tools", 1, tgsversion.raw_parameter) #undef PING_BUFFER_TIME diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 971a9f837b..fe994facdc 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -158,8 +158,7 @@ SUBSYSTEM_DEF(ticker) for(var/client/C in GLOB.clients) window_flash(C, ignorepref = TRUE) //let them know lobby has opened up. to_chat(world, "Welcome to [station_name()]!") - if(CONFIG_GET(flag/irc_announce_new_game)) - world.TgsTargetedChatBroadcast("New round starting on [SSmapping.config.map_name]!", FALSE) + send2chat("New round starting on [SSmapping.config.map_name]!", CONFIG_GET(string/chat_announce_new_game)) current_state = GAME_STATE_PREGAME //Everyone who wants to be an observer is now spawned create_observers() @@ -488,7 +487,7 @@ SUBSYSTEM_DEF(ticker) if("SCORE") SSvote.initiate_vote("map","server",hideresults=TRUE,votesystem = MAJORITY_JUDGEMENT_VOTING) // fallback - SSvote.initiate_vote("map","server",hideresults=TRUE,votesystem = MAJORITY_JUDGEMENT_VOTING) + SSvote.initiate_vote("map","server",hideresults=TRUE) /datum/controller/subsystem/ticker/proc/HasRoundStarted() return current_state >= GAME_STATE_PLAYING diff --git a/code/datums/action.dm b/code/datums/action.dm index 54c719a6d5..04d9c706ed 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -820,3 +820,11 @@ target.layer = old_layer target.plane = old_plane current_button.appearance_cache = target.appearance + +/proc/get_action_of_type(mob/M, var/action_type) + if(!M.actions || !ispath(action_type, /datum/action)) + return + for(var/datum/action/A in M.actions) + if(istype(A, action_type)) + return A + return \ No newline at end of file diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index d467f66b6a..a8e03946b6 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -25,6 +25,7 @@ GLOBAL_LIST_EMPTY(uplinks) var/unlock_code var/failsafe_code var/datum/ui_state/checkstate + var/compact_mode = FALSE var/debug = FALSE /datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/ui_state/_checkstate) @@ -122,7 +123,7 @@ GLOBAL_LIST_EMPTY(uplinks) active = TRUE ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "uplink", name, 450, 750, master_ui, state) + ui = new(user, src, ui_key, "uplink", name, 620, 580, master_ui, state) ui.set_autoupdate(FALSE) // This UI is only ever opened by one person, and never is updated outside of user input. ui.set_style("syndicate") ui.open() @@ -139,29 +140,35 @@ GLOBAL_LIST_EMPTY(uplinks) var/list/data = list() data["telecrystals"] = telecrystals data["lockable"] = lockable + data["compact_mode"] = compact_mode + return data + +/datum/component/uplink/ui_static_data(mob/user) + var/list/data = list() data["categories"] = list() for(var/category in uplink_items) var/list/cat = list( "name" = category, "items" = (category == selected_cat ? list() : null)) - if(category == selected_cat) - for(var/item in uplink_items[category]) - var/datum/uplink_item/I = uplink_items[category][item] - if(I.limited_stock == 0) + for(var/item in uplink_items[category]) + var/datum/uplink_item/I = uplink_items[category][item] + if(I.limited_stock == 0) + continue + if(I.restricted_roles.len) + var/is_inaccessible = TRUE + for(var/R in I.restricted_roles) + if(R == user.mind.assigned_role || debug) + is_inaccessible = FALSE + if(is_inaccessible) continue - if(I.restricted_roles.len) - var/is_inaccessible = 1 - for(var/R in I.restricted_roles) - if(R == user.mind.assigned_role || debug) - is_inaccessible = 0 if(is_inaccessible) continue - cat["items"] += list(list( - "name" = I.name, - "cost" = I.cost, - "desc" = I.desc, - )) + cat["items"] += list(list( + "name" = I.name, + "cost" = I.cost, + "desc" = I.desc, + )) data["categories"] += list(cat) return data @@ -189,6 +196,8 @@ GLOBAL_LIST_EMPTY(uplinks) SStgui.close_uis(src) if("select") selected_cat = params["category"] + if("compact_toggle") + compact_mode = !compact_mode return TRUE /datum/component/uplink/proc/MakePurchase(mob/user, datum/uplink_item/U) diff --git a/code/datums/elements/mob_holder.dm b/code/datums/elements/mob_holder.dm index a63be406c1..04f84ee008 100644 --- a/code/datums/elements/mob_holder.dm +++ b/code/datums/elements/mob_holder.dm @@ -1,5 +1,5 @@ /datum/element/mob_holder - element_flags = ELEMENT_BESPOKE + element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH id_arg_index = 2 var/worn_state var/alt_worn diff --git a/code/datums/elements/wuv.dm b/code/datums/elements/wuv.dm index 55bc9bafad..fffb90c681 100644 --- a/code/datums/elements/wuv.dm +++ b/code/datums/elements/wuv.dm @@ -1,6 +1,6 @@ /datum/element/wuv //D'awwwww - element_flags = ELEMENT_BESPOKE + element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH id_arg_index = 2 //the for the me emote proc call when petted. var/pet_emote diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm index 7d040a4982..0b0fed407c 100644 --- a/code/datums/helper_datums/getrev.dm +++ b/code/datums/helper_datums/getrev.dm @@ -27,7 +27,8 @@ for(var/line in testmerge) var/datum/tgs_revision_information/test_merge/tm = line - msg += "Test merge active of PR #[tm.number] commit [tm.commit]" + msg += "Test merge active of PR #[tm.number] commit [tm.pull_request_commit]" + SSblackbox.record_feedback("associative", "testmerged_prs", 1, list("number" = "[tm.number]", "commit" = "[tm.pull_request_commit]", "title" = "[tm.title]", "author" = "[tm.author]")) if(commit && commit != originmastercommit) msg += "HEAD: [commit]" @@ -75,7 +76,8 @@ else if(!pc) msg += "No commit information" if(world.TgsAvailable()) - msg += "Server tools version: [world.TgsVersion()]" + var/datum/tgs_version/version = world.TgsVersion() + msg += "Server tools version: [version.raw_parameter]" // Game mode odds msg += "
Current Informational Settings:" diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm index faa7eec392..b2177a860a 100644 --- a/code/datums/traits/negative.dm +++ b/code/datums/traits/negative.dm @@ -144,9 +144,8 @@ GLOBAL_LIST_EMPTY(family_heirlooms) /datum/quirk/nearsighted/on_spawn() var/mob/living/carbon/human/H = quirk_holder var/obj/item/clothing/glasses/regular/glasses = new(get_turf(H)) - H.put_in_hands(glasses) - H.equip_to_slot(glasses, SLOT_GLASSES) - H.regenerate_icons() //this is to remove the inhand icon, which persists even if it's not in their hands + if(!H.equip_to_slot_if_possible(glasses, SLOT_GLASSES)) + H.put_in_hands(glasses) /datum/quirk/nyctophobia name = "Nyctophobia" diff --git a/code/datums/weather/weather.dm b/code/datums/weather/weather.dm index 01b9facbb8..6761ecbb4c 100644 --- a/code/datums/weather/weather.dm +++ b/code/datums/weather/weather.dm @@ -61,7 +61,7 @@ if(A.z in impacted_z_levels) impacted_areas |= A weather_duration = rand(weather_duration_lower, weather_duration_upper) - START_PROCESSING(SSweather, src) + START_PROCESSING(SSweather, src) //The reason this doesn't start and stop at main stage is because processing list is also used to see active running weathers (for example, you wouldn't want two ash storms starting at once.) update_areas() for(var/M in GLOB.player_list) var/turf/mob_turf = get_turf(M) @@ -107,6 +107,14 @@ STOP_PROCESSING(SSweather, src) update_areas() +/datum/weather/process() + if(aesthetic || (stage != MAIN_STAGE)) + return + for(var/i in GLOB.mob_living_list) + var/mob/living/L = i + if(can_weather_act(L)) + weather_act(L) + /datum/weather/proc/can_weather_act(mob/living/L) //Can this weather impact a mob? var/turf/mob_turf = get_turf(L) if(mob_turf && !(mob_turf.z in impacted_z_levels)) diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index 3bfcececda..adc1748ded 100644 --- a/code/game/machinery/doors/brigdoors.dm +++ b/code/game/machinery/doors/brigdoors.dm @@ -2,13 +2,11 @@ #define FONT_SIZE "5pt" #define FONT_COLOR "#09f" #define FONT_STYLE "Arial Black" -#define MAX_TIMER 9000 - -#define PRESET_SHORT 1200 -#define PRESET_MEDIUM 1800 -#define PRESET_LONG 3000 - +#define MAX_TIMER 15 MINUTES +#define PRESET_SHORT 2 MINUTES +#define PRESET_MEDIUM 3 MINUTES +#define PRESET_LONG 5 MINUTES /////////////////////////////////////////////////////////////////////////////////////////////// // Brig Door control displays. @@ -25,7 +23,7 @@ desc = "A remote control for a door." req_access = list(ACCESS_SECURITY) density = FALSE - var/id = null // id of linked machinery/lockers + var/id // id of linked machinery/lockers var/activation_time = 0 var/timer_duration = 0 @@ -43,8 +41,6 @@ Radio = new/obj/item/radio(src) Radio.listening = 0 -/obj/machinery/door_timer/Initialize() - . = ..() if(id != null) for(var/obj/machinery/door/window/brigdoor/M in urange(20, src)) if (M.id == id) @@ -71,7 +67,7 @@ return if(timing) - if(world.realtime - activation_time >= timer_duration) + if(REALTIMEOFDAY - activation_time >= timer_duration) timer_end() // open doors, reset timer, clear status screen update_icon() @@ -80,14 +76,13 @@ ..() update_icon() - // open/closedoor checks if door_timer has power, if so it checks if the // linked door is open/closed (by density) then opens it/closes it. /obj/machinery/door_timer/proc/timer_start() if(stat & (NOPOWER|BROKEN)) return 0 - activation_time = world.realtime + activation_time = REALTIMEOFDAY timing = TRUE for(var/obj/machinery/door/window/brigdoor/door in targets) @@ -104,7 +99,6 @@ C.update_icon() return 1 - /obj/machinery/door_timer/proc/timer_end(forced = FALSE) if(stat & (NOPOWER|BROKEN)) @@ -136,7 +130,7 @@ /obj/machinery/door_timer/proc/time_left(seconds = FALSE) - . = max(0,timer_duration - (activation_time ? world.realtime - activation_time : 0)) + . = max(0,timer_duration - (activation_time ? REALTIMEOFDAY - activation_time : 0)) if(seconds) . /= 10 @@ -240,7 +234,7 @@ preset_time = PRESET_LONG . = set_timer(preset_time) if(timing) - activation_time = world.realtime + activation_time = REALTIMEOFDAY else . = FALSE diff --git a/code/game/objects/items/RPD.dm b/code/game/objects/items/RPD.dm index 237aca02a9..8b8a02d190 100644 --- a/code/game/objects/items/RPD.dm +++ b/code/game/objects/items/RPD.dm @@ -345,7 +345,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( A = get_turf(A) var/can_make_pipe = (isturf(A) || is_type_in_typecache(A, make_pipe_whitelist)) - . = FALSE + . = TRUE if((mode & DESTROY_MODE) && istype(A, /obj/item/pipe) || istype(A, /obj/structure/disposalconstruct) || istype(A, /obj/structure/c_transit_tube) || istype(A, /obj/structure/c_transit_tube_pod) || istype(A, /obj/item/pipe_meter)) to_chat(user, "You start destroying a pipe...") diff --git a/code/game/objects/items/devices/geiger_counter.dm b/code/game/objects/items/devices/geiger_counter.dm index ce0e492393..2af449df24 100644 --- a/code/game/objects/items/devices/geiger_counter.dm +++ b/code/game/objects/items/devices/geiger_counter.dm @@ -38,6 +38,7 @@ /obj/item/geiger_counter/Destroy() STOP_PROCESSING(SSobj, src) + QDEL_NULL(soundloop) return ..() /obj/item/geiger_counter/process() diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index e17f96495d..45911afc73 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -51,6 +51,7 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \ new/datum/stack_recipe("closet", /obj/structure/closet, 2, time = 15, one_per_turf = TRUE, on_floor = TRUE), \ null, \ new/datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \ + new/datum/stack_recipe("trash bin", /obj/structure/closet/crate/bin, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE),\ null, \ new/datum/stack_recipe("floor tile", /obj/item/stack/tile/plasteel, 1, 4, 20), \ new/datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60), \ @@ -733,7 +734,6 @@ GLOBAL_LIST_INIT(plastic_recipes, list( new /datum/stack_recipe("opaque plastic flaps", /obj/structure/plasticflaps/opaque, 5, one_per_turf = TRUE, on_floor = TRUE, time = 40), \ new /datum/stack_recipe("water bottle", /obj/item/reagent_containers/glass/beaker/waterbottle/empty), \ new /datum/stack_recipe("large water bottle", /obj/item/reagent_containers/glass/beaker/waterbottle/large/empty,3), \ - new /datum/stack_recipe("large trash cart", /obj/structure/closet/crate/bin,50),\ new /datum/stack_recipe("wet floor sign", /obj/item/caution, 2))) /obj/item/stack/sheet/plastic diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index 028f36b1d1..67e54128a4 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -399,10 +399,12 @@ /obj/item/storage/bag/bio/ComponentInitialize() . = ..() var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_NORMAL //Allows you to pick up Lungs, Liver, and Stomach STR.max_combined_w_class = 200 STR.max_items = 25 STR.insert_preposition = "in" - STR.can_hold = typecacheof(list(/obj/item/slime_extract, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/blood, /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/food/snacks/deadmouse, /obj/item/reagent_containers/food/snacks/monkeycube)) + STR.can_hold = typecacheof(list(/obj/item/slime_extract, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/blood, /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/food/snacks/deadmouse, /obj/item/reagent_containers/food/snacks/monkeycube, /obj/item/organ, /obj/item/reagent_containers/food/snacks/meat/slab, /obj/item/bodypart)) + STR.cant_hold = typecacheof(list(/obj/item/organ/brain, /obj/item/organ/liver/cybernetic, /obj/item/organ/heart/cybernetic, /obj/item/organ/lungs/cybernetic, /obj/item/organ/tongue/cybernetic, /obj/item/organ/ears/cybernetic, /obj/item/organ/eyes/robotic, /obj/item/organ/cyberimp)) /obj/item/storage/bag/bio/holding name = "bio bag of holding" diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm index 8c0f315ca3..add2d12ee6 100644 --- a/code/game/objects/items/teleportation.dm +++ b/code/game/objects/items/teleportation.dm @@ -138,7 +138,7 @@ /obj/item/hand_tele/pre_attack(atom/target, mob/user, params) if(try_dispel_portal(target, user)) - return FALSE + return TRUE return ..() /obj/item/hand_tele/proc/try_dispel_portal(atom/target, mob/user) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index 1517b30d9c..88c8d51479 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -2,38 +2,21 @@ name = "\proper captain's locker" req_access = list(ACCESS_CAPTAIN) icon_state = "cap" -/obj/structure/closet/secure_closet/captains/PopulateContents() +/obj/structure/closet/secure_closet/captains/PopulateContents() //Excess clothing and such can be found in the Captain's Wardrobe. You can also find this file in code/modules/vending/wardrobes. ..() - new /obj/item/clothing/suit/hooded/wintercoat/captain(src) - new /obj/item/storage/backpack/captain(src) - new /obj/item/storage/backpack/satchel/cap(src) - new /obj/item/storage/backpack/duffelbag/captain(src) - new /obj/item/clothing/neck/cloak/cap(src) - new /obj/item/clothing/neck/petcollar(src) + new /obj/item/clothing/neck/petcollar(src) //I considered removing the pet stuff too but eh, who knows. We might get Renault back. Plus I guess you could use that collar for... other means. Aren't you supposed to be guarding the disk? new /obj/item/pet_carrier(src) - new /obj/item/clothing/shoes/sneakers/brown(src) - new /obj/item/clothing/under/rank/captain(src) - new /obj/item/clothing/under/rank/captain/skirt(src) new /obj/item/clothing/suit/armor/vest/capcarapace(src) - new /obj/item/clothing/head/caphat(src) - new /obj/item/clothing/under/captainparade(src) new /obj/item/clothing/suit/armor/vest/capcarapace/alt(src) - new /obj/item/clothing/head/caphat/parade(src) - new /obj/item/clothing/head/caphat/beret(src) - new /obj/item/clothing/suit/captunic(src) - new /obj/item/clothing/under/rank/captain/femformal(src) //citadel edit new /obj/item/clothing/head/crown/fancy(src) new /obj/item/cartridge/captain(src) new /obj/item/storage/box/silver_ids(src) new /obj/item/radio/headset/heads/captain/alt(src) new /obj/item/radio/headset/heads/captain(src) - new /obj/item/clothing/glasses/sunglasses/gar/supergar(src) - new /obj/item/clothing/gloves/color/captain(src) new /obj/item/storage/belt/sabre(src) new /obj/item/gun/energy/e_gun(src) new /obj/item/door_remote/captain(src) new /obj/item/storage/photo_album/Captain(src) - new /obj/item/clothing/head/caphat/beret/white(src) /obj/structure/closet/secure_closet/hop name = "\proper head of personnel's locker" diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index a6c0b22ad7..b14303984e 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -47,6 +47,12 @@ if(manifest) tear_manifest(user) +/obj/structure/closet/crate/tool_interact(obj/item/W, mob/user) + if(W.tool_behaviour == TOOL_WIRECUTTER && manifest) + tear_manifest(user) + return TRUE + return ..() + /obj/structure/closet/crate/open(mob/living/user) . = ..() if(. && manifest) diff --git a/code/game/objects/structures/crates_lockers/crates/bins.dm b/code/game/objects/structures/crates_lockers/crates/bins.dm index 7646fdb35f..bc3697a550 100644 --- a/code/game/objects/structures/crates_lockers/crates/bins.dm +++ b/code/game/objects/structures/crates_lockers/crates/bins.dm @@ -4,8 +4,8 @@ icon_state = "largebins" open_sound = 'sound/effects/bin_open.ogg' close_sound = 'sound/effects/bin_close.ogg' - material_drop = /obj/item/stack/sheet/plastic - material_drop_amount = 40 + material_drop = /obj/item/stack/sheet/metal + material_drop_amount = 10 anchored = TRUE horizontal = FALSE delivery_icon = null diff --git a/code/game/world.dm b/code/game/world.dm index 6b380e0f94..77361310b8 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -10,6 +10,10 @@ GLOBAL_LIST(topic_status_cache) /world/New() enable_debugger() +#if DM_VERSION >= 513 && DM_BUILD >= 1506 + world.Profile(PROFILE_START) +#endif + log_world("World loaded at [TIME_STAMP("hh:mm:ss", FALSE)]!") SetupExternalRSC() @@ -18,7 +22,7 @@ GLOBAL_LIST(topic_status_cache) make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once) - TgsNew() + TgsNew(minimum_required_security_level = TGS_SECURITY_TRUSTED) GLOB.revdata = new diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index ad2eeb7289..cf6d54336e 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -1058,7 +1058,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention) set name = "Start Line Profiling" set desc = "Starts tracking line by line profiling for code lines that support it" - PROFILE_START + LINE_PROFILE_START message_admins("[key_name_admin(src)] started line by line profiling.") SSblackbox.record_feedback("tally", "admin_verb", 1, "Start Line Profiling") @@ -1069,7 +1069,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention) set name = "Stops Line Profiling" set desc = "Stops tracking line by line profiling for code lines that support it" - PROFILE_STOP + LINE_PROFILE_STOP message_admins("[key_name_admin(src)] stopped line by line profiling.") SSblackbox.record_feedback("tally", "admin_verb", 1, "Stop Line Profiling") diff --git a/code/modules/antagonists/clockcult/clock_items/replica_fabricator.dm b/code/modules/antagonists/clockcult/clock_items/replica_fabricator.dm index 501bcdc1c4..7be9ef039b 100644 --- a/code/modules/antagonists/clockcult/clock_items/replica_fabricator.dm +++ b/code/modules/antagonists/clockcult/clock_items/replica_fabricator.dm @@ -68,8 +68,8 @@ /obj/item/clockwork/replica_fabricator/pre_attack(atom/target, mob/living/user, params) if(!target || !user || !is_servant_of_ratvar(user) || istype(target, /obj/item/storage)) - return TRUE - return fabricate(target, user) + return ..() + return !fabricate(target, user) //A note here; return values are for if we CAN BE PUT ON A TABLE, not IF WE ARE SUCCESSFUL, unless no_table_check is TRUE /obj/item/clockwork/replica_fabricator/proc/fabricate(atom/target, mob/living/user, silent, no_table_check) diff --git a/code/modules/antagonists/cult/ritual.dm b/code/modules/antagonists/cult/ritual.dm index ba2a96289d..e92f562db3 100644 --- a/code/modules/antagonists/cult/ritual.dm +++ b/code/modules/antagonists/cult/ritual.dm @@ -116,7 +116,7 @@ This file contains the cult dagger and rune list code if(user.blood_volume) user.apply_damage(initial(rune_to_scribe.scribe_damage), BRUTE, pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) var/scribe_mod = initial(rune_to_scribe.scribe_delay) - if(istype(get_turf(user), /turf/open/floor/engine/cult)) + if(istype(get_turf(user), /turf/open/floor/engine/cult) && !(ispath(rune_to_scribe, /obj/effect/rune/narsie))) scribe_mod *= 0.5 if(!do_after(user, scribe_mod, target = get_turf(user))) for(var/V in shields) diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index fe3b5a3aeb..0d815703c5 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -381,6 +381,7 @@ playsound(src, 'sound/machines/nuke/confirm_beep.ogg', 50, FALSE) set_active() update_ui_mode() + . = TRUE else playsound(src, 'sound/machines/nuke/angry_beep.ogg', 50, FALSE) if("anchor") diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index 539b5ce57a..1e8cce32c0 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -251,6 +251,7 @@ /obj/machinery/atmospherics/components/unary/cryo_cell/close_machine(mob/living/carbon/user) if((isnull(user) || istype(user)) && state_open && !panel_open) ..(user) + reagent_transfer = 0 return occupant /obj/machinery/atmospherics/components/unary/cryo_cell/container_resist(mob/living/user) diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm index 3562350473..c4bb6e8cdd 100644 --- a/code/modules/awaymissions/capture_the_flag.dm +++ b/code/modules/awaymissions/capture_the_flag.dm @@ -466,11 +466,13 @@ // MELEE GANG /obj/item/claymore/ctf - slot_flags = SLOT_BACK + slot_flags = ITEM_SLOT_BACK + armour_penetration = 100 + total_mass = 1 /obj/item/claymore/ctf/pre_attack(atom/target, mob/user, params) if(!is_ctf_target(target)) - return FALSE + return TRUE return ..() /obj/item/claymore/ctf/dropped() diff --git a/code/modules/cargo/bounties/reagent.dm b/code/modules/cargo/bounties/reagent.dm index ca76c80df7..391b4ff464 100644 --- a/code/modules/cargo/bounties/reagent.dm +++ b/code/modules/cargo/bounties/reagent.dm @@ -105,6 +105,7 @@ datum/bounty/reagent/complex_drink/New() /datum/reagent/consumable/ethanol/hearty_punch,\ /datum/reagent/consumable/ethanol/manhattan_proj,\ /datum/reagent/consumable/ethanol/narsour,\ + /datum/reagent/consumable/ethanol/cogchamp,\ /datum/reagent/consumable/ethanol/neurotoxin,\ /datum/reagent/consumable/ethanol/patron,\ /datum/reagent/consumable/ethanol/quadruple_sec,\ diff --git a/code/modules/cargo/exports/large_objects.dm b/code/modules/cargo/exports/large_objects.dm index b8541dcd33..bf67286f11 100644 --- a/code/modules/cargo/exports/large_objects.dm +++ b/code/modules/cargo/exports/large_objects.dm @@ -6,7 +6,7 @@ k_elasticity = 0 unit_name = "crate" export_types = list(/obj/structure/closet/crate) - exclude_types = list(/obj/structure/closet/crate/large, /obj/structure/closet/crate/wooden) + exclude_types = list(/obj/structure/closet/crate/large, /obj/structure/closet/crate/wooden, /obj/structure/closet/crate/bin) /datum/export/large/crate/total_printout(datum/export_report/ex, notes = TRUE) // That's why a goddamn metal crate costs that much. . = ..() diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm index 7c1121d137..ab2f89ffc4 100644 --- a/code/modules/clothing/outfits/standard.dm +++ b/code/modules/clothing/outfits/standard.dm @@ -272,7 +272,7 @@ /datum/outfit/wizard name = "Blue Wizard" - uniform = /obj/item/clothing/under/color/lightpurple + uniform = /obj/item/clothing/under/color/lightpurple/trackless suit = /obj/item/clothing/suit/wizrobe shoes = /obj/item/clothing/shoes/sandal/magic ears = /obj/item/radio/headset diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index e9b96af8eb..b61918c4b8 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -325,17 +325,16 @@ body_parts_covered = CHEST|ARMS /obj/item/clothing/suit/ran - name = "Shikigami costume" + name = "shikigami costume" desc = "A costume that looks like a certain shikigami, is super fluffy." icon_state = "ran_suit" item_state = "ran_suit" body_parts_covered = CHEST|GROIN|LEGS flags_inv = HIDEJUMPSUIT|HIDETAUR heat_protection = CHEST|GROIN|LEGS //fluffy tails! -//2061 /obj/item/clothing/head/ran - name = "Shikigami hat" + name = "shikigami hat" desc = "A hat that looks like it keeps any fluffy ears contained super warm, has little charms over it." icon_state = "ran_hat" item_state = "ran_hat" @@ -880,7 +879,6 @@ blood_overlay_type = "armor" body_parts_covered = CHEST resistance_flags = NONE - mutantrace_variation = NONE armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 5, "bio" = 0, "rad" = 0, "fire" = -5, "acid" = -15) //nylon sucks against acid /obj/item/clothing/suit/assu_suit diff --git a/code/modules/clothing/under/color.dm b/code/modules/clothing/under/color.dm index 12cafb7e46..a18b7e5817 100644 --- a/code/modules/clothing/under/color.dm +++ b/code/modules/clothing/under/color.dm @@ -41,6 +41,10 @@ item_color = "black" resistance_flags = NONE +/obj/item/clothing/under/color/black/trackless + desc = "A black jumpsuit that has its sensors removed." + has_sensor = NO_SENSORS + /obj/item/clothing/under/skirt/color/black name = "black jumpskirt" icon_state = "black_skirt" @@ -189,13 +193,16 @@ item_state = "b_suit" item_color = "teal_skirt" - /obj/item/clothing/under/color/lightpurple name = "purple jumpsuit" icon_state = "lightpurple" item_state = "p_suit" item_color = "lightpurple" +/obj/item/clothing/under/color/lightpurple/trackless + desc = "A magically colored jumpsuit. No sensors are attached!" + has_sensor = NO_SENSORS + /obj/item/clothing/under/skirt/color/lightpurple name = "lightpurple jumpskirt" icon_state = "lightpurple_skirt" diff --git a/code/modules/error_handler/error_handler.dm b/code/modules/error_handler/error_handler.dm index 418b75e1ce..6a3d2c2233 100644 --- a/code/modules/error_handler/error_handler.dm +++ b/code/modules/error_handler/error_handler.dm @@ -19,6 +19,13 @@ GLOBAL_VAR_INIT(total_runtimes_skipped, 0) log_world("The bug with recursion runtimes has been fixed. Please remove the snowflake check from world/Error in [__FILE__]:[__LINE__]") return //this will never happen. + else if(copytext(E.name,1,18) == "Out of resources!")//18 == length() of that string + 1 + log_world("BYOND out of memory. Restarting") + log_game("BYOND out of memory. Restarting") + TgsEndProcess() + Reboot(reason = 1) + return ..() + if (islist(stack_trace_storage)) for (var/line in splittext(E.desc, "\n")) if (text2ascii(line) != 32) diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm index cd5c9d850b..7bd5e66430 100644 --- a/code/modules/food_and_drinks/drinks/drinks.dm +++ b/code/modules/food_and_drinks/drinks/drinks.dm @@ -107,9 +107,9 @@ smash(hit_atom, throwingdatum?.thrower, TRUE) /obj/item/reagent_containers/food/drinks/proc/smash(atom/target, mob/thrower, ranged = FALSE) - if(!isGlass) + if(!isGlass && !istype(src, /obj/item/reagent_containers/food/drinks/bottle)) //I don't like this but I also don't want to rework drink container hierarchy return - if(QDELING(src) || !target) //Invalid loc + if(QDELING(src) || (ranged && !target)) return if(bartender_check(target) && ranged) return @@ -126,12 +126,69 @@ B.transform = M B.pixel_x = rand(-12, 12) B.pixel_y = rand(-12, 12) - if(prob(33)) - new/obj/item/shard(drop_location()) - playsound(src, "shatter", 70, 1) + if(isGlass) + playsound(src, "shatter", 70, 1) + if(prob(33)) + new/obj/item/shard(drop_location()) + else + B.force = 0 + B.throwforce = 0 + B.desc = "A carton with the bottom half burst open. Might give you a papercut." transfer_fingerprints_to(B) qdel(src) +/obj/item/reagent_containers/food/drinks/MouseDrop(atom/over, atom/src_location, atom/over_location, src_control, over_control, params) + var/mob/user = usr + . = ..() + if (!istype(src_location) || !istype(over_location)) + return + if (!user || user.incapacitated() || !user.Adjacent(src)) + return + if (!(locate(/obj/structure/table) in src_location) || !(locate(/obj/structure/table) in over_location)) + return + + //Are we an expert slider? + var/datum/action/innate/D = get_action_of_type(user, /datum/action/innate/drink_fling) + if(!D?.active) + if (!src_location.Adjacent(over_location)) // Regular users can only do short slides. + return + if (prob(10)) + user.visible_message("\The [user] tries to slide \the [src] down the table, but fails miserably.", "You fail to slide \the [src] down the table!") + smash(over_location, user, FALSE) + return + user.visible_message("\The [user] slides \the [src] down the table.", "You slide \the [src] down the table!") + forceMove(over_location) + return + var/distance = MANHATTAN_DISTANCE(over_location, src) + if (distance >= 8 || distance == 0) // More than a full screen to go, or trying to slide to the same tile + return + + // Geometrically checking if we're on a straight line. + var/datum/vector/V = atoms2vector(src, over_location) + var/datum/vector/V_norm = V.duplicate() + V_norm.normalize() + if (!V_norm.is_integer()) + return // Only a cardinal vector (north, south, east, west) can pass this test + + // Checks if there's tables on the path. + var/turf/dest = get_translated_turf(V) + var/turf/temp_turf = src_location + + do + temp_turf = temp_turf.get_translated_turf(V_norm) + if (!locate(/obj/structure/table) in temp_turf) + var/datum/vector/V2 = atoms2vector(src, temp_turf) + vector_translate(V2, 0.1 SECONDS) + user.visible_message("\The [user] slides \the [src] down the table... and straight into the ground!", "You slide \the [src] down the table, and straight into the ground!") + smash(over_location, user, FALSE) + return + while (temp_turf != dest) + + vector_translate(V, 0.1 SECONDS) + user.visible_message("\The [user] expertly slides \the [src] down the table.", "You slide \the [src] down the table. What a pro.") + return + + //////////////////////////////////////////////////////////////////////////////// /// Drinks. END //////////////////////////////////////////////////////////////////////////////// @@ -223,19 +280,24 @@ spillable = TRUE /obj/item/reagent_containers/food/drinks/mug/on_reagent_change(changetype) + cut_overlays() if(reagents.total_volume) - icon_state = "tea" + var/mutable_appearance/MA = mutable_appearance(icon,"mugoverlay") + MA.color = mix_color_from_reagents(reagents.reagent_list) + add_overlay(MA) else icon_state = "tea_empty" /obj/item/reagent_containers/food/drinks/mug/tea name = "Duke Purple tea" + icon_state = "tea" desc = "An insult to Duke Purple is an insult to the Space Queen! Any proper gentleman will fight you, if you sully this tea." list_reagents = list(/datum/reagent/consumable/tea = 30) /obj/item/reagent_containers/food/drinks/mug/coco name = "Dutch hot coco" desc = "Made in Space South America." + icon_state = "coco" list_reagents = list(/datum/reagent/consumable/hot_coco = 30, /datum/reagent/consumable/sugar = 5) foodtype = SUGAR resistance_flags = FREEZE_PROOF @@ -289,28 +351,6 @@ icon_state = "juicebox" volume = 15 //I figure if you have to craft these it should at least be slightly better than something you can get for free from a watercooler -/obj/item/reagent_containers/food/drinks/sillycup/smallcarton/smash(atom/target, mob/thrower, ranged = FALSE) - if(bartender_check(target) && ranged) - return - var/obj/item/broken_bottle/B = new (loc) - B.icon_state = icon_state - var/icon/I = new('icons/obj/drinks.dmi', src.icon_state) - I.Blend(B.broken_outline, ICON_OVERLAY, rand(5), 1) - I.SwapColor(rgb(255, 0, 220, 255), rgb(0, 0, 0, 0)) - B.icon = I - B.name = "broken [name]" - B.force = 0 - B.throwforce = 0 - B.desc = "A carton with the bottom half burst open. Might give you a papercut." - if(ranged) - var/matrix/M = matrix(B.transform) - M.Turn(rand(-170, 170)) - B.transform = M - B.pixel_x = rand(-12, 12) - B.pixel_y = rand(-12, 12) - transfer_fingerprints_to(B) - qdel(src) - /obj/item/reagent_containers/food/drinks/sillycup/smallcarton/on_reagent_change(changetype) if (reagents.reagent_list.len) switch(reagents.get_master_reagent_id()) diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm index 7f2b24ca11..07026e79de 100644 --- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm +++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm @@ -16,40 +16,6 @@ isGlass = TRUE foodtype = ALCOHOL - -/obj/item/reagent_containers/food/drinks/bottle/smash(mob/living/target, mob/thrower, ranged = FALSE) - //Creates a shattering noise and replaces the bottle with a broken_bottle - if(bartender_check(target) && ranged) - return - var/obj/item/broken_bottle/B = new (loc) - if(!ranged) - thrower.put_in_hands(B) - else - var/matrix/M = matrix(B.transform) - M.Turn(rand(-170, 170)) - B.transform = M - B.pixel_x = rand(-12, 12) - B.pixel_y = rand(-12, 12) - B.icon_state = icon_state - - var/icon/I = new('icons/obj/drinks.dmi', src.icon_state) - I.Blend(B.broken_outline, ICON_OVERLAY, rand(5), 1) - I.SwapColor(rgb(255, 0, 220, 255), rgb(0, 0, 0, 0)) - B.icon = I - - if(isGlass) - if(prob(33)) - new/obj/item/shard(drop_location()) - playsound(src, "shatter", 70, 1) - else - B.force = 0 - B.throwforce = 0 - B.desc = "A carton with the bottom half burst open. Might give you a papercut." - B.name = "broken [name]" - transfer_fingerprints_to(B) - - qdel(src) - /obj/item/reagent_containers/food/drinks/bottle/attack(mob/living/target, mob/living/user) if(!target) @@ -109,7 +75,7 @@ //Keeping this here for now, I'll ask if I should keep it here. /obj/item/broken_bottle name = "broken bottle" - desc = "A bottle with a sharp broken bottom." + desc = "A shattered glass container with sharp edges." icon = 'icons/obj/drinks.dmi' icon_state = "broken_bottle" force = 9 diff --git a/code/modules/food_and_drinks/food/snacks_egg.dm b/code/modules/food_and_drinks/food/snacks_egg.dm index f01966a0ff..c65e42c0e4 100644 --- a/code/modules/food_and_drinks/food/snacks_egg.dm +++ b/code/modules/food_and_drinks/food/snacks_egg.dm @@ -96,6 +96,16 @@ tastes = list("egg" = 4, "salt" = 1, "pepper" = 1) foodtype = MEAT | FRIED | BREAKFAST +/obj/item/reagent_containers/food/snacks/baconegg + name = "bacon and eggs" + desc = "A fried egg with a side of bacon. Delicious!" + icon_state = "baconegg" + bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1) + bitesize = 1 + filling_color = "#FFFFF0" + tastes = list("egg" = 2, "bacon" = 2, "salt" = 1, "pepper" = 1) + foodtype = MEAT | FRIED | BREAKFAST + /obj/item/reagent_containers/food/snacks/boiledegg name = "boiled egg" desc = "A hard boiled egg." diff --git a/code/modules/food_and_drinks/food/snacks_pastry.dm b/code/modules/food_and_drinks/food/snacks_pastry.dm index 1c8b70dc13..de1f00ae5d 100644 --- a/code/modules/food_and_drinks/food/snacks_pastry.dm +++ b/code/modules/food_and_drinks/food/snacks_pastry.dm @@ -353,6 +353,13 @@ tastes = list("muffin" = 3, "spookiness" = 1) foodtype = GRAIN | FRUIT | SUGAR | BREAKFAST +/obj/item/reagent_containers/food/snacks/muffin/poppy + name = "poppy muffin" + icon_state = "poppymuffin" + desc = "A classic lemon poppy seed muffin. Do not consume prior to drug testing." + tastes = list("muffin" = 3, "lemon" = 1, "seeds" = 1) + foodtype = GRAIN | SUGAR | BREAKFAST + /obj/item/reagent_containers/food/snacks/chawanmushi name = "chawanmushi" desc = "A legendary egg custard that makes friends out of enemies. Probably too hot for a cat to eat." diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm index 9df650500a..c94118ddf1 100644 --- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm +++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm @@ -585,6 +585,14 @@ mix_message = "The mixture develops a sinister glow." mix_sound = 'sound/effects/singlebeat.ogg' +/datum/chemical_reaction/cogchamp + name = "CogChamp" + id = /datum/reagent/consumable/ethanol/cogchamp + results = list(/datum/reagent/consumable/ethanol/cogchamp = 3) + required_reagents = list(/datum/reagent/consumable/ethanol/cognac = 1, /datum/reagent/fuel = 1, /datum/reagent/consumable/ethanol/screwdrivercocktail = 1) + mix_message = "You hear faint sounds of gears turning as it mixes." + mix_sound = 'sound/effects/clockcult_gateway_closing.ogg' + /datum/chemical_reaction/quadruplesec name = "Quadruple Sec" id = /datum/reagent/consumable/ethanol/quadruple_sec diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm index 6d495d1c79..c049cd7563 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm @@ -13,6 +13,15 @@ result = /obj/item/reagent_containers/food/snacks/friedegg subcategory = CAT_EGG +/datum/crafting_recipe/food/baconegg + name = "Bacon and Eggs" + reqs = list( + /obj/item/reagent_containers/food/snacks/friedegg = 1, + /obj/item/reagent_containers/food/snacks/meat/bacon = 1 + ) + result = /obj/item/reagent_containers/food/snacks/baconegg + subcategory = CAT_EGG + /datum/crafting_recipe/food/omelette name = "Omelette" reqs = list( diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm index b545702e3e..62b8509eb1 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm @@ -377,6 +377,17 @@ datum/crafting_recipe/food/donut/meat result = /obj/item/reagent_containers/food/snacks/muffin/booberry subcategory = CAT_PASTRY +/datum/crafting_recipe/food/poppymuffin + name = "Poppy muffin" + reqs = list( + /datum/reagent/consumable/milk = 5, + /obj/item/reagent_containers/food/snacks/pastrybase = 1, + /obj/item/reagent_containers/food/snacks/grown/citrus/lemon = 1, + /obj/item/seeds/poppy = 1 + ) + result = /obj/item/reagent_containers/food/snacks/muffin/poppy + subcategory = CAT_PASTRY + /datum/crafting_recipe/food/chawanmushi name = "Chawanmushi" reqs = list( diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm index 0ace449757..cffeceea9c 100644 --- a/code/modules/jobs/job_types/bartender.dm +++ b/code/modules/jobs/job_types/bartender.dm @@ -28,3 +28,7 @@ backpack_contents = list(/obj/item/storage/box/beanbag=1,/obj/item/book/granter/action/drink_fling=1) shoes = /obj/item/clothing/shoes/laceup +/datum/job/bartender/after_spawn(mob/living/H, mob/M, latejoin = FALSE) + . = ..() + var/datum/action/innate/drink_fling/D = new + D.Grant(H) diff --git a/code/modules/mining/equipment/resonator.dm b/code/modules/mining/equipment/resonator.dm index f63b459f10..133cb41c33 100644 --- a/code/modules/mining/equipment/resonator.dm +++ b/code/modules/mining/equipment/resonator.dm @@ -46,7 +46,7 @@ /obj/item/resonator/pre_attack(atom/target, mob/user, params) if(check_allowed_items(target, 1)) CreateResonance(target, user) - return TRUE + return ..() //resonance field, crushes rock, damages mobs /obj/effect/temp_visual/resonance diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index 1ddb3a3189..ac4cee8c42 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -93,7 +93,7 @@ req_access = list() circuit = /obj/item/circuitboard/computer/mining_shuttle/common shuttleId = "mining_common" - possible_destinations = "whiteship_home;lavaland_common_away;landing_zone_dock;mining_public" + possible_destinations = "lavaland_common_away;commonmining_home" /**********************Mining car (Crate like thing, not the rail car)**************************/ diff --git a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm index 241ec8118e..92bc8e407b 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm @@ -16,7 +16,7 @@ from doing this unless you absolutely know what you are doing, and have defined a conversion in savefile.dm */ -/proc/init_sprite_accessory_subtypes(prototype, list/L, list/male, list/female,var/roundstart = FALSE)//Roundstart argument builds a specific list for roundstart parts where some parts may be locked +/proc/init_sprite_accessory_subtypes(prototype, list/L, list/male, list/female, roundstart = FALSE, skip_prototype = TRUE)//Roundstart argument builds a specific list for roundstart parts where some parts may be locked if(!istype(L)) L = list() if(!istype(male)) @@ -25,7 +25,7 @@ female = list() for(var/path in typesof(prototype)) - if(path == prototype) + if(path == prototype && skip_prototype) continue if(roundstart) var/datum/sprite_accessory/P = path diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 534509523a..1be9a0d72d 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -581,6 +581,9 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put if(cultslurring) cultslurring = max(cultslurring-1, 0) + if(clockcultslurring) + clockcultslurring = max(clockcultslurring-1, 0) + if(silent) silent = max(silent-1, 0) diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 84f0004805..031a2e9b94 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -89,6 +89,7 @@ var/stuttering = 0 var/slurring = 0 var/cultslurring = 0 + var/clockcultslurring = 0 var/derpspeech = 0 var/list/implants = null diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index b20511986d..b0f627f82b 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -354,6 +354,9 @@ GLOBAL_LIST_INIT(department_radio_keys, list( if(cultslurring) message = cultslur(message) + + if(clockcultslurring) + message = CLOCK_CULT_SLUR(message) message = capitalize(message) diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm index 05b2bc77ba..d8e910642d 100644 --- a/code/modules/mob/living/silicon/pai/pai_defense.dm +++ b/code/modules/mob/living/silicon/pai/pai_defense.dm @@ -1,3 +1,4 @@ +#define PAI_EMP_SILENCE_DURATION 3 MINUTES /mob/living/silicon/pai/blob_act(obj/structure/blob/B) return FALSE @@ -8,7 +9,7 @@ return take_holo_damage(50/severity) Knockdown(400/severity) - silent = max((3 MINUTES)/severity, silent) + silent = max(silent, (PAI_EMP_SILENCE_DURATION) / SSmobs.wait / severity) if(holoform) fold_in(force = TRUE) emitter_next_use = world.time + emitter_emp_cd diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm index f02d21c2af..873051c336 100644 --- a/code/modules/mob/living/simple_animal/friendly/dog.dm +++ b/code/modules/mob/living/simple_animal/friendly/dog.dm @@ -19,7 +19,7 @@ /mob/living/simple_animal/pet/dog/ComponentInitialize() . = ..() - AddElement(/datum/element/wuv, "yaps_happily!", EMOTE_AUDIBLE, /datum/mood_event/pet_animal, "growls!", EMOTE_AUDIBLE) + AddElement(/datum/element/wuv, "yaps happily!", EMOTE_AUDIBLE, /datum/mood_event/pet_animal, "growls!", EMOTE_AUDIBLE) AddElement(/datum/element/mob_holder, held_icon) //Corgis and pugs are now under one dog subtype diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index f4133bcf9d..17e0d3d25b 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -147,6 +147,10 @@ . += newletter return sanitize(.) +//Ratvarian Slurring! + +#define CLOCK_CULT_SLUR(phrase) sanitize(text2ratvar(phrase)) + ///Adds stuttering to the message passed in /proc/stutter(phrase) phrase = html_decode(phrase) @@ -420,13 +424,10 @@ It's fairly easy to fix if dealing with single letters but not so much with comp return TRUE /mob/proc/getImplant(type) - if (!istype(src,/mob/living)) - return - var/mob/living/L = src - for (var/I in L.implants) - if (istype(I,type)) - return I - return null + return + +/mob/living/getImplant(type) + return locate(type) in implants /proc/canGhostWrite(var/mob/A, var/obj/target, var/desc="", var/allow_all=FALSE) if(allow_all & TRUE) diff --git a/code/modules/ninja/outfit.dm b/code/modules/ninja/outfit.dm index 7ee71db1f1..323deed5c4 100644 --- a/code/modules/ninja/outfit.dm +++ b/code/modules/ninja/outfit.dm @@ -1,6 +1,6 @@ /datum/outfit/ninja name = "Space Ninja" - uniform = /obj/item/clothing/under/color/black + uniform = /obj/item/clothing/under/color/black/trackless suit = /obj/item/clothing/suit/space/space_ninja glasses = /obj/item/clothing/glasses/night mask = /obj/item/clothing/mask/gas/space_ninja diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index b15b701272..982afa49c8 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -107,7 +107,7 @@ var/icon_update_needed = FALSE var/obj/machinery/computer/apc_control/remote_control = null var/mob/living/carbon/hijacker - var/hijackerlast = FALSE + var/hijackerlast = TRUE /obj/machinery/power/apc/unlocked locked = FALSE @@ -399,14 +399,14 @@ if (hijacker) var/obj/item/implant/hijack/H = hijacker.getImplant(/obj/item/implant/hijack) hijackerreturn = H && !H.stealthmode - if(last_update_state == update_state && last_update_overlay == update_overlay && hijackerreturn ? hijackerlast : !hijackerlast) + if(last_update_state == update_state && last_update_overlay == update_overlay && hijackerreturn == hijackerlast) return 0 if(last_update_state != update_state) results += 1 - if(last_update_overlay != update_overlay || hijackerreturn ? !hijackerlast : hijackerlast) + if(last_update_overlay != update_overlay || hijackerreturn != hijackerlast) results += 2 - if (hijackerreturn ? !hijackerlast : hijackerlast) - hijackerlast = hijackerreturn ? TRUE : FALSE + if (hijackerreturn != hijackerlast) + hijackerlast = hijackerreturn return results // Used in process so it doesn't update the icon too much diff --git a/code/modules/projectiles/ammunition/energy/gravity.dm b/code/modules/projectiles/ammunition/energy/gravity.dm index eabb4f66d7..be7b618803 100644 --- a/code/modules/projectiles/ammunition/energy/gravity.dm +++ b/code/modules/projectiles/ammunition/energy/gravity.dm @@ -15,15 +15,15 @@ . = ..() /obj/item/ammo_casing/energy/gravity/repulse - projectile_type = /obj/item/projectile/gravityrepulse + projectile_type = /obj/item/projectile/gravity/repulse select_name = "repulse" /obj/item/ammo_casing/energy/gravity/attract - projectile_type = /obj/item/projectile/gravityattract + projectile_type = /obj/item/projectile/gravity/attract select_name = "attract" /obj/item/ammo_casing/energy/gravity/chaos - projectile_type = /obj/item/projectile/gravitychaos + projectile_type = /obj/item/projectile/gravity/chaos select_name = "chaos" diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index e1b62620c7..be43bc48fd 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -150,7 +150,7 @@ if(istype(v, /obj/item/ammo_casing/energy)) //already set ammo_type[v] = isnull(user_can_select)? TRUE : user_can_select else - C = new v //if you put non energycasing/type stuff in here you deserve the runtime + C = new v(src) //if you put non energycasing/type stuff in here you deserve the runtime ammo_type[i] = C ammo_type[C] = isnull(user_can_select)? TRUE : user_can_select set_firemode_index(initial(current_firemode_index)) diff --git a/code/modules/projectiles/pins.dm b/code/modules/projectiles/pins.dm index 0465a611cd..70551d07b6 100644 --- a/code/modules/projectiles/pins.dm +++ b/code/modules/projectiles/pins.dm @@ -69,13 +69,10 @@ if(gun) qdel(gun) - - /obj/item/firing_pin/magic name = "magic crystal shard" desc = "A small enchanted shard which allows magical weapons to fire." - // Test pin, works only near firing range. /obj/item/firing_pin/test_range name = "test-range firing pin" @@ -229,3 +226,16 @@ if(gun) gun.pin = null return ..() + +//Station Locked + +/obj/item/firing_pin/away + name = "station locked pin" + desc = "A firing pin that only will fire when off the station." + +/obj/item/firing_pin/away/pin_auth(mob/living/user) + var/area/station_area = get_area(src) + if(!station_area || is_station_level(station_area.z)) + to_chat(user, "The pin beeps, refusing to fire.") + return FALSE + return TRUE diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm index 02ec167b80..c28d85511e 100644 --- a/code/modules/projectiles/projectile/bullets/shotgun.dm +++ b/code/modules/projectiles/projectile/bullets/shotgun.dm @@ -61,7 +61,7 @@ /obj/item/projectile/bullet/pellet/shotgun_buckshot name = "buckshot pellet" - damage = 10 + damage = 12.5 /obj/item/projectile/bullet/pellet/shotgun_rubbershot name = "rubbershot pellet" diff --git a/code/modules/projectiles/projectile/special/gravity.dm b/code/modules/projectiles/projectile/special/gravity.dm index 0ef9bc6653..ba21ecb28c 100644 --- a/code/modules/projectiles/projectile/special/gravity.dm +++ b/code/modules/projectiles/projectile/special/gravity.dm @@ -1,90 +1,65 @@ -/obj/item/projectile/gravityrepulse +/obj/item/projectile/gravity + name = "gravity bolt" + icon = 'icons/effects/effects.dmi' + icon_state = "chronofield" + hitsound = 'sound/weapons/wave.ogg' + damage = 0 + damage_type = BRUTE + nodamage = TRUE + var/power = 4 + var/list/thrown = list() //normally we wouldn't need this but incase on_hit is called multiple times, yeah.. this is a good idea. + +/obj/item/projectile/gravity/Initialize(mapload) + . = ..() + var/obj/item/ammo_casing/energy/gravity/G = loc + if(istype(G)) + power = min(G.gun.power, 15) + +/obj/item/projectile/gravity/on_hit() + . = ..() + var/turf/T = get_turf(src) + var/list/tothrow = list() + var/list/cachedrange = range(T, power) + for(var/mob/M in cachedrange) + tothrow += M + for(var/obj/O in cachedrange) + tothrow += O + var/safety = 50 + for(var/i in tothrow) + if(!safety) + break + var/atom/movable/AM = i + if((AM == src) || (AM == firer) || (AM.move_resist > MOVE_FORCE_EXTREMELY_STRONG) || AM.anchored || thrown[AM]) + continue + thrown[AM] = TRUE + safety-- + var/target = get_target(T, AM) + if(!target) + return FALSE + AM.throw_at(target, power + 1, 1) + for(var/turf/F in range(T,power)) + new /obj/effect/temp_visual/gravpush(F) + +/obj/item/projectile/gravity/proc/get_target(turf/origin, atom/movable/AM) + return origin + +/obj/item/projectile/gravity/repulse name = "repulsion bolt" - icon = 'icons/effects/effects.dmi' - icon_state = "chronofield" - hitsound = 'sound/weapons/wave.ogg' - damage = 0 - damage_type = BRUTE - nodamage = 1 color = "#33CCFF" - var/turf/T - var/power = 4 - var/list/thrown_items = list() -/obj/item/projectile/gravityrepulse/Initialize() - . = ..() - var/obj/item/ammo_casing/energy/gravity/repulse/C = loc - if(istype(C)) //Hard-coded maximum power so servers can't be crashed by trying to throw the entire Z level's items - power = min(C.gun.power, 15) +/obj/item/projectile/gravity/repulse/get_target(turf/origin, atom/movable/AM) + return get_turf_in_angle(Get_Angle(origin, AM), origin, power) -/obj/item/projectile/gravityrepulse/on_hit() - . = ..() - T = get_turf(src) - for(var/atom/movable/A in range(T, power)) - if(A == src || (firer && A == src.firer) || A.anchored || thrown_items[A]) - continue - var/throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(A, src))) - A.throw_at(throwtarget,power+1,1) - thrown_items[A] = A - for(var/turf/F in range(T,power)) - new /obj/effect/temp_visual/gravpush(F) - -/obj/item/projectile/gravityattract +/obj/item/projectile/gravity/attract name = "attraction bolt" - icon = 'icons/effects/effects.dmi' - icon_state = "chronofield" - hitsound = 'sound/weapons/wave.ogg' - damage = 0 - damage_type = BRUTE - nodamage = 1 color = "#FF6600" - var/turf/T - var/power = 4 - var/list/thrown_items = list() -/obj/item/projectile/gravityattract/Initialize() - . = ..() - var/obj/item/ammo_casing/energy/gravity/attract/C = loc - if(istype(C)) //Hard-coded maximum power so servers can't be crashed by trying to throw the entire Z level's items - power = min(C.gun.power, 15) +/obj/item/projectile/gravity/attract/get_target(turf/origin, atom/movable/AM) + return origin -/obj/item/projectile/gravityattract/on_hit() - . = ..() - T = get_turf(src) - for(var/atom/movable/A in range(T, power)) - if(A == src || (firer && A == src.firer) || A.anchored || thrown_items[A]) - continue - A.throw_at(T, power+1, 1) - thrown_items[A] = A - for(var/turf/F in range(T,power)) - new /obj/effect/temp_visual/gravpush(F) - -/obj/item/projectile/gravitychaos +/obj/item/projectile/gravity/chaos name = "gravitational blast" - icon = 'icons/effects/effects.dmi' - icon_state = "chronofield" - hitsound = 'sound/weapons/wave.ogg' - damage = 0 - damage_type = BRUTE - nodamage = 1 color = "#101010" - var/turf/T - var/power = 4 - var/list/thrown_items = list() -/obj/item/projectile/gravitychaos/Initialize() - . = ..() - var/obj/item/ammo_casing/energy/gravity/chaos/C = loc - if(istype(C)) //Hard-coded maximum power so servers can't be crashed by trying to throw the entire Z level's items - power = min(C.gun.power, 15) - -/obj/item/projectile/gravitychaos/on_hit() - . = ..() - T = get_turf(src) - for(var/atom/movable/A in range(T, power)) - if(A == src|| (firer && A == src.firer) || A.anchored || thrown_items[A]) - continue - A.throw_at(get_edge_target_turf(A, pick(GLOB.cardinals)), power+1, 1) - thrown_items[A] = A - for(var/turf/Z in range(T,power)) - new /obj/effect/temp_visual/gravpush(Z) +/obj/item/projectile/gravity/chaos/get_target(turf/origin, atom/movable/AM) + return get_turf_in_angle(rand(0, 359), origin, power) diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 7a3a7eeec2..ccdbbcc915 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -1513,6 +1513,23 @@ All effects don't start immediately, but rather get worse over time; the rate is M.stuttering = min(M.stuttering + 3, 3) ..() +/datum/reagent/consumable/ethanol/cogchamp + name = "CogChamp" + description = "Now you can fill yourself with the power of Ratvar!" + color = rgb(255, 201, 49) + boozepwr = 10 + quality = DRINK_FANTASTIC + taste_description = "a brass taste with a hint of oil" + glass_icon_state = "cogchamp" + glass_name = "CogChamp" + glass_desc = "Not even Ratvar's Four Generals could withstand this! Qevax Jryy!" + value = 8.13 + +/datum/reagent/consumable/ethanol/cogchamp/on_mob_life(mob/living/carbon/M) + M.clockcultslurring = min(M.clockcultslurring + 3, 3) + M.stuttering = min(M.stuttering + 3, 3) + ..() + /datum/reagent/consumable/ethanol/triple_sec name = "Triple Sec" description = "A sweet and vibrant orange liqueur." diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index b6cb387b81..52eee9f8ea 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -383,7 +383,7 @@ name = "Hot Chocolate" description = "Made with love! And coco beans." nutriment_factor = 3 * REAGENTS_METABOLISM - color = "#403010" // rgb: 64, 48, 16 + color = "#660000" // rgb: 221, 202, 134 taste_description = "creamy chocolate" glass_icon_state = "chocolateglass" glass_name = "glass of chocolate" diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 23176f8a05..6d5c546e7e 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -105,11 +105,11 @@ /obj/item/reagent_containers/proc/bartender_check(atom/target) . = FALSE var/turf/T = get_turf(src) - if(!T || target.CanPass(src, T) || !thrownby || !thrownby.actions) + if(!T || !target.CanPass(src, T) || !thrownby || !thrownby.actions) return - for(var/datum/action/innate/drink_fling/D in thrownby.actions) - if(D.active) - return TRUE + var/datum/action/innate/D = get_action_of_type(thrownby, /datum/action/innate/drink_fling) + if(D?.active) + return TRUE /obj/item/reagent_containers/proc/ForceResetRotation() transform = initial(transform) @@ -131,13 +131,14 @@ if(thrownby) log_combat(thrownby, M, "splashed", R) reagents.reaction(target, TOUCH) - + else if(bartender_check(target) && thrown) visible_message("[src] lands onto the [target.name] without spilling a single drop.") transform = initial(transform) addtimer(CALLBACK(src, .proc/ForceResetRotation), 1) return + else if(isturf(target) && reagents.reagent_list.len && thrownby) log_combat(thrownby, target, "splashed (thrown) [english_list(reagents.reagent_list)]", "in [AREACOORD(target)]") diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index eac8edcbc8..fd4282b1b0 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -423,9 +423,9 @@ else unload_hypo(vial,user) -/obj/item/hypospray/mkii/AltClick(mob/living/user) +/obj/item/hypospray/mkii/CtrlClick(mob/living/user) . = ..() - if(user.canUseTopic(src, FALSE)) + if(user.canUseTopic(src, FALSE) && user.get_active_held_item(src)) switch(mode) if(HYPO_SPRAY) mode = HYPO_INJECT @@ -437,7 +437,7 @@ /obj/item/hypospray/mkii/examine(mob/user) . = ..() - . += "Alt-Click it to toggle its mode from spraying to injecting and vice versa." + . += "Ctrl-Click it to toggle its mode from spraying to injecting and vice versa." #undef HYPO_SPRAY #undef HYPO_INJECT diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index e8c8d14141..4562f348fc 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -172,6 +172,7 @@ /obj/item/reagent_containers/spray/drying_agent name = "drying agent spray" desc = "A spray bottle for drying agent." + icon_state = "cleaner_drying" volume = 100 list_reagents = list(/datum/reagent/drying_agent = 100) amount_per_transfer_from_this = 2 diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm index 2bc56f2fbd..72b2c91e4c 100644 --- a/code/modules/research/designs/misc_designs.dm +++ b/code/modules/research/designs/misc_designs.dm @@ -289,6 +289,16 @@ ////////////Janitor Designs////////////// ///////////////////////////////////////// +/datum/design/mop + name = "Mop" + desc = "Just your everyday standard mop." + id = "mop" + build_type = PROTOLATHE + materials = list(MAT_METAL = 1200, MAT_GLASS = 100) + build_path = /obj/item/mop + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_SERVICE + /datum/design/advmop name = "Advanced Mop" desc = "An upgraded mop with a large internal capacity for holding water or other cleaning chemicals." diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm index 1d65edbe9a..467679fea6 100644 --- a/code/modules/research/designs/weapon_designs.dm +++ b/code/modules/research/designs/weapon_designs.dm @@ -225,6 +225,16 @@ category = list("Firing Pins") departmental_flags = DEPARTMENTAL_FLAG_SECURITY +/datum/design/pin_away + name = "Station Locked Pin" + desc = "This is a security firing pin which only authorizes users who are off station." + id = "pin_away" + build_type = PROTOLATHE + materials = list(MAT_METAL = 1500, MAT_GLASS = 2000) + build_path = /obj/item/firing_pin/away + category = list("Firing Pins") + departmental_flags = DEPARTMENTAL_FLAG_SECURITY + ////////////// //Guns//////// ////////////// diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index d33ef29155..71cfe7c0f5 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -52,13 +52,12 @@ Nothing else in the console has ID requirements. research_control = FALSE /proc/CallMaterialName(ID) + if(GLOB.chemical_reagents_list[ID]) + var/datum/reagent/reagent = GLOB.chemical_reagents_list[ID] + return reagent.name if (ID[1] == "$" && GLOB.materials_list[ID]) var/datum/material/material = GLOB.materials_list[ID] return material.name - - else if(GLOB.chemical_reagents_list[ID]) - var/datum/reagent/reagent = GLOB.chemical_reagents_list[ID] - return reagent.name return "ERROR: Report This" /obj/machinery/computer/rdconsole/proc/SyncRDevices() //Makes sure it is properly sync'ed up with the devices attached to it (if any). diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm index 5037f23cd1..befaf3d96a 100644 --- a/code/modules/research/stock_parts.dm +++ b/code/modules/research/stock_parts.dm @@ -22,7 +22,7 @@ If you create T5+ please take a pass at gene_modder.dm [L40]. Max_values MUST fi if(works_from_distance) user.Beam(T, icon_state = "rped_upgrade", time = 5) T.exchange_parts(user, src) - return FALSE + return TRUE return ..() /obj/item/storage/part_replacer/afterattack(obj/machinery/T, mob/living/user, adjacent, params) diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index e1abfedde6..58aa922936 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -602,7 +602,7 @@ display_name = "Basic Tools" description = "Basic mechanical, electronic, surgical and botanical tools." prereq_ids = list("base") - design_ids = list("screwdriver", "wrench", "wirecutters", "crowbar", "multitool", "welding_tool", "tscanner", "analyzer", "cable_coil", "pipe_painter", "airlock_painter", "scalpel", "circular_saw", "surgicaldrill", "retractor", "cautery", "hemostat", "cultivator", "plant_analyzer", "shovel", "spade", "hatchet") + design_ids = list("screwdriver", "wrench", "wirecutters", "crowbar", "multitool", "welding_tool", "tscanner", "analyzer", "cable_coil", "pipe_painter", "airlock_painter", "scalpel", "circular_saw", "surgicaldrill", "retractor", "cautery", "hemostat", "cultivator", "plant_analyzer", "shovel", "spade", "hatchet", "mop") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 500) export_price = 5000 @@ -666,7 +666,7 @@ display_name = "Weapon Development Technology" description = "Our researchers have found new to weaponize just about everything now." prereq_ids = list("engineering") - design_ids = list("pin_testing", "tele_shield", "lasercarbine") + design_ids = list("pin_testing", "tele_shield", "lasercarbine", "pin_away") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 7500) export_price = 5000 diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm index 097be23c40..c9affe92f9 100644 --- a/code/modules/surgery/bodyparts/bodyparts.dm +++ b/code/modules/surgery/bodyparts/bodyparts.dm @@ -5,6 +5,7 @@ force = 3 throwforce = 3 icon = 'icons/mob/human_parts.dmi' + w_class = WEIGHT_CLASS_SMALL icon_state = "" layer = BELOW_MOB_LAYER //so it isn't hidden behind objects when on the floor var/mob/living/carbon/owner = null diff --git a/code/modules/surgery/experimental_dissection.dm b/code/modules/surgery/experimental_dissection.dm index 40fe90a829..a94abafe4c 100644 --- a/code/modules/surgery/experimental_dissection.dm +++ b/code/modules/surgery/experimental_dissection.dm @@ -24,8 +24,8 @@ /datum/surgery_step/dissection name = "dissection" - implements = list(/obj/item/scalpel/augment = 75, /obj/item/scalpel/advanced = 60, /obj/item/scalpel = 45, /obj/item/kitchen/knife = 20, /obj/item/shard = 10)// special tools not only cut down time but also improve probability, doesn't use TOOL_SCALPEL because different scalpels have different probs - time = 125 + implements = list(/obj/item/scalpel/alien = 100, /obj/item/scalpel/advanced = 99, /obj/item/scalpel = 90, /obj/item/kitchen/knife = 45, /obj/item/shard = 25)// special tools not only cut down time but also improve probability, doesn't use TOOL_SCALPEL because different scalpels have different probs + time = 100 silicons_obey_prob = TRUE repeatable = TRUE @@ -110,4 +110,4 @@ requires_tech = TRUE replaced_by = null -#undef BASE_HUMAN_REWARD \ No newline at end of file +#undef BASE_HUMAN_REWARD diff --git a/code/modules/tgs/core/core.dm b/code/modules/tgs/core/core.dm index 61f1e71d2e..70252cfb49 100644 --- a/code/modules/tgs/core/core.dm +++ b/code/modules/tgs/core/core.dm @@ -1,47 +1,60 @@ -/world/TgsNew(datum/tgs_event_handler/event_handler) - var/tgs_version = world.params[TGS_VERSION_PARAMETER] - if(!tgs_version) +/world/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE) + var/current_api = TGS_READ_GLOBAL(tgs) + if(current_api) + TGS_ERROR_LOG("TgsNew(): TGS API datum already set ([current_api])! Was TgsNew() called more than once?") return - var/path = SelectTgsApi(tgs_version) - if(!path) - TGS_ERROR_LOG("Found unsupported API version: [tgs_version]. If this is a valid version please report this, backporting is done on demand.") +#ifdef TGS_V3_API + minimum_required_security_level = TGS_SECURITY_TRUSTED +#endif + var/raw_parameter = world.params[TGS_VERSION_PARAMETER] + if(!raw_parameter) + return - TGS_INFO_LOG("Activating API for version [tgs_version]") - var/datum/tgs_api/new_api = new path + var/datum/tgs_version/version = new(raw_parameter) + if(!version.Valid(FALSE)) + TGS_ERROR_LOG("Failed to validate TGS version parameter: [raw_parameter]!") + return - var/result = new_api.OnWorldNew(event_handler ? event_handler : new /datum/tgs_event_handler/tgs_default) - if(result && result != TGS_UNIMPLEMENTED) - TGS_WRITE_GLOBAL(tgs, new_api) - else + var/api_datum + switch(version.suite) + if(3) +#ifndef TGS_V3_API + TGS_ERROR_LOG("Detected V3 API but TGS_V3_API isn't defined!") +#else + switch(version.major) + if(2) + api_datum = /datum/tgs_api/v3210 +#endif + if(4) + switch(version.major) + if(0) + api_datum = /datum/tgs_api/v4 + + var/datum/tgs_version/max_api_version = TgsMaximumAPIVersion(); + if(version.suite != null && version.major != null && version.minor != null && version.patch != null && version.deprefixed_parameter > max_api_version.deprefixed_parameter) + TGS_ERROR_LOG("Detected unknown API version! Defaulting to latest. Update the DMAPI to fix this problem.") + api_datum = /datum/tgs_api/latest + + if(!api_datum) + TGS_ERROR_LOG("Found unsupported API version: [raw_parameter]. If this is a valid version please report this, backporting is done on demand.") + return + + TGS_INFO_LOG("Activating API for version [version.deprefixed_parameter]") + var/datum/tgs_api/new_api = new api_datum(version) + + TGS_WRITE_GLOBAL(tgs, new_api) + + var/result = new_api.OnWorldNew(event_handler, minimum_required_security_level) + if(!result || result == TGS_UNIMPLEMENTED) + TGS_WRITE_GLOBAL(tgs, null) TGS_ERROR_LOG("Failed to activate API!") -/world/proc/SelectTgsApi(tgs_version) - //remove the old 3.0 header - tgs_version = replacetext(tgs_version, "/tg/station 13 Server v", "") - - var/list/version_bits = splittext(tgs_version, ".") - - var/super = text2num(version_bits[1]) - var/major = text2num(version_bits[2]) - var/minor = text2num(version_bits[3]) - var/patch = text2num(version_bits[4]) - - switch(super) - if(3) - switch(major) - if(2) - return /datum/tgs_api/v3210 - - if(super != null && major != null && minor != null && patch != null && tgs_version > TgsMaximumAPIVersion()) - TGS_ERROR_LOG("Detected unknown API version! Defaulting to latest. Update the DMAPI to fix this problem.") - return /datum/tgs_api/latest - /world/TgsMaximumAPIVersion() - return "4.0.0.0" + return new /datum/tgs_version("4.0.x.x") /world/TgsMinimumAPIVersion() - return "3.2.0.0" + return new /datum/tgs_version("3.2.0.0") /world/TgsInitializationComplete() var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) @@ -71,7 +84,9 @@ return TGS_READ_GLOBAL(tgs) != null /world/TgsVersion() - return world.params[TGS_VERSION_PARAMETER] + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + return api.version /world/TgsInstanceName() var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) @@ -116,6 +131,11 @@ if(api) api.ChatPrivateMessage(message, user) +/world/TgsSecurityLevel() + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + api.SecurityLevel() + /* The MIT License diff --git a/code/modules/tgs/core/datum.dm b/code/modules/tgs/core/datum.dm index 6af39a75df..fb2508059a 100644 --- a/code/modules/tgs/core/datum.dm +++ b/code/modules/tgs/core/datum.dm @@ -1,9 +1,14 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null) /datum/tgs_api + var/datum/tgs_version/version + +/datum/tgs_api/New(datum/tgs_version/version) + . = ..() + src.version = version /datum/tgs_api/latest - parent_type = /datum/tgs_api/v3210 + parent_type = /datum/tgs_api/v4 TGS_PROTECT_DATUM(/datum/tgs_api) @@ -46,6 +51,9 @@ TGS_PROTECT_DATUM(/datum/tgs_api) /datum/tgs_api/proc/ChatPrivateMessage(message, admin_only) return TGS_UNIMPLEMENTED +/datum/tgs_api/proc/SecurityLevel() + return TGS_UNIMPLEMENTED + /* The MIT License diff --git a/code/modules/tgs/core/default_event_handler.dm b/code/modules/tgs/core/default_event_handler.dm deleted file mode 100644 index 716715bb26..0000000000 --- a/code/modules/tgs/core/default_event_handler.dm +++ /dev/null @@ -1,30 +0,0 @@ -/datum/tgs_event_handler/tgs_default/HandleEvent(event_code) - //TODO - return - -/* -The MIT License - -Copyright (c) 2017 Jordan Brown - -Permission is hereby granted, free of charge, -to any person obtaining a copy of this software and -associated documentation files (the "Software"), to -deal in the Software without restriction, including -without limitation the rights to use, copy, modify, -merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom -the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR -ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ diff --git a/code/modules/tgs/core/tgs_version.dm b/code/modules/tgs/core/tgs_version.dm new file mode 100644 index 0000000000..b97745611f --- /dev/null +++ b/code/modules/tgs/core/tgs_version.dm @@ -0,0 +1,22 @@ +/datum/tgs_version/New(raw_parameter) + src.raw_parameter = raw_parameter + deprefixed_parameter = replacetext(raw_parameter, "/tg/station 13 Server v", "") + var/list/version_bits = splittext(deprefixed_parameter, ".") + + suite = text2num(version_bits[1]) + if(version_bits.len > 1) + major = text2num(version_bits[2]) + if(version_bits.len > 2) + minor = text2num(version_bits[3]) + if(version_bits.len == 4) + patch = text2num(version_bits[4]) + +/datum/tgs_version/proc/Valid(allow_wildcards = FALSE) + if(suite == null) + return FALSE + if(allow_wildcards) + return TRUE + return !Wildcard() + +/datum/tgs_version/Wildcard() + return major == null || minor == null || patch == null diff --git a/code/modules/tgs/includes.dm b/code/modules/tgs/includes.dm index 7ca906c840..247f1fda5d 100644 --- a/code/modules/tgs/includes.dm +++ b/code/modules/tgs/includes.dm @@ -1,6 +1,10 @@ #include "core\_definitions.dm" #include "core\core.dm" #include "core\datum.dm" -#include "core\default_event_handler.dm" +#include "core\tgs_version.dm" +#ifdef TGS_V3_API #include "v3210\api.dm" #include "v3210\commands.dm" +#endif +#include "v4\api.dm" +#include "v4\commands.dm" diff --git a/code/modules/tgs/v3210/api.dm b/code/modules/tgs/v3210/api.dm index 2a95f7861e..c536995b04 100644 --- a/code/modules/tgs/v3210/api.dm +++ b/code/modules/tgs/v3210/api.dm @@ -56,8 +56,9 @@ /datum/tgs_api/v3210/proc/file2list(filename) return splittext(trim_left(trim_right(file2text(filename))), "\n") -/datum/tgs_api/v3210/OnWorldNew(datum/tgs_event_handler/event_handler) //don't use event handling in this version +/datum/tgs_api/v3210/OnWorldNew(datum/tgs_event_handler/event_handler, minimum_required_security_level) //don't use event handling in this version . = FALSE + comms_key = world.params[SERVICE_WORLD_PARAM] instance_name = world.params[SERVICE_INSTANCE_PARAM] if(!instance_name) @@ -170,6 +171,7 @@ var/datum/tgs_revision_information/ri = new ri.commit = commit ri.origin_commit = originmastercommit + return ri /datum/tgs_api/v3210/EndProcess() sleep(world.tick_lag) //flush the buffers @@ -187,9 +189,12 @@ /datum/tgs_api/v3210/ChatTargetedBroadcast(message, admin_only) ExportService("[admin_only ? SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE : SERVICE_REQUEST_IRC_BROADCAST] [message]") -/datum/tgs_api/v3210/ChatPrivateMessage(message, admin_only) +/datum/tgs_api/v3210/ChatPrivateMessage(message, datum/tgs_chat_user/user) return TGS_UNIMPLEMENTED +/datum/tgs_api/v3210/SecurityLevel() + return TGS_SECURITY_TRUSTED + #undef REBOOT_MODE_NORMAL #undef REBOOT_MODE_HARD #undef REBOOT_MODE_SHUTDOWN diff --git a/code/modules/tgs/v4/api.dm b/code/modules/tgs/v4/api.dm new file mode 100644 index 0000000000..b61cddbeba --- /dev/null +++ b/code/modules/tgs/v4/api.dm @@ -0,0 +1,342 @@ +#define TGS4_PARAM_INFO_JSON "tgs_json" + +#define TGS4_INTEROP_ACCESS_IDENTIFIER "tgs_tok" + +#define TGS4_RESPONSE_SUCCESS "tgs_succ" + +#define TGS4_TOPIC_CHANGE_PORT "tgs_port" +#define TGS4_TOPIC_CHANGE_REBOOT_MODE "tgs_rmode" +#define TGS4_TOPIC_CHAT_COMMAND "tgs_chat_comm" +#define TGS4_TOPIC_EVENT "tgs_event" +#define TGS4_TOPIC_INTEROP_RESPONSE "tgs_interop" + +#define TGS4_COMM_NEW_PORT "tgs_new_port" +#define TGS4_COMM_VALIDATE "tgs_validate" +#define TGS4_COMM_SERVER_PRIMED "tgs_prime" +#define TGS4_COMM_WORLD_REBOOT "tgs_reboot" +#define TGS4_COMM_END_PROCESS "tgs_kill" +#define TGS4_COMM_CHAT "tgs_chat_send" + +#define TGS4_PARAMETER_COMMAND "tgs_com" +#define TGS4_PARAMETER_DATA "tgs_data" + +#define TGS4_PORT_CRITFAIL_MESSAGE " Must exit to let watchdog reboot..." + +#define EXPORT_TIMEOUT_DS 200 + +/datum/tgs_api/v4 + var/access_identifier + var/instance_name + var/json_path + var/chat_channels_json_path + var/chat_commands_json_path + var/server_commands_json_path + var/reboot_mode = TGS_REBOOT_MODE_NORMAL + var/security_level + + var/requesting_new_port = FALSE + + var/list/intercepted_message_queue + + var/list/custom_commands + + var/list/cached_test_merges + var/datum/tgs_revision_information/cached_revision + + var/datum/tgs_event_handler/event_handler + + var/export_lock = FALSE + var/list/last_interop_response + +/datum/tgs_api/v4/ApiVersion() + return "4.0.0.0" + +/datum/tgs_api/v4/OnWorldNew(datum/tgs_event_handler/event_handler, minimum_required_security_level) + json_path = world.params[TGS4_PARAM_INFO_JSON] + if(!json_path) + TGS_ERROR_LOG("Missing [TGS4_PARAM_INFO_JSON] world parameter!") + return + var/json_file = file2text(json_path) + if(!json_file) + TGS_ERROR_LOG("Missing specified json file: [json_path]") + return + var/cached_json = json_decode(json_file) + if(!cached_json) + TGS_ERROR_LOG("Failed to decode info json: [json_file]") + return + + access_identifier = cached_json["accessIdentifier"] + server_commands_json_path = cached_json["serverCommandsJson"] + + if(cached_json["apiValidateOnly"]) + TGS_INFO_LOG("Validating API and exiting...") + Export(TGS4_COMM_VALIDATE, list(TGS4_PARAMETER_DATA = "[minimum_required_security_level]")) + del(world) + + security_level = cached_json["securityLevel"] + chat_channels_json_path = cached_json["chatChannelsJson"] + chat_commands_json_path = cached_json["chatCommandsJson"] + src.event_handler = event_handler + instance_name = cached_json["instanceName"] + + ListCustomCommands() + + var/list/revisionData = cached_json["revision"] + if(revisionData) + cached_revision = new + cached_revision.commit = revisionData["commitSha"] + cached_revision.origin_commit = revisionData["originCommitSha"] + + cached_test_merges = list() + var/list/json = cached_json["testMerges"] + for(var/entry in json) + var/datum/tgs_revision_information/test_merge/tm = new + tm.time_merged = text2num(entry["timeMerged"]) + + var/list/revInfo = entry["revision"] + if(revInfo) + tm.commit = revInfo["commitSha"] + tm.origin_commit = revInfo["originCommitSha"] + + tm.title = entry["titleAtMerge"] + tm.body = entry["bodyAtMerge"] + tm.url = entry["url"] + tm.author = entry["author"] + tm.number = entry["number"] + tm.pull_request_commit = entry["pullRequestRevision"] + tm.comment = entry["comment"] + + cached_test_merges += tm + + return TRUE + +/datum/tgs_api/v4/OnInitializationComplete() + Export(TGS4_COMM_SERVER_PRIMED) + + var/tgs4_secret_sleep_offline_sauce = 24051994 + var/old_sleep_offline = world.sleep_offline + world.sleep_offline = tgs4_secret_sleep_offline_sauce + sleep(1) + if(world.sleep_offline == tgs4_secret_sleep_offline_sauce) //if not someone changed it + world.sleep_offline = old_sleep_offline + +/datum/tgs_api/v4/OnTopic(T) + var/list/params = params2list(T) + var/their_sCK = params[TGS4_INTEROP_ACCESS_IDENTIFIER] + if(!their_sCK) + return FALSE //continue world/Topic + + if(their_sCK != access_identifier) + return "Invalid comms key!"; + + var/command = params[TGS4_PARAMETER_COMMAND] + if(!command) + return "No command!" + + . = TGS4_RESPONSE_SUCCESS + + switch(command) + if(TGS4_TOPIC_CHAT_COMMAND) + var/result = HandleCustomCommand(params[TGS4_PARAMETER_DATA]) + if(result == null) + result = "Error running chat command!" + return result + if(TGS4_TOPIC_EVENT) + intercepted_message_queue = list() + var/list/event_notification = json_decode(params[TGS4_PARAMETER_DATA]) + var/list/event_parameters = event_notification["Parameters"] + + var/list/event_call = list(event_notification["Type"]) + if(event_parameters) + event_call += event_parameters + + if(event_handler != null) + event_handler.HandleEvent(arglist(event_call)) + + . = json_encode(intercepted_message_queue) + intercepted_message_queue = null + return + if(TGS4_TOPIC_INTEROP_RESPONSE) + last_interop_response = json_decode(params[TGS4_PARAMETER_DATA]) + return + if(TGS4_TOPIC_CHANGE_PORT) + var/new_port = text2num(params[TGS4_PARAMETER_DATA]) + if (!(new_port > 0)) + return "Invalid port: [new_port]" + + //the topic still completes, miraculously + //I honestly didn't believe byond could do it + if(event_handler != null) + event_handler.HandleEvent(TGS_EVENT_PORT_SWAP, new_port) + if(!world.OpenPort(new_port)) + return "Port change failed!" + return + if(TGS4_TOPIC_CHANGE_REBOOT_MODE) + var/new_reboot_mode = text2num(params[TGS4_PARAMETER_DATA]) + if(event_handler != null) + event_handler.HandleEvent(TGS_EVENT_REBOOT_MODE_CHANGE, reboot_mode, new_reboot_mode) + reboot_mode = new_reboot_mode + return + + return "Unknown command: [command]" + +/datum/tgs_api/v4/proc/Export(command, list/data, override_requesting_new_port = FALSE) + if(!data) + data = list() + data[TGS4_PARAMETER_COMMAND] = command + var/json = json_encode(data) + + while(requesting_new_port && !override_requesting_new_port) + sleep(1) + + //we need some port open at this point to facilitate return communication + if(!world.port) + requesting_new_port = TRUE + if(!world.OpenPort(0)) //open any port + TGS_ERROR_LOG("Unable to open random port to retrieve new port![TGS4_PORT_CRITFAIL_MESSAGE]") + del(world) + + //request a new port + export_lock = FALSE + var/list/new_port_json = Export(TGS4_COMM_NEW_PORT, list(TGS4_PARAMETER_DATA = "[world.port]"), TRUE) //stringify this on purpose + + if(!new_port_json) + TGS_ERROR_LOG("No new port response from server![TGS4_PORT_CRITFAIL_MESSAGE]") + del(world) + + var/new_port = new_port_json[TGS4_PARAMETER_DATA] + if(!isnum(new_port) || new_port <= 0) + TGS_ERROR_LOG("Malformed new port json ([json_encode(new_port_json)])![TGS4_PORT_CRITFAIL_MESSAGE]") + del(world) + + if(new_port != world.port && !world.OpenPort(new_port)) + TGS_ERROR_LOG("Unable to open port [new_port]![TGS4_PORT_CRITFAIL_MESSAGE]") + del(world) + requesting_new_port = FALSE + + while(export_lock) + sleep(1) + export_lock = TRUE + + last_interop_response = null + fdel(server_commands_json_path) + text2file(json, server_commands_json_path) + + for(var/I = 0; I < EXPORT_TIMEOUT_DS && !last_interop_response; ++I) + sleep(1) + + if(!last_interop_response) + TGS_ERROR_LOG("Failed to get export result for: [json]") + else + . = last_interop_response + + export_lock = FALSE + +/datum/tgs_api/v4/OnReboot() + var/list/result = Export(TGS4_COMM_WORLD_REBOOT) + if(!result) + return + + //okay so the standard TGS4 proceedure is: right before rebooting change the port to whatever was sent to us in the above json's data parameter + + var/port = result[TGS4_PARAMETER_DATA] + if(!isnum(port)) + return //this is valid, server may just want use to reboot + + if(port == 0) + //to byond 0 means any port and "none" means close vOv + port = "none" + + if(!world.OpenPort(port)) + TGS_ERROR_LOG("Unable to set port to [port]!") + +/datum/tgs_api/v4/InstanceName() + return instance_name + +/datum/tgs_api/v4/TestMerges() + return cached_test_merges + +/datum/tgs_api/v4/EndProcess() + Export(TGS4_COMM_END_PROCESS) + +/datum/tgs_api/v4/Revision() + return cached_revision + +/datum/tgs_api/v4/ChatBroadcast(message, list/channels) + var/list/ids + if(length(channels)) + ids = list() + for(var/I in channels) + var/datum/tgs_chat_channel/channel = I + ids += channel.id + message = list("message" = message, "channelIds" = ids) + if(intercepted_message_queue) + intercepted_message_queue += list(message) + else + Export(TGS4_COMM_CHAT, message) + +/datum/tgs_api/v4/ChatTargetedBroadcast(message, admin_only) + var/list/channels = list() + for(var/I in ChatChannelInfo()) + var/datum/tgs_chat_channel/channel = I + if (!channel.is_private_channel && ((channel.is_admin_channel && admin_only) || (!channel.is_admin_channel && !admin_only))) + channels += channel.id + message = list("message" = message, "channelIds" = channels) + if(intercepted_message_queue) + intercepted_message_queue += list(message) + else + Export(TGS4_COMM_CHAT, message) + +/datum/tgs_api/v4/ChatPrivateMessage(message, datum/tgs_chat_user/user) + message = list("message" = message, "channelIds" = list(user.channel.id)) + if(intercepted_message_queue) + intercepted_message_queue += list(message) + else + Export(TGS4_COMM_CHAT, message) + +/datum/tgs_api/v4/ChatChannelInfo() + . = list() + //no caching cause tgs may change this + var/list/json = json_decode(file2text(chat_channels_json_path)) + for(var/I in json) + . += DecodeChannel(I) + +/datum/tgs_api/v4/proc/DecodeChannel(channel_json) + var/datum/tgs_chat_channel/channel = new + channel.id = channel_json["id"] + channel.friendly_name = channel_json["friendlyName"] + channel.connection_name = channel_json["connectionName"] + channel.is_admin_channel = channel_json["isAdminChannel"] + channel.is_private_channel = channel_json["isPrivateChannel"] + channel.custom_tag = channel_json["tag"] + return channel + +/datum/tgs_api/v4/SecurityLevel() + return security_level + +/* +The MIT License + +Copyright (c) 2017 Jordan Brown + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ diff --git a/code/modules/tgs/v4/commands.dm b/code/modules/tgs/v4/commands.dm new file mode 100644 index 0000000000..af21a86fb6 --- /dev/null +++ b/code/modules/tgs/v4/commands.dm @@ -0,0 +1,69 @@ +/datum/tgs_api/v4/proc/ListCustomCommands() + var/results = list() + custom_commands = list() + for(var/I in typesof(/datum/tgs_chat_command) - /datum/tgs_chat_command) + var/datum/tgs_chat_command/stc = new I + var/command_name = stc.name + if(!command_name || findtext(command_name, " ") || findtext(command_name, "'") || findtext(command_name, "\"")) + TGS_ERROR_LOG("Custom command [command_name] ([I]) can't be used as it is empty or contains illegal characters!") + continue + + if(results[command_name]) + var/datum/other = custom_commands[command_name] + TGS_ERROR_LOG("Custom commands [other.type] and [I] have the same name (\"[command_name]\"), only [other.type] will be available!") + continue + results += list(list("name" = command_name, "help_text" = stc.help_text, "admin_only" = stc.admin_only)) + custom_commands[command_name] = stc + + var/commands_file = chat_commands_json_path + if(!commands_file) + return + text2file(json_encode(results), commands_file) + +/datum/tgs_api/v4/proc/HandleCustomCommand(command_json) + var/list/data = json_decode(command_json) + var/command = data["command"] + var/user = data["user"] + var/params = data["params"] + + var/datum/tgs_chat_user/u = new + u.id = user["id"] + u.friendly_name = user["friendlyName"] + u.mention = user["mention"] + u.channel = DecodeChannel(user["channel"]) + + var/datum/tgs_chat_command/sc = custom_commands[command] + if(sc) + var/result = sc.Run(u, params) + if(result == null) + result = "" + return result + return "Unknown command: [command]!" + +/* + +The MIT License + +Copyright (c) 2017 Jordan Brown + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ diff --git a/code/modules/vending/snack.dm b/code/modules/vending/snack.dm index efb0905f6b..9dda649b24 100644 --- a/code/modules/vending/snack.dm +++ b/code/modules/vending/snack.dm @@ -4,22 +4,25 @@ product_slogans = "Try our new nougat bar!;Twice the calories for half the price!" product_ads = "The healthiest!;Award-winning chocolate bars!;Mmm! So good!;Oh my god it's so juicy!;Have a snack.;Snacks are good for you!;Have some more Getmore!;Best quality snacks straight from mars.;We love chocolate!;Try our new jerky!" icon_state = "snack" - products = list(/obj/item/reagent_containers/food/snacks/candy = 6, - /obj/item/reagent_containers/food/drinks/dry_ramen = 6, - /obj/item/reagent_containers/food/snacks/chips = 6, - /obj/item/reagent_containers/food/snacks/sosjerky = 6, - /obj/item/reagent_containers/food/snacks/no_raisin = 6, - /obj/item/reagent_containers/food/snacks/spacetwinkie = 6, - /obj/item/reagent_containers/food/snacks/cheesiehonkers = 6) + products = list(/obj/item/reagent_containers/food/snacks/candy = 5, + /obj/item/reagent_containers/food/snacks/chocolatebar = 5, + /obj/item/reagent_containers/food/drinks/dry_ramen = 5, + /obj/item/reagent_containers/food/snacks/chips = 5, + /obj/item/reagent_containers/food/snacks/sosjerky = 5, + /obj/item/reagent_containers/food/snacks/no_raisin = 5, + /obj/item/reagent_containers/food/snacks/spacetwinkie = 5, + /obj/item/reagent_containers/food/snacks/cheesiehonkers = 5, + /obj/item/reagent_containers/food/snacks/cornchips = 5) contraband = list( - /obj/item/reagent_containers/food/snacks/cracker = 12, - /obj/item/reagent_containers/food/snacks/beans = 2, - /obj/item/reagent_containers/food/snacks/honeybar = 6, - /obj/item/reagent_containers/food/snacks/syndicake = 6) + /obj/item/reagent_containers/food/snacks/cracker = 10, + /obj/item/reagent_containers/food/snacks/honeybar = 5, + /obj/item/reagent_containers/food/snacks/syndicake = 5, + /obj/item/reagent_containers/food/snacks/beans = 2) premium = list( /obj/item/reagent_containers/food/snacks/lollipop = 2, /obj/item/reagent_containers/food/snacks/spiderlollipop = 2, /obj/item/reagent_containers/food/snacks/chococoin = 1, + /obj/item/storage/box/marshmallow = 1, /obj/item/storage/box/donkpockets = 2) refill_canister = /obj/item/vending_refill/snack diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm index 0a3ded63bd..5d2e08734e 100644 --- a/code/modules/vending/wardrobes.dm +++ b/code/modules/vending/wardrobes.dm @@ -399,3 +399,35 @@ /obj/item/vending_refill/wardrobe/viro_wardrobe machine_name = "ViroDrobe" + +/obj/machinery/vending/wardrobe/cap_wardrobe + name = "Captain's Wardrobe" + desc = "The latest and greatest in Nanotrasen fashion for your great leader." + icon_state = "capsdrobe" + icon_deny = "capsdrobe-deny" + product_ads = "Only the greatest for a commander such as ours." + req_access = list(ACCESS_CAPTAIN) + vend_reply = "A wonderful day to you, great leader." + products = list(/obj/item/clothing/suit/hooded/wintercoat/captain = 1, + /obj/item/storage/backpack/captain = 1, + /obj/item/storage/backpack/satchel/cap = 1, + /obj/item/storage/backpack/duffelbag/captain = 1, + /obj/item/clothing/neck/cloak/cap = 1, + /obj/item/clothing/shoes/sneakers/brown = 2, + /obj/item/clothing/under/rank/captain = 1, + /obj/item/clothing/under/rank/captain/skirt = 1, + /obj/item/clothing/head/caphat = 1, + /obj/item/clothing/head/caphat/parade = 1, + /obj/item/clothing/head/caphat/beret = 1, + /obj/item/clothing/head/caphat/beret/white = 1, + /obj/item/clothing/under/captainparade = 1, + /obj/item/clothing/suit/captunic = 1, + /obj/item/clothing/under/rank/captain/femformal = 1, + /obj/item/clothing/glasses/sunglasses/gar/supergar = 1, + /obj/item/clothing/gloves/color/captain = 1) + refill_canister = /obj/item/vending_refill/wardrobe/cap_wardrobe + +/obj/item/vending_refill/wardrobe/cap_wardrobe + machine_name = "Captain's Wardrobe" + icon_state = "refill_caps" + \ No newline at end of file diff --git a/config/config.txt b/config/config.txt index b91e8fce33..0ab0cc911e 100644 --- a/config/config.txt +++ b/config/config.txt @@ -448,8 +448,14 @@ MINUTE_CLICK_LIMIT 400 ##How long to wait between messaging admins about occurences of a unique error #ERROR_MSG_DELAY 50 -## Send a message to IRC when starting a new game -#IRC_ANNOUNCE_NEW_GAME +## Chat Announce Options +## Various messages to be sent to game chats +## Uncommenting these will enable them, by default they will be broadcast to Game chat channels on TGS3 or non-admin channels on TGS4 +## If using TGS4, the string option can be set as a chat channel tag to limit the message to channels of that tag type (case-sensitive) +## i.e. CHAT_ANNOUNCE_NEW_GAME chat_channel_tag + +## Send a message with the station name starting a new game +#CHAT_ANNOUNCE_NEW_GAME ## Allow admin hrefs that don't use the new token system, will eventually be removed DEBUG_ADMIN_HREFS @@ -500,3 +506,5 @@ FAIL2TOPIC_MAX_FAILS 5 ## Firewall rule name used on physical server FAIL2TOPIC_RULE_NAME _dd_fail2topic +## Enable automatic profiling - Byond 513.1506 and newer only. +#AUTO_PROFILE diff --git a/html/changelogs/AutoChangeLog-pr-10861.yml b/html/changelogs/AutoChangeLog-pr-10861.yml new file mode 100644 index 0000000000..5071cc30f9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10861.yml @@ -0,0 +1,4 @@ +author: "ancientpower" +delete-after: True +changes: + - rscadd: "Ported drink sliding from /vg/station." diff --git a/html/changelogs/AutoChangeLog-pr-10913.yml b/html/changelogs/AutoChangeLog-pr-10913.yml new file mode 100644 index 0000000000..8bf549a154 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10913.yml @@ -0,0 +1,4 @@ +author: "Feasel" +delete-after: True +changes: + - balance: "Buffed dissection success chances." diff --git a/html/changelogs/AutoChangeLog-pr-10943.yml b/html/changelogs/AutoChangeLog-pr-10943.yml new file mode 100644 index 0000000000..f45d8b1d39 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10943.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed a little inconvenience with the character setup preview dummy having extra unwarranted bits." diff --git a/html/changelogs/AutoChangeLog-pr-10955.yml b/html/changelogs/AutoChangeLog-pr-10955.yml new file mode 100644 index 0000000000..46ff62efaf --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10955.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - rscadd: "gravity gun repulse and chaos now work in all angles, rather than just basic cardinals and diagonals. fun." diff --git a/html/changelogs/AutoChangeLog-pr-10961.yml b/html/changelogs/AutoChangeLog-pr-10961.yml new file mode 100644 index 0000000000..eaaafab472 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10961.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed an issue with the nearsighted prescription glasses taking over worn eyewear." diff --git a/html/changelogs/AutoChangeLog-pr-10969.yml b/html/changelogs/AutoChangeLog-pr-10969.yml new file mode 100644 index 0000000000..fdd53cdd2f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10969.yml @@ -0,0 +1,4 @@ +author: "Seris02" +delete-after: True +changes: + - rscadd: "crowbarring manifests off crates" diff --git a/html/changelogs/AutoChangeLog-pr-10973.yml b/html/changelogs/AutoChangeLog-pr-10973.yml new file mode 100644 index 0000000000..8946cddb43 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10973.yml @@ -0,0 +1,4 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - rscadd: "Firing pins that only works when not on station" diff --git a/html/changelogs/AutoChangeLog-pr-10987.yml b/html/changelogs/AutoChangeLog-pr-10987.yml new file mode 100644 index 0000000000..abea439a86 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10987.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - imageadd: "Fixed dozen missing privates sprites." diff --git a/html/changelogs/AutoChangeLog-pr-10989.yml b/html/changelogs/AutoChangeLog-pr-10989.yml new file mode 100644 index 0000000000..0a5b2ad3c8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10989.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "A little fix concerning some R&D and reagents." diff --git a/html/changelogs/AutoChangeLog-pr-10992.yml b/html/changelogs/AutoChangeLog-pr-10992.yml new file mode 100644 index 0000000000..1d6d10396b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10992.yml @@ -0,0 +1,4 @@ +author: "Hatterhat" +delete-after: True +changes: + - balance: "Buckshot individual pellet damage up from 10 to 12.5. Still firing 6 pellets." diff --git a/html/changelogs/AutoChangeLog-pr-10994.yml b/html/changelogs/AutoChangeLog-pr-10994.yml new file mode 100644 index 0000000000..c27a1afc00 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10994.yml @@ -0,0 +1,4 @@ +author: "DeltaFire15" +delete-after: True +changes: + - balance: "Nar'Sie runes no longer benefit from runed floors." diff --git a/html/changelogs/AutoChangeLog-pr-10996.yml b/html/changelogs/AutoChangeLog-pr-10996.yml new file mode 100644 index 0000000000..8bb7646cd6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10996.yml @@ -0,0 +1,6 @@ +author: "PersianXerxes" +delete-after: True +changes: + - rscadd: "SMES and PACMAN attached to gulag Security to power electrified windows +remove: Removed Sec vendor from gulag Security" + - tweak: "Separation of gulag and public mining" diff --git a/html/changelogs/AutoChangeLog-pr-10997.yml b/html/changelogs/AutoChangeLog-pr-10997.yml new file mode 100644 index 0000000000..a380a04f68 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10997.yml @@ -0,0 +1,12 @@ +author: "Owai-Seek" +delete-after: True +changes: + - rscadd: "Bacon and Eggs food item. Delicious! Added a Lemony Poppy Seed Muffin." + - tweak: "Snack Vendor has Chocolates, Tortilla Chips, and a Marshmallow Box" + - balance: "Mops can now be printed at service lathe once tools are researched." + - balance: "Biobags can hold most organic limbs/organs, but not brains, implants, or cybernetics." + - balance: "Trash Bag can now hold limbs (but not heads.)" + - balance: "Most snack vendor items reduced by 1." + - bugfix: "Trash Cans are now actually craftable, and only require metal instead of plastic." + - imageadd: "Bacon and Eggs, Drying Agent Bottle." + - imageadd: "Mugs now show reagent colors of contained reagents. Thanks Seris!" diff --git a/html/changelogs/AutoChangeLog-pr-11003.yml b/html/changelogs/AutoChangeLog-pr-11003.yml new file mode 100644 index 0000000000..4c551c4d09 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11003.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - bugfix: "Energy weapons now once again have their lens in contents." diff --git a/html/changelogs/AutoChangeLog-pr-11005.yml b/html/changelogs/AutoChangeLog-pr-11005.yml new file mode 100644 index 0000000000..d0576c7ba8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11005.yml @@ -0,0 +1,4 @@ +author: "Arturlang" +delete-after: True +changes: + - tweak: "Hyposprays now switch modes on CTRL click, instead of alt, as it was already reserved for dispension amount." diff --git a/html/changelogs/AutoChangeLog-pr-11012.yml b/html/changelogs/AutoChangeLog-pr-11012.yml new file mode 100644 index 0000000000..1d233f0692 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11012.yml @@ -0,0 +1,4 @@ +author: "keronshb" +delete-after: True +changes: + - rscadd: "Adds the CogChamp drink and Sprite" diff --git a/html/changelogs/AutoChangeLog-pr-11018.yml b/html/changelogs/AutoChangeLog-pr-11018.yml new file mode 100644 index 0000000000..2795317861 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11018.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - bugfix: "pais are no longer muted for literally a whole hour on emp." diff --git a/html/changelogs/AutoChangeLog-pr-11020.yml b/html/changelogs/AutoChangeLog-pr-11020.yml new file mode 100644 index 0000000000..52677b98e9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11020.yml @@ -0,0 +1,4 @@ +author: "Zellular" +delete-after: True +changes: + - imageadd: "Movement state for pupdozer and its decals" diff --git a/html/changelogs/AutoChangeLog-pr-11022.yml b/html/changelogs/AutoChangeLog-pr-11022.yml new file mode 100644 index 0000000000..ac317e56b0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11022.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - rscadd: "auto profiler subsystem from tg" diff --git a/html/changelogs/AutoChangeLog-pr-11024.yml b/html/changelogs/AutoChangeLog-pr-11024.yml new file mode 100644 index 0000000000..3af136f15e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11024.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - bugfix: "Brig cells now are more accurate by using timeofday instead of realtime" diff --git a/html/changelogs/AutoChangeLog-pr-11026.yml b/html/changelogs/AutoChangeLog-pr-11026.yml new file mode 100644 index 0000000000..c99aad2d14 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11026.yml @@ -0,0 +1,5 @@ +author: "Trilbyspaceclone" +delete-after: True +changes: + - balance: "The suit full of spiders also known as a ninja now is a tactical turtleneck" + - balance: "The Wiznerds now dont have suits set to max" diff --git a/html/changelogs/AutoChangeLog-pr-11027.yml b/html/changelogs/AutoChangeLog-pr-11027.yml new file mode 100644 index 0000000000..4e5f5b46ba --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11027.yml @@ -0,0 +1,5 @@ +author: "ShadeAware" +delete-after: True +changes: + - rscadd: "The Captain's Wardrobe, a special one-of-a-kind and ID-locked wardrobe for the Captain that holds all of their snowflakey gear. +Remove: Snowflake gear from the Captain's locker, since now it has its own vendor." diff --git a/html/changelogs/AutoChangeLog-pr-11029.yml b/html/changelogs/AutoChangeLog-pr-11029.yml new file mode 100644 index 0000000000..17f34bbfa6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11029.yml @@ -0,0 +1,4 @@ +author: "Putnam3145" +delete-after: True +changes: + - tweak: "default should be... default" diff --git a/html/changelogs/AutoChangeLog-pr-11032.yml b/html/changelogs/AutoChangeLog-pr-11032.yml new file mode 100644 index 0000000000..6d026e444a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11032.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - bugfix: "Cryo now actually transfers reagents at tier 4 on enter rather than every 80 machine fire()-process()s regardless of if it was \"reset\" by open/close." diff --git a/html/changelogs/AutoChangeLog-pr-11035.yml b/html/changelogs/AutoChangeLog-pr-11035.yml new file mode 100644 index 0000000000..94a57db904 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11035.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - bugfix: "ctf claymores now actually spawn (and fit)." diff --git a/html/changelogs/AutoChangeLog-pr-11038.yml b/html/changelogs/AutoChangeLog-pr-11038.yml new file mode 100644 index 0000000000..b157c31af8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11038.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - bugfix: "STOP_PROCESSING now removes from currentrun to prevent another process cycle from happening where it shouldn't." diff --git a/html/changelogs/AutoChangeLog-pr-11043.yml b/html/changelogs/AutoChangeLog-pr-11043.yml new file mode 100644 index 0000000000..28217af630 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11043.yml @@ -0,0 +1,4 @@ +author: "Seris02" +delete-after: True +changes: + - bugfix: "apc icons" diff --git a/html/changelogs/AutoChangeLog-pr-11044.yml b/html/changelogs/AutoChangeLog-pr-11044.yml new file mode 100644 index 0000000000..7dec153778 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11044.yml @@ -0,0 +1,4 @@ +author: "Arturlang" +delete-after: True +changes: + - rscadd: "The syndicate uplinks interface has been redone in TGUI Next" diff --git a/icons/mob/suit_digi.dmi b/icons/mob/suit_digi.dmi index bb00742a17..c6bda60d38 100644 Binary files a/icons/mob/suit_digi.dmi and b/icons/mob/suit_digi.dmi differ diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi index b03a1cdeae..17d6024586 100644 Binary files a/icons/obj/drinks.dmi and b/icons/obj/drinks.dmi differ diff --git a/icons/obj/food/containers.dmi b/icons/obj/food/containers.dmi index 93acc07453..2639d6860a 100644 Binary files a/icons/obj/food/containers.dmi and b/icons/obj/food/containers.dmi differ diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi index a719150f11..670269da00 100644 Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ diff --git a/icons/obj/janitor.dmi b/icons/obj/janitor.dmi index cb3870dc61..9128654a5b 100644 Binary files a/icons/obj/janitor.dmi and b/icons/obj/janitor.dmi differ diff --git a/icons/obj/vending.dmi b/icons/obj/vending.dmi index 7d08a83fb7..b11e43d665 100644 Binary files a/icons/obj/vending.dmi and b/icons/obj/vending.dmi differ diff --git a/icons/obj/vending_restock.dmi b/icons/obj/vending_restock.dmi index c9437d7d80..035c01de6b 100644 Binary files a/icons/obj/vending_restock.dmi and b/icons/obj/vending_restock.dmi differ diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 3a586d061d..5c7d5a39e9 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -10,12 +10,6 @@ var/hidden_undershirt = FALSE var/hidden_socks = FALSE -//Species vars -/datum/species - var/list/cum_fluids = list("semen") - var/list/milk_fluids = list("milk") - var/list/femcum_fluids = list("femcum") - //Mob procs /mob/living/carbon/human/proc/underwear_toggle() set name = "Toggle undergarments" @@ -46,20 +40,12 @@ var/list/obj/item/organ/genital/genit_list = list() if(!client?.prefs.arousable || (aphro && (client?.prefs.cit_toggles & NO_APHRO)) || (maso && !HAS_TRAIT(src, TRAIT_MASO))) return // no adjusting made here - if(strength>0) - for(var/obj/item/organ/genital/G in internal_organs) - if(!G.aroused_state && prob(strength*G.sensitivity)) - G.set_aroused_state(TRUE) - G.update_appearance() - if(G.aroused_state) - genit_list += G - else - for(var/obj/item/organ/genital/G in internal_organs) - if(G.aroused_state && prob(strength*G.sensitivity)) - G.set_aroused_state(FALSE) - G.update_appearance() - if(G.aroused_state) - genit_list += G + for(var/obj/item/organ/genital/G in internal_organs) + if(G.genital_flags & GENITAL_CAN_AROUSE && !G.aroused_state && prob(strength*G.sensitivity)) + G.set_aroused_state(strength > 0) + G.update_appearance() + if(G.aroused_state) + genit_list += G return genit_list /obj/item/organ/genital/proc/climaxable(mob/living/carbon/human/H, silent = FALSE) //returns the fluid source (ergo reagents holder) if found. diff --git a/modular_citadel/code/modules/arousal/genitals.dm b/modular_citadel/code/modules/arousal/genitals.dm index ca01ef46cb..b7f178bca5 100644 --- a/modular_citadel/code/modules/arousal/genitals.dm +++ b/modular_citadel/code/modules/arousal/genitals.dm @@ -32,23 +32,20 @@ else update() -/obj/item/organ/genital/Destroy() - if(linked_organ) - update_link(TRUE)//this should remove any other links it has - return ..() - /obj/item/organ/genital/proc/set_aroused_state(new_state) + if(!(genital_flags & GENITAL_CAN_AROUSE)) + return FALSE if(!((HAS_TRAIT(owner,TRAIT_PERMABONER) && !new_state) || HAS_TRAIT(owner,TRAIT_NEVERBONER) && new_state)) aroused_state = new_state return aroused_state -/obj/item/organ/genital/proc/update(removing = FALSE) +/obj/item/organ/genital/proc/update() if(QDELETED(src)) return update_size() update_appearance() - if(linked_organ_slot || (linked_organ && removing)) - update_link(removing) + if(linked_organ_slot || (linked_organ && !owner)) + update_link() //exposure and through-clothing code /mob/living/carbon @@ -113,17 +110,7 @@ set desc = "Allows you to toggle which genitals are showing signs of arousal." var/list/genital_list = list() for(var/obj/item/organ/genital/G in internal_organs) - var/datum/sprite_accessory/S - switch(G.type) - if(/obj/item/organ/genital/penis) - S = GLOB.cock_shapes_list[G.shape] - if(/obj/item/organ/genital/testicles) - S = GLOB.balls_shapes_list[G.shape] - if(/obj/item/organ/genital/vagina) - S = GLOB.vagina_shapes_list[G.shape] - if(/obj/item/organ/genital/breasts) - S = GLOB.breasts_shapes_list[G.shape] - if(S?.alt_aroused) + if(G.genital_flags & GENITAL_CAN_AROUSE) genital_list += G if(!genital_list.len) //There's nothing that can show arousal return @@ -174,19 +161,18 @@ return TRUE return FALSE -/obj/item/organ/genital/proc/update_link(removing = FALSE) - if(!removing && owner) +/obj/item/organ/genital/proc/update_link() + if(owner) if(linked_organ) - return + return FALSE linked_organ = owner.getorganslot(linked_organ_slot) if(linked_organ) linked_organ.linked_organ = src linked_organ.upon_link() upon_link() return TRUE - else - if(linked_organ) - linked_organ.linked_organ = null + if(linked_organ) + linked_organ.linked_organ = null linked_organ = null return FALSE @@ -200,10 +186,13 @@ update() RegisterSignal(owner, COMSIG_MOB_DEATH, .proc/update_appearance) -/obj/item/organ/genital/Remove(mob/living/carbon/M, special = FALSE, drop_if_replaced = TRUE) - update(TRUE) - if(!QDELETED(owner)) - UnregisterSignal(owner, COMSIG_MOB_DEATH) +/obj/item/organ/genital/Remove(special = FALSE) + . = ..() + var/mob/living/carbon/human/H = . + update() + if(!QDELETED(H)) + UnregisterSignal(H, COMSIG_MOB_DEATH) + H.update_genitals() //proc to give a player their genitals and stuff when they log in /mob/living/carbon/human/proc/give_genitals(clean = FALSE)//clean will remove all pre-existing genitals. proc will then give them any genitals that are enabled in their DNA @@ -238,12 +227,6 @@ /obj/item/organ/genital/proc/get_features(mob/living/carbon/human/H) return -/datum/species/proc/genitals_layertext(layer) - switch(layer) - if(GENITALS_BEHIND_LAYER) - return "BEHIND" - if(GENITALS_FRONT_LAYER) - return "FRONT" //procs to handle sprite overlays being applied to humans @@ -262,8 +245,90 @@ update_genitals() /mob/living/carbon/human/proc/update_genitals() - if(!QDELETED(src)) - dna.species.handle_genitals(src) + if(QDELETED(src)) + return + var/static/list/relevant_layers = list("[GENITALS_BEHIND_LAYER]" = "BEHIND", "[GENITALS_FRONT_LAYER]" = "FRONT") + var/static/list/layers_num + if(!layers_num) + for(var/L in relevant_layers) + LAZYSET(layers_num, L, text2num(L)) + for(var/L in relevant_layers) //Less hardcode + remove_overlay(layers_num[L]) + remove_overlay(GENITALS_EXPOSED_LAYER) + if(!LAZYLEN(internal_organs) || ((NOGENITALS in dna.species.species_traits) && !genital_override) || HAS_TRAIT(src, TRAIT_HUSK)) + return + + //start scanning for genitals + + var/list/gen_index[GENITAL_LAYER_INDEX_LENGTH] + var/list/genitals_to_add + var/list/fully_exposed + for(var/obj/item/organ/genital/G in internal_organs) + if(G.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes + LAZYADD(gen_index[G.layer_index], G) + for(var/L in gen_index) + if(L) //skip nulls + LAZYADD(genitals_to_add, L) + if(!genitals_to_add) + return + //Now we added all genitals that aren't internal and should be rendered + //start applying overlays + for(var/layer in relevant_layers) + var/list/standing = list() + var/layertext = relevant_layers[layer] + for(var/A in genitals_to_add) + var/obj/item/organ/genital/G = A + var/datum/sprite_accessory/S + var/size = G.size + switch(G.type) + if(/obj/item/organ/genital/penis) + S = GLOB.cock_shapes_list[G.shape] + if(/obj/item/organ/genital/testicles) + S = GLOB.balls_shapes_list[G.shape] + if(/obj/item/organ/genital/vagina) + S = GLOB.vagina_shapes_list[G.shape] + if(/obj/item/organ/genital/breasts) + S = GLOB.breasts_shapes_list[G.shape] + + if(!S || S.icon_state == "none") + continue + var/aroused_state = G.aroused_state && S.alt_aroused + + var/mutable_appearance/genital_overlay = mutable_appearance(S.icon, layer = -layer) + if(S.center) + genital_overlay = center_image(genital_overlay, S.dimension_x, S.dimension_y) + + if(dna.species.use_skintones && dna.features["genitals_use_skintone"]) + genital_overlay.color = "#[skintone2hex(skin_tone)]" + else + switch(S.color_src) + if("cock_color") + genital_overlay.color = "#[dna.features["cock_color"]]" + if("balls_color") + genital_overlay.color = "#[dna.features["balls_color"]]" + if("breasts_color") + genital_overlay.color = "#[dna.features["breasts_color"]]" + if("vag_color") + genital_overlay.color = "#[dna.features["vag_color"]]" + + genital_overlay.icon_state = "[G.slot]_[S.icon_state]_[size][dna.species.use_skintones ? "_s" : ""]_[aroused_state]_[layertext]" + + if(layer == GENITALS_FRONT_LAYER && CHECK_BITFIELD(G.genital_flags, GENITAL_THROUGH_CLOTHES)) + genital_overlay.layer = -GENITALS_EXPOSED_LAYER + LAZYADD(fully_exposed, genital_overlay) // to be added to a layer with higher priority than clothes, hence the name of the bitflag. + else + standing += genital_overlay + + if(LAZYLEN(standing)) + overlays_standing[layers_num[layer]] = standing + + if(LAZYLEN(fully_exposed)) + overlays_standing[GENITALS_EXPOSED_LAYER] = fully_exposed + apply_overlay(GENITALS_EXPOSED_LAYER) + + for(var/L in relevant_layers) + apply_overlay(layers_num[L]) + //Checks to see if organs are new on the mob, and changes their colours so that they don't get crazy colours. /mob/living/carbon/human/proc/emergent_genital_call() @@ -292,86 +357,3 @@ else if (willyCheck == FALSE) dna.features["cock_color"] = dna.features["breasts_color"] return TRUE - -/datum/species/proc/handle_genitals(mob/living/carbon/human/H)//more like handle sadness - if(!H)//no args - CRASH("H = null") - if(!LAZYLEN(H.internal_organs) || ((NOGENITALS in species_traits) && !H.genital_override) || HAS_TRAIT(H, TRAIT_HUSK)) - return - var/list/relevant_layers = list(GENITALS_BEHIND_LAYER, GENITALS_FRONT_LAYER) - - for(var/L in relevant_layers) //Less hardcode - H.remove_overlay(L) - H.remove_overlay(GENITALS_EXPOSED_LAYER) - //start scanning for genitals - - var/list/gen_index[GENITAL_LAYER_INDEX_LENGTH] - var/list/genitals_to_add - var/list/fully_exposed - for(var/obj/item/organ/genital/G in H.internal_organs) - if(G.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes - LAZYADD(gen_index[G.layer_index], G) - for(var/L in gen_index) - if(L) //skip nulls - LAZYADD(genitals_to_add, L) - if(!genitals_to_add) - return - //Now we added all genitals that aren't internal and should be rendered - //start applying overlays - for(var/layer in relevant_layers) - var/list/standing = list() - var/layertext = genitals_layertext(layer) - for(var/A in genitals_to_add) - var/obj/item/organ/genital/G = A - var/datum/sprite_accessory/S - var/size = G.size - var/aroused_state = G.aroused_state - switch(G.type) - if(/obj/item/organ/genital/penis) - S = GLOB.cock_shapes_list[G.shape] - if(/obj/item/organ/genital/testicles) - S = GLOB.balls_shapes_list[G.shape] - if(/obj/item/organ/genital/vagina) - S = GLOB.vagina_shapes_list[G.shape] - if(/obj/item/organ/genital/breasts) - S = GLOB.breasts_shapes_list[G.shape] - - if(!S || S.icon_state == "none") - continue - - var/mutable_appearance/genital_overlay = mutable_appearance(S.icon, layer = -layer) - genital_overlay.icon_state = "[G.slot]_[S.icon_state]_[size]_[aroused_state]_[layertext]" - - if(S.center) - genital_overlay = center_image(genital_overlay, S.dimension_x, S.dimension_y) - - if(use_skintones && H.dna.features["genitals_use_skintone"]) - genital_overlay.color = "#[skintone2hex(H.skin_tone)]" - else - switch(S.color_src) - if("cock_color") - genital_overlay.color = "#[H.dna.features["cock_color"]]" - if("balls_color") - genital_overlay.color = "#[H.dna.features["balls_color"]]" - if("breasts_color") - genital_overlay.color = "#[H.dna.features["breasts_color"]]" - if("vag_color") - genital_overlay.color = "#[H.dna.features["vag_color"]]" - - genital_overlay.icon_state = "[G.slot]_[S.icon_state]_[size]-s_[aroused_state]_[layertext]" - - if(layer == GENITALS_FRONT_LAYER && CHECK_BITFIELD(G.genital_flags, GENITAL_THROUGH_CLOTHES)) - genital_overlay.layer = -GENITALS_EXPOSED_LAYER - LAZYADD(fully_exposed, genital_overlay) // to be added to a layer with higher priority than clothes, hence the name of the bitflag. - else - standing += genital_overlay - - if(LAZYLEN(standing)) - H.overlays_standing[layer] = standing - - if(LAZYLEN(fully_exposed)) - H.overlays_standing[GENITALS_EXPOSED_LAYER] = fully_exposed - H.apply_overlay(GENITALS_EXPOSED_LAYER) - - for(var/L in relevant_layers) - H.apply_overlay(L) diff --git a/modular_citadel/code/modules/arousal/genitals_sprite_accessories.dm b/modular_citadel/code/modules/arousal/genitals_sprite_accessories.dm index 0c1763b8e2..594fc83e46 100644 --- a/modular_citadel/code/modules/arousal/genitals_sprite_accessories.dm +++ b/modular_citadel/code/modules/arousal/genitals_sprite_accessories.dm @@ -85,36 +85,36 @@ //Vaginas /datum/sprite_accessory/vagina icon = 'modular_citadel/icons/obj/genitals/vagina_onmob.dmi' - icon_state = null name = "vagina" color_src = "vag_color" + alt_aroused = TRUE /datum/sprite_accessory/vagina/human icon_state = "human" name = "Human" - alt_aroused = TRUE /datum/sprite_accessory/vagina/tentacles icon_state = "tentacle" name = "Tentacle" - alt_aroused = TRUE /datum/sprite_accessory/vagina/dentata icon_state = "dentata" name = "Dentata" - alt_aroused = TRUE /datum/sprite_accessory/vagina/hairy icon_state = "hairy" name = "Hairy" + alt_aroused = FALSE /datum/sprite_accessory/vagina/spade icon_state = "spade" name = "Spade" + alt_aroused = FALSE /datum/sprite_accessory/vagina/furred icon_state = "furred" name = "Furred" + alt_aroused = FALSE /datum/sprite_accessory/vagina/gaping icon_state = "gaping" @@ -125,7 +125,6 @@ icon = 'modular_citadel/icons/obj/genitals/breasts_onmob.dmi' name = "breasts" color_src = "breasts_color" - alt_aroused = TRUE /datum/sprite_accessory/breasts/pair icon_state = "pair" diff --git a/modular_citadel/code/modules/arousal/organs/breasts.dm b/modular_citadel/code/modules/arousal/organs/breasts.dm index 1537d5cebe..dc7923e448 100644 --- a/modular_citadel/code/modules/arousal/organs/breasts.dm +++ b/modular_citadel/code/modules/arousal/organs/breasts.dm @@ -1,3 +1,6 @@ +#define BREASTS_ICON_MIN_SIZE 1 +#define BREASTS_ICON_MAX_SIZE 6 + /obj/item/organ/genital/breasts name = "breasts" desc = "Female milk producing organs." @@ -9,7 +12,7 @@ fluid_id = /datum/reagent/consumable/milk fluid_rate = MILK_RATE shape = "pair" - genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_FUID_PRODUCTION + genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_FUID_PRODUCTION|GENITAL_CAN_AROUSE masturbation_verb = "massage" arousal_verb = "Your breasts start feeling sensitive" unarousal_verb = "Your breasts no longer feel sensitive" @@ -49,21 +52,21 @@ var/datum/reagent/R = GLOB.chemical_reagents_list[fluid_id] if(R) desc += " They're leaking [lowertext(R.name)]." - var/string + var/datum/sprite_accessory/S = GLOB.breasts_shapes_list[shape] + var/icon_shape = S ? S.icon_state : "pair" + var/icon_size = CLAMP(breast_values[size], BREASTS_ICON_MIN_SIZE, BREASTS_ICON_MAX_SIZE) + icon_state = "breasts_[icon_shape]_[breast_values[icon_size]]" if(owner) if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"]) if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow... var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need. color = "#[skintone2hex(H.skin_tone)]" - string = "breasts_[GLOB.breasts_shapes_icons[shape]]_[size]-s" + icon_state += "_s" else color = "#[owner.dna.features["breasts_color"]]" - string = "breasts_[GLOB.breasts_shapes_icons[shape]]_[size]" if(ishuman(owner)) var/mob/living/carbon/human/H = owner - icon_state = sanitize_text(string) H.update_genitals() - icon_state = sanitize_text(string) //Allows breasts to grow and change size, with sprite changes too. //maximum wah @@ -130,3 +133,6 @@ cached_size = size size = breast_values[size] prev_size = cached_size + +#undef BREASTS_ICON_MIN_SIZE +#undef BREASTS_ICON_MAX_SIZE \ No newline at end of file diff --git a/modular_citadel/code/modules/arousal/organs/penis.dm b/modular_citadel/code/modules/arousal/organs/penis.dm index c6d3c764ac..38f463a97c 100644 --- a/modular_citadel/code/modules/arousal/organs/penis.dm +++ b/modular_citadel/code/modules/arousal/organs/penis.dm @@ -8,13 +8,13 @@ masturbation_verb = "stroke" arousal_verb = "You pop a boner" unarousal_verb = "Your boner goes down" - genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH + genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_CAN_AROUSE linked_organ_slot = ORGAN_SLOT_TESTICLES fluid_transfer_factor = 0.5 size = 2 //arbitrary value derived from length and girth for sprites. layer_index = PENIS_LAYER_INDEX var/length = 6 //inches - var/prev_length = 6 //really should be renamed to prev_length + var/prev_length = 6 var/girth = 4.38 var/girth_ratio = COCK_GIRTH_RATIO_DEF //0.73; check citadel_defines.dm @@ -73,22 +73,21 @@ /obj/item/organ/genital/penis/update_appearance() . = ..() - var/string + var/datum/sprite_accessory/S = GLOB.cock_shapes_list[shape] + var/icon_shape = S ? S.icon_state : "human" + icon_state = "penis_[icon_shape]_[size]" var/lowershape = lowertext(shape) desc = "You see [aroused_state ? "an erect" : "a flaccid"] [lowershape] [name]. You estimate it's about [round(length, 0.25)] inch[round(length, 0.25) != 1 ? "es" : ""] long and [round(girth, 0.25)] inch[round(girth, 0.25) != 1 ? "es" : ""] in girth." - if(owner) if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"]) if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow... var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need. color = "#[skintone2hex(H.skin_tone)]" - string = "penis_[GLOB.cock_shapes_icons[shape]]_[size]-s" + icon_state += "_s" else color = "#[owner.dna.features["cock_color"]]" - string = "penis_[GLOB.cock_shapes_icons[shape]]_[size]" if(ishuman(owner)) var/mob/living/carbon/human/H = owner - icon_state = sanitize_text(string) H.update_genitals() /obj/item/organ/genital/penis/get_features(mob/living/carbon/human/H) diff --git a/modular_citadel/code/modules/arousal/organs/testicles.dm b/modular_citadel/code/modules/arousal/organs/testicles.dm index 9573020417..eb6c1536cb 100644 --- a/modular_citadel/code/modules/arousal/organs/testicles.dm +++ b/modular_citadel/code/modules/arousal/organs/testicles.dm @@ -43,19 +43,19 @@ /obj/item/organ/genital/testicles/update_appearance() . = ..() desc = "You see an [size_name] pair of testicles." + var/datum/sprite_accessory/S = GLOB.balls_shapes_list[shape] + var/icon_shape = S ? S.icon_state : "single" + icon_state = "testicles_[icon_shape]_[size]" if(owner) - var/string if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"]) if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow... var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need. color = "#[skintone2hex(H.skin_tone)]" - string = "testicles_[GLOB.balls_shapes_icons[shape]]_[size]-s" + icon_state += "_s" else color = "#[owner.dna.features["balls_color"]]" - string = "testicles_[GLOB.balls_shapes_icons[shape]]_[size]" if(ishuman(owner)) var/mob/living/carbon/human/H = owner - icon_state = sanitize_text(string) H.update_genitals() /obj/item/organ/genital/testicles/get_features(mob/living/carbon/human/H) diff --git a/modular_citadel/code/modules/arousal/organs/vagina.dm b/modular_citadel/code/modules/arousal/organs/vagina.dm index 3f1bcc5f9b..311afe75b0 100644 --- a/modular_citadel/code/modules/arousal/organs/vagina.dm +++ b/modular_citadel/code/modules/arousal/organs/vagina.dm @@ -6,7 +6,7 @@ zone = BODY_ZONE_PRECISE_GROIN slot = "vagina" size = 1 //There is only 1 size right now - genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH + genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_CAN_AROUSE masturbation_verb = "finger" arousal_verb = "You feel wetness on your crotch" unarousal_verb = "You no longer feel wet" @@ -22,7 +22,7 @@ /obj/item/organ/genital/vagina/update_appearance() . = ..() - var/string //Keeping this code here, so making multiple sprites for the different kinds is easier. + icon_state = "vagina" var/lowershape = lowertext(shape) var/details @@ -55,13 +55,11 @@ if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow... var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need. color = "#[skintone2hex(H.skin_tone)]" - string = "vagina-s" + icon_state += "_s" else color = "#[owner.dna.features["vag_color"]]" - string = "vagina" if(ishuman(owner)) var/mob/living/carbon/human/H = owner - icon_state = sanitize_text(string) H.update_genitals() /obj/item/organ/genital/vagina/get_features(mob/living/carbon/human/H) diff --git a/modular_citadel/icons/mob/markings_notmammals.dmi b/modular_citadel/icons/mob/markings_notmammals.dmi index 79c97968ed..43452c8d14 100644 Binary files a/modular_citadel/icons/mob/markings_notmammals.dmi and b/modular_citadel/icons/mob/markings_notmammals.dmi differ diff --git a/modular_citadel/icons/mob/widerobot.dmi b/modular_citadel/icons/mob/widerobot.dmi index a77a109eb9..3f48c3902c 100644 Binary files a/modular_citadel/icons/mob/widerobot.dmi and b/modular_citadel/icons/mob/widerobot.dmi differ diff --git a/modular_citadel/icons/obj/genitals/breasts.dmi b/modular_citadel/icons/obj/genitals/breasts.dmi index d70207ee69..24656062d2 100644 Binary files a/modular_citadel/icons/obj/genitals/breasts.dmi and b/modular_citadel/icons/obj/genitals/breasts.dmi differ diff --git a/modular_citadel/icons/obj/genitals/breasts_onmob.dmi b/modular_citadel/icons/obj/genitals/breasts_onmob.dmi index 371041b6f4..578086c4c3 100644 Binary files a/modular_citadel/icons/obj/genitals/breasts_onmob.dmi and b/modular_citadel/icons/obj/genitals/breasts_onmob.dmi differ diff --git a/modular_citadel/icons/obj/genitals/penis.dmi b/modular_citadel/icons/obj/genitals/penis.dmi index 517758b248..c3fd184a7c 100644 Binary files a/modular_citadel/icons/obj/genitals/penis.dmi and b/modular_citadel/icons/obj/genitals/penis.dmi differ diff --git a/modular_citadel/icons/obj/genitals/penis_onmob.dmi b/modular_citadel/icons/obj/genitals/penis_onmob.dmi index 4f84c52360..4a92bffa2a 100644 Binary files a/modular_citadel/icons/obj/genitals/penis_onmob.dmi and b/modular_citadel/icons/obj/genitals/penis_onmob.dmi differ diff --git a/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi b/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi index ae2339e2e0..e8efbec216 100644 Binary files a/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi and b/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi differ diff --git a/modular_citadel/icons/obj/genitals/testicles.dmi b/modular_citadel/icons/obj/genitals/testicles.dmi index 3d7a5f4f48..386eab0956 100644 Binary files a/modular_citadel/icons/obj/genitals/testicles.dmi and b/modular_citadel/icons/obj/genitals/testicles.dmi differ diff --git a/modular_citadel/icons/obj/genitals/vagina.dmi b/modular_citadel/icons/obj/genitals/vagina.dmi index 39bdd48e89..1bbe62ba0e 100644 Binary files a/modular_citadel/icons/obj/genitals/vagina.dmi and b/modular_citadel/icons/obj/genitals/vagina.dmi differ diff --git a/modular_citadel/icons/obj/genitals/vagina_onmob.dmi b/modular_citadel/icons/obj/genitals/vagina_onmob.dmi index ab71b22e3b..6c34ffadfa 100644 Binary files a/modular_citadel/icons/obj/genitals/vagina_onmob.dmi and b/modular_citadel/icons/obj/genitals/vagina_onmob.dmi differ diff --git a/tgstation.dme b/tgstation.dme index ac66fb7d12..e55c425c1c 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -152,6 +152,7 @@ #include "code\__HELPERS\type2type_vr.dm" #include "code\__HELPERS\typelists.dm" #include "code\__HELPERS\unsorted.dm" +#include "code\__HELPERS\vector.dm" #include "code\__HELPERS\view.dm" #include "code\__HELPERS\sorts\__main.dm" #include "code\__HELPERS\sorts\InsertSort.dm" @@ -273,6 +274,7 @@ #include "code\controllers\subsystem\pathfinder.dm" #include "code\controllers\subsystem\persistence.dm" #include "code\controllers\subsystem\ping.dm" +#include "code\controllers\subsystem\profiler.dm" #include "code\controllers\subsystem\radiation.dm" #include "code\controllers\subsystem\radio.dm" #include "code\controllers\subsystem\research.dm" @@ -291,7 +293,6 @@ #include "code\controllers\subsystem\vis_overlays.dm" #include "code\controllers\subsystem\vore.dm" #include "code\controllers\subsystem\vote.dm" -#include "code\controllers\subsystem\weather.dm" #include "code\controllers\subsystem\processing\chemistry.dm" #include "code\controllers\subsystem\processing\circuit.dm" #include "code\controllers\subsystem\processing\fastprocess.dm" @@ -302,6 +303,7 @@ #include "code\controllers\subsystem\processing\processing.dm" #include "code\controllers\subsystem\processing\projectiles.dm" #include "code\controllers\subsystem\processing\quirks.dm" +#include "code\controllers\subsystem\processing\weather.dm" #include "code\controllers\subsystem\processing\wet_floors.dm" #include "code\datums\action.dm" #include "code\datums\ai_laws.dm" diff --git a/tgui-next/packages/tgui/interfaces/Uplink.js b/tgui-next/packages/tgui/interfaces/Uplink.js index 075355221a..4f2b047c9b 100644 --- a/tgui-next/packages/tgui/interfaces/Uplink.js +++ b/tgui-next/packages/tgui/interfaces/Uplink.js @@ -103,6 +103,7 @@ export class Uplink extends Component { compact={compact_mode} items={items} hoveredItem={hoveredItem} + telecrystals={telecrystals} onBuyMouseOver={item => this.setHoveredItem(item)} onBuyMouseOut={item => this.setHoveredItem({})} onBuy={item => act(ref, 'buy', { diff --git a/tgui-next/packages/tgui/routes.js b/tgui-next/packages/tgui/routes.js index 7aa2546c70..76c2834c7b 100644 --- a/tgui-next/packages/tgui/routes.js +++ b/tgui-next/packages/tgui/routes.js @@ -91,6 +91,7 @@ import { TankDispenser } from './interfaces/TankDispenser'; import { Teleporter } from './interfaces/Teleporter'; import { ThermoMachine } from './interfaces/ThermoMachine'; import { TurbineComputer } from './interfaces/TurbineComputer'; +import { Uplink } from './interfaces/Uplink'; import { VaultController } from './interfaces/VaultController'; import { Wires } from './interfaces/Wires'; import { AtmosRelief } from './interfaces/AtmosRelief'; @@ -500,6 +501,11 @@ const ROUTES = { component: () => TurbineComputer, scrollable: false, }, + uplink: { + component: () => Uplink, + scrollable: true, + theme: 'syndicate', + }, vault_controller: { component: () => VaultController, scrollable: false, diff --git a/tools/tgs4_scripts/PostCompile.bat b/tools/tgs4_scripts/PostCompile.bat deleted file mode 100644 index 47aae169c6..0000000000 --- a/tools/tgs4_scripts/PostCompile.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off - -powershell -NoProfile -ExecutionPolicy Bypass -File PostCompile.ps1 -game_path %1 diff --git a/tools/tgs4_scripts/PostCompile.ps1 b/tools/tgs4_scripts/PostCompile.ps1 deleted file mode 100644 index 8e46fa8061..0000000000 --- a/tools/tgs4_scripts/PostCompile.ps1 +++ /dev/null @@ -1,18 +0,0 @@ -param( - $game_path -) - -Write-Host "Deploying tgstation compilation..." - -cd $game_path - -mkdir build - -#.github is a little special cause of the prefix -mv .github build/.github - -mv * build #thank god it's that easy - -&"build/tools/deploy.sh" $game_path $game_path/build - -Remove-Item build -Recurse