diff --git a/_maps/deathmatch/arena_station.dmm b/_maps/deathmatch/arena_station.dmm index c7654810360e1..50089df45e8a0 100644 --- a/_maps/deathmatch/arena_station.dmm +++ b/_maps/deathmatch/arena_station.dmm @@ -930,7 +930,7 @@ /area/deathmatch) "LY" = ( /obj/structure/closet/secure_closet, -/obj/item/gun/energy/beam_rifle, +/obj/item/gun/energy/xray, /turf/open/indestructible/vault, /area/deathmatch) "Mc" = ( diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index e26e63400333f..ef02944be5751 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -12780,6 +12780,9 @@ /area/station/security/checkpoint/science) "fnm" = ( /obj/structure/filingcabinet/chestdrawer, +/obj/item/book/manual/wiki/engineering_guide{ + pixel_y = 6 + }, /turf/open/floor/iron/grimy, /area/station/engineering/main) "fnw" = ( @@ -17534,10 +17537,6 @@ /obj/structure/table/greyscale, /obj/item/clothing/gloves/color/yellow, /obj/item/wrench, -/obj/item/multitool{ - pixel_x = 4; - pixel_y = 5 - }, /turf/open/floor/iron/grimy, /area/station/engineering/main) "gUC" = ( @@ -29651,8 +29650,14 @@ pixel_y = 4 }, /obj/machinery/light/small/directional/south, -/obj/item/book/manual/wiki/engineering_guide{ - pixel_y = 4 +/obj/item/flatpack{ + board = /obj/item/circuitboard/machine/flatpacker; + pixel_x = -6; + pixel_y = 5 + }, +/obj/item/multitool{ + pixel_x = 7; + pixel_y = -2 }, /turf/open/floor/iron/grimy, /area/station/engineering/main) @@ -45117,7 +45122,7 @@ /obj/structure/rack, /obj/effect/spawner/random/armory/riot_helmet, /obj/effect/spawner/random/armory/bulletproof_helmet, -/obj/item/gun/energy/e_gun/dragnet, +/obj/effect/spawner/random/armory/dragnet, /turf/open/floor/iron/dark/small, /area/station/ai_monitored/security/armory) "qaV" = ( diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 57ff65acf22af..9f1a266b18575 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -882,11 +882,8 @@ pixel_x = 3 }, /obj/structure/window/reinforced/spawner/directional/north, -/obj/item/gun/energy/e_gun/dragnet{ - pixel_y = 4 - }, -/obj/item/gun/energy/e_gun/dragnet, /obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/spawner/random/armory/dragnet, /turf/open/floor/iron/dark, /area/station/ai_monitored/security/armory) "alG" = ( @@ -78577,6 +78574,15 @@ /obj/structure/cable, /obj/machinery/firealarm/directional/east, /obj/effect/decal/cleanable/dirt, +/obj/item/flatpack{ + board = /obj/item/circuitboard/machine/flatpacker; + pixel_x = -6; + pixel_y = 5 + }, +/obj/item/multitool{ + pixel_x = 8 + }, +/obj/structure/table, /turf/open/floor/iron, /area/station/engineering/storage_shared) "tFG" = ( diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 984cf0ca1298e..9e5ecd8c0486f 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -3845,7 +3845,7 @@ "bil" = ( /obj/structure/railing/wooden_fence, /turf/open/misc/hay/icemoon, -/area/icemoon/surface) +/area/icemoon/underground/explored) "bin" = ( /obj/effect/turf_decal/stripes/asteroid/line{ dir = 4 @@ -6355,7 +6355,7 @@ dir = 1 }, /turf/open/misc/hay/icemoon, -/area/icemoon/surface) +/area/icemoon/underground/explored) "bPV" = ( /obj/item/kirbyplants/random/dead, /turf/open/floor/plating/snowed/icemoon, @@ -11342,7 +11342,7 @@ /area/icemoon/surface/outdoors/nospawn) "dlu" = ( /turf/closed/wall/mineral/wood/nonmetal, -/area/icemoon/surface) +/area/icemoon/underground/explored) "dlB" = ( /obj/structure/table/wood, /obj/item/storage/photo_album/chapel, @@ -20638,7 +20638,7 @@ dir = 5 }, /turf/open/misc/hay/icemoon, -/area/icemoon/surface) +/area/icemoon/underground/explored) "ghE" = ( /obj/structure/disposalpipe/segment, /obj/machinery/camera/directional/west{ @@ -23048,7 +23048,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, -/obj/effect/mapping_helpers/airlock/access/all/medical/chemistry, +/obj/effect/mapping_helpers/airlock/access/all/medical/general, /obj/effect/turf_decal/tile/yellow/full, /turf/open/floor/iron/large, /area/station/medical/treatment_center) @@ -26929,7 +26929,7 @@ dir = 6 }, /turf/open/misc/hay/icemoon, -/area/icemoon/surface) +/area/icemoon/underground/explored) "idN" = ( /obj/structure/window/reinforced/spawner/directional/north, /obj/machinery/door/window/brigdoor/left/directional/south{ @@ -30518,15 +30518,12 @@ "jko" = ( /obj/structure/railing, /obj/structure/rack, -/obj/item/gun/energy/e_gun/dragnet{ - pixel_y = 4 - }, -/obj/item/gun/energy/e_gun/dragnet, /obj/structure/cable, /obj/machinery/door/firedoor/border_only, /obj/effect/turf_decal/tile/red/half/contrasted{ dir = 1 }, +/obj/effect/spawner/random/armory/dragnet, /turf/open/floor/iron/dark/textured, /area/station/ai_monitored/security/armory/upper) "jkx" = ( @@ -30551,7 +30548,7 @@ dir = 9 }, /turf/open/misc/hay/icemoon, -/area/icemoon/surface) +/area/icemoon/underground/explored) "jkN" = ( /obj/effect/spawner/random/entertainment/arcade, /obj/machinery/status_display/ai/directional/north, @@ -36851,7 +36848,7 @@ /obj/structure/table/wood, /obj/item/flashlight/lantern/on, /turf/open/misc/hay/icemoon, -/area/icemoon/surface) +/area/icemoon/underground/explored) "kZa" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -40539,7 +40536,7 @@ dir = 10 }, /turf/open/misc/hay/icemoon, -/area/icemoon/surface) +/area/icemoon/underground/explored) "mhq" = ( /obj/structure/closet, /obj/effect/spawner/random/maintenance, @@ -43322,7 +43319,7 @@ }, /obj/item/soap/deluxe, /turf/open/misc/hay/icemoon, -/area/icemoon/surface) +/area/icemoon/underground/explored) "ncB" = ( /obj/machinery/door/airlock/security/glass{ name = "Brig Walkway" @@ -45443,7 +45440,7 @@ "nEI" = ( /obj/item/flashlight/lantern/on, /turf/open/misc/hay/icemoon, -/area/icemoon/surface) +/area/icemoon/underground/explored) "nEV" = ( /obj/machinery/vending/wardrobe/sec_wardrobe, /obj/structure/cable, @@ -47295,7 +47292,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/mapping_helpers/airlock/access/all/medical/chemistry, +/obj/effect/mapping_helpers/airlock/access/all/medical/general, /turf/open/floor/iron/smooth, /area/station/maintenance/department/medical/central) "oiD" = ( @@ -53710,7 +53707,7 @@ "qbM" = ( /obj/structure/ore_container/food_trough/raptor_trough, /turf/open/misc/hay/icemoon, -/area/icemoon/surface) +/area/icemoon/underground/explored) "qbO" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -58945,7 +58942,7 @@ }, /obj/item/raptor_dex, /turf/open/misc/hay/icemoon, -/area/icemoon/surface) +/area/icemoon/underground/explored) "rAr" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -59334,7 +59331,7 @@ dir = 4 }, /turf/open/misc/hay/icemoon, -/area/icemoon/surface) +/area/icemoon/underground/explored) "rEp" = ( /obj/structure/table, /obj/item/hand_labeler, @@ -74888,8 +74885,13 @@ /obj/effect/turf_decal/siding/yellow/corner, /obj/machinery/status_display/evac/directional/south, /obj/structure/table, -/obj/effect/spawner/random/trash/food_packaging, -/obj/effect/spawner/random/trash/cigbutt, +/obj/item/flatpack{ + board = /obj/item/circuitboard/machine/flatpacker; + pixel_x = -5 + }, +/obj/item/multitool{ + pixel_x = 8 + }, /turf/open/floor/iron, /area/station/engineering/lobby) "wve" = ( @@ -74902,7 +74904,7 @@ /area/station/service/chapel) "wvu" = ( /turf/open/misc/hay/icemoon, -/area/icemoon/surface) +/area/icemoon/underground/explored) "wvv" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -78456,7 +78458,7 @@ dir = 8 }, /turf/open/misc/hay/icemoon, -/area/icemoon/surface) +/area/icemoon/underground/explored) "xxI" = ( /obj/machinery/airalarm/directional/north, /obj/item/kirbyplants/random, diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index dc42fb3fe9ce6..6cd01a35c9daf 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -9215,6 +9215,9 @@ dir = 4 }, /obj/machinery/light/small/directional/north, +/obj/item/lightreplacer{ + pixel_y = 7 + }, /turf/open/floor/iron/dark/corner{ dir = 1 }, @@ -32127,12 +32130,11 @@ /area/station/maintenance/fore) "loY" = ( /obj/structure/rack, -/obj/item/gun/energy/e_gun/dragnet, -/obj/item/gun/energy/e_gun/dragnet, /obj/effect/turf_decal/tile/blue/half/contrasted{ dir = 4 }, /obj/machinery/light/small/directional/west, +/obj/effect/spawner/random/armory/dragnet, /turf/open/floor/iron/dark, /area/station/ai_monitored/security/armory) "lpo" = ( @@ -58915,13 +58917,17 @@ "uJz" = ( /obj/effect/turf_decal/bot, /obj/structure/rack, -/obj/item/lightreplacer{ - pixel_y = 7 - }, /obj/machinery/status_display/evac/directional/east, /obj/effect/turf_decal/tile/yellow{ dir = 4 }, +/obj/item/flatpack{ + board = /obj/item/circuitboard/machine/flatpacker; + pixel_x = -5 + }, +/obj/item/multitool{ + pixel_x = 8 + }, /turf/open/floor/iron/checker, /area/station/engineering/storage_shared) "uJB" = ( diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index 3c8cf0e7cb56c..7ce411f102fc1 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -53022,7 +53022,19 @@ /obj/effect/turf_decal/trimline/yellow/corner{ dir = 4 }, -/obj/item/storage/toolbox/mechanical, +/obj/item/storage/toolbox/mechanical{ + pixel_x = 8; + pixel_y = -4 + }, +/obj/item/flatpack{ + board = /obj/item/circuitboard/machine/flatpacker; + pixel_x = -6; + pixel_y = 5 + }, +/obj/item/multitool{ + pixel_x = 7; + pixel_y = 10 + }, /turf/open/floor/iron/corner{ dir = 4 }, @@ -57656,7 +57668,7 @@ /area/station/science/lower) "oOW" = ( /obj/structure/rack, -/obj/item/gun/energy/e_gun/dragnet, +/obj/effect/spawner/random/armory/dragnet, /turf/open/floor/iron/dark, /area/station/ai_monitored/security/armory) "oOY" = ( diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index b0c8d17c83315..a8b81413f9cb6 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -28696,10 +28696,9 @@ /area/station/cargo/storage) "jlQ" = ( /obj/structure/rack, -/obj/item/gun/energy/e_gun/dragnet, -/obj/item/gun/energy/e_gun/dragnet, /obj/item/radio/intercom/directional/north, /obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/spawner/random/armory/dragnet, /turf/open/floor/iron/dark, /area/station/ai_monitored/security/armory) "jlX" = ( @@ -49386,6 +49385,13 @@ }, /obj/structure/cable, /obj/structure/table, +/obj/item/multitool{ + pixel_x = 8 + }, +/obj/item/flatpack{ + board = /obj/item/circuitboard/machine/flatpacker; + pixel_x = -5 + }, /turf/open/floor/iron, /area/station/engineering/break_room) "qwq" = ( diff --git a/_maps/map_files/wawastation/wawastation.dmm b/_maps/map_files/wawastation/wawastation.dmm index 3116f34a2033b..f06276d3e9fa2 100644 --- a/_maps/map_files/wawastation/wawastation.dmm +++ b/_maps/map_files/wawastation/wawastation.dmm @@ -4483,7 +4483,7 @@ /obj/machinery/computer/security/mining{ dir = 8 }, -/obj/structure/sign/poster/official/random/directional/east, +/obj/machinery/keycard_auth/directional/east, /obj/effect/turf_decal/tile/dark_blue/half/contrasted{ dir = 4 }, @@ -6617,6 +6617,7 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, +/obj/effect/mapping_helpers/airlock/access/all/science/general, /turf/open/floor/iron/white, /area/station/science/research) "ctL" = ( @@ -6900,7 +6901,13 @@ /area/station/cargo/storage) "cAy" = ( /obj/structure/table/glass, -/obj/effect/spawner/random/food_or_drink/refreshing_beverage, +/obj/item/flatpack{ + board = /obj/item/circuitboard/machine/flatpacker; + pixel_x = -5 + }, +/obj/item/multitool{ + pixel_x = 8 + }, /turf/open/floor/iron, /area/station/engineering/lobby) "cAC" = ( @@ -8328,15 +8335,16 @@ /turf/open/floor/iron/dark, /area/station/science/ordnance) "dbJ" = ( -/obj/effect/mapping_helpers/airlock/access/all/command/general, /obj/machinery/door/airlock/command/glass{ name = "Bridge" }, +/obj/effect/mapping_helpers/airlock/access/any/command/general, /obj/machinery/door/firedoor, /obj/structure/cable, /obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ cycle_id = "bridgec" }, +/obj/effect/mapping_helpers/airlock/access/any/admin/general, /turf/open/floor/iron, /area/station/hallway/secondary/command) "dbN" = ( @@ -9041,6 +9049,7 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, +/obj/effect/mapping_helpers/airlock/access/all/science/general, /turf/open/floor/iron/white, /area/station/science/research) "dmH" = ( @@ -9205,7 +9214,7 @@ /area/station/medical/virology) "dpf" = ( /obj/structure/transport/linear/public, -/obj/machinery/light/floor, +/obj/machinery/light/floor/transport, /turf/open/floor/plating/elevatorshaft, /area/station/medical/treatment_center) "dpj" = ( @@ -9536,6 +9545,7 @@ "duB" = ( /obj/structure/cable, /obj/structure/window/reinforced/spawner/directional/west, +/obj/machinery/firealarm/directional/east, /turf/open/floor/iron/dark, /area/station/security/prison) "duS" = ( @@ -13177,14 +13187,10 @@ /turf/open/floor/iron, /area/station/hallway/primary/central) "eHa" = ( -/obj/machinery/computer/security/telescreen/minisat{ - dir = 8; - pixel_x = 29; - pixel_y = 1 - }, /obj/effect/turf_decal/tile/dark_blue/half/contrasted{ dir = 4 }, +/obj/structure/sign/poster/official/random/directional/east, /turf/open/floor/iron, /area/station/command/bridge) "eHc" = ( @@ -13538,12 +13544,11 @@ /area/station/maintenance/department/medical) "eQJ" = ( /obj/structure/rack, -/obj/item/gun/energy/e_gun/dragnet, -/obj/item/gun/energy/e_gun/dragnet, /obj/effect/turf_decal/tile/red/half/contrasted{ dir = 1 }, /obj/item/radio/intercom/directional/south, +/obj/effect/spawner/random/armory/dragnet, /turf/open/floor/iron/dark, /area/station/ai_monitored/security/armory) "eQQ" = ( @@ -16051,9 +16056,7 @@ /area/station/security/breakroom) "fLM" = ( /obj/structure/transport/linear/public, -/obj/machinery/light/floor{ - _status_traits = list("underfloor" = list("innate")) - }, +/obj/machinery/light/floor/transport, /turf/open/floor/plating/elevatorshaft, /area/station/cargo/storage) "fLU" = ( @@ -22387,10 +22390,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/wood/tile, /area/station/service/bar) -"hWN" = ( -/obj/machinery/firealarm/directional/south, -/turf/open/openspace, -/area/station/security/prison) "hWW" = ( /obj/structure/cable, /obj/effect/landmark/start/atmospheric_technician, @@ -27768,6 +27767,9 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, +/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ + cycle_id = "bridgehop" + }, /turf/open/floor/carpet/green, /area/station/command/heads_quarters/hop) "jSu" = ( @@ -31976,6 +31978,9 @@ /obj/effect/turf_decal/siding/wood, /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/access/any/command/hop, +/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ + cycle_id = "bridgehop" + }, /turf/open/floor/iron, /area/station/command/heads_quarters/hop) "loR" = ( @@ -34170,6 +34175,7 @@ /obj/structure/disposalpipe/trunk{ dir = 1 }, +/obj/machinery/digital_clock/directional/south, /turf/open/floor/iron, /area/station/cargo/storage) "mff" = ( @@ -35003,13 +35009,14 @@ "mtG" = ( /obj/machinery/door/airlock/command, /obj/machinery/door/firedoor, -/obj/effect/mapping_helpers/airlock/access/all/command/general, +/obj/effect/mapping_helpers/airlock/access/any/command/general, /obj/structure/disposalpipe/segment{ dir = 4 }, /obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ cycle_id = "bridgec" }, +/obj/effect/mapping_helpers/airlock/access/any/admin/general, /turf/open/floor/iron/dark/side{ dir = 4 }, @@ -35463,6 +35470,7 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, +/obj/effect/mapping_helpers/airlock/access/any/engineering/construction, /turf/open/floor/iron, /area/station/engineering/lobby) "mBY" = ( @@ -36121,6 +36129,7 @@ dir = 4 }, /obj/machinery/door/firedoor, +/obj/effect/mapping_helpers/airlock/access/all/science/general, /turf/open/floor/iron/white, /area/station/science/research) "mOo" = ( @@ -38612,6 +38621,8 @@ color = "#52B4E9" }, /obj/structure/disposalpipe/trunk, +/obj/machinery/requests_console/auto_name/directional/north, +/obj/effect/mapping_helpers/requests_console/assistance, /turf/open/floor/iron/white, /area/station/medical/storage) "nKc" = ( @@ -39883,6 +39894,7 @@ "omE" = ( /obj/structure/table/glass, /obj/effect/spawner/random/food_or_drink/snack, +/obj/effect/spawner/random/food_or_drink/refreshing_beverage, /turf/open/floor/iron, /area/station/engineering/lobby) "omL" = ( @@ -40454,13 +40466,14 @@ /obj/machinery/door/airlock/multi_tile/public{ dir = 4 }, -/obj/effect/mapping_helpers/airlock/access/all/command/general, +/obj/effect/mapping_helpers/airlock/access/any/command/general, /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/unres{ dir = 8 }, /obj/structure/cable, /obj/effect/mapping_helpers/airlock/autoname, +/obj/effect/mapping_helpers/airlock/access/any/admin/general, /turf/open/floor/iron/dark/smooth_large, /area/station/command/meeting_room) "oxU" = ( @@ -42401,6 +42414,7 @@ /obj/effect/turf_decal/siding/thinplating/dark{ dir = 9 }, +/obj/machinery/firealarm/directional/west, /turf/open/floor/iron/checker, /area/station/science/research) "pgW" = ( @@ -45393,12 +45407,13 @@ /area/station/science/ordnance) "qhg" = ( /obj/structure/cable, -/obj/effect/mapping_helpers/airlock/access/all/command/general, /obj/machinery/door/airlock/command, +/obj/effect/mapping_helpers/airlock/access/any/command/general, /obj/effect/mapping_helpers/airlock/autoname, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/mapping_helpers/airlock/access/any/admin/general, /turf/open/floor/iron/dark/smooth_large, /area/station/command/emergency_closet) "qhm" = ( @@ -45690,7 +45705,7 @@ /obj/structure/cable, /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/plating, +/turf/open/floor/iron, /area/station/commons/storage/primary) "qmI" = ( /obj/effect/turf_decal/tile/purple/fourcorners, @@ -46621,6 +46636,10 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat/teleporter) +"qFS" = ( +/obj/structure/window/reinforced/spawner/directional/south, +/turf/open/floor/glass/reinforced, +/area/station/security/prison) "qGk" = ( /turf/closed/wall/r_wall, /area/station/hallway/secondary/command) @@ -47050,10 +47069,13 @@ /turf/open/floor/iron, /area/station/cargo/warehouse) "qOO" = ( -/obj/structure/sign/poster/official/random/directional/west, /obj/effect/turf_decal/tile/dark_blue/half/contrasted{ dir = 8 }, +/obj/machinery/computer/security/telescreen/minisat{ + dir = 4; + pixel_x = -29 + }, /turf/open/floor/iron, /area/station/command/bridge) "qOP" = ( @@ -47867,7 +47889,7 @@ /obj/machinery/computer/security{ dir = 4 }, -/obj/machinery/keycard_auth/directional/west, +/obj/structure/sign/poster/official/random/directional/west, /obj/effect/turf_decal/tile/dark_blue/half/contrasted{ dir = 8 }, @@ -49240,7 +49262,6 @@ /turf/open/floor/iron/white, /area/station/medical/treatment_center) "ryG" = ( -/obj/effect/mapping_helpers/airlock/access/any/engineering/maintenance/departmental, /obj/structure/cable, /obj/machinery/door/airlock/engineering/glass{ name = "Break Room" @@ -49249,6 +49270,8 @@ /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/mapping_helpers/airlock/access/any/engineering/general, +/obj/effect/mapping_helpers/airlock/access/any/engineering/construction, /turf/open/floor/iron, /area/station/engineering/break_room) "ryP" = ( @@ -51337,7 +51360,8 @@ /obj/machinery/door/firedoor/border_only{ dir = 4 }, -/obj/machinery/newscaster/directional/north, +/obj/machinery/requests_console/auto_name/directional/north, +/obj/effect/mapping_helpers/requests_console/assistance, /turf/open/floor/iron, /area/station/cargo/storage) "sgW" = ( @@ -55272,7 +55296,8 @@ "tBe" = ( /obj/machinery/computer/pod/old/mass_driver_controller/trash{ pixel_x = -32; - pixel_y = 6 + pixel_y = 6; + range = 5 }, /obj/structure/cable, /obj/machinery/button/door/directional/west{ @@ -56484,6 +56509,7 @@ /obj/structure/table/wood, /obj/item/flashlight/lamp, /obj/machinery/camera/autoname/directional/north, +/obj/machinery/keycard_auth/directional/north, /turf/open/floor/carpet/green, /area/station/command/heads_quarters/hop) "tUG" = ( @@ -59086,6 +59112,20 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron/large, /area/station/service/hydroponics/garden) +"uPg" = ( +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 9 + }, +/obj/machinery/lift_indicator/directional/south{ + linked_elevator_id = "medbay1"; + pixel_x = -32 + }, +/obj/machinery/button/elevator/directional/south{ + id = "medbay1"; + pixel_x = -32 + }, +/turf/open/floor/iron/white, +/area/station/medical/treatment_center) "uPi" = ( /obj/effect/turf_decal/tile/brown/half/contrasted, /obj/effect/decal/cleanable/dirt, @@ -59673,7 +59713,7 @@ /area/station/medical/virology) "vay" = ( /obj/structure/table/reinforced, -/obj/item/storage/medkit, +/obj/item/storage/medkit/regular, /obj/effect/turf_decal/tile/dark_blue/half/contrasted{ dir = 1 }, @@ -60952,13 +60992,6 @@ /obj/effect/turf_decal/box, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat/foyer) -"vBA" = ( -/obj/machinery/light/floor{ - _status_traits = list("underfloor" = list("innate")) - }, -/obj/structure/transport/linear/public, -/turf/open/floor/plating/elevatorshaft, -/area/station/cargo/storage) "vBD" = ( /obj/structure/chair/office/light{ dir = 1 @@ -61565,6 +61598,7 @@ /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/mapping_helpers/airlock/access/any/engineering/construction, /turf/open/floor/iron, /area/station/engineering/break_room) "vMN" = ( @@ -61823,7 +61857,7 @@ "vQf" = ( /obj/machinery/suit_storage_unit/standard_unit, /obj/machinery/door/window/brigdoor/right/directional/east{ - req_access = list("bridge") + req_access = list("command") }, /obj/effect/turf_decal/bot, /obj/machinery/light/small/dim/directional/west, @@ -64860,6 +64894,7 @@ }, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/mapping_helpers/airlock/access/all/science/general, /turf/open/floor/iron/white, /area/station/science/research) "wWk" = ( @@ -65161,12 +65196,6 @@ /turf/open/floor/iron/white/smooth_large, /area/station/science/research) "xaC" = ( -/obj/machinery/button/elevator/directional/south{ - id = "medbay1" - }, -/obj/machinery/lift_indicator/directional/south{ - linked_elevator_id = "medbay1" - }, /obj/machinery/portable_atmospherics/canister/anesthetic_mix, /obj/machinery/atmospherics/components/unary/portables_connector/visible{ dir = 1 @@ -65253,6 +65282,10 @@ /obj/structure/rack, /turf/open/floor/plating, /area/station/asteroid) +"xbr" = ( +/obj/structure/window/reinforced/spawner/directional/west, +/turf/open/floor/glass/reinforced, +/area/station/security/prison) "xbs" = ( /obj/machinery/airalarm/directional/south, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -65888,10 +65921,10 @@ /turf/open/floor/engine, /area/station/science/xenobiology) "xnc" = ( -/obj/effect/mapping_helpers/airlock/access/all/command/general, /obj/machinery/door/airlock/command/glass{ name = "Bridge" }, +/obj/effect/mapping_helpers/airlock/access/any/command/general, /obj/structure/cable, /obj/machinery/door/firedoor, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -65900,6 +65933,7 @@ /obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ cycle_id = "bridgec" }, +/obj/effect/mapping_helpers/airlock/access/any/admin/general, /turf/open/floor/iron, /area/station/hallway/secondary/command) "xne" = ( @@ -66439,7 +66473,8 @@ }, /obj/structure/cable, /obj/machinery/door/firedoor, -/obj/effect/mapping_helpers/airlock/access/all/command/general, +/obj/effect/mapping_helpers/airlock/access/any/command/general, +/obj/effect/mapping_helpers/airlock/access/any/admin/general, /turf/open/floor/iron/dark/smooth_large, /area/station/command/corporate_dock) "xxH" = ( @@ -67238,6 +67273,10 @@ name = "Captain's Fax Machine" }, /obj/structure/table/reinforced, +/obj/machinery/keycard_auth/directional/south{ + pixel_y = -24; + pixel_x = 8 + }, /turf/open/floor/carpet/royalblue, /area/station/command/heads_quarters/captain/private) "xNh" = ( @@ -68121,7 +68160,7 @@ name = "Primary Tool Storage" }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/plating, +/turf/open/floor/iron, /area/station/commons/storage/primary) "ydC" = ( /obj/effect/decal/cleanable/dirt/dust, @@ -82644,11 +82683,11 @@ pwn eaL eUB dgR -xDp +uPg bui yit -yit dpf +yit dKw miD dFY @@ -83632,7 +83671,7 @@ uDB uDB uDB sdc -vBA +fLM soZ jCX jCX @@ -83899,10 +83938,10 @@ lwW uyL esN fXZ -fEi gli gli gli +fEi gli gli hgi @@ -151186,9 +151225,9 @@ hHw uRG oyP dAq +xbr +qFS wSc -rwW -hWN jOV vxX vxX diff --git a/_maps/virtual_domains/fredingtonfastingbear.dmm b/_maps/virtual_domains/fredingtonfastingbear.dmm index a9118edf73487..4da8210c90e1a 100644 --- a/_maps/virtual_domains/fredingtonfastingbear.dmm +++ b/_maps/virtual_domains/fredingtonfastingbear.dmm @@ -535,6 +535,10 @@ }, /turf/open/floor/iron/kitchen, /area/ruin/space/has_grav/powered/virtual_domain) +"Ak" = ( +/obj/effect/landmark/bitrunning/cache_spawn, +/turf/open/floor/iron/kitchen, +/area/ruin/space/has_grav/powered/virtual_domain) "AF" = ( /obj/structure/table/wood, /obj/item/reagent_containers/cup/glass/bottle/goldschlager{ @@ -594,7 +598,7 @@ /turf/open/floor/iron/kitchen, /area/ruin/space/has_grav/powered/virtual_domain) "DV" = ( -/obj/machinery/door, +/obj/machinery/door/airlock, /turf/open/floor/iron/cafeteria, /area/virtual_domain/protected_space/fullbright) "EO" = ( @@ -633,6 +637,7 @@ "Gn" = ( /obj/machinery/light/built/directional/east, /obj/effect/decal/cleanable/food/tomato_smudge, +/obj/effect/landmark/bitrunning/cache_spawn, /turf/open/floor/iron/kitchen/small, /area/ruin/space/has_grav/powered/virtual_domain) "GD" = ( @@ -947,7 +952,7 @@ /area/ruin/space/has_grav/powered/virtual_domain) "VS" = ( /obj/structure/table/reinforced, -/obj/machinery/computer/camera_advanced, +/obj/item/modular_computer/laptop/preset/civilian, /turf/open/floor/iron/cafeteria, /area/virtual_domain/protected_space/fullbright) "VW" = ( @@ -2802,7 +2807,7 @@ Cm Ne Ne ve -Ux +Ak Ux Ux Ux diff --git a/_maps/virtual_domains/starfront_saloon.dmm b/_maps/virtual_domains/starfront_saloon.dmm deleted file mode 100644 index 277382b6dbbf2..0000000000000 --- a/_maps/virtual_domains/starfront_saloon.dmm +++ /dev/null @@ -1,1834 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"ae" = ( -/obj/item/kirbyplants/random, -/obj/effect/turf_decal/tile/dark_red/half, -/turf/open/floor/sepia, -/area/virtual_domain) -"cK" = ( -/obj/effect/landmark/bitrunning/mob_segment, -/turf/template_noop, -/area/virtual_domain) -"cU" = ( -/turf/template_noop, -/area/virtual_domain/safehouse) -"df" = ( -/obj/effect/spawner/random/vending/snackvend, -/turf/open/floor/sepia, -/area/virtual_domain) -"do" = ( -/obj/effect/spawner/random/trash/garbage, -/turf/open/floor/sepia, -/area/virtual_domain) -"eU" = ( -/obj/effect/spawner/random/structure/crate, -/obj/machinery/light/small/directional/north, -/turf/open/floor/catwalk_floor, -/area/virtual_domain) -"gh" = ( -/obj/effect/spawner/random/vending/colavend, -/turf/open/floor/sepia, -/area/virtual_domain) -"hz" = ( -/obj/item/clothing/head/cowboy, -/obj/item/clothing/head/cowboy, -/obj/item/clothing/head/cowboy, -/obj/structure/closet, -/turf/template_noop, -/area/virtual_domain/safehouse) -"il" = ( -/turf/open/floor/sepia, -/area/virtual_domain) -"it" = ( -/obj/modular_map_root/generic{ - key = "station_medium" - }, -/turf/open/floor/sepia, -/area/virtual_domain) -"iJ" = ( -/obj/machinery/light/directional/south, -/obj/effect/spawner/random/structure/table, -/obj/effect/spawner/random/entertainment/plushie, -/obj/effect/turf_decal/tile/dark_red/half, -/turf/open/floor/sepia, -/area/virtual_domain) -"iO" = ( -/obj/effect/spawner/random/structure/crate, -/obj/effect/turf_decal/tile/dark_red/half, -/turf/open/floor/sepia, -/area/virtual_domain) -"jt" = ( -/obj/item/gun/energy/marksman_revolver{ - pixel_x = 8; - pixel_y = 4 - }, -/obj/item/gun/energy/marksman_revolver{ - pixel_x = 4 - }, -/obj/item/gun/energy/marksman_revolver{ - pixel_x = -4; - pixel_y = -4 - }, -/obj/structure/table, -/turf/template_noop, -/area/virtual_domain/safehouse) -"ma" = ( -/obj/machinery/light/directional/south, -/obj/effect/spawner/random/structure/table, -/obj/effect/spawner/random/decoration/generic, -/obj/effect/turf_decal/tile/dark_red/half, -/turf/open/floor/sepia, -/area/virtual_domain) -"mq" = ( -/obj/effect/baseturf_helper/virtual_domain, -/turf/closed/indestructible/binary, -/area/virtual_domain) -"mu" = ( -/turf/closed/wall, -/area/virtual_domain) -"on" = ( -/obj/structure/table/greyscale, -/obj/machinery/recharger{ - pixel_x = 8; - pixel_y = 4 - }, -/obj/machinery/recharger{ - pixel_x = -8; - pixel_y = 4 - }, -/turf/template_noop, -/area/virtual_domain/safehouse) -"oR" = ( -/obj/effect/spawner/random/structure/chair_maintenance{ - dir = 8 - }, -/turf/open/floor/sepia, -/area/virtual_domain) -"po" = ( -/obj/effect/baseturf_helper/virtual_domain, -/obj/modular_map_root/safehouse{ - key = "den" - }, -/turf/template_noop, -/area/virtual_domain/safehouse) -"sX" = ( -/obj/effect/spawner/random/decoration/statue, -/turf/open/floor/sepia, -/area/virtual_domain) -"uW" = ( -/obj/effect/decal/cleanable/dirt/dust, -/turf/open/floor/sepia, -/area/virtual_domain) -"ve" = ( -/obj/effect/spawner/random/trash/graffiti, -/turf/open/floor/catwalk_floor, -/area/virtual_domain) -"wB" = ( -/obj/effect/spawner/random/engineering/tank, -/obj/machinery/light/small/directional/north, -/turf/open/floor/catwalk_floor, -/area/virtual_domain) -"wK" = ( -/obj/machinery/light/small/directional/north, -/turf/open/floor/catwalk_floor, -/area/virtual_domain) -"yF" = ( -/obj/machinery/light/directional/south, -/obj/effect/spawner/random/structure/table, -/obj/effect/spawner/random/food_or_drink/snack, -/obj/effect/turf_decal/tile/dark_red/half, -/turf/open/floor/sepia, -/area/virtual_domain) -"zU" = ( -/obj/machinery/light/directional/south, -/obj/effect/spawner/random/structure/table, -/obj/effect/turf_decal/tile/dark_red/half, -/obj/machinery/recharger{ - pixel_x = 8; - pixel_y = 4 - }, -/turf/open/floor/sepia, -/area/virtual_domain) -"Au" = ( -/obj/effect/spawner/random/trash/garbage, -/obj/machinery/light/small/directional/north, -/turf/open/floor/catwalk_floor, -/area/virtual_domain) -"AF" = ( -/obj/effect/turf_decal/tile/dark_red/half, -/obj/effect/turf_decal/tile/dark_red/half, -/turf/open/floor/sepia, -/area/virtual_domain) -"Bi" = ( -/obj/effect/spawner/random/structure/chair_maintenance{ - dir = 4 - }, -/turf/open/floor/sepia, -/area/virtual_domain) -"BX" = ( -/obj/effect/spawner/random/trash/graffiti, -/obj/effect/turf_decal/tile/dark_red/half, -/turf/open/floor/sepia, -/area/virtual_domain) -"Ey" = ( -/obj/machinery/light/directional/south, -/obj/effect/spawner/random/structure/table, -/obj/effect/spawner/random/decoration/ornament, -/obj/effect/turf_decal/tile/dark_red/half, -/turf/open/floor/sepia, -/area/virtual_domain) -"EK" = ( -/obj/effect/spawner/random/structure/chair_maintenance{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt/dust, -/turf/open/floor/sepia, -/area/virtual_domain) -"Gz" = ( -/obj/effect/spawner/random/structure/crate, -/obj/effect/turf_decal/tile/dark_red/half, -/obj/effect/spawner/random/armory/shotgun, -/turf/open/floor/sepia, -/area/virtual_domain) -"GY" = ( -/obj/effect/spawner/random/entertainment/arcade, -/turf/open/floor/sepia, -/area/virtual_domain) -"Ib" = ( -/obj/effect/spawner/random/trash/bin, -/turf/open/floor/sepia, -/area/virtual_domain) -"Il" = ( -/obj/effect/turf_decal/tile/dark_red/half, -/obj/effect/decal/cleanable/dirt/dust, -/turf/open/floor/sepia, -/area/virtual_domain) -"Ix" = ( -/obj/structure/closet, -/obj/effect/spawner/random/maintenance/three, -/obj/effect/spawner/random/exotic/antag_gear, -/obj/machinery/light/small/directional/north, -/turf/open/floor/catwalk_floor, -/area/virtual_domain) -"Ja" = ( -/turf/closed/indestructible/binary, -/area/virtual_domain) -"JA" = ( -/obj/effect/spawner/random/structure/crate, -/turf/open/floor/catwalk_floor, -/area/virtual_domain) -"KD" = ( -/obj/effect/landmark/bitrunning/cache_spawn, -/turf/template_noop, -/area/virtual_domain) -"KN" = ( -/obj/effect/spawner/structure/window/reinforced, -/turf/open/floor/plating, -/area/virtual_domain) -"Lu" = ( -/obj/structure/table/greyscale, -/obj/machinery/recharger{ - pixel_x = 8; - pixel_y = 4 - }, -/obj/machinery/recharger{ - pixel_x = -8; - pixel_y = 4 - }, -/obj/effect/turf_decal/tile/dark_red/half, -/obj/machinery/light/directional/south, -/turf/open/floor/sepia, -/area/virtual_domain) -"MG" = ( -/obj/effect/spawner/random/trash/graffiti, -/obj/machinery/light/small/directional/north, -/turf/open/floor/catwalk_floor, -/area/virtual_domain) -"Oq" = ( -/obj/machinery/light/small/directional/south, -/turf/open/floor/sepia, -/area/virtual_domain) -"Ox" = ( -/obj/structure/closet, -/obj/effect/spawner/random/maintenance/five, -/obj/effect/spawner/random/armory/laser_gun, -/obj/machinery/light/small/directional/north, -/turf/open/floor/catwalk_floor, -/area/virtual_domain) -"OX" = ( -/turf/open/floor/catwalk_floor, -/area/virtual_domain) -"OZ" = ( -/obj/effect/spawner/random/structure/billboard, -/turf/open/floor/sepia, -/area/virtual_domain) -"PE" = ( -/turf/template_noop, -/area/virtual_domain) -"Qi" = ( -/obj/modular_map_root/generic{ - key = "station_small" - }, -/turf/open/floor/sepia, -/area/virtual_domain) -"QM" = ( -/obj/modular_map_root/generic{ - key = "station_large" - }, -/turf/open/floor/sepia, -/area/virtual_domain) -"QO" = ( -/obj/machinery/light/directional/east, -/turf/open/floor/sepia, -/area/virtual_domain) -"Rk" = ( -/obj/effect/spawner/random/trash/graffiti, -/turf/open/floor/sepia, -/area/virtual_domain) -"Te" = ( -/obj/machinery/light/directional/south, -/obj/effect/spawner/random/structure/table, -/obj/effect/spawner/random/engineering/toolbox, -/obj/effect/turf_decal/tile/dark_red/half, -/turf/open/floor/sepia, -/area/virtual_domain) -"Tn" = ( -/turf/open/space/basic, -/area/virtual_domain) -"TM" = ( -/obj/machinery/light/directional/south, -/obj/effect/turf_decal/tile/dark_red/half, -/turf/open/floor/sepia, -/area/virtual_domain) -"VX" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/sepia, -/area/virtual_domain) -"Wd" = ( -/obj/effect/turf_decal/tile/dark_red/half, -/turf/open/floor/sepia, -/area/virtual_domain) -"Wp" = ( -/obj/effect/landmark/bitrunning/mob_segment, -/turf/open/floor/sepia, -/area/virtual_domain) - -(1,1,1) = {" -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -mq -"} -(2,1,1) = {" -Ja -il -il -il -il -mu -df -il -cU -cU -cU -cU -cU -po -il -OX -Ja -"} -(3,1,1) = {" -Ja -mu -mu -mu -mu -mu -il -il -cU -jt -on -hz -cU -cU -il -OX -Ja -"} -(4,1,1) = {" -Ja -OX -OX -OX -OX -OX -Qi -il -cU -cU -cU -cU -cU -cU -il -OX -Ja -"} -(5,1,1) = {" -Ja -PE -PE -PE -PE -PE -gh -il -cU -cU -cU -cU -cU -cU -il -OX -Ja -"} -(6,1,1) = {" -Ja -PE -PE -PE -PE -PE -il -il -cU -cU -cU -cU -cU -cU -il -OX -Ja -"} -(7,1,1) = {" -Ja -PE -PE -PE -PE -PE -il -il -cU -cU -cU -cU -cU -cU -il -OX -Ja -"} -(8,1,1) = {" -Ja -PE -PE -PE -PE -PE -il -il -cU -cU -cU -cU -cU -cU -il -il -Ja -"} -(9,1,1) = {" -Ja -PE -PE -PE -PE -PE -il -il -il -il -il -il -il -il -il -il -Ja -"} -(10,1,1) = {" -Ja -Ix -OX -OX -OX -OX -il -il -it -il -il -il -TM -mu -KN -KN -Ja -"} -(11,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -Ib -il -il -il -ae -KN -Tn -Tn -Ja -"} -(12,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(13,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -Il -KN -Tn -Tn -Ja -"} -(14,1,1) = {" -Ja -PE -PE -PE -cK -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(15,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(16,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -VX -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(17,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(18,1,1) = {" -Ja -Au -OX -OX -OX -OX -il -il -it -il -sX -il -iO -KN -Tn -Tn -Ja -"} -(19,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -Te -mu -Tn -Tn -Ja -"} -(20,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(21,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -AF -KN -Tn -Tn -Ja -"} -(22,1,1) = {" -Ja -PE -PE -PE -cK -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(23,1,1) = {" -Ja -PE -KD -PE -PE -PE -PE -PE -il -il -il -Wp -Wd -KN -Tn -Tn -Ja -"} -(24,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(25,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -VX -il -Wd -KN -Tn -Tn -Ja -"} -(26,1,1) = {" -Ja -wB -OX -OX -OX -OX -il -il -it -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(27,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -Ib -il -il -il -iJ -mu -Tn -Tn -Ja -"} -(28,1,1) = {" -Ja -PE -KD -PE -PE -PE -PE -PE -il -uW -il -il -ae -KN -Tn -Tn -Ja -"} -(29,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -oR -oR -il -Wd -KN -Tn -Tn -Ja -"} -(30,1,1) = {" -Ja -PE -PE -PE -cK -PE -PE -PE -Oq -mu -mu -il -Wd -KN -Tn -Tn -Ja -"} -(31,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -Bi -EK -il -Wd -KN -Tn -Tn -Ja -"} -(32,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(33,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(34,1,1) = {" -Ja -wK -ve -OX -OX -OX -VX -il -it -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(35,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -OZ -il -zU -mu -Tn -Tn -Ja -"} -(36,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(37,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -VX -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(38,1,1) = {" -Ja -PE -PE -PE -cK -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(39,1,1) = {" -Ja -PE -KD -PE -PE -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(40,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(41,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -uW -il -il -Wd -KN -Tn -Tn -Ja -"} -(42,1,1) = {" -Ja -Ox -OX -OX -OX -OX -il -il -it -uW -il -Wp -Gz -KN -Tn -Tn -Ja -"} -(43,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -uW -il -il -Lu -mu -Tn -Tn -Ja -"} -(44,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -do -il -il -il -ae -KN -Tn -Tn -Ja -"} -(45,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(46,1,1) = {" -Ja -PE -KD -PE -cK -PE -PE -PE -il -il -il -VX -Wd -KN -Tn -Tn -Ja -"} -(47,1,1) = {" -Ja -PE -PE -PE -PE -KD -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(48,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(49,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -Ib -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(50,1,1) = {" -Ja -MG -OX -OX -OX -OX -VX -il -il -il -QM -il -Wd -KN -Tn -Tn -Ja -"} -(51,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -PE -PE -il -il -yF -mu -Tn -Tn -Ja -"} -(52,1,1) = {" -Ja -PE -KD -PE -PE -PE -PE -PE -PE -PE -il -il -Wd -KN -Tn -Tn -Ja -"} -(53,1,1) = {" -Ja -PE -PE -cK -PE -PE -KD -PE -PE -PE -uW -il -Wd -KN -Tn -Tn -Ja -"} -(54,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -PE -PE -uW -il -Wd -KN -Tn -Tn -Ja -"} -(55,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -PE -PE -il -il -Wd -KN -Tn -Tn -Ja -"} -(56,1,1) = {" -Ja -PE -PE -PE -PE -PE -cK -PE -PE -PE -il -il -Wd -KN -Tn -Tn -Ja -"} -(57,1,1) = {" -Ja -PE -KD -PE -PE -PE -KD -PE -PE -PE -il -il -Wd -KN -Tn -Tn -Ja -"} -(58,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -PE -PE -GY -il -Wd -KN -Tn -Tn -Ja -"} -(59,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -PE -PE -il -il -Wd -KN -Tn -Tn -Ja -"} -(60,1,1) = {" -Ja -eU -OX -OX -OX -OX -il -il -it -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(61,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -Ib -il -il -il -Ey -mu -Tn -Tn -Ja -"} -(62,1,1) = {" -Ja -PE -PE -KD -PE -PE -PE -PE -do -il -il -VX -ae -KN -Tn -Tn -Ja -"} -(63,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(64,1,1) = {" -Ja -PE -PE -PE -cK -PE -PE -PE -il -il -Wp -il -Wd -KN -Tn -Tn -Ja -"} -(65,1,1) = {" -Ja -PE -KD -PE -PE -KD -PE -PE -il -il -sX -il -Wd -KN -Tn -Tn -Ja -"} -(66,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -il -il -il -il -Wd -KN -Tn -Tn -Ja -"} -(67,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -Rk -il -il -uW -Wd -KN -Tn -Tn -Ja -"} -(68,1,1) = {" -Ja -wB -OX -OX -OX -OX -VX -il -il -il -QM -uW -Wd -KN -Tn -Tn -Ja -"} -(69,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -PE -PE -il -il -ma -mu -Tn -Tn -Ja -"} -(70,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -PE -PE -il -il -Wd -KN -Tn -Tn -Ja -"} -(71,1,1) = {" -Ja -PE -PE -KD -PE -PE -PE -KD -PE -PE -il -uW -Wd -KN -Tn -Tn -Ja -"} -(72,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -PE -PE -il -il -Wd -KN -Tn -Tn -Ja -"} -(73,1,1) = {" -Ja -PE -PE -cK -PE -PE -PE -PE -PE -PE -il -il -Wd -KN -Tn -Tn -Ja -"} -(74,1,1) = {" -Ja -PE -PE -PE -PE -PE -cK -PE -PE -PE -il -il -Wd -KN -Tn -Tn -Ja -"} -(75,1,1) = {" -Ja -PE -KD -PE -PE -PE -KD -PE -PE -PE -il -il -Wd -KN -Tn -Tn -Ja -"} -(76,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -PE -PE -il -il -Wd -KN -Tn -Tn -Ja -"} -(77,1,1) = {" -Ja -PE -PE -PE -PE -PE -PE -PE -PE -PE -il -VX -BX -KN -Tn -Tn -Ja -"} -(78,1,1) = {" -Ja -eU -JA -OX -OX -OX -OX -OX -OX -il -QO -il -Wd -KN -Tn -Tn -Ja -"} -(79,1,1) = {" -Ja -mu -mu -mu -mu -mu -mu -mu -mu -mu -mu -mu -mu -mu -Tn -Tn -Ja -"} -(80,1,1) = {" -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -Ja -"} diff --git a/_maps/virtual_domains/syndicate_assault.dmm b/_maps/virtual_domains/syndicate_assault.dmm index 81bb35a257a75..3822d2cc1e076 100644 --- a/_maps/virtual_domains/syndicate_assault.dmm +++ b/_maps/virtual_domains/syndicate_assault.dmm @@ -65,6 +65,7 @@ req_access = list("syndicate"); secure = 1 }, +/obj/item/gun/ballistic/automatic/pistol, /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/powered/virtual_domain) "cw" = ( @@ -388,6 +389,11 @@ /obj/structure/sign/poster/contraband/syndicate_pistol, /turf/closed/wall/r_wall/syndicate, /area/ruin/space/has_grav/powered/virtual_domain) +"og" = ( +/obj/structure/table/reinforced, +/obj/item/reagent_containers/cup/glass/trophy/silver_cup, +/turf/open/floor/mineral/plastitanium/red, +/area/ruin/space/has_grav/powered/virtual_domain) "oM" = ( /obj/structure/cable, /turf/open/floor/mineral/plastitanium, @@ -498,10 +504,16 @@ /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/powered/virtual_domain) "sH" = ( -/obj/structure/displaycase{ +/obj/structure/closet/syndicate{ + anchored = 1; + desc = "A basic closet for all your villainous needs."; + locked = 1; + name = "Closet"; req_access = list("syndicate"); - start_showpiece_type = /obj/item/gun/ballistic/automatic/pistol/deagle/camo + secure = 1 }, +/obj/item/ammo_box/c9mm, +/obj/item/gun/ballistic/automatic/pistol, /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/powered/virtual_domain) "sK" = ( @@ -600,6 +612,9 @@ /obj/item/ammo_box/c9mm, /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/powered/virtual_domain) +"xS" = ( +/turf/closed/wall/r_wall/syndicate/nodiagonal, +/area/ruin/space/has_grav/powered/virtual_domain) "yl" = ( /obj/machinery/door/airlock/grunge{ name = "Captain's Room" @@ -688,6 +703,7 @@ /obj/item/crowbar/red, /obj/item/ammo_box/magazine/m9mm_aps, /obj/item/ammo_box/magazine/m9mm_aps, +/obj/item/gun/ballistic/automatic/pistol, /turf/open/floor/carpet/royalblack, /area/ruin/space/has_grav/powered/virtual_domain) "Cn" = ( @@ -927,6 +943,7 @@ /obj/item/crowbar/red, /obj/item/ammo_box/magazine/m9mm, /obj/item/ammo_box/magazine/m9mm, +/obj/item/gun/ballistic/automatic/pistol, /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/powered/virtual_domain) "Mm" = ( @@ -1076,6 +1093,7 @@ /obj/item/ammo_box/magazine/m9mm, /obj/item/ammo_box/magazine/m9mm, /obj/machinery/light/small/directional/north, +/obj/item/gun/ballistic/automatic/pistol, /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/powered/virtual_domain) "Sq" = ( @@ -2206,7 +2224,7 @@ qx qx qx ru -vp +og Jg ru bh @@ -2264,7 +2282,7 @@ qx qx qx ru -sH +Kz Kz yl bh @@ -2743,7 +2761,7 @@ ru ru ru ru -Vk +ru qx qx qx @@ -3091,7 +3109,7 @@ uP ru hD ru -Ig +xS qx qx qx @@ -3203,7 +3221,7 @@ tI Kz Kz ct -xJ +sH ru qx qx diff --git a/_maps/virtual_domains/xeno_nest.dmm b/_maps/virtual_domains/xeno_nest.dmm index 907436758c781..65f183d69c401 100644 --- a/_maps/virtual_domains/xeno_nest.dmm +++ b/_maps/virtual_domains/xeno_nest.dmm @@ -140,7 +140,7 @@ /area/ruin/space/has_grav/powered/virtual_domain) "F" = ( /obj/structure/table/greyscale, -/obj/item/gun/energy/beam_rifle, +/obj/item/gun/energy/xray, /obj/item/gun/energy/laser{ pixel_x = 4; pixel_y = -6 diff --git a/code/__DEFINES/ai/pet_commands.dm b/code/__DEFINES/ai/pet_commands.dm index 1e692b9f805aa..7404cb9acda84 100644 --- a/code/__DEFINES/ai/pet_commands.dm +++ b/code/__DEFINES/ai/pet_commands.dm @@ -7,3 +7,6 @@ #define BB_PET_TARGETING_STRATEGY "BB_pet_targeting" /// Typecache of weakrefs to mobs this mob is friends with, will follow their instructions and won't attack them #define BB_FRIENDS_LIST "BB_friends_list" + +///mothroach next meal key! +#define BB_MOTHROACH_NEXT_EAT "mothroach_next_eat" diff --git a/code/__DEFINES/fish.dm b/code/__DEFINES/fish.dm index 24242699e3d01..8e03c920d248d 100644 --- a/code/__DEFINES/fish.dm +++ b/code/__DEFINES/fish.dm @@ -9,8 +9,8 @@ #define FAV_BAIT_DIFFICULTY_MOD -5 /// Difficulty modifier when bait is fish's disliked #define DISLIKED_BAIT_DIFFICULTY_MOD 15 -/// Difficulty modifier when our fisherman has the trait TRAIT_SETTLER -#define SETTLER_DIFFICULTY_MOD -5 +/// Difficulty modifier when our fisherman has the trait TRAIT_EXPERT_FISHER +#define EXPERT_FISHER_DIFFICULTY_MOD -5 #define FISH_TRAIT_MINOR_DIFFICULTY_BOOST 5 diff --git a/code/__DEFINES/keybinding.dm b/code/__DEFINES/keybinding.dm index 2a2a092c6d05b..5f025ad99cffb 100644 --- a/code/__DEFINES/keybinding.dm +++ b/code/__DEFINES/keybinding.dm @@ -26,6 +26,7 @@ //Client #define COMSIG_KB_CLIENT_GETHELP_DOWN "keybinding_client_gethelp_down" #define COMSIG_KB_CLIENT_SCREENSHOT_DOWN "keybinding_client_screenshot_down" +#define COMSIG_KB_CLIENT_FULLSCREEN_DOWN "keybinding_client_fullscreen_down" #define COMSIG_KB_CLIENT_MINIMALHUD_DOWN "keybinding_client_minimalhud_down" //Communication diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index e8904f0bb1f86..a0c40856dace1 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -84,6 +84,8 @@ #define BODYTYPE_ALIEN (1<<3) ///The limb is from a golem #define BODYTYPE_GOLEM (1<<4) +//The limb is a peg limb +#define BODYTYPE_PEG (1<<5) // Bodyshape defines for how things can be worn, i.e., what "shape" the mob sprite is ///The limb fits the human mold. This is not meant to be literal, if the sprite "fits" on a human, it is "humanoid", regardless of origin. @@ -95,7 +97,7 @@ ///The limb is snouted. #define BODYSHAPE_SNOUTED (1<<3) -#define BODYTYPE_BIOSCRAMBLE_INCOMPATIBLE (BODYTYPE_ROBOTIC | BODYTYPE_LARVA_PLACEHOLDER | BODYTYPE_GOLEM) +#define BODYTYPE_BIOSCRAMBLE_INCOMPATIBLE (BODYTYPE_ROBOTIC | BODYTYPE_LARVA_PLACEHOLDER | BODYTYPE_GOLEM | BODYTYPE_PEG) #define BODYTYPE_CAN_BE_BIOSCRAMBLED(bodytype) (!(bodytype & BODYTYPE_BIOSCRAMBLE_INCOMPATIBLE)) // Defines for Species IDs. Used to refer to the name of a species, for things like bodypart names or species preferences. @@ -135,6 +137,8 @@ #define BODYPART_ID_LARVA "larva" #define BODYPART_ID_PSYKER "psyker" #define BODYPART_ID_MEAT "meat" +#define BODYPART_ID_PEG "peg" + //See: datum/species/var/digitigrade_customization ///The species does not have digitigrade legs in generation. @@ -444,6 +448,8 @@ #define FLASH_PROTECTION_NONE 0 #define FLASH_PROTECTION_FLASH 1 #define FLASH_PROTECTION_WELDER 2 +#define FLASH_PROTECTION_WELDER_PLUS 3 +#define FLASH_PROTECTION_MAXIMUM 4 // AI Toggles #define AI_CAMERA_LUMINOSITY 5 @@ -631,6 +637,7 @@ // Otherwise they are completely arbitrary #define MONKEY_HEIGHT_DWARF 2 #define MONKEY_HEIGHT_MEDIUM 4 +#define MONKEY_HEIGHT_TALL HUMAN_HEIGHT_DWARF #define HUMAN_HEIGHT_DWARF 6 #define HUMAN_HEIGHT_SHORTEST 8 #define HUMAN_HEIGHT_SHORT 10 diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index 9e38eada92313..62ae5a7394a0a 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -106,3 +106,8 @@ /// Flags for sharpness in obj/item #define SHARP_EDGED (1<<0) #define SHARP_POINTY (1<<1) + +/// Flags for specifically what kind of items to get in get_equipped_items +#define INCLUDE_POCKETS (1<<0) +#define INCLUDE_ACCESSORIES (1<<1) +#define INCLUDE_HELD (1<<2) diff --git a/code/__DEFINES/research.dm b/code/__DEFINES/research.dm index d3f99314f1d8f..cf35d553ec4dc 100644 --- a/code/__DEFINES/research.dm +++ b/code/__DEFINES/research.dm @@ -4,8 +4,15 @@ //! Techweb names for new point types. Can be used to define specific point values for specific types of research (science, security, engineering, etc.) #define TECHWEB_POINT_TYPE_GENERIC "General Research" +//! Amount of points required to unlock nodes of corresponding tiers +#define TECHWEB_TIER_1_POINTS 40 +#define TECHWEB_TIER_2_POINTS 80 +#define TECHWEB_TIER_3_POINTS 120 +#define TECHWEB_TIER_4_POINTS 160 +#define TECHWEB_TIER_5_POINTS 200 + //! Amount of points gained per second by a single R&D server, see: [research][code/controllers/subsystem/research.dm] -#define TECHWEB_SINGLE_SERVER_INCOME 52.3 +#define TECHWEB_SINGLE_SERVER_INCOME 1 //! Swab cell line types #define CELL_LINE_TABLE_SLUDGE "cell_line_sludge_table" diff --git a/code/__DEFINES/research/anomalies.dm b/code/__DEFINES/research/anomalies.dm index db605431c610c..a1e30cd142f00 100644 --- a/code/__DEFINES/research/anomalies.dm +++ b/code/__DEFINES/research/anomalies.dm @@ -2,7 +2,7 @@ #define MAX_CORES_BLUESPACE 3 #define MAX_CORES_GRAVITATIONAL 8 #define MAX_CORES_FLUX 8 -#define MAX_CORES_VORTEX 8 +#define MAX_CORES_VORTEX 1 #define MAX_CORES_PYRO 8 #define MAX_CORES_HALLUCINATION 8 #define MAX_CORES_BIOSCRAMBLER 8 diff --git a/code/__DEFINES/research/slimes.dm b/code/__DEFINES/research/slimes.dm index f54248a21a3ac..e03c6af8f581d 100644 --- a/code/__DEFINES/research/slimes.dm +++ b/code/__DEFINES/research/slimes.dm @@ -61,3 +61,6 @@ #define SLIME_TYPE_SEPIA "sepia" #define SLIME_TYPE_SILVER "silver" #define SLIME_TYPE_YELLOW "yellow" + +// The alpha value of transperent slime types +#define SLIME_TRANSPARENCY_ALPHA 180 diff --git a/code/__DEFINES/surgery.dm b/code/__DEFINES/surgery.dm index 42e00045761e5..feddc24c6f858 100644 --- a/code/__DEFINES/surgery.dm +++ b/code/__DEFINES/surgery.dm @@ -33,6 +33,8 @@ #define IS_ORGANIC_LIMB(limb) (limb.bodytype & BODYTYPE_ORGANIC) /// Helper to figure out if a limb is robotic #define IS_ROBOTIC_LIMB(limb) (limb.bodytype & BODYTYPE_ROBOTIC) +/// Helper to figure out if a limb is a peg limb +#define IS_PEG_LIMB(limb) (limb.bodytype & BODYTYPE_PEG) // Flags for the bodypart_flags var on /obj/item/bodypart /// Bodypart cannot be dismembered or amputated diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 17d9008a543b3..c34e0f2925e9f 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -138,8 +138,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_AGENDER "agender" /// Species with this trait have a blood clan mechanic #define TRAIT_BLOOD_CLANS "blood_clans" -/// Species with this trait have markings (this SUCKS, remove this later in favor of bodypart overlays) -#define TRAIT_HAS_MARKINGS "has_markings" /// Species with this trait use skin tones for coloration #define TRAIT_USES_SKINTONES "uses_skintones" /// Species with this trait use mutant colors for coloration @@ -366,6 +364,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_GAMERGOD "gamer-god" #define TRAIT_GIANT "giant" #define TRAIT_DWARF "dwarf" +/// Makes you way too tall. Like just too much, dude, it's kind of creepy. Humanoid only. +#define TRAIT_TOO_TALL "too_tall" /// makes your footsteps completely silent #define TRAIT_SILENT_FOOTSTEPS "silent_footsteps" /// hnnnnnnnggggg..... you're pretty good.... @@ -1151,7 +1151,17 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Does this item bypass ranged armor checks? #define TRAIT_BYPASS_RANGED_ARMOR "bypass_ranged_armor" +/// Traits given by settler, each with their own specific effects for cases where someone would have that trait, but not the other settler effects + +#define TRAIT_EXPERT_FISHER "expert_fisher" // fishing is easier +#define TRAIT_ROUGHRIDER "roughrider" // you can improve speed on mounted animals with a good mood +#define TRAIT_STUBBY_BODY "stubby_body" // you have a stubby body that lessens your agility +#define TRAIT_BEAST_EMPATHY "beast_empathy" // you're good with animals, such as with taming them +#define TRAIT_STURDY_FRAME "sturdy_frame" // you suffer much lesser effects from equipment that slows you down + /// This item cannot be selected for or used by a theft objective (Spies, Traitors, etc.) #define TRAIT_ITEM_OBJECTIVE_BLOCKED "item_objective_blocked" +/// This trait lets you attach limbs to any player without surgery. +#define TRAIT_EASY_ATTACH "easy_attach" // END TRAIT DEFINES diff --git a/code/__DEFINES/wires.dm b/code/__DEFINES/wires.dm index 2b4c528abc212..4926996f26bd3 100644 --- a/code/__DEFINES/wires.dm +++ b/code/__DEFINES/wires.dm @@ -64,6 +64,8 @@ #define WIRE_ZAP1 "High Voltage Circuit 1" #define WIRE_ZAP2 "High Voltage Circuit 2" #define WIRE_OVERCLOCK "Overclock" +#define WIRE_EQUIPMENT "Equipment" +#define WIRE_ENVIRONMENT "Environment" // Wire states for the AI #define AI_WIRE_NORMAL 0 diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 0aaca9a0907cf..aa953760bce71 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -205,18 +205,30 @@ return winset(flashed_client, "mainwindow", "flash=5") -///Recursively checks if an item is inside a given type, even through layers of storage. Returns the atom if it finds it. +///Recursively checks if an item is inside a given type/atom, even through layers of storage. Returns the atom if it finds it. /proc/recursive_loc_check(atom/movable/target, type) - var/atom/atom_to_find = target - if(istype(atom_to_find, type)) - return atom_to_find - - while(!istype(atom_to_find.loc, type)) - if(!atom_to_find.loc) - return - atom_to_find = atom_to_find.loc - - return atom_to_find.loc + var/atom/atom_to_find = null + + if(ispath(type)) + atom_to_find = target + if(istype(atom_to_find, type)) + return atom_to_find + + while(!istype(atom_to_find.loc, type)) + if(!atom_to_find.loc) + return + atom_to_find = atom_to_find.loc + else if(isatom(type)) + atom_to_find = target + if(atom_to_find.loc == type) + return atom_to_find + + while(atom_to_find.loc != type) + if(!atom_to_find.loc) + return + atom_to_find = atom_to_find.loc + + return atom_to_find ///Send a message in common radio when a player arrives /proc/announce_arrival(mob/living/carbon/human/character, rank) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 67f33d0460e47..ead7b324cea13 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -390,6 +390,7 @@ DEFINE_BITFIELD(bodytype, list( "BODYTYPE_LARVA_PLACEHOLDER" = BODYTYPE_LARVA_PLACEHOLDER, "BODYTYPE_ALIEN" = BODYTYPE_ALIEN, "BODYTYPE_GOLEM" = BODYTYPE_GOLEM, + "BODYTYPE_PEG" = BODYTYPE_PEG, )) DEFINE_BITFIELD(acceptable_bodytype, list( @@ -398,6 +399,7 @@ DEFINE_BITFIELD(acceptable_bodytype, list( "BODYTYPE_LARVA_PLACEHOLDER" = BODYTYPE_LARVA_PLACEHOLDER, "BODYTYPE_ALIEN" = BODYTYPE_ALIEN, "BODYTYPE_GOLEM" = BODYTYPE_GOLEM, + "BODYTYPE_PEG" = BODYTYPE_PEG, )) DEFINE_BITFIELD(bodyshape, list( diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 1fe465da39f0d..66f32028c6b9c 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -138,6 +138,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_BALD" = TRAIT_BALD, "TRAIT_BALLOON_SUTRA" = TRAIT_BALLOON_SUTRA, "TRAIT_BATON_RESISTANCE" = TRAIT_BATON_RESISTANCE, + "TRAIT_BEAST_EMPATHY" = TRAIT_BEAST_EMPATHY, "TRAIT_BEING_BLADE_SHIELDED" = TRAIT_BEING_BLADE_SHIELDED, "TRAIT_BLOB_ALLY" = TRAIT_BLOB_ALLY, "TRAIT_BLOCK_SHUTTLE_MOVEMENT" = TRAIT_BLOCK_SHUTTLE_MOVEMENT, @@ -208,6 +209,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_EXAMINE_FISHING_SPOT" = TRAIT_EXAMINE_FISHING_SPOT, "TRAIT_EXAMINE_FITNESS" = TRAIT_EXAMINE_FITNESS, "TRAIT_EXPANDED_FOV" = TRAIT_EXPANDED_FOV, + "TRAIT_EXPERT_FISHER" = TRAIT_EXPERT_FISHER, "TRAIT_EXTROVERT" = TRAIT_EXTROVERT, "TRAIT_FAKEDEATH" = TRAIT_FAKEDEATH, "TRAIT_FASTMED" = TRAIT_FASTMED, @@ -248,7 +250,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_HARDLY_WOUNDED" = TRAIT_HARDLY_WOUNDED, "TRAIT_HAS_BEEN_KIDNAPPED" = TRAIT_HAS_BEEN_KIDNAPPED, "TRAIT_HAS_CRANIAL_FISSURE" = TRAIT_HAS_CRANIAL_FISSURE, - "TRAIT_HAS_MARKINGS" = TRAIT_HAS_MARKINGS, "TRAIT_HATED_BY_DOGS" = TRAIT_HATED_BY_DOGS, "TRAIT_HEAD_INJURY_BLOCKED" = TRAIT_HEAD_INJURY_BLOCKED, "TRAIT_HEALS_FROM_CARP_RIFTS" = TRAIT_HEALS_FROM_CARP_RIFTS, @@ -415,6 +416,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_ROCK_METAMORPHIC" = TRAIT_ROCK_METAMORPHIC, "TRAIT_ROCK_STONER" = TRAIT_ROCK_STONER, "TRAIT_ROD_SUPLEX" = TRAIT_ROD_SUPLEX, + "TRAIT_ROUGHRIDER" = TRAIT_ROUGHRIDER, "TRAIT_SABRAGE_PRO" = TRAIT_SABRAGE_PRO, "TRAIT_SECURITY_HUD" = TRAIT_SECURITY_HUD, "TRAIT_SEE_GLASS_COLORS" = TRAIT_SEE_GLASS_COLORS, @@ -446,7 +448,9 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_STIMULATED" = TRAIT_STIMULATED, "TRAIT_STRONG_GRABBER" = TRAIT_STRONG_GRABBER, "TRAIT_STRONG_STOMACH" = TRAIT_STRONG_STOMACH, + "TRAIT_STUBBY_BODY" = TRAIT_STUBBY_BODY, "TRAIT_STUNIMMUNE" = TRAIT_STUNIMMUNE, + "TRAIT_STURDY_FRAME" = TRAIT_STURDY_FRAME, "TRAIT_SUCCUMB_OVERRIDE" = TRAIT_SUCCUMB_OVERRIDE, "TRAIT_SUICIDED" = TRAIT_SUICIDED, "TRAIT_SUPERMATTER_SOOTHER" = TRAIT_SUPERMATTER_SOOTHER, @@ -465,6 +469,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_THINKING_IN_CHARACTER" = TRAIT_THINKING_IN_CHARACTER, "TRAIT_THROWINGARM" = TRAIT_THROWINGARM, "TRAIT_TIME_STOP_IMMUNE" = TRAIT_TIME_STOP_IMMUNE, + "TRAIT_TOO_TALL" = TRAIT_TOO_TALL, "TRAIT_TOWER_OF_BABEL" = TRAIT_TOWER_OF_BABEL, "TRAIT_TOXIMMUNE" = TRAIT_TOXIMMUNE, "TRAIT_TOXINLOVER" = TRAIT_TOXINLOVER, @@ -548,6 +553,9 @@ GLOBAL_LIST_INIT(traits_by_type, list( /obj/item/bodypart = list( "TRAIT_PARALYSIS" = TRAIT_PARALYSIS, ), + /obj/item/bodypart = list( + "TRAIT_EASY_ATTACH" = TRAIT_EASY_ATTACH, + ), /obj/item/card/id = list( "TRAIT_JOB_FIRST_ID_CARD" = TRAIT_JOB_FIRST_ID_CARD, "TRAIT_MAGNETIC_ID_CARD" = TRAIT_MAGNETIC_ID_CARD, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index d9f6350a07480..d709113d2b175 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -36,6 +36,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_BADTOUCH" = TRAIT_BADTOUCH, "TRAIT_BALD" = TRAIT_BALD, "TRAIT_BATON_RESISTANCE" = TRAIT_BATON_RESISTANCE, + "TRAIT_BEAST_EMPATHY" = TRAIT_BEAST_EMPATHY, "TRAIT_BLOCK_SHUTTLE_MOVEMENT" = TRAIT_BLOCK_SHUTTLE_MOVEMENT, "TRAIT_BLOOD_CLANS" = TRAIT_BLOOD_CLANS, "TRAIT_BLOODSHOT_EYES" = TRAIT_BLOODSHOT_EYES, @@ -72,6 +73,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_EMPATH" = TRAIT_EMPATH, "TRAIT_EXAMINE_FITNESS" = TRAIT_EXAMINE_FITNESS, "TRAIT_EXPANDED_FOV" = TRAIT_EXPANDED_FOV, + "TRAIT_EXPERT_FISHER" = TRAIT_EXPERT_FISHER, "TRAIT_FAKEDEATH" = TRAIT_FAKEDEATH, "TRAIT_FAST_CUFFING" = TRAIT_FAST_CUFFING, "TRAIT_FAT" = TRAIT_FAT, @@ -94,7 +96,6 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_GUNFLIP" = TRAIT_GUNFLIP, "TRAIT_HANDS_BLOCKED" = TRAIT_HANDS_BLOCKED, "TRAIT_HARDLY_WOUNDED" = TRAIT_HARDLY_WOUNDED, - "TRAIT_HAS_MARKINGS" = TRAIT_HAS_MARKINGS, "TRAIT_HEAVY_SLEEPER" = TRAIT_HEAVY_SLEEPER, "TRAIT_HIDE_EXTERNAL_ORGANS" = TRAIT_HIDE_EXTERNAL_ORGANS, "TRAIT_HOLY" = TRAIT_HOLY, @@ -189,6 +190,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_RESISTHIGHPRESSURE" = TRAIT_RESISTHIGHPRESSURE, "TRAIT_RESISTLOWPRESSURE" = TRAIT_RESISTLOWPRESSURE, "TRAIT_RESTRAINED" = TRAIT_RESTRAINED, + "TRAIT_ROUGHRIDER" = TRAIT_ROUGHRIDER, "TRAIT_SECURITY_HUD" = TRAIT_SECURITY_HUD, "TRAIT_SELF_AWARE" = TRAIT_SELF_AWARE, "TRAIT_SETTLER" = TRAIT_SETTLER, @@ -209,7 +211,9 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_STABLELIVER" = TRAIT_STABLELIVER, "TRAIT_STRONG_GRABBER" = TRAIT_STRONG_GRABBER, "TRAIT_STRONG_STOMACH" = TRAIT_STRONG_STOMACH, + "TRAIT_STUBBY_BODY" = TRAIT_STUBBY_BODY, "TRAIT_STUNIMMUNE" = TRAIT_STUNIMMUNE, + "TRAIT_STURDY_FRAME" = TRAIT_STURDY_FRAME, "TRAIT_SURGEON" = TRAIT_SURGEON, "TRAIT_SURGICALLY_ANALYZED" = TRAIT_SURGICALLY_ANALYZED, "TRAIT_TAGGER" = TRAIT_TAGGER, diff --git a/code/_onclick/click_alt.dm b/code/_onclick/click_alt.dm index 957f55ab21793..51c58408e2557 100644 --- a/code/_onclick/click_alt.dm +++ b/code/_onclick/click_alt.dm @@ -24,14 +24,7 @@ client.loot_panel.open(tile) return - var/can_use_click_action = FALSE - if(isturf(target)) - // Turfs are special because they can't be used with can_perform_action - can_use_click_action = can_perform_turf_action(target) - else - can_use_click_action = can_perform_action(target, (target.interaction_flags_click | SILENT_ADJACENCY)) - - if(can_use_click_action) + if(can_perform_action(target, (target.interaction_flags_click | SILENT_ADJACENCY))) // If it has a signal handler that returns a click action, done. if(SEND_SIGNAL(target, COMSIG_CLICK_ALT, src) & CLICK_ACTION_ANY) return @@ -97,18 +90,13 @@ if(SEND_SIGNAL(src, COMSIG_MOB_ALTCLICKON_SECONDARY, target) & COMSIG_MOB_CANCEL_CLICKON) return - var/can_use_click_action = FALSE - if(isturf(target)) - // Turfs are special because they can't be used with can_perform_action - can_use_click_action = can_perform_turf_action(target) - else - can_use_click_action = can_perform_action(target, target.interaction_flags_click | SILENT_ADJACENCY) - if(!can_use_click_action) + if(!can_perform_action(target, target.interaction_flags_click | SILENT_ADJACENCY)) return //Hook on the atom to intercept the click if(SEND_SIGNAL(target, COMSIG_CLICK_ALT_SECONDARY, src) & COMPONENT_CANCEL_CLICK_ALT_SECONDARY) return + if(isobserver(src) && client && check_rights_for(client, R_DEBUG)) client.toggle_tag_datum(src) return @@ -124,14 +112,3 @@ /atom/proc/click_alt_secondary(mob/user) SHOULD_CALL_PARENT(FALSE) return NONE - -/// Helper proc to validate turfs. Used because can_perform_action does not support turfs. -/mob/proc/can_perform_turf_action(turf/target) - if(!CanReach(target)) // No error message for parity with SILENT_ADJACENCY - return FALSE - - if(incapacitated()) - to_chat(src, span_warning("You can't use this!")) - return FALSE - - return TRUE diff --git a/code/_onclick/click_ctrl.dm b/code/_onclick/click_ctrl.dm index bb0491b2bb923..2e80f01781603 100644 --- a/code/_onclick/click_ctrl.dm +++ b/code/_onclick/click_ctrl.dm @@ -20,13 +20,8 @@ if(SEND_SIGNAL(target, COMSIG_CLICK_CTRL, src) & CLICK_ACTION_ANY) return TRUE - var/can_use_click_action = FALSE - if(isturf(target)) - // Turfs are special because they can't be used with can_perform_action - can_use_click_action = can_perform_turf_action(target) - else - can_use_click_action = can_perform_action(target, target.interaction_flags_click | SILENT_ADJACENCY) - if(!can_use_click_action) + // This means the action has been processed even though nothing happened + if(!can_perform_action(target, target.interaction_flags_click | SILENT_ADJACENCY)) return TRUE // If it has a custom click_alt that returns success/block, done. @@ -99,17 +94,9 @@ if(SEND_SIGNAL(target, COMSIG_CLICK_CTRL_SHIFT, src) & CLICK_ACTION_ANY) return - var/can_use_click_action = FALSE - if(isturf(target)) - // Turfs are special because they can't be used with can_perform_action - can_use_click_action = can_perform_turf_action(target) - else - can_use_click_action = can_perform_action(target, target.interaction_flags_click | SILENT_ADJACENCY) - if(!can_use_click_action) - return - // Proceed with ctrl shift click - target.click_ctrl_shift(src) + if(can_perform_action(target, target.interaction_flags_click | SILENT_ADJACENCY)) + target.click_ctrl_shift(src) /** * ## Custom ctrl shift click interaction diff --git a/code/_onclick/hud/action_button.dm b/code/_onclick/hud/action_button.dm index b2665e1f98ed0..b3d2de3683b67 100644 --- a/code/_onclick/hud/action_button.dm +++ b/code/_onclick/hud/action_button.dm @@ -94,7 +94,7 @@ old_object.MouseExited(over_location, over_control, params) last_hovored_ref = WEAKREF(over_object) - over_object.MouseEntered(over_location, over_control, params) + over_object?.MouseEntered(over_location, over_control, params) /atom/movable/screen/movable/action_button/MouseEntered(location, control, params) . = ..() diff --git a/code/controllers/subsystem/sprite_accessories.dm b/code/controllers/subsystem/sprite_accessories.dm index ec5934ac8e8d4..f381df80df6da 100644 --- a/code/controllers/subsystem/sprite_accessories.dm +++ b/code/controllers/subsystem/sprite_accessories.dm @@ -35,7 +35,7 @@ SUBSYSTEM_DEF(accessories) // just 'accessories' for brevity var/list/socks_list //! stores /datum/sprite_accessory/socks indexed by name //Lizard Bits (all datum lists indexed by name) - var/list/body_markings_list + var/list/lizard_markings_list var/list/snouts_list var/list/horns_list var/list/frills_list @@ -87,7 +87,7 @@ SUBSYSTEM_DEF(accessories) // just 'accessories' for brevity socks_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/socks)[DEFAULT_SPRITE_LIST] - body_markings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings)[DEFAULT_SPRITE_LIST] + lizard_markings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/lizard_markings)[DEFAULT_SPRITE_LIST] tails_list_human = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, add_blank = TRUE)[DEFAULT_SPRITE_LIST] tails_list_lizard = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard, add_blank = TRUE)[DEFAULT_SPRITE_LIST] tails_list_monkey = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/monkey, add_blank = TRUE)[DEFAULT_SPRITE_LIST] diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 468882f0e86ec..efca8dd19b5cc 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -697,6 +697,13 @@ SUBSYSTEM_DEF(ticker) to_chat(world, span_boldannounce("Rebooting World in [DisplayTimeText(delay)]. [reason]")) + var/statspage = CONFIG_GET(string/roundstatsurl) + var/gamelogloc = CONFIG_GET(string/gamelogurl) + if(statspage) + to_chat(world, span_info("Round statistics and logs can be viewed at this website!")) + else if(gamelogloc) + to_chat(world, span_info("Round logs can be located at this website!")) + var/start_wait = world.time UNTIL(round_end_sound_sent || (world.time - start_wait) > (delay * 2)) //don't wait forever sleep(delay - (world.time - start_wait)) @@ -707,13 +714,6 @@ SUBSYSTEM_DEF(ticker) if(end_string) end_state = end_string - var/statspage = CONFIG_GET(string/roundstatsurl) - var/gamelogloc = CONFIG_GET(string/gamelogurl) - if(statspage) - to_chat(world, span_info("Round statistics and logs can be viewed at this website!")) - else if(gamelogloc) - to_chat(world, span_info("Round logs can be located at this website!")) - log_game(span_boldannounce("Rebooting World. [reason]")) world.Reboot() diff --git a/code/datums/bodypart_overlays/markings_bodypart_overlay.dm b/code/datums/bodypart_overlays/markings_bodypart_overlay.dm new file mode 100644 index 0000000000000..c2c6f54d861d3 --- /dev/null +++ b/code/datums/bodypart_overlays/markings_bodypart_overlay.dm @@ -0,0 +1,31 @@ +/// For body markings applied on the species, which need some extra code +/datum/bodypart_overlay/simple/body_marking + layers = EXTERNAL_ADJACENT + /// Listen to the gendercode, if the limb is bimorphic + var/use_gender = FALSE + /// Which dna feature key to draw from + var/dna_feature_key + /// Which bodyparts do we apply ourselves to? + var/list/applies_to = list(/obj/item/bodypart/head, /obj/item/bodypart/chest, /obj/item/bodypart/arm/left, /obj/item/bodypart/arm/right, \ + /obj/item/bodypart/leg/left, /obj/item/bodypart/leg/right) + +/// Get the accessory list from SSaccessories. Used in species.dm to get the right sprite +/datum/bodypart_overlay/simple/body_marking/proc/get_accessory(name) + CRASH("get_accessories() not overriden on [type] !") + +/datum/bodypart_overlay/simple/body_marking/get_image(layer, obj/item/bodypart/limb) + var/gender_string = (use_gender && limb.is_dimorphic) ? (limb.gender == MALE ? MALE : FEMALE + "_") : "" //we only got male and female sprites + return image(icon, gender_string + icon_state + "_" + limb.body_zone, layer = layer) + +/datum/bodypart_overlay/simple/body_marking/moth + dna_feature_key = "moth_markings" + +/datum/bodypart_overlay/simple/body_marking/moth/get_accessory(name) + return SSaccessories.moth_markings_list[name] + +/datum/bodypart_overlay/simple/body_marking/lizard + dna_feature_key = "lizard_markings" + applies_to = list(/obj/item/bodypart/chest) + +/datum/bodypart_overlay/simple/body_marking/lizard/get_accessory(name) + return SSaccessories.lizard_markings_list[name] diff --git a/code/datums/components/crafting/guncrafting.dm b/code/datums/components/crafting/guncrafting.dm index 6d4f4713f8bb1..dcf42ee47b1a5 100644 --- a/code/datums/components/crafting/guncrafting.dm +++ b/code/datums/components/crafting/guncrafting.dm @@ -84,8 +84,8 @@ desc = "A suitcase containing the necessary gun parts to tranform a standard energy gun into a temperature gun. Fantastic at birthday parties and killing indigenious populations of lizardpeople." /obj/item/weaponcrafting/gunkit/beam_rifle - name = "particle acceleration rifle part kit (lethal)" - desc = "The coup de grace of guncrafting. This suitcase contains the highly experimental rig for a particle acceleration rifle. Requires an energy gun, a stabilized flux anomaly and a stabilized gravity anomaly." + name = "\improper Event Horizon anti-existential beam rifle part kit (DOOMSDAY DEVICE, DO NOT CONSTRUCT)" + desc = "What fevered minds wrought this terrible construction kit? To create a frame to harness the strange energies that flow through the Spinward Sector towards such horrible acts of violence?" /obj/item/weaponcrafting/gunkit/ebow name = "energy crossbow part kit (less lethal)" diff --git a/code/datums/components/crafting/ranged_weapon.dm b/code/datums/components/crafting/ranged_weapon.dm index b646c4472ed98..666e84964c553 100644 --- a/code/datums/components/crafting/ranged_weapon.dm +++ b/code/datums/components/crafting/ranged_weapon.dm @@ -72,21 +72,18 @@ blacklist += subtypesof(/obj/item/gun/energy/e_gun) /datum/crafting_recipe/beam_rifle - name = "Particle Acceleration Rifle" - result = /obj/item/gun/energy/beam_rifle + name = "Event Horizon Anti-Existential Beam Rifle" + result = /obj/item/gun/energy/event_horizon reqs = list( - /obj/item/gun/energy/e_gun = 1, - /obj/item/assembly/signaler/anomaly/flux = 1, + /obj/item/assembly/signaler/anomaly/flux = 2, /obj/item/assembly/signaler/anomaly/grav = 1, + /obj/item/assembly/signaler/anomaly/vortex = MAX_CORES_VORTEX, + /obj/item/assembly/signaler/anomaly/bluespace = 1, /obj/item/weaponcrafting/gunkit/beam_rifle = 1, ) - time = 10 SECONDS + time = 30 SECONDS //Maybe the delay will make you reconsider your choices category = CAT_WEAPON_RANGED -/datum/crafting_recipe/beam_rifle/New() - ..() - blacklist += subtypesof(/obj/item/gun/energy/e_gun) - /datum/crafting_recipe/ebow name = "Energy Crossbow" result = /obj/item/gun/energy/recharge/ebow/large diff --git a/code/datums/components/riding/riding_mob.dm b/code/datums/components/riding/riding_mob.dm index a808784b815ec..78158c55e8eb7 100644 --- a/code/datums/components/riding/riding_mob.dm +++ b/code/datums/components/riding/riding_mob.dm @@ -110,9 +110,14 @@ last_move_diagonal = ((direction & (direction - 1)) && (living_parent.loc == next)) var/modified_move_cooldown = vehicle_move_cooldown var/modified_move_delay = vehicle_move_delay - if(ishuman(user) && HAS_TRAIT(user, TRAIT_SETTLER)) - var/mob/living/carbon/human/settler_rider = user - switch(settler_rider.mob_mood.sanity_level) + if(ishuman(user) && HAS_TRAIT(user, TRAIT_ROUGHRIDER)) // YEEHAW! + var/mob/living/carbon/human/rough_rider = user + var/ride_benefit = null + if(HAS_TRAIT(rough_rider, TRAIT_PRIMITIVE)) // closer to a beast than a man; you don't need to think to ride! + ride_benefit = SANITY_LEVEL_GREAT + else + ride_benefit = rough_rider.mob_mood.sanity_level + switch(ride_benefit) if(SANITY_LEVEL_GREAT) modified_move_cooldown *= 0.5 modified_move_delay *= 0.5 diff --git a/code/datums/components/tameable.dm b/code/datums/components/tameable.dm index 43f48005bf89e..0d77688a22e7a 100644 --- a/code/datums/components/tameable.dm +++ b/code/datums/components/tameable.dm @@ -42,7 +42,7 @@ var/inform_tamer = FALSE atom_parent.balloon_alert(attacker, "fed") var/modified_tame_chance = current_tame_chance - if(HAS_TRAIT(attacker, TRAIT_SETTLER)) + if(HAS_TRAIT(attacker, TRAIT_BEAST_EMPATHY)) modified_tame_chance += 50 inform_tamer = TRUE if(unique || !already_friends(attacker)) @@ -71,7 +71,7 @@ if(inform_tamer) source.balloon_alert(tamer, "tamed") - if(HAS_TRAIT(tamer, TRAIT_SETTLER)) + if(HAS_TRAIT(tamer, TRAIT_BEAST_EMPATHY)) INVOKE_ASYNC(src, PROC_REF(rename_pet), source, tamer) if(unique) qdel(src) diff --git a/code/datums/components/temporary_body.dm b/code/datums/components/temporary_body.dm index 3da289a6d3462..28a7000a4951d 100644 --- a/code/datums/components/temporary_body.dm +++ b/code/datums/components/temporary_body.dm @@ -10,17 +10,23 @@ var/datum/weakref/old_mind_ref ///The old body we will be put back into when parent is being deleted. var/datum/weakref/old_body_ref + /// Returns the mind if the parent dies by any means + var/delete_on_death = FALSE -/datum/component/temporary_body/Initialize(datum/mind/old_mind, mob/living/old_body) +/datum/component/temporary_body/Initialize(datum/mind/old_mind, mob/living/old_body, delete_on_death = FALSE) if(!isliving(parent) || !isliving(old_body)) return COMPONENT_INCOMPATIBLE ADD_TRAIT(old_body, TRAIT_MIND_TEMPORARILY_GONE, REF(src)) src.old_mind_ref = WEAKREF(old_mind) src.old_body_ref = WEAKREF(old_body) + src.delete_on_death = delete_on_death /datum/component/temporary_body/RegisterWithParent() RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(on_parent_destroy)) + if(delete_on_death) + RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(on_parent_destroy)) + /datum/component/temporary_body/UnregisterFromParent() UnregisterSignal(parent, COMSIG_QDELETING) diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm index e672a86d72083..966987828bd54 100644 --- a/code/datums/diseases/transformation.dm +++ b/code/datums/diseases/transformation.dm @@ -62,7 +62,7 @@ if(HAS_TRAIT_FROM(affected_mob, TRAIT_NO_TRANSFORM, REF(src))) return ADD_TRAIT(affected_mob, TRAIT_NO_TRANSFORM, REF(src)) - for(var/obj/item/W in affected_mob.get_equipped_items(include_pockets = TRUE)) + for(var/obj/item/W in affected_mob.get_equipped_items(INCLUDE_POCKETS)) affected_mob.dropItemToGround(W) for(var/obj/item/I in affected_mob.held_items) affected_mob.dropItemToGround(I) diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 75fb406e3371e..d5677dad7ca61 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -207,8 +207,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) L[DNA_MUTANT_COLOR_BLOCK] = sanitize_hexcolor(features["mcolor"], include_crunch = FALSE) if(features["ethcolor"]) L[DNA_ETHEREAL_COLOR_BLOCK] = sanitize_hexcolor(features["ethcolor"], include_crunch = FALSE) - if(features["body_markings"]) - L[DNA_LIZARD_MARKINGS_BLOCK] = construct_block(SSaccessories.body_markings_list.Find(features["body_markings"]), length(SSaccessories.body_markings_list)) + if(features["lizard_markings"]) + L[DNA_LIZARD_MARKINGS_BLOCK] = construct_block(SSaccessories.lizard_markings_list.Find(features["lizard_markings"]), length(SSaccessories.lizard_markings_list)) if(features["tail_cat"]) L[DNA_TAIL_BLOCK] = construct_block(SSaccessories.tails_list_human.Find(features["tail_cat"]), length(SSaccessories.tails_list_human)) if(features["tail_lizard"]) @@ -354,7 +354,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(DNA_ETHEREAL_COLOR_BLOCK) set_uni_feature_block(blocknumber, sanitize_hexcolor(features["ethcolor"], include_crunch = FALSE)) if(DNA_LIZARD_MARKINGS_BLOCK) - set_uni_feature_block(blocknumber, construct_block(SSaccessories.body_markings_list.Find(features["body_markings"]), length(SSaccessories.body_markings_list))) + set_uni_feature_block(blocknumber, construct_block(SSaccessories.lizard_markings_list.Find(features["lizard_markings"]), length(SSaccessories.lizard_markings_list))) if(DNA_TAIL_BLOCK) set_uni_feature_block(blocknumber, construct_block(SSaccessories.tails_list_human.Find(features["tail_cat"]), length(SSaccessories.tails_list_human))) if(DNA_LIZARD_TAIL_BLOCK) @@ -423,7 +423,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) /datum/dna/proc/update_instability(alert=TRUE) stability = 100 for(var/datum/mutation/human/M in mutations) - if(M.class == MUT_EXTRA) + if(M.class == MUT_EXTRA || M.instability < 0) stability -= M.instability * GET_MUTATION_STABILIZER(M) if(holder) var/message @@ -649,8 +649,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) dna.features["mcolor"] = sanitize_hexcolor(get_uni_feature_block(features, DNA_MUTANT_COLOR_BLOCK)) if(dna.features["ethcolor"]) dna.features["ethcolor"] = sanitize_hexcolor(get_uni_feature_block(features, DNA_ETHEREAL_COLOR_BLOCK)) - if(dna.features["body_markings"]) - dna.features["body_markings"] = SSaccessories.body_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_MARKINGS_BLOCK), length(SSaccessories.body_markings_list))] + if(dna.features["lizard_markings"]) + dna.features["lizard_markings"] = SSaccessories.lizard_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_MARKINGS_BLOCK), length(SSaccessories.lizard_markings_list))] if(dna.features["snout"]) dna.features["snout"] = SSaccessories.snouts_list[deconstruct_block(get_uni_feature_block(features, DNA_SNOUT_BLOCK), length(SSaccessories.snouts_list))] if(dna.features["horns"]) @@ -686,14 +686,10 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) external_organ.mutate_feature(features, src) if(icon_update) - if(mutcolor_update) - update_body(is_creating = TRUE) - else - update_body() + update_body(is_creating = mutcolor_update) if(mutations_overlay_update) update_mutations_overlay() - /mob/proc/domutcheck() return diff --git a/code/datums/elements/basic_eating.dm b/code/datums/elements/basic_eating.dm index 92b303c9be2a0..4f4f493e0ef33 100644 --- a/code/datums/elements/basic_eating.dm +++ b/code/datums/elements/basic_eating.dm @@ -93,4 +93,5 @@ if(isstack(target)) //if stack, only consume 1 var/obj/item/stack/food_stack = target final_target = food_stack.split_stack(eater, 1) + eater.log_message("has eaten [target]!", LOG_ATTACK) qdel(final_target) diff --git a/code/datums/elements/climbable.dm b/code/datums/elements/climbable.dm index 004f05dd5f584..a2c67742a357e 100644 --- a/code/datums/elements/climbable.dm +++ b/code/datums/elements/climbable.dm @@ -69,7 +69,7 @@ if(HAS_TRAIT(user, TRAIT_FREERUNNING)) //do you have any idea how fast I am??? adjusted_climb_time *= 0.8 adjusted_climb_stun *= 0.8 - if(HAS_TRAIT(user, TRAIT_SETTLER)) //hold on, gimme a moment, my tiny legs can't get over the goshdamn table + if(HAS_TRAIT(user, TRAIT_STUBBY_BODY)) //hold on, gimme a moment, my tiny legs can't get over the goshdamn table adjusted_climb_time *= 1.5 adjusted_climb_stun *= 1.5 LAZYADDASSOCLIST(current_climbers, climbed_thing, user) @@ -82,6 +82,10 @@ log_combat(user, climbed_thing, "climbed onto") if(adjusted_climb_stun) user.Stun(adjusted_climb_stun) + var/atom/movable/buckle_target = climbed_thing + if(istype(buckle_target)) + if(buckle_target.is_buckle_possible(user)) + buckle_target.buckle_mob(user) else to_chat(user, span_warning("You fail to climb onto [climbed_thing].")) LAZYREMOVEASSOC(current_climbers, climbed_thing, user) @@ -112,7 +116,6 @@ /datum/element/climbable/proc/mousedrop_receive(atom/climbed_thing, atom/movable/dropped_atom, mob/user, params) SIGNAL_HANDLER - . = COMPONENT_CANCEL_MOUSEDROPPED_ONTO if(user != dropped_atom || !isliving(dropped_atom)) return if(!HAS_TRAIT(dropped_atom, TRAIT_FENCE_CLIMBER) && !HAS_TRAIT(dropped_atom, TRAIT_CAN_HOLD_ITEMS)) // If you can hold items you can probably climb a fence @@ -120,3 +123,4 @@ var/mob/living/living_target = dropped_atom if(living_target.mobility_flags & MOBILITY_MOVE) INVOKE_ASYNC(src, PROC_REF(climb_structure), climbed_thing, living_target, params) + return COMPONENT_CANCEL_MOUSEDROPPED_ONTO diff --git a/code/datums/elements/skill_reward.dm b/code/datums/elements/skill_reward.dm index 7809eea85f715..891f933793ea0 100644 --- a/code/datums/elements/skill_reward.dm +++ b/code/datums/elements/skill_reward.dm @@ -29,7 +29,7 @@ ///We check if the item can be equipped, otherwise we drop it. /datum/element/skill_reward/proc/drop_if_unworthy(datum/source, mob/living/user) SIGNAL_HANDLER - if(check_equippable(user) || !(source in user.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE))) + if(check_equippable(user) || !(source in user.get_equipped_items(INCLUDE_POCKETS | INCLUDE_ACCESSORIES))) return NONE to_chat(user, span_warning("You feel completely and utterly unworthy to even touch \the [source].")) user.dropItemToGround(source, TRUE) diff --git a/code/datums/id_trim/jobs.dm b/code/datums/id_trim/jobs.dm index cfa608011bdf9..4d4c44138e0c2 100644 --- a/code/datums/id_trim/jobs.dm +++ b/code/datums/id_trim/jobs.dm @@ -545,11 +545,13 @@ ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_SCIENCE, + ACCESS_XENOBIOLOGY, ) extra_access = list( ACCESS_ROBOTICS, ACCESS_TECH_STORAGE, - ACCESS_XENOBIOLOGY, + ACCESS_ORDNANCE, + ACCESS_ORDNANCE_STORAGE, ) template_access = list( ACCESS_CAPTAIN, @@ -960,6 +962,8 @@ ACCESS_GENETICS, ACCESS_XENOBIOLOGY, ACCESS_MORGUE_SECURE, + ACCESS_ORDNANCE, + ACCESS_ORDNANCE_STORAGE, ) template_access = list( ACCESS_CAPTAIN, diff --git a/code/datums/keybinding/client.dm b/code/datums/keybinding/client.dm index 81b9bb6c287a3..f36645692c992 100644 --- a/code/datums/keybinding/client.dm +++ b/code/datums/keybinding/client.dm @@ -32,6 +32,20 @@ winset(user, null, "command=.auto") return TRUE +/datum/keybinding/client/toggle_fullscreen + hotkey_keys = list("F11") + name = "toggle_fullscreen" + full_name = "Toggle Fullscreen" + description = "Makes the game window fullscreen." + keybind_signal = COMSIG_KB_CLIENT_FULLSCREEN_DOWN + +/datum/keybinding/client/toggle_fullscreen/down(client/user) + . = ..() + if(.) + return + user.toggle_fullscreen() + return TRUE + /datum/keybinding/client/minimal_hud hotkey_keys = list("F12") name = "minimal_hud" diff --git a/code/datums/mocking/client.dm b/code/datums/mocking/client.dm index dc1db213f34be..4b724ef705e82 100644 --- a/code/datums/mocking/client.dm +++ b/code/datums/mocking/client.dm @@ -48,3 +48,6 @@ /datum/client_interface/proc/set_macros() return + +/datum/client_interface/proc/update_ambience_pref() + return diff --git a/code/datums/mutations/_mutations.dm b/code/datums/mutations/_mutations.dm index 4913a057e011a..95f59ade38c39 100644 --- a/code/datums/mutations/_mutations.dm +++ b/code/datums/mutations/_mutations.dm @@ -1,3 +1,23 @@ + +/// Negatives that are virtually harmless and mostly just funny (language) +// Set to 0 because munchkinning via miscommunication = bad +#define NEGATIVE_STABILITY_MINI 0 +/// Negatives that are slightly annoying (unused) +#define NEGATIVE_STABILITY_MINOR -20 +/// Negatives that present an uncommon or weak, consistent hindrance to gameplay (cough, paranoia) +#define NEGATIVE_STABILITY_MODERATE -30 +/// Negatives that present a major consistent hindrance to gameplay (deaf, mute, acid flesh) +#define NEGATIVE_STABILITY_MAJOR -40 + +/// Positives that provide basically no benefit (glowy) +#define POSITIVE_INSTABILITY_MINI 5 +/// Positives that are niche in application or useful in rare circumstances (parlor tricks, geladikinesis, autotomy) +#define POSITIVE_INSTABILITY_MINOR 10 +/// Positives that provide a new ability that's roughly par with station equipment (insulated, cryokinesis) +#define POSITIVE_INSTABILITY_MODERATE 25 +/// Positives that are unique, very powerful, and noticeably change combat/gameplay (hulk, tk) +#define POSITIVE_INSTABILITY_MAJOR 35 + /datum/mutation var/name diff --git a/code/datums/mutations/adaptation.dm b/code/datums/mutations/adaptation.dm index 1c183f9367d3a..2cac87dd4b4c4 100644 --- a/code/datums/mutations/adaptation.dm +++ b/code/datums/mutations/adaptation.dm @@ -4,7 +4,7 @@ quality = POSITIVE difficulty = 16 text_gain_indication = "Your body feels warm!" - instability = 25 + instability = POSITIVE_INSTABILITY_MAJOR conflicts = list(/datum/mutation/human/pressure_adaptation) /datum/mutation/human/temperature_adaptation/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut) @@ -31,7 +31,7 @@ quality = POSITIVE difficulty = 16 text_gain_indication = "Your body feels numb!" - instability = 25 + instability = POSITIVE_INSTABILITY_MAJOR conflicts = list(/datum/mutation/human/temperature_adaptation) /datum/mutation/human/pressure_adaptation/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut) diff --git a/code/datums/mutations/antenna.dm b/code/datums/mutations/antenna.dm index 80edceea1e5ed..fc1a94276f702 100644 --- a/code/datums/mutations/antenna.dm +++ b/code/datums/mutations/antenna.dm @@ -4,7 +4,7 @@ quality = POSITIVE text_gain_indication = "You feel an antenna sprout from your forehead." text_lose_indication = "Your antenna shrinks back down." - instability = 5 + instability = POSITIVE_INSTABILITY_MINOR difficulty = 8 var/datum/weakref/radio_weakref @@ -47,7 +47,7 @@ text_gain_indication = "You hear distant voices at the corners of your mind." text_lose_indication = "The distant voices fade." power_path = /datum/action/cooldown/spell/pointed/mindread - instability = 40 + instability = POSITIVE_INSTABILITY_MINOR difficulty = 8 locked = TRUE diff --git a/code/datums/mutations/autotomy.dm b/code/datums/mutations/autotomy.dm index 5a70455db5fb8..bb78ceb08dcf7 100644 --- a/code/datums/mutations/autotomy.dm +++ b/code/datums/mutations/autotomy.dm @@ -3,7 +3,7 @@ desc = "Allows a creature to voluntary discard a random appendage." quality = POSITIVE text_gain_indication = span_notice("Your joints feel loose.") - instability = 30 + instability = POSITIVE_INSTABILITY_MINOR power_path = /datum/action/cooldown/spell/self_amputation energy_coeff = 1 diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index 896820746d61d..eaa1ba1f5cafa 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -4,6 +4,7 @@ /datum/mutation/human/epilepsy name = "Epilepsy" desc = "A genetic defect that sporadically causes seizures." + instability = NEGATIVE_STABILITY_MODERATE quality = NEGATIVE text_gain_indication = "You get a headache." synchronizer_coeff = 1 @@ -50,6 +51,7 @@ /datum/mutation/human/bad_dna name = "Unstable DNA" desc = "Strange mutation that causes the holder to randomly mutate." + instability = NEGATIVE_STABILITY_MAJOR quality = NEGATIVE text_gain_indication = "You feel strange." locked = TRUE @@ -79,6 +81,7 @@ /datum/mutation/human/cough name = "Cough" desc = "A chronic cough." + instability = NEGATIVE_STABILITY_MODERATE quality = MINOR_NEGATIVE text_gain_indication = "You start coughing." synchronizer_coeff = 1 @@ -96,6 +99,7 @@ /datum/mutation/human/paranoia name = "Paranoia" desc = "Subject is easily terrified, and may suffer from hallucinations." + instability = NEGATIVE_STABILITY_MODERATE quality = NEGATIVE text_gain_indication = "You feel screams echo through your mind..." text_lose_indication = "The screaming in your mind fades." @@ -112,8 +116,8 @@ desc = "A mutation believed to be the cause of dwarfism." quality = POSITIVE difficulty = 16 - instability = 5 - conflicts = list(/datum/mutation/human/gigantism) + instability = POSITIVE_INSTABILITY_MINOR + conflicts = list(/datum/mutation/human/gigantism, /datum/mutation/human/acromegaly) locked = TRUE // Default intert species for now, so locked from regular pool. /datum/mutation/human/dwarfism/on_acquiring(mob/living/carbon/human/owner) @@ -128,10 +132,71 @@ REMOVE_TRAIT(owner, TRAIT_DWARF, GENETIC_MUTATION) owner.visible_message(span_danger("[owner] suddenly grows!"), span_notice("Everything around you seems to shrink..")) +/datum/mutation/human/acromegaly + name = "Acromegaly" + desc = "A mutation believed to be the cause of acromegaly, or 'being unusually tall'." + quality = MINOR_NEGATIVE + difficulty = 16 + instability = NEGATIVE_STABILITY_MODERATE + synchronizer_coeff = 1 + conflicts = list(/datum/mutation/human/dwarfism) + +/datum/mutation/human/acromegaly/on_acquiring(mob/living/carbon/human/owner) + if(..()) + return + ADD_TRAIT(owner, TRAIT_TOO_TALL, GENETIC_MUTATION) + owner.visible_message(span_danger("[owner] suddenly grows tall!"), span_notice("You feel a small strange urge to fight small men with slingshots. Or maybe play some basketball.")) + RegisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(head_bonk)) + owner.regenerate_icons() + +/datum/mutation/human/acromegaly/on_losing(mob/living/carbon/human/owner) + if(..()) + return + REMOVE_TRAIT(owner, TRAIT_TOO_TALL, GENETIC_MUTATION) + owner.visible_message(span_danger("[owner] suddenly shrinks!"), span_notice("You return to your usual height.")) + UnregisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(head_bonk)) + owner.regenerate_icons() + +// This is specifically happening because they're not used to their new height and are stumbling around into machinery made for normal humans +/datum/mutation/human/acromegaly/proc/head_bonk(mob/living/parent) + SIGNAL_HANDLER + var/turf/airlock_turf = get_turf(parent) + var/atom/movable/whacked_by = locate(/obj/machinery/door/airlock) in airlock_turf || locate(/obj/machinery/door/firedoor) in airlock_turf || locate(/obj/structure/mineral_door) in airlock_turf + if(!whacked_by || prob(100 - (8 * GET_MUTATION_SYNCHRONIZER(src)))) + return + to_chat(parent, span_danger("You hit your head on \the [whacked_by]'s header!")) + var/dmg = HAS_TRAIT(parent, TRAIT_HEAD_INJURY_BLOCKED) ? rand(1,4) : rand(2,9) + parent.apply_damage(dmg, BRUTE, BODY_ZONE_HEAD) + parent.do_attack_animation(whacked_by, ATTACK_EFFECT_PUNCH) + playsound(whacked_by, 'sound/effects/bang.ogg', 10, TRUE) + parent.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH, 10 SECONDS) + +/datum/mutation/human/gigantism + name = "Gigantism" //negative version of dwarfism + desc = "The cells within the subject spread out to cover more area, making the subject appear larger." + quality = MINOR_NEGATIVE + difficulty = 12 + conflicts = list(/datum/mutation/human/dwarfism) + +/datum/mutation/human/gigantism/on_acquiring(mob/living/carbon/human/owner) + if(..()) + return + ADD_TRAIT(owner, TRAIT_GIANT, GENETIC_MUTATION) + owner.update_transform(1.25) + owner.visible_message(span_danger("[owner] suddenly grows!"), span_notice("Everything around you seems to shrink..")) + +/datum/mutation/human/gigantism/on_losing(mob/living/carbon/human/owner) + if(..()) + return + REMOVE_TRAIT(owner, TRAIT_GIANT, GENETIC_MUTATION) + owner.update_transform(0.8) + owner.visible_message(span_danger("[owner] suddenly shrinks!"), span_notice("Everything around you seems to grow..")) + //Clumsiness has a very large amount of small drawbacks depending on item. /datum/mutation/human/clumsy name = "Clumsiness" desc = "A genome that inhibits certain brain functions, causing the holder to appear clumsy. Honk!" + instability = NEGATIVE_STABILITY_MAJOR quality = MINOR_NEGATIVE text_gain_indication = "You feel lightheaded." @@ -151,6 +216,7 @@ name = "Tourette's Syndrome" desc = "A chronic twitch that forces the user to scream bad words." //definitely needs rewriting quality = NEGATIVE + instability = 0 text_gain_indication = "You twitch." synchronizer_coeff = 1 @@ -173,6 +239,7 @@ /datum/mutation/human/deaf name = "Deafness" desc = "The holder of this genome is completely deaf." + instability = NEGATIVE_STABILITY_MAJOR quality = NEGATIVE text_gain_indication = "You can't seem to hear anything." @@ -194,6 +261,7 @@ text_gain_indication = "You feel unusually monkey-like." text_lose_indication = "You feel like your old self." quality = NEGATIVE + instability = NEGATIVE_STABILITY_MAJOR // mmmonky remove_on_aheal = FALSE locked = TRUE //Species specific, keep out of actual gene pool mutadone_proof = TRUE @@ -219,7 +287,7 @@ desc = "You permanently emit a light with a random color and intensity." quality = POSITIVE text_gain_indication = "Your skin begins to glow softly." - instability = 5 + instability = POSITIVE_INSTABILITY_MINI power_coeff = 1 conflicts = list(/datum/mutation/human/glow/anti) var/glow_power = 2 @@ -257,6 +325,7 @@ desc = "Your skin seems to attract and absorb nearby light creating 'darkness' around you." text_gain_indication = "The light around you seems to disappear." conflicts = list(/datum/mutation/human/glow) + instability = POSITIVE_INSTABILITY_MINOR locked = TRUE glow_power = -1.5 @@ -265,10 +334,10 @@ /datum/mutation/human/strong name = "Strength" - desc = "The user's muscles slightly expand." + desc = "The user's muscles slightly expand. Commonly seen in top-ranking boxers." quality = POSITIVE text_gain_indication = "You feel strong." - instability = 5 + instability = POSITIVE_INSTABILITY_MINI difficulty = 16 /datum/mutation/human/strong/on_acquiring(mob/living/carbon/human/owner) @@ -286,10 +355,11 @@ /datum/mutation/human/stimmed name = "Stimmed" - desc = "The user's chemical balance is more robust." + desc = "The user's chemical balance is more robust. This mutation is known to slightly improve workout efficiency." quality = POSITIVE + instability = POSITIVE_INSTABILITY_MINI text_gain_indication = "You feel stimmed." - instability = 5 + instability = 15 difficulty = 16 /datum/mutation/human/stimmed/on_acquiring(mob/living/carbon/human/owner) @@ -311,7 +381,7 @@ text_gain_indication = "Your fingertips go numb." text_lose_indication = "Your fingertips regain feeling." difficulty = 16 - instability = 25 + instability = POSITIVE_INSTABILITY_MODERATE /datum/mutation/human/insulated/on_acquiring(mob/living/carbon/human/owner) if(..()) @@ -355,7 +425,7 @@ text_gain_indication = "The space around you twists sickeningly." text_lose_indication = "The space around you settles back to normal." difficulty = 18//high so it's hard to unlock and abuse - instability = 10 + instability = NEGATIVE_STABILITY_MODERATE synchronizer_coeff = 1 energy_coeff = 1 power_coeff = 1 @@ -381,6 +451,7 @@ /datum/mutation/human/acidflesh name = "Acidic Flesh" desc = "Subject has acidic chemicals building up underneath the skin. This is often lethal." + instability = NEGATIVE_STABILITY_MAJOR quality = NEGATIVE text_gain_indication = "A horrible burning sensation envelops you as your flesh turns to acid!" text_lose_indication = "A feeling of relief fills you as your flesh goes back to normal." @@ -398,30 +469,10 @@ owner.visible_message(span_warning("[owner]'s skin bubbles and pops."), span_userdanger("Your bubbling flesh pops! It burns!")) playsound(owner,'sound/weapons/sear.ogg', 50, TRUE) -/datum/mutation/human/gigantism - name = "Gigantism"//negative version of dwarfism - desc = "The cells within the subject spread out to cover more area, making the subject appear larger." - quality = MINOR_NEGATIVE - difficulty = 12 - conflicts = list(/datum/mutation/human/dwarfism) - -/datum/mutation/human/gigantism/on_acquiring(mob/living/carbon/human/owner) - if(..()) - return - ADD_TRAIT(owner, TRAIT_GIANT, GENETIC_MUTATION) - owner.update_transform(1.25) - owner.visible_message(span_danger("[owner] suddenly grows!"), span_notice("Everything around you seems to shrink..")) - -/datum/mutation/human/gigantism/on_losing(mob/living/carbon/human/owner) - if(..()) - return - REMOVE_TRAIT(owner, TRAIT_GIANT, GENETIC_MUTATION) - owner.update_transform(0.8) - owner.visible_message(span_danger("[owner] suddenly shrinks!"), span_notice("Everything around you seems to grow..")) - /datum/mutation/human/spastic name = "Spastic" desc = "Subject suffers from muscle spasms." + instability = NEGATIVE_STABILITY_MODERATE quality = NEGATIVE text_gain_indication = "You flinch." text_lose_indication = "Your flinching subsides." @@ -440,6 +491,7 @@ /datum/mutation/human/extrastun name = "Two Left Feet" desc = "A mutation that replaces the right foot with another left foot. Symptoms include kissing the floor when taking a step." + instability = NEGATIVE_STABILITY_MODERATE quality = NEGATIVE text_gain_indication = "Your right foot feels... left." text_lose_indication = "Your right foot feels alright." @@ -471,6 +523,7 @@ /datum/mutation/human/martyrdom name = "Internal Martyrdom" desc = "A mutation that makes the body destruct when near death. Not damaging, but very, VERY disorienting." + instability = NEGATIVE_STABILITY_MAJOR // free stability >:) locked = TRUE quality = POSITIVE //not that cloning will be an option a lot but generally lets keep this around i guess? text_gain_indication = "You get an intense feeling of heartburn." @@ -518,6 +571,7 @@ /datum/mutation/human/headless name = "H.A.R.S." desc = "A mutation that makes the body reject the head, the brain receding into the chest. Stands for Head Allergic Rejection Syndrome. Warning: Removing this mutation is very dangerous, though it will regenerate non-vital head organs." + instability = NEGATIVE_STABILITY_MAJOR difficulty = 12 //pretty good for traitors quality = NEGATIVE //holy shit no eyes or tongue or ears text_gain_indication = "Something feels off." diff --git a/code/datums/mutations/chameleon.dm b/code/datums/mutations/chameleon.dm index d5cbc36d20a1f..e3ce8826a9438 100644 --- a/code/datums/mutations/chameleon.dm +++ b/code/datums/mutations/chameleon.dm @@ -6,7 +6,7 @@ difficulty = 16 text_gain_indication = "You feel one with your surroundings." text_lose_indication = "You feel oddly exposed." - instability = 25 + instability = POSITIVE_INSTABILITY_MAJOR power_coeff = 1 /datum/mutation/human/chameleon/on_acquiring(mob/living/carbon/human/owner) diff --git a/code/datums/mutations/cold.dm b/code/datums/mutations/cold.dm index 57c4f854fc7a2..32e162bf7d3a0 100644 --- a/code/datums/mutations/cold.dm +++ b/code/datums/mutations/cold.dm @@ -3,7 +3,7 @@ desc = "Allows the user to concentrate moisture and sub-zero forces into snow." quality = POSITIVE text_gain_indication = "Your hand feels cold." - instability = 10 + instability = POSITIVE_INSTABILITY_MINOR difficulty = 10 synchronizer_coeff = 1 power_path = /datum/action/cooldown/spell/conjure_item/snow @@ -25,7 +25,7 @@ desc = "Draws negative energy from the sub-zero void to freeze surrounding temperatures at subject's will." quality = POSITIVE //upsides and downsides text_gain_indication = "Your hand feels cold." - instability = 30 + instability = POSITIVE_INSTABILITY_MODERATE difficulty = 12 synchronizer_coeff = 1 energy_coeff = 1 diff --git a/code/datums/mutations/fire_breath.dm b/code/datums/mutations/fire_breath.dm index f8631761ba202..5836997729456 100644 --- a/code/datums/mutations/fire_breath.dm +++ b/code/datums/mutations/fire_breath.dm @@ -7,7 +7,7 @@ text_gain_indication = "Your throat is burning!" text_lose_indication = "Your throat is cooling down." power_path = /datum/action/cooldown/spell/cone/staggered/fire_breath - instability = 30 + instability = POSITIVE_INSTABILITY_MODERATE energy_coeff = 1 power_coeff = 1 diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm index 63e0abc22a33f..3fdc5de52ce2b 100644 --- a/code/datums/mutations/hulk.dm +++ b/code/datums/mutations/hulk.dm @@ -8,7 +8,7 @@ text_gain_indication = "Your muscles hurt!" species_allowed = list(SPECIES_HUMAN) //no skeleton/lizard hulk health_req = 25 - instability = 40 + instability = POSITIVE_INSTABILITY_MAJOR var/scream_delay = 50 var/last_scream = 0 /// List of traits to add/remove when someone gets this mutation. diff --git a/code/datums/mutations/olfaction.dm b/code/datums/mutations/olfaction.dm index 305f6d16e8389..f487702a3c6c8 100644 --- a/code/datums/mutations/olfaction.dm +++ b/code/datums/mutations/olfaction.dm @@ -6,7 +6,7 @@ text_gain_indication = "Smells begin to make more sense..." text_lose_indication = "Your sense of smell goes back to normal." power_path = /datum/action/cooldown/spell/olfaction - instability = 30 + instability = POSITIVE_INSTABILITY_MODERATE synchronizer_coeff = 1 /datum/mutation/human/olfaction/modify() @@ -119,6 +119,9 @@ /// Actually go through and give the user a hint of the direction our target is. /datum/action/cooldown/spell/olfaction/proc/on_the_trail(mob/living/caster) var/mob/living/carbon/current_target = tracking_ref?.resolve() + //Using get_turf to deal with those pesky closets that put your x y z to 0 + var/turf/current_target_turf = get_turf(current_target) + var/turf/caster_turf = get_turf(caster) if(!current_target) to_chat(caster, span_warning("You're not tracking a scent, but the game thought you were. \ Something's gone wrong! Report this as a bug.")) @@ -130,14 +133,14 @@ to_chat(caster, span_warning("You smell out the trail to yourself. Yep, it's you.")) return - if(caster.z < current_target.z) + if(caster_turf.z < current_target_turf.z) to_chat(caster, span_warning("The trail leads... way up above you? Huh. They must be really, really far away.")) return - else if(caster.z > current_target.z) + else if(caster_turf.z > current_target_turf.z) to_chat(caster, span_warning("The trail leads... way down below you? Huh. They must be really, really far away.")) return - var/direction_text = span_bold("[dir2text(get_dir(caster, current_target))]") + var/direction_text = span_bold("[dir2text(get_dir(caster_turf, current_target_turf))]") if(direction_text) to_chat(caster, span_notice("You consider [current_target]'s scent. The trail leads [direction_text].")) diff --git a/code/datums/mutations/passive.dm b/code/datums/mutations/passive.dm index 9d694aaf1ebbb..14135fe426ea4 100644 --- a/code/datums/mutations/passive.dm +++ b/code/datums/mutations/passive.dm @@ -2,7 +2,7 @@ name = "Biotech Compatibility" desc = "Subject is more compatibile with biotechnology such as skillchips." quality = POSITIVE - instability = 5 + instability = POSITIVE_INSTABILITY_MINI /datum/mutation/human/biotechcompat/on_acquiring(mob/living/carbon/human/owner) . = ..() @@ -16,7 +16,7 @@ name = "Clever" desc = "Causes the subject to feel just a little bit smarter. Most effective in specimens with low levels of intelligence." quality = POSITIVE - instability = 20 + instability = POSITIVE_INSTABILITY_MODERATE // literally makes you on par with station equipment text_gain_indication = "You feel a little bit smarter." text_lose_indication = "Your mind feels a little bit foggy." diff --git a/code/datums/mutations/radioactive.dm b/code/datums/mutations/radioactive.dm index 8f710bfa497a4..8700e405662a6 100644 --- a/code/datums/mutations/radioactive.dm +++ b/code/datums/mutations/radioactive.dm @@ -3,7 +3,7 @@ desc = "A volatile mutation that causes the host to sent out deadly beta radiation. This affects both the hosts and their surroundings." quality = NEGATIVE text_gain_indication = "You can feel it in your bones!" - instability = 5 + instability = NEGATIVE_STABILITY_MAJOR difficulty = 8 power_coeff = 1 /// Weakref to our radiation emitter component diff --git a/code/datums/mutations/sight.dm b/code/datums/mutations/sight.dm index 8b26f6ca268f0..66e307c247846 100644 --- a/code/datums/mutations/sight.dm +++ b/code/datums/mutations/sight.dm @@ -2,6 +2,7 @@ /datum/mutation/human/nearsight name = "Near Sightness" desc = "The holder of this mutation has poor eyesight." + instability = NEGATIVE_STABILITY_MODERATE quality = MINOR_NEGATIVE text_gain_indication = "You can't see very well." @@ -19,6 +20,7 @@ /datum/mutation/human/blind name = "Blindness" desc = "Renders the subject completely blind." + instability = NEGATIVE_STABILITY_MAJOR quality = NEGATIVE text_gain_indication = "You can't seem to see anything." @@ -40,7 +42,7 @@ difficulty = 18 text_gain_indication = "You can see the heat rising off of your skin..." text_lose_indication = "You can no longer see the heat rising off of your skin..." - instability = 25 + instability = POSITIVE_INSTABILITY_MAJOR // thermals aren't station equipment synchronizer_coeff = 1 power_coeff = 1 energy_coeff = 1 @@ -110,7 +112,7 @@ name = "X Ray Vision" desc = "A strange genome that allows the user to see between the spaces of walls." //actual x-ray would mean you'd constantly be blasting rads, wich might be fun for later //hmb text_gain_indication = "The walls suddenly disappear!" - instability = 35 + instability = POSITIVE_INSTABILITY_MAJOR locked = TRUE /datum/mutation/human/xray/on_acquiring(mob/living/carbon/human/owner) @@ -182,6 +184,7 @@ /datum/mutation/human/illiterate name = "Illiterate" desc = "Causes a severe case of Aphasia that prevents reading or writing." + instability = NEGATIVE_STABILITY_MAJOR quality = NEGATIVE text_gain_indication = "You feel unable to read or write." text_lose_indication = "You feel able to read and write again." diff --git a/code/datums/mutations/speech.dm b/code/datums/mutations/speech.dm index 4c78c19610439..1400503dfc45d 100644 --- a/code/datums/mutations/speech.dm +++ b/code/datums/mutations/speech.dm @@ -4,6 +4,7 @@ /datum/mutation/human/nervousness name = "Nervousness" desc = "Causes the holder to stutter." + instability = NEGATIVE_STABILITY_MINI quality = MINOR_NEGATIVE text_gain_indication = "You feel nervous." @@ -14,6 +15,7 @@ /datum/mutation/human/wacky name = "Wacky" desc = "You are not a clown. You are the entire circus." + instability = NEGATIVE_STABILITY_MINI quality = MINOR_NEGATIVE text_gain_indication = "You feel an off sensation in your voicebox." text_lose_indication = "The off sensation passes." @@ -36,6 +38,7 @@ /datum/mutation/human/mute name = "Mute" desc = "Completely inhibits the vocal section of the brain." + instability = NEGATIVE_STABILITY_MAJOR quality = NEGATIVE text_gain_indication = "You feel unable to express yourself at all." text_lose_indication = "You feel able to speak freely again." @@ -53,6 +56,7 @@ /datum/mutation/human/unintelligible name = "Unintelligible" desc = "Partially inhibits the vocal center of the brain, severely distorting speech." + instability = NEGATIVE_STABILITY_MODERATE quality = NEGATIVE text_gain_indication = "You can't seem to form any coherent thoughts!" text_lose_indication = "Your mind feels more clear." @@ -70,6 +74,7 @@ /datum/mutation/human/swedish name = "Swedish" desc = "A horrible mutation originating from the distant past. Thought to be eradicated after the incident in 2037." + instability = NEGATIVE_STABILITY_MINI quality = MINOR_NEGATIVE text_gain_indication = "You feel Swedish, however that works." text_lose_indication = "The feeling of Swedishness passes." @@ -101,6 +106,7 @@ /datum/mutation/human/chav name = "Chav" desc = "Unknown" + instability = NEGATIVE_STABILITY_MINI quality = MINOR_NEGATIVE text_gain_indication = "Ye feel like a reet prat like, innit?" text_lose_indication = "You no longer feel like being rude and sassy." @@ -138,6 +144,7 @@ /datum/mutation/human/elvis name = "Elvis" desc = "A terrifying mutation named after its 'patient-zero'." + instability = NEGATIVE_STABILITY_MINI quality = MINOR_NEGATIVE locked = TRUE text_gain_indication = "You feel pretty good, honeydoll." @@ -203,6 +210,7 @@ /datum/mutation/human/medieval name = "Medieval" desc = "A horrible mutation originating from the distant past, thought to have once been a common gene in all of old world Europe." + instability = NEGATIVE_STABILITY_MINI quality = MINOR_NEGATIVE text_gain_indication = "You feel like seeking the holy grail!" text_lose_indication = "You no longer feel like seeking anything." @@ -243,6 +251,7 @@ /datum/mutation/human/piglatin name = "Pig Latin" desc = "Historians say back in the 2020's humanity spoke entirely in this mystical language." + instability = NEGATIVE_STABILITY_MINI quality = MINOR_NEGATIVE text_gain_indication = span_notice("Omethingsay eelsfay offyay.") text_lose_indication = span_notice("The off sensation passes.") diff --git a/code/datums/mutations/telekinesis.dm b/code/datums/mutations/telekinesis.dm index 53d8beb56ff50..bd6ba13070df3 100644 --- a/code/datums/mutations/telekinesis.dm +++ b/code/datums/mutations/telekinesis.dm @@ -6,7 +6,7 @@ difficulty = 18 text_gain_indication = "You feel smarter!" limb_req = BODY_ZONE_HEAD - instability = 30 + instability = POSITIVE_INSTABILITY_MAJOR ///Typecache of atoms that TK shouldn't interact with var/static/list/blacklisted_atoms = typecacheof(list(/atom/movable/screen)) diff --git a/code/datums/mutations/telepathy.dm b/code/datums/mutations/telepathy.dm index 8619c2bddc476..0e3dffb48b4a4 100644 --- a/code/datums/mutations/telepathy.dm +++ b/code/datums/mutations/telepathy.dm @@ -6,5 +6,5 @@ text_lose_indication = "You don't hear your mind echo anymore." difficulty = 12 power_path = /datum/action/cooldown/spell/list_target/telepathy - instability = 10 + instability = POSITIVE_INSTABILITY_MINOR // basically a mediocre PDA messager energy_coeff = 1 diff --git a/code/datums/mutations/tongue_spike.dm b/code/datums/mutations/tongue_spike.dm index e6249041250b8..9e25ad6f4f296 100644 --- a/code/datums/mutations/tongue_spike.dm +++ b/code/datums/mutations/tongue_spike.dm @@ -3,7 +3,7 @@ desc = "Allows a creature to voluntary shoot their tongue out as a deadly weapon." quality = POSITIVE text_gain_indication = span_notice("Your feel like you can throw your voice.") - instability = 15 + instability = POSITIVE_INSTABILITY_MINI // worthless. also serves as a bit of a hint that it's not good power_path = /datum/action/cooldown/spell/tongue_spike energy_coeff = 1 @@ -89,7 +89,7 @@ desc = "Allows a creature to voluntary shoot their tongue out as biomass, allowing a long range transfer of chemicals." quality = POSITIVE text_gain_indication = span_notice("Your feel like you can really connect with people by throwing your voice.") - instability = 15 + instability = POSITIVE_INSTABILITY_MINOR // slightly less worthless. slightly. locked = TRUE power_path = /datum/action/cooldown/spell/tongue_spike/chem energy_coeff = 1 diff --git a/code/datums/mutations/touch.dm b/code/datums/mutations/touch.dm index ca94f109ac664..eaa4909703525 100644 --- a/code/datums/mutations/touch.dm +++ b/code/datums/mutations/touch.dm @@ -7,7 +7,7 @@ text_gain_indication = "You feel power flow through your hands." text_lose_indication = "The energy in your hands subsides." power_path = /datum/action/cooldown/spell/touch/shock - instability = 35 + instability = POSITIVE_INSTABILITY_MODERATE // bad stun baton energy_coeff = 1 power_coeff = 1 diff --git a/code/datums/mutations/void_magnet.dm b/code/datums/mutations/void_magnet.dm index 48f04eda636a7..b5c893e32c547 100644 --- a/code/datums/mutations/void_magnet.dm +++ b/code/datums/mutations/void_magnet.dm @@ -3,7 +3,7 @@ desc = "A rare genome that attracts odd forces not usually observed." quality = MINOR_NEGATIVE //upsides and downsides text_gain_indication = span_notice("You feel a heavy, dull force just beyond the walls watching you.") - instability = 30 + instability = POSITIVE_INSTABILITY_MODERATE // useful, but has large drawbacks power_path = /datum/action/cooldown/spell/void/cursed energy_coeff = 1 synchronizer_coeff = 1 diff --git a/code/datums/mutations/webbing.dm b/code/datums/mutations/webbing.dm index 0fda118d0ed60..002687d55be0f 100644 --- a/code/datums/mutations/webbing.dm +++ b/code/datums/mutations/webbing.dm @@ -4,7 +4,7 @@ desc = "Allows the user to lay webbing, and travel through it." quality = POSITIVE text_gain_indication = "Your skin feels webby." - instability = 15 + instability = POSITIVE_INSTABILITY_MODERATE // useful until you're lynched power_path = /datum/action/cooldown/mob_cooldown/lay_web/genetic energy_coeff = 1 diff --git a/code/datums/quirks/positive_quirks/settler.dm b/code/datums/quirks/positive_quirks/settler.dm index 9b52403404b12..3b4084242b811 100644 --- a/code/datums/quirks/positive_quirks/settler.dm +++ b/code/datums/quirks/positive_quirks/settler.dm @@ -9,17 +9,26 @@ value = 4 mob_trait = TRAIT_SETTLER quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE - medical_record_text = "Patient appears to be abnormally stout." + medical_record_text = "Patient has been exposed to planetary conditions for extended periods, resulting in an excessively stout build." mail_goodies = list( /obj/item/clothing/shoes/workboots/mining, /obj/item/gps, ) + /// Most of the behavior of settler is from these traits, rather than exclusively the quirk + var/list/settler_traits = list( + TRAIT_EXPERT_FISHER, + TRAIT_ROUGHRIDER, + TRAIT_STUBBY_BODY, + TRAIT_BEAST_EMPATHY, + TRAIT_STURDY_FRAME, + ) /datum/quirk/item_quirk/settler/add(client/client_source) var/mob/living/carbon/human/human_quirkholder = quirk_holder human_quirkholder.set_mob_height(HUMAN_HEIGHT_SHORTEST) human_quirkholder.add_movespeed_modifier(/datum/movespeed_modifier/settler) human_quirkholder.physiology.hunger_mod *= 0.5 //good for you, shortass, you don't get hungry nearly as often + human_quirkholder.add_traits(settler_traits, QUIRK_TRAIT) /datum/quirk/item_quirk/settler/add_unique(client/client_source) give_item_to_holder(/obj/item/storage/box/papersack/wheat, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) @@ -32,3 +41,4 @@ human_quirkholder.set_mob_height(HUMAN_HEIGHT_MEDIUM) human_quirkholder.remove_movespeed_modifier(/datum/movespeed_modifier/settler) human_quirkholder.physiology.hunger_mod *= 2 + human_quirkholder.remove_traits(settler_traits, QUIRK_TRAIT) diff --git a/code/datums/sprite_accessories.dm b/code/datums/sprite_accessories.dm index e6e8b956e6568..e5cf49475e22e 100644 --- a/code/datums/sprite_accessories.dm +++ b/code/datums/sprite_accessories.dm @@ -1700,24 +1700,24 @@ // MutantParts Definitions // ///////////////////////////// -/datum/sprite_accessory/body_markings - icon = 'icons/mob/human/species/lizard/lizard_misc.dmi' +/datum/sprite_accessory/lizard_markings + icon = 'icons/mob/human/species/lizard/lizard_markings.dmi' -/datum/sprite_accessory/body_markings/none +/datum/sprite_accessory/lizard_markings/none name = "None" icon_state = "none" -/datum/sprite_accessory/body_markings/dtiger +/datum/sprite_accessory/lizard_markings/dtiger name = "Dark Tiger Body" icon_state = "dtiger" gender_specific = TRUE -/datum/sprite_accessory/body_markings/ltiger +/datum/sprite_accessory/lizard_markings/ltiger name = "Light Tiger Body" icon_state = "ltiger" gender_specific = TRUE -/datum/sprite_accessory/body_markings/lbelly +/datum/sprite_accessory/lizard_markings/lbelly name = "Light Belly" icon_state = "lbelly" gender_specific = TRUE diff --git a/code/datums/status_effects/buffs/stop_drop_roll.dm b/code/datums/status_effects/buffs/stop_drop_roll.dm index 43d37654e6177..17b4d6d768de3 100644 --- a/code/datums/status_effects/buffs/stop_drop_roll.dm +++ b/code/datums/status_effects/buffs/stop_drop_roll.dm @@ -24,6 +24,9 @@ // Start with one weaker roll owner.spin(spintime = actual_interval, speed = actual_interval / 4) owner.adjust_fire_stacks(-0.25) + + for (var/obj/item/dropped in owner.loc) + dropped.extinguish() // Effectively extinguish your items by rolling on them return TRUE /datum/status_effect/stop_drop_roll/on_remove() diff --git a/code/datums/status_effects/debuffs/fire_stacks.dm b/code/datums/status_effects/debuffs/fire_stacks.dm index 62f8c9ca24e32..dd625ab919aca 100644 --- a/code/datums/status_effects/debuffs/fire_stacks.dm +++ b/code/datums/status_effects/debuffs/fire_stacks.dm @@ -247,7 +247,7 @@ owner.clear_mood_event("on_fire") SEND_SIGNAL(owner, COMSIG_LIVING_EXTINGUISHED, owner) cache_stacks() - for(var/obj/item/equipped in owner.get_equipped_items()) + for(var/obj/item/equipped in (owner.get_equipped_items(INCLUDE_HELD))) equipped.extinguish() /datum/status_effect/fire_handler/fire_stacks/on_remove() diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index c9e94e0dd97f5..3d4bd7e93655c 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -31,7 +31,7 @@ SIGNAL_HANDLER if(istype(attacking_item, /obj/item/kinetic_crusher)) - total_damage += damage_dealt + total_damage += (-1 * damage_dealt) /datum/status_effect/syphon_mark id = "syphon_mark" diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index 9bcc0f03b7a0e..2a5bd2a98fd7a 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -735,12 +735,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) return COMPONENT_CANCEL_MOUSEDROP_ONTO else if(!istype(over_object, /atom/movable/screen)) - var/action_status - if(isturf(over_object)) - action_status = user.can_perform_turf_action(over_object) - else - action_status = user.can_perform_action(over_object, FORBID_TELEKINESIS_REACH) - if(!action_status) + if(!user.can_perform_action(over_object, FORBID_TELEKINESIS_REACH)) return parent.add_fingerprint(user) @@ -791,7 +786,6 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) /datum/storage/proc/on_mousedropped_onto(datum/source, obj/item/dropping, mob/user) SIGNAL_HANDLER - . = COMPONENT_CANCEL_MOUSEDROPPED_ONTO if(!istype(dropping)) return if(dropping != user.get_active_held_item()) @@ -804,6 +798,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) return attempt_insert(dropping, user) + return COMPONENT_CANCEL_MOUSEDROPPED_ONTO /// Signal handler for whenever we're attacked by an object. /datum/storage/proc/on_item_interact(datum/source, mob/user, obj/item/thing, params) diff --git a/code/datums/storage/subtypes/bag_of_holding.dm b/code/datums/storage/subtypes/bag_of_holding.dm index a4ea699e42e21..aa812f5d1e007 100644 --- a/code/datums/storage/subtypes/bag_of_holding.dm +++ b/code/datums/storage/subtypes/bag_of_holding.dm @@ -38,7 +38,7 @@ user.investigate_log("has been gibbed by a bag of holding recursive insertion.", INVESTIGATE_DEATHS) user.gib() - var/obj/boh_tear/tear = new(rift_loc) + var/obj/reality_tear/tear = new(rift_loc) tear.start_disaster() qdel(to_insert) qdel(parent) diff --git a/code/datums/wires/apc.dm b/code/datums/wires/apc.dm index 54d179802a311..50847df994372 100644 --- a/code/datums/wires/apc.dm +++ b/code/datums/wires/apc.dm @@ -4,8 +4,13 @@ /datum/wires/apc/New(atom/holder) wires = list( - WIRE_POWER1, WIRE_POWER2, - WIRE_IDSCAN, WIRE_AI + WIRE_EQUIPMENT, + WIRE_LIGHT, + WIRE_ENVIRONMENT, + WIRE_POWER1, + WIRE_POWER2, + WIRE_INTERFACE, + WIRE_AI ) add_duds(6) ..() @@ -22,17 +27,32 @@ var/list/status = list() status += "The interface light is [A.locked ? "red" : "green"]." status += "The short indicator is [A.shorted ? "lit" : "off"]." + status += "The channel one light is [A.equipment ? "on" : "off"]." + status += "The channel two light is [A.lighting ? "on" : "off"]." + status += "The channel three light is [A.environ ? "on" : "off"]." status += "The AI connection light is [!A.aidisabled ? "on" : "off"]." return status -/datum/wires/apc/on_pulse(wire) +/datum/wires/apc/on_pulse(wire, user) var/obj/machinery/power/apc/A = holder switch(wire) + if(WIRE_EQUIPMENT) + A.equipment = A.equipment > APC_CHANNEL_OFF ? APC_CHANNEL_OFF : APC_CHANNEL_AUTO_ON + A.update_appearance() + A.update() + if(WIRE_LIGHT) + A.lighting = A.lighting > APC_CHANNEL_OFF ? APC_CHANNEL_OFF : APC_CHANNEL_AUTO_ON + A.update_appearance() + A.update() + if(WIRE_ENVIRONMENT) + A.environ = A.environ > APC_CHANNEL_OFF ? APC_CHANNEL_OFF : APC_CHANNEL_AUTO_ON + A.update_appearance() + A.update() if(WIRE_POWER1, WIRE_POWER2) // Short for a long while. if(!A.shorted) A.shorted = TRUE addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/power/apc, reset), wire), 2 MINUTES) - if(WIRE_IDSCAN) // Unlock for a little while. + if(WIRE_INTERFACE) // Unlock for a little while. A.locked = FALSE addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/power/apc, reset), wire), 30 SECONDS) if(WIRE_AI) // Disable AI control for a very short time. @@ -43,12 +63,26 @@ /datum/wires/apc/on_cut(wire, mend, source) var/obj/machinery/power/apc/A = holder switch(wire) + if(WIRE_EQUIPMENT) + A.equipment = mend ? APC_CHANNEL_AUTO_ON : APC_CHANNEL_OFF + A.update_appearance() + A.update() + if(WIRE_LIGHT) + A.lighting = mend ? APC_CHANNEL_AUTO_ON : APC_CHANNEL_OFF + A.update_appearance() + A.update() + if(WIRE_ENVIRONMENT) + A.environ = mend ? APC_CHANNEL_AUTO_ON : APC_CHANNEL_OFF + A.update_appearance() + A.update() if(WIRE_POWER1, WIRE_POWER2) // Short out. if(mend && !is_cut(WIRE_POWER1) && !is_cut(WIRE_POWER2)) A.shorted = FALSE else A.shorted = TRUE A.shock(usr, 50) + if(WIRE_INTERFACE) + A.locked = !mend if(WIRE_AI) // Disable AI control. A.aidisabled = !mend diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index d8ae957994794..8135a3af59346 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -595,7 +595,7 @@ stop_pulling() else if(pulling.anchored || pulling.move_resist > move_force) stop_pulling() - if(!only_pulling && pulledby && moving_diagonally != FIRST_DIAG_STEP && (get_dist(src, pulledby) > 1 || z != pulledby.z)) //separated from our puller and not in the middle of a diagonal move. + if(!only_pulling && pulledby && moving_diagonally != FIRST_DIAG_STEP && (get_dist(src, pulledby) > 1 || (z != pulledby.z && !z_allowed))) //separated from our puller and not in the middle of a diagonal move. pulledby.stop_pulling() /atom/movable/proc/set_glide_size(target = 8) @@ -792,7 +792,14 @@ if(target_turf != current_turf || (moving_diagonally != SECOND_DIAG_STEP && ISDIAGONALDIR(pull_dir)) || get_dist(src, pulling) > 1) pulling.move_from_pull(src, target_turf, glide_size) - check_pulling() + if (pulledby) + if (pulledby.currently_z_moving) + check_pulling(z_allowed = TRUE) + //dont call check_pulling() here at all if there is a pulledby that is not currently z moving + //because it breaks stair conga lines, for some fucking reason. + //it's fine because the pull will be checked when this whole proc is called by the mob doing the pulling anyways + else + check_pulling() //glide_size strangely enough can change mid movement animation and update correctly while the animation is playing //This means that if you don't override it late like this, it will just be set back by the movement update that's called when you move turfs. diff --git a/code/game/machinery/civilian_bounties.dm b/code/game/machinery/civilian_bounties.dm index e5cd81cc965a1..fa0d28c999c88 100644 --- a/code/game/machinery/civilian_bounties.dm +++ b/code/game/machinery/civilian_bounties.dm @@ -168,7 +168,7 @@ return inserted_scan_id.registered_account.civilian_bounty = inserted_scan_id.registered_account.bounties[choice] inserted_scan_id.registered_account.bounties = null - SSblackbox.record_feedback("tally", "bounties_assigned", 1, choice.type) + SSblackbox.record_feedback("tally", "bounties_assigned", 1, inserted_scan_id.registered_account.civilian_bounty.type) return inserted_scan_id.registered_account.civilian_bounty /obj/machinery/computer/piratepad_control/civilian/click_alt(mob/user) diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm index f0d7b2e30eb52..9028d6d367d91 100644 --- a/code/game/machinery/computer/dna_console.dm +++ b/code/game/machinery/computer/dna_console.dm @@ -1,5 +1,20 @@ -/// Base timeout for creating mutation activators and other injectors -#define INJECTOR_TIMEOUT 100 +/// Base timeout for creating mutation activators +#define MIN_ACTIVATOR_TIMEOUT 5 SECONDS +/// Base cooldown multiplier for activator upgrades +#define ACTIVATOR_COOLDOWN_MULTIPLIER 0.25 +/// Base timeout for creating mutation injectors +#define MIN_INJECTOR_TIMEOUT 10 SECONDS +/// Base cooldown multiplier for injecotr upgrades +#define INJECTOR_COOLDOWN_MULTIPLIER 0.15 + +/// Base timeout for creating advanced injectors +#define MIN_ADVANCED_TIMEOUT 15 SECONDS +/// Base cooldown multiplier for advanced injector upgrades +#define ADVANCED_COOLDOWN_MULTIPLIER 0.1 + +/// Used for other things like UI/UE/Initial CD +#define MISC_INJECTOR_TIMEOUT 60 SECONDS + /// Maximum number of genetic makeup storage slots in DNA Console #define NUMBER_OF_BUFFERS 3 /// Timeout for DNA Scramble in DNA Consoles @@ -221,7 +236,7 @@ connect_to_scanner() // Set appropriate ready timers and limits for machines functions - injector_ready = world.time + INJECTOR_TIMEOUT + injector_ready = world.time + MISC_INJECTOR_TIMEOUT scramble_ready = world.time + SCRAMBLE_TIMEOUT joker_ready = world.time + JOKER_TIMEOUT COOLDOWN_START(src, enzyme_copy_timer, ENZYME_COPY_BASE_COOLDOWN) @@ -816,21 +831,33 @@ I.research = TRUE // If there's an operational connected scanner, we can use its upgrades // to improve our injector's genetic damage generation + var/cd_reduction_mult = 1 + ACTIVATOR_COOLDOWN_MULTIPLIER + var/base_cd_time = max(MIN_ACTIVATOR_TIMEOUT, abs(HM.instability) SECONDS) + if(scanner_operational()) I.damage_coeff = connected_scanner.damage_coeff*4 - injector_ready = world.time + INJECTOR_TIMEOUT * (1 - 0.1 * connected_scanner.precision_coeff) - else - injector_ready = world.time + INJECTOR_TIMEOUT + // T1: 1.25 - 0.25: 1: 100% + // T4: 1.25 - 1: 0.25 = 25% + // 25% reduction per tier + cd_reduction_mult -= ACTIVATOR_COOLDOWN_MULTIPLIER * (connected_scanner.precision_coeff) + + injector_ready = world.time + (base_cd_time * cd_reduction_mult) else I.name = "[HM.name] mutator" - I.doitanyway = TRUE + I.force_mutate = TRUE // If there's an operational connected scanner, we can use its upgrades // to improve our injector's genetic damage generation + var/cd_reduction_mult = 1 + INJECTOR_COOLDOWN_MULTIPLIER + var/base_cd_time = max(MIN_INJECTOR_TIMEOUT, abs(HM.instability) * 1 SECONDS) + if(scanner_operational()) - I.damage_coeff = connected_scanner.damage_coeff - injector_ready = world.time + INJECTOR_TIMEOUT * 5 * (1 - 0.1 * connected_scanner.precision_coeff) - else - injector_ready = world.time + INJECTOR_TIMEOUT * 5 + I.damage_coeff = connected_scanner.damage_coeff*4 + // T1: 1.15 - 0.15: 1: 100% + // T4: 1.15 - 0.60: 0.55: 55% + // 15% reduction per tier + cd_reduction_mult -= (INJECTOR_COOLDOWN_MULTIPLIER * connected_scanner.precision_coeff) + + injector_ready = world.time + (base_cd_time * cd_reduction_mult) if(connected_scanner) connected_scanner.use_energy(connected_scanner.active_power_usage) else @@ -1349,7 +1376,7 @@ // If we successfully created an injector, don't forget to set the new // ready timer. if(I) - injector_ready = world.time + INJECTOR_TIMEOUT + injector_ready = world.time + MISC_INJECTOR_TIMEOUT if(connected_scanner) connected_scanner.use_energy(connected_scanner.active_power_usage) else @@ -1538,22 +1565,29 @@ // Run through each mutation in our Advanced Injector and add them to a // new injector + var/total_stability for(var/A in injector) var/datum/mutation/human/HM = A I.add_mutations += new HM.type(copymut=HM) + total_stability += HM.instability // Force apply any mutations, this is functionality similar to mutators - I.doitanyway = TRUE + I.force_mutate = TRUE I.name = "Advanced [inj_name] injector" // If there's an operational connected scanner, we can use its upgrades // to improve our injector's genetic damage generation + var/cd_reduction_mult = 1 + ADVANCED_COOLDOWN_MULTIPLIER + var/base_cd_time = max(MIN_ADVANCED_TIMEOUT, abs(total_stability) SECONDS) + if(scanner_operational()) - I.damage_coeff = connected_scanner.damage_coeff - injector_ready = world.time + INJECTOR_TIMEOUT * 8 * (1 - 0.1 * connected_scanner.precision_coeff) - else - injector_ready = world.time + INJECTOR_TIMEOUT * 8 + I.damage_coeff = connected_scanner.damage_coeff*4 + // T1: 1.1 - 0.1: 1: 100% + // T4: 1.1 - 0.4: 0.7 = 70% + // 10% reduction per tier + cd_reduction_mult -= ADVANCED_COOLDOWN_MULTIPLIER * (connected_scanner.precision_coeff) + injector_ready = world.time + (base_cd_time * cd_reduction_mult) return // Adds a mutation to an advanced injector @@ -2299,11 +2333,20 @@ SIGNAL_HANDLER set_connected_scanner(null) +#undef MIN_ACTIVATOR_TIMEOUT +#undef ACTIVATOR_COOLDOWN_MULTIPLIER +#undef MIN_INJECTOR_TIMEOUT +#undef INJECTOR_COOLDOWN_MULTIPLIER + +#undef MIN_ADVANCED_TIMEOUT +#undef ADVANCED_COOLDOWN_MULTIPLIER + +#undef MISC_INJECTOR_TIMEOUT + #undef GENETIC_DAMAGE_PULSE_UNIQUE_IDENTITY #undef GENETIC_DAMAGE_PULSE_UNIQUE_FEATURES #undef ENZYME_COPY_BASE_COOLDOWN -#undef INJECTOR_TIMEOUT #undef NUMBER_OF_BUFFERS #undef SCRAMBLE_TIMEOUT #undef JOKER_TIMEOUT diff --git a/code/game/machinery/computer/records/security.dm b/code/game/machinery/computer/records/security.dm index c41779e7384ec..dac62612a4c74 100644 --- a/code/game/machinery/computer/records/security.dm +++ b/code/game/machinery/computer/records/security.dm @@ -176,7 +176,7 @@ return TRUE if("set_note") - var/note = trim(params["note"], MAX_MESSAGE_LEN) + var/note = strip_html_full(params["note"], MAX_MESSAGE_LEN) investigate_log("[user] has changed the security note of record: \"[target]\" from \"[target.security_note]\" to \"[note]\".") target.security_note = note return TRUE @@ -199,7 +199,7 @@ /// Handles adding a crime to a particular record. /obj/machinery/computer/records/security/proc/add_crime(mob/user, datum/record/crew/target, list/params) - var/input_name = trim(params["name"], MAX_CRIME_NAME_LEN) + var/input_name = strip_html_full(params["name"], MAX_CRIME_NAME_LEN) if(!input_name) to_chat(usr, span_warning("You must enter a name for the crime.")) playsound(src, 'sound/machines/terminal_error.ogg', 75, TRUE) @@ -213,7 +213,7 @@ var/input_details if(params["details"]) - input_details = trim(params["details"], MAX_MESSAGE_LEN) + input_details = strip_html_full(params["details"], MAX_MESSAGE_LEN) if(params["fine"] == 0) var/datum/crime/new_crime = new(name = input_name, details = input_details, author = usr) @@ -245,13 +245,13 @@ return FALSE if(params["name"] && length(params["name"]) > 2 && params["name"] != editing_crime.name) - var/new_name = trim(params["name"], MAX_CRIME_NAME_LEN) + var/new_name = strip_html_full(params["name"], MAX_CRIME_NAME_LEN) investigate_log("[user] edited crime: \"[editing_crime.name]\" for target: \"[target.name]\", changing the name to: \"[new_name]\".", INVESTIGATE_RECORDS) editing_crime.name = new_name return TRUE if(params["details"] && length(params["description"]) > 2 && params["name"] != editing_crime.name) - var/new_details = trim(params["details"], MAX_MESSAGE_LEN) + var/new_details = strip_html_full(params["details"], MAX_MESSAGE_LEN) investigate_log("[user] edited crime \"[editing_crime.name]\" for target: \"[target.name]\", changing the details to: \"[new_details]\" from: \"[editing_crime.details]\".", INVESTIGATE_RECORDS) editing_crime.details = new_details return TRUE @@ -327,9 +327,9 @@ playsound(src, 'sound/machines/printer.ogg', 100, TRUE) var/obj/item/printable - var/input_alias = trim(params["alias"], MAX_NAME_LEN) || target.name - var/input_description = trim(params["desc"], MAX_BROADCAST_LEN) || "No further details." - var/input_header = trim(params["head"], 8) || capitalize(params["type"]) + var/input_alias = strip_html_full(params["alias"], MAX_NAME_LEN) || target.name + var/input_description = strip_html_full(params["desc"], MAX_BROADCAST_LEN) || "No further details." + var/input_header = strip_html_full(params["head"], 8) || capitalize(params["type"]) switch(params["type"]) if("missing") diff --git a/code/game/machinery/dna_scanner.dm b/code/game/machinery/dna_scanner.dm index 4775642881fcc..cb0ab9900d5cc 100644 --- a/code/game/machinery/dna_scanner.dm +++ b/code/game/machinery/dna_scanner.dm @@ -11,9 +11,9 @@ circuit = /obj/item/circuitboard/machine/dnascanner var/locked = FALSE - var/damage_coeff + var/damage_coeff = 1 var/scan_level - var/precision_coeff + var/precision_coeff = 1 var/message_cooldown var/breakout_time = 1200 var/obj/machinery/computer/scan_consolenew/linked_console = null diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index ae37691f1c1a1..37310e2aceb49 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -601,7 +601,11 @@ if(!machine_stat) update_icon(ALL, AIRLOCK_DENY) playsound(src,doorDeni,50,FALSE,3) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon), ALL, AIRLOCK_CLOSED), AIRLOCK_DENY_ANIMATION_TIME) + addtimer(CALLBACK(src, PROC_REF(handle_deny_end)), AIRLOCK_DENY_ANIMATION_TIME) + +/obj/machinery/door/airlock/proc/handle_deny_end() + if(airlock_state == AIRLOCK_DENY) + update_icon(ALL, AIRLOCK_CLOSED) /obj/machinery/door/airlock/examine(mob/user) . = ..() diff --git a/code/game/machinery/flatpacker.dm b/code/game/machinery/flatpacker.dm index 1eb8f6e2cc5cb..03382dce8d81e 100644 --- a/code/game/machinery/flatpacker.dm +++ b/code/game/machinery/flatpacker.dm @@ -231,6 +231,10 @@ materials.retrieve_sheets(amount, ejecting, drop_location()) return TRUE +/obj/machinery/flatpacker/screwdriver_act(mob/living/user, obj/item/tool) + . = ITEM_INTERACT_BLOCKING + if(default_deconstruction_screwdriver(user, icon_state, icon_state, tool)) + return ITEM_INTERACT_SUCCESS /obj/machinery/flatpacker/Destroy() QDEL_NULL(inserted_board) @@ -238,7 +242,7 @@ /obj/item/flatpack name = "flatpack" - desc = "A box containing a compacted packed machine. Use multitool to deploy." + desc = "A box containing a compactly packed machine. Use multitool to deploy." icon = 'icons/obj/devices/circuitry_n_data.dmi' icon_state = "flatpack" w_class = WEIGHT_CLASS_HUGE //cart time @@ -249,13 +253,25 @@ /// The board we deploy var/obj/item/circuitboard/machine/board -/obj/item/flatpack/Initialize(mapload, obj/item/circuitboard/machine/board) +/obj/item/flatpack/Initialize(mapload, obj/item/circuitboard/machine/new_board) . = ..() - if(!isnull(board)) - src.board = board // i got board + var/static/list/tool_behaviors + if(!tool_behaviors) + tool_behaviors = string_assoc_nested_list(list( + TOOL_MULTITOOL = list( + SCREENTIP_CONTEXT_LMB = "Deploy", + ), + )) + AddElement(/datum/element/contextual_screentip_tools, tool_behaviors) + if(isnull(board) && isnull(new_board)) + return INITIALIZE_HINT_QDEL //how + + board = !isnull(new_board) ? new_board : new board(src) // i got board + if(board.loc != src) board.forceMove(src) - var/obj/machinery/build = initial(board.build_path) - name += " ([initial(build.name)])" + var/obj/machinery/build = initial(board.build_path) + name += " ([initial(build.name)])" + /obj/item/flatpack/Destroy() QDEL_NULL(board) diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm index d977605b2436f..b99c8000c58a4 100644 --- a/code/game/objects/effects/decals/cleanable/misc.dm +++ b/code/game/objects/effects/decals/cleanable/misc.dm @@ -444,6 +444,7 @@ beauty = -50 clean_type = CLEAN_TYPE_BLOOD mouse_opacity = MOUSE_OPACITY_OPAQUE + resistance_flags = UNACIDABLE | ACID_PROOF | FIRE_PROOF | FLAMMABLE //gross way of doing this but would need to disassemble fire_act call stack otherwise /// Maximum amount of hotspots this pool can create before deleting itself var/burn_amount = 3 /// Is this fuel pool currently burning? @@ -453,6 +454,10 @@ /obj/effect/decal/cleanable/fuel_pool/Initialize(mapload, burn_stacks) . = ..() + var/static/list/ignition_trigger_connections = list( + COMSIG_TURF_MOVABLE_THROW_LANDED = PROC_REF(ignition_trigger), + ) + AddElement(/datum/element/connect_loc, ignition_trigger_connections) for(var/obj/effect/decal/cleanable/fuel_pool/pool in get_turf(src)) //Can't use locate because we also belong to that turf if(pool == src) continue @@ -509,6 +514,26 @@ ignite() return ..() +/obj/effect/decal/cleanable/fuel_pool/on_entered(datum/source, atom/movable/entered_atom) + . = ..() + if(entered_atom.throwing) // don't light from things being thrown over us, we handle that somewhere else + return + ignition_trigger(source = src, enflammable_atom = entered_atom) + +/obj/effect/decal/cleanable/fuel_pool/proc/ignition_trigger(datum/source, atom/movable/enflammable_atom) + SIGNAL_HANDLER + + if(isitem(enflammable_atom)) + var/obj/item/enflamed_item = enflammable_atom + if(enflamed_item.get_temperature() > FIRE_MINIMUM_TEMPERATURE_TO_EXIST) + ignite() + return + else if(isliving(enflammable_atom)) + var/mob/living/enflamed_liver = enflammable_atom + if(enflamed_liver.on_fire) + ignite() + + /obj/effect/decal/cleanable/fuel_pool/hivis icon_state = "fuel_pool_hivis" diff --git a/code/game/objects/effects/effect_system/effects_sparks.dm b/code/game/objects/effects/effect_system/effects_sparks.dm index 874c53fa83c7d..c715cc1d7457d 100644 --- a/code/game/objects/effects/effect_system/effects_sparks.dm +++ b/code/game/objects/effects/effect_system/effects_sparks.dm @@ -26,24 +26,80 @@ return INITIALIZE_HINT_LATELOAD /obj/effect/particle_effect/sparks/LateInitialize() + RegisterSignals(src, list(COMSIG_MOVABLE_CROSS, COMSIG_MOVABLE_CROSS_OVER), PROC_REF(sparks_touched)) flick(icon_state, src) playsound(src, SFX_SPARKS, 100, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - var/turf/T = loc - if(isturf(T)) - T.hotspot_expose(1000,100) + var/turf/location = loc + if(isturf(location)) + affect_location(location, just_initialized = TRUE) QDEL_IN(src, 20) /obj/effect/particle_effect/sparks/Destroy() - var/turf/T = loc - if(isturf(T)) - T.hotspot_expose(1000,100) + var/turf/location = loc + if(isturf(location)) + affect_location(location) return ..() /obj/effect/particle_effect/sparks/Move() ..() - var/turf/T = loc - if(isturf(T)) - T.hotspot_expose(1000,100) + var/turf/location = loc + if(isturf(location)) + affect_location(location) + +/* +* Apply the effects of this spark to its location. +* +* When the spark is first created, Cross() and Crossed() don't get called, +* so for the first initialization, we make sure to specifically invoke the +* behavior of the spark on all the mobs and objects in the location. +* turf/location - The place the spark is affectiong +* just_initialized - If the spark is just being created, and we need to manually affect everything in the location +*/ +/obj/effect/particle_effect/sparks/proc/affect_location(turf/location, just_initialized = FALSE) + location.hotspot_expose(1000,100) + if(just_initialized) + for(var/atom/movable/singed in location) + sparks_touched(src, singed) + +/* +* This is called when anything passes through the same tiles as a spark, or when a spark passes through something's tile. +* +* This is invoked by the signals sent by every atom when they're crossed or crossing something. It +* signifies that something has been touched by sparks, and should be affected by possible pyrotechnic affects.. +* datum/source - Can either be the spark itself or an object that just walked into it +* mob/living/singed_mob - The mob that was touched by the spark +*/ +/obj/effect/particle_effect/sparks/proc/sparks_touched(datum/source, atom/movable/singed) + SIGNAL_HANDLER + + if(isobj(singed)) + var/obj/singed_obj = singed + if(singed_obj.reagents) + var/datum/reagents/reagents = singed_obj.reagents // heat up things that contain reagents before we check to see if they burn + reagents?.expose_temperature(1000) // we set this at 1000 because that's the max reagent temp for a chem heater, higher temps require more than sparks + if(singed_obj.custom_materials && (GET_MATERIAL_REF(/datum/material/plasma) in singed_obj.custom_materials)) + singed_obj.fire_act(FIRE_MINIMUM_TEMPERATURE_TO_SPREAD,100) + return // if it's made of plasma we just start burning no matter what, even furniture (see right below) + if(isstructure(singed_obj) || ismachinery(singed_obj)) // don't ignite furniture even if it's flammable, leave that to actual fires + return + if(singed_obj.resistance_flags & FLAMMABLE && !(singed_obj.resistance_flags & ON_FIRE)) //only fire_act flammable objects instead of burning EVERYTHING + if(isitem(singed_obj)) + var/obj/item/singed_item = singed_obj + var/ignite_chance = 120 // base chance applies to anything under WEIGHT_CLASS_NORMAL, so burn everything flammable that's small/tiny + if(singed_item.w_class > WEIGHT_CLASS_SMALL) + var/ignite_chance_penalty = (singed_item.w_class * 2 + round(singed_item.w_class * 0.5)) * 10 // size penalties to ignite chance: normal = 70, bulky = 100, + ignite_chance -= ignite_chance_penalty // the bigger the item, the less likely it is to ignite + if(prob(ignite_chance)) + singed_item.fire_act(FIRE_MINIMUM_TEMPERATURE_TO_SPREAD,100) + return + else + singed_obj.fire_act(FIRE_MINIMUM_TEMPERATURE_TO_SPREAD,100) + return + if(isliving(singed)) + var/mob/living/singed_living = singed + if(singed_living.fire_stacks) + singed_living.ignite_mob(FALSE) //ignite the mob, silent = FALSE (You're set on fire!) + return /datum/effect_system/spark_spread effect_type = /obj/effect/particle_effect/sparks diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index a7aabee6f4d2a..255f34eff51dd 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -101,7 +101,7 @@ . = INITIALIZE_HINT_QDEL CRASH("Somebody fucked up.") if(_lifespan > 0) - addtimer(src, PROC_REF(expire), _lifespan, TIMER_DELETE_ME) + addtimer(CALLBACK(src, PROC_REF(expire)), _lifespan, TIMER_DELETE_ME) link_portal(_linked) hardlinked = automatic_link if(isturf(hard_target_override)) diff --git a/code/game/objects/effects/spawners/random/armory.dm b/code/game/objects/effects/spawners/random/armory.dm index 5292ca6ad0986..dfb71ff10d54b 100644 --- a/code/game/objects/effects/spawners/random/armory.dm +++ b/code/game/objects/effects/spawners/random/armory.dm @@ -45,6 +45,16 @@ icon_state = "shotgun" loot = list(/obj/item/gun/ballistic/shotgun/riot) +/obj/effect/spawner/random/armory/dragnet + name = "DRAGnet spawner" + icon_state = "dragnet" + loot = list(/obj/item/gun/energy/e_gun/dragnet) + spawn_loot_count = 2 + +/obj/effect/spawner/random/armory/dragnet/spawn_loot(lootcount_override) + . = ..() + new /obj/item/dragnet_beacon(get_turf(src)) //And give them a beacon too! + // Armor /obj/effect/spawner/random/armory/bulletproof_helmet name = "bulletproof helmet spawner" diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index c43f32daacbdf..5dc826e8fd51e 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -552,26 +552,26 @@ if(ispath(trim)) SSid_access.apply_trim_to_card(src, trim) -/obj/item/card/id/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/rupee)) +/obj/item/card/id/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(istype(tool, /obj/item/rupee)) to_chat(user, span_warning("Your ID smartly rejects the strange shard of glass. Who knew, apparently it's not ACTUALLY valuable!")) - return - else if(iscash(W)) - insert_money(W, user) - return - else if(istype(W, /obj/item/storage/bag/money)) - var/obj/item/storage/bag/money/money_bag = W + return ITEM_INTERACT_BLOCKING + else if(iscash(tool)) + return insert_money(tool, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING + else if(istype(tool, /obj/item/storage/bag/money)) + var/obj/item/storage/bag/money/money_bag = tool var/list/money_contained = money_bag.contents var/money_added = mass_insert_money(money_contained, user) - if (money_added) - to_chat(user, span_notice("You stuff the contents into the card! They disappear in a puff of bluespace smoke, adding [money_added] worth of credits to the linked account.")) - return - else - return ..() + if(!money_added) + return ITEM_INTERACT_BLOCKING + to_chat(user, span_notice("You stuff the contents into the card! They disappear in a puff of bluespace smoke, adding [money_added] worth of credits to the linked account.")) + return ITEM_INTERACT_SUCCESS + return NONE /** * Insert credits or coins into the ID card and add their value to the associated bank account. * + * Returns TRUE if the money was successfully inserted, FALSE otherwise. * Arguments: * money - The item to attempt to convert to credits and insert into the card. * user - The user inserting the item. @@ -584,11 +584,11 @@ if(!registered_account) to_chat(user, span_warning("[src] doesn't have a linked account to deposit [money] into!")) - return + return FALSE var/cash_money = money.get_item_credit_value() if(!cash_money) to_chat(user, span_warning("[money] doesn't seem to be worth anything!")) - return + return FALSE registered_account.adjust_money(cash_money, "System: Deposit") SSblackbox.record_feedback("amount", "credits_inserted", cash_money) log_econ("[cash_money] credits were inserted into [src] owned by [src.registered_name]") @@ -599,6 +599,7 @@ to_chat(user, span_notice("The linked account now reports a balance of [registered_account.account_balance] cr.")) qdel(money) + return TRUE /** * Insert multiple money or money-equivalent items at once. @@ -953,20 +954,41 @@ return ..() - -/obj/item/card/id/advanced/attackby(obj/item/W, mob/user, params) +/obj/item/card/id/advanced/item_interaction(mob/living/user, obj/item/tool, list/modifiers) . = ..() - if(istype(W, /obj/item/toy/crayon)) - var/obj/item/toy/crayon/our_crayon = W - if(tgui_alert(usr, "Recolor Department or Subdepartment?", "Recoloring ID...", list("Department", "Subdepartment")) == "Department") - if(!do_after(user, 2 SECONDS)) // Doesn't technically require a spraycan's cap to be off but shhh - return + if(.) + return . + + if(istype(tool, /obj/item/toy/crayon)) + return recolor_id(user, tool) + +/obj/item/card/id/advanced/proc/recolor_id(mob/living/user, obj/item/toy/crayon/our_crayon) + if(our_crayon.is_capped) + balloon_alert(user, "take the cap off first!") + return ITEM_INTERACT_BLOCKING + var/choice = tgui_alert(usr, "Recolor Department or Subdepartment?", "Recoloring ID...", list("Department", "Subdepartment")) + if(isnull(choice) \ + || QDELETED(user) \ + || QDELETED(src) \ + || QDELETED(our_crayon) \ + || !usr.can_perform_action(src, ALLOW_RESTING) \ + || !usr.can_perform_action(our_crayon, ALLOW_RESTING) \ + ) + return ITEM_INTERACT_BLOCKING + + switch(choice) + if("Department") + if(!do_after(user, 2 SECONDS)) + return ITEM_INTERACT_BLOCKING department_color_override = our_crayon.paint_color balloon_alert(user, "recolored") - else if(do_after(user, 1 SECONDS)) + if("Subdepartment") + if(!do_after(user, 1 SECONDS)) + return ITEM_INTERACT_BLOCKING subdepartment_color_override = our_crayon.paint_color balloon_alert(user, "recolored") - update_icon() + update_icon() + return ITEM_INTERACT_SUCCESS /obj/item/card/id/advanced/proc/update_intern_status(datum/source, mob/user, slot) SIGNAL_HANDLER @@ -1275,27 +1297,38 @@ /// Time left on a card till they can leave. var/time_left = 0 -/obj/item/card/id/advanced/prisoner/attackby(obj/item/card/id/C, mob/user) - ..() - var/list/id_access = C.GetAccess() +/obj/item/card/id/advanced/prisoner/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = ..() + if(.) + return . + + if(isidcard(tool)) + return set_sentence_time(user, tool) + +/obj/item/card/id/advanced/prisoner/proc/set_sentence_time(mob/living/user, obj/item/card/id/our_card) + var/list/id_access = our_card.GetAccess() if(!(ACCESS_BRIG in id_access)) - return FALSE - if(loc != user) + balloon_alert(user, "access denied!") + return ITEM_INTERACT_BLOCKING + if(!user.is_holding(src)) to_chat(user, span_warning("You must be holding the ID to continue!")) - return FALSE - if(timed) + return ITEM_INTERACT_BLOCKING + + if(timed) // If we already have a time set, reset the card timed = FALSE time_to_assign = initial(time_to_assign) registered_name = initial(registered_name) STOP_PROCESSING(SSobj, src) - to_chat(user, "Restating prisoner ID to default parameters.") - return + to_chat(user, "Resetting prisoner ID to default parameters.") + return ITEM_INTERACT_SUCCESS + var/choice = tgui_input_number(user, "Sentence time in seconds", "Sentencing") - if(!choice || QDELETED(user) || QDELETED(src) || !usr.can_perform_action(src, FORBID_TELEKINESIS_REACH) || loc != user) - return FALSE + if(isnull(choice) || QDELETED(user) || QDELETED(src) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH) || !user.is_holding(src)) + return ITEM_INTERACT_BLOCKING time_to_assign = choice - to_chat(user, "You set the sentence time to [time_to_assign] seconds.") + to_chat(user, "You set the sentence time to [DisplayTimeText(time_to_assign * 10)].") timed = TRUE + return ITEM_INTERACT_SUCCESS /obj/item/card/id/advanced/prisoner/proc/start_timer() say("Sentence started, welcome to the corporate rehabilitation center!") @@ -1307,10 +1340,15 @@ return if(timed) - if(time_left <= 0) + if(time_to_assign > 0) + . += span_notice("The digital timer on the card is set to [DisplayTimeText(time_to_assign * 10)]. The timer will start once the prisoner passes through the prison gate scanners.") + else if(time_left <= 0) . += span_notice("The digital timer on the card has zero seconds remaining. You leave a changed man, but a free man nonetheless.") else - . += span_notice("The digital timer on the card has [time_left] seconds remaining. Don't do the crime if you can't do the time.") + . += span_notice("The digital timer on the card has [DisplayTimeText(time_left * 10)] remaining. Don't do the crime if you can't do the time.") + + . += span_notice("[EXAMINE_HINT("Swipe")] a security ID on the card to [timed ? "re" : ""]set the genpop sentence time.") + . += span_notice("Remember to [EXAMINE_HINT("swipe")] the card on a genpop locker to link it.") /obj/item/card/id/advanced/prisoner/process(seconds_per_tick) if(!timed) @@ -1761,11 +1799,10 @@ voice_name += " (as [scribbled_name])" stored_name[NAME_PART_INDEX] = voice_name -/obj/item/card/cardboard/attackby(obj/item/item, mob/living/user, params) - if(user.can_write(item, TRUE)) - INVOKE_ASYNC(src, PROC_REF(modify_card), user, item) - return TRUE - return ..() +/obj/item/card/cardboard/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(user.can_write(tool, TRUE)) + INVOKE_ASYNC(src, PROC_REF(modify_card), user, tool) + return ITEM_INTERACT_SUCCESS ///Lets the user write a name, assignment or trim on the card, or reset it. Only the name is important for the component. /obj/item/card/cardboard/proc/modify_card(mob/living/user, obj/item/item) diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index 174a8fde5f7c2..be5d0b8ec2b1c 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -55,6 +55,10 @@ CIGARETTE PACKETS ARE IN FANCY.DM desc = "A [initial(name)]. This one is lit." attack_verb_continuous = string_list(list("burns", "singes")) attack_verb_simple = string_list(list("burn", "singe")) + if(isliving(loc)) + var/mob/living/male_model = loc + if(male_model.fire_stacks && !(male_model.on_fire)) + male_model.ignite_mob() START_PROCESSING(SSobj, src) update_appearance() @@ -282,7 +286,8 @@ CIGARETTE PACKETS ARE IN FANCY.DM var/obj/item/reagent_containers/cup/glass = interacting_with if(!istype(glass)) //you can dip cigarettes into beakers return NONE - + if(istype(glass, /obj/item/reagent_containers/cup/mortar)) + return NONE if(glass.reagents.trans_to(src, chem_volume, transferred_by = user)) //if reagents were transferred, show the message to_chat(user, span_notice("You dip \the [src] into \the [glass].")) //if not, either the beaker was empty, or the cigarette was full @@ -875,6 +880,10 @@ CIGARETTE PACKETS ARE IN FANCY.DM attack_verb_continuous = string_list(list("burns", "singes")) attack_verb_simple = string_list(list("burn", "singe")) START_PROCESSING(SSobj, src) + if(isliving(loc)) + var/mob/living/male_model = loc + if(male_model.fire_stacks && !(male_model.on_fire)) + male_model.ignite_mob() else hitsound = SFX_SWING_HIT force = 0 diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 99e7c43235ab9..67ec498a1fbc6 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -170,7 +170,7 @@ organ_list += (O.gender == "plural" ? O.name : "\an [O.name]") var/pill_count = 0 - for(var/datum/action/item_action/hands_free/activate_pill/AP in M.actions) + for(var/datum/action/item_action/activate_pill/AP in M.actions) pill_count++ if(M == user)//if we're looking on our own mouth diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm index c3203a0ace7a9..598c16c9041a8 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -211,6 +211,7 @@ it explodes properly when it gets a signal (and it does). */ /obj/item/transfer_valve/proc/toggle_valve(obj/item/tank/target, change_volume = TRUE) + playsound(src, 'sound/effects/valve_opening.ogg', 50) if(!valve_open && tank_one && tank_two) var/turf/bombturf = get_turf(src) diff --git a/code/game/objects/items/dna_injector.dm b/code/game/objects/items/dna_injector.dm index 0dc20c6dbb4d9..8fee497a4f9ee 100644 --- a/code/game/objects/items/dna_injector.dm +++ b/code/game/objects/items/dna_injector.dm @@ -163,7 +163,7 @@ /obj/item/dnainjector/activator name = "\improper DNA activator" desc = "Activates the current mutation on injection, if the subject has it." - var/doitanyway = FALSE + var/force_mutate = FALSE var/research = FALSE //Set to true to get expended and filled injectors for chromosomes var/filled = FALSE var/crispr_charge = FALSE // Look for viruses, look at symptoms, if research and Dormant DNA Activator or Viral Evolutionary Acceleration, set to true @@ -176,7 +176,7 @@ if(istype(added_mutation, /datum/mutation/human)) mutation = added_mutation.type if(!target.dna.activate_mutation(added_mutation)) - if(doitanyway) + if(force_mutate) target.dna.add_mutation(added_mutation, MUT_EXTRA) else if(research && target.client) filled = TRUE @@ -184,7 +184,7 @@ for(var/datum/symptom/symp in disease.symptoms) if((symp.type == /datum/symptom/genetic_mutation) || (symp.type == /datum/symptom/viralevolution)) crispr_charge = TRUE - log_combat(user, target, "[!doitanyway ? "failed to inject" : "injected"]", "[src] ([mutation])[crispr_charge ? " with CRISPR charge" : ""]") + log_combat(user, target, "[!force_mutate ? "failed to inject" : "injected"]", "[src] ([mutation])[crispr_charge ? " with CRISPR charge" : ""]") return TRUE /// DNA INJECTORS diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm index be47d7009053b..ac309e275d77c 100644 --- a/code/game/objects/items/extinguisher.dm +++ b/code/game/objects/items/extinguisher.dm @@ -32,7 +32,11 @@ /// Can we refill this at a water tank? var/refilling = FALSE /// What tank we need to refill this. - var/tanktype = /obj/structure/reagent_dispensers/watertank + var/tanktypes = list( + /obj/structure/reagent_dispensers/watertank, + /obj/structure/reagent_dispensers/plumbed, + /obj/structure/reagent_dispensers/water_cooler, + ) /// something that should be replaced with base_icon_state var/sprite_name = "fire_extinguisher" /// Maximum distance launched water will travel. @@ -131,7 +135,10 @@ tank_holder_icon_state = "holder_foam_extinguisher" dog_fashion = null chem = /datum/reagent/firefighting_foam - tanktype = /obj/structure/reagent_dispensers/foamtank + tanktypes = list( + /obj/structure/reagent_dispensers/foamtank, + /obj/structure/reagent_dispensers/plumbed, + ) sprite_name = "foam_extinguisher" precision = TRUE max_water = 100 @@ -178,10 +185,14 @@ . += span_notice("Alt-click to empty it.") /obj/item/extinguisher/proc/AttemptRefill(atom/target, mob/user) - if(istype(target, tanktype) && target.Adjacent(user)) + if(is_type_in_list(target, tanktypes) && target.Adjacent(user)) if(reagents.total_volume == reagents.maximum_volume) balloon_alert(user, "already full!") return TRUE + // Make sure we're refilling with the proper chem. + if(!(target.reagents.has_reagent(chem))) + balloon_alert(user, "can't refill with this liquid!") + return TRUE var/obj/structure/reagent_dispensers/W = target //will it work? var/transferred = W.reagents.trans_to(src, max_water, transferred_by = user) if(transferred > 0) @@ -305,5 +316,8 @@ name = "fire extender" desc = "A traditional red fire extinguisher. Made in Britain... wait, what?" chem = /datum/reagent/fuel - tanktype = /obj/structure/reagent_dispensers/fueltank + tanktypes = list( + /obj/structure/reagent_dispensers/fueltank, + /obj/structure/reagent_dispensers/plumbed + ) cooling_power = 0 diff --git a/code/game/objects/items/food/misc.dm b/code/game/objects/items/food/misc.dm index 0e598c6820296..31ac87c0ff690 100644 --- a/code/game/objects/items/food/misc.dm +++ b/code/game/objects/items/food/misc.dm @@ -184,7 +184,7 @@ /obj/item/food/melonfruitbowl name = "melon fruit bowl" - desc = "For people who wants edible fruit bowls." + desc = "For people who want to experience an explosion of flavour." icon_state = "melonfruitbowl" food_reagents = list( /datum/reagent/consumable/nutriment = 6, diff --git a/code/game/objects/items/grenades/_grenade.dm b/code/game/objects/items/grenades/_grenade.dm index 5deb833b1f234..ec16b4c22fe95 100644 --- a/code/game/objects/items/grenades/_grenade.dm +++ b/code/game/objects/items/grenades/_grenade.dm @@ -16,7 +16,6 @@ flags_1 = PREVENT_CONTENTS_EXPLOSION_1 // We detonate upon being exploded. obj_flags = CONDUCTS_ELECTRICITY slot_flags = ITEM_SLOT_BELT - resistance_flags = FLAMMABLE max_integrity = 40 /// Bitfields which prevent the grenade from detonating if set. Includes ([GRENADE_DUD]|[GRENADE_USED]) var/dud_flags = NONE diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index ffcb5d1857cda..d3e8bdd0ad88d 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -523,6 +523,7 @@ /obj/item/restraints/legcuffs/beartrap/energy/cyborg breakouttime = 2 SECONDS // Cyborgs shouldn't have a strong restraint + slowdown = 3 /obj/item/restraints/legcuffs/bola name = "bola" diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 2d886163a50ba..1a695442d8a76 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -425,6 +425,7 @@ . = ..() if(!.) return . + ADD_TRAIT(cyborg, TRAIT_FASTMED, REF(src)) for(var/obj/item/borg/cyborg_omnitool/medical/omnitool_upgrade in cyborg.model.modules) if(omnitool_upgrade.upgraded) to_chat(user, span_warning("This unit is already equipped with an omnitool upgrade!")) @@ -436,6 +437,7 @@ . = ..() if(!.) return . + REMOVE_TRAIT(cyborg, TRAIT_FASTMED, REF(src)) for(var/obj/item/borg/cyborg_omnitool/omnitool in cyborg.model.modules) omnitool.downgrade_omnitool() diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 7b6d4b6207340..662f94c61d5e1 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -347,6 +347,12 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \ new /datum/stack_recipe("pew (left)", /obj/structure/chair/pew/left, 3, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), new /datum/stack_recipe("pew (right)", /obj/structure/chair/pew/right, 3, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE) )), + new/datum/stack_recipe_list("peg limbs", list( + new /datum/stack_recipe("peg arm (left)", /obj/item/bodypart/arm/left/ghetto, 2, crafting_flags = NONE, category = CAT_MISC), + new /datum/stack_recipe("peg arm (right)", /obj/item/bodypart/arm/right/ghetto, 2, crafting_flags = NONE, category = CAT_MISC), + new /datum/stack_recipe("peg leg (left)", /obj/item/bodypart/leg/left/ghetto, 2, crafting_flags = NONE, category = CAT_MISC), + new /datum/stack_recipe("peg leg (right)", /obj/item/bodypart/leg/right/ghetto, 2, crafting_flags = NONE, category = CAT_MISC) + )), null, \ )) @@ -377,6 +383,21 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \ /obj/item/stack/sheet/mineral/wood/fifty amount = 50 +/obj/item/stack/sheet/mineral/wood/interact_with_atom(mob/living/carbon/human/target, mob/user) + if(!istype(target)) + return NONE + + var/obj/item/bodypart/affecting = target.get_bodypart(check_zone(user.zone_selected)) + if(affecting && IS_PEG_LIMB(affecting)) + if(user == target) + user.visible_message(span_notice("[user] starts to fix their [affecting.name]."), span_notice("You start fixing [target == user ? "your" : "[target]'s"] [affecting.name].")) + if(!do_after(user, 5 SECONDS, target)) + return ITEM_INTERACT_FAILURE + if(target.item_heal(user, brute_heal = 15, burn_heal = 15, heal_message_brute = "splintering", heal_message_burn = "charring", required_bodytype = BODYTYPE_PEG)) + use(1) + return ITEM_INTERACT_SUCCESS + else + return NONE /* * Bamboo */ diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm index 72c84c9ee995e..fe15dab29588e 100644 --- a/code/game/objects/items/tanks/tanks.dm +++ b/code/game/objects/items/tanks/tanks.dm @@ -445,7 +445,7 @@ balloon_alert(user, "can't reach!") return - if((src in user.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE)) && !user.canUnEquip(src)) + if((src in user.get_equipped_items(INCLUDE_POCKETS | INCLUDE_ACCESSORIES)) && !user.canUnEquip(src)) balloon_alert(user, "it's stuck!") return diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm index 0e9b9743a4593..b2b0109c04c88 100644 --- a/code/game/objects/items/tools/weldingtool.dm +++ b/code/game/objects/items/tools/weldingtool.dm @@ -160,7 +160,7 @@ if(!use_tool(attacked_humanoid, user, use_delay, volume=50, amount=1)) return ITEM_INTERACT_BLOCKING - item_heal_robotic(attacked_humanoid, user, 15, 0) + attacked_humanoid.item_heal(user, brute_heal = 15, burn_heal = 0, heal_message_brute = "dents", heal_message_burn = "burnt wires", required_bodytype = BODYTYPE_ROBOTIC) return ITEM_INTERACT_SUCCESS /obj/item/weldingtool/afterattack(atom/target, mob/user, click_parameters) diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 9ebcbb253d20b..d07f7ad21c5f5 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -132,6 +132,7 @@ take_damage(clamp(0.02 * exposed_temperature, 0, 20), BURN, FIRE, 0) if(!(resistance_flags & ON_FIRE) && (resistance_flags & FLAMMABLE) && !(resistance_flags & FIRE_PROOF)) AddComponent(/datum/component/burning, custom_fire_overlay || GLOB.fire_overlay, burning_particles) + SEND_SIGNAL(src, COMSIG_ATOM_FIRE_ACT, exposed_temperature, exposed_volume) return TRUE return ..() diff --git a/code/game/objects/structures/mystery_box.dm b/code/game/objects/structures/mystery_box.dm index ab8a25f04c675..9dc8152f5b7bf 100644 --- a/code/game/objects/structures/mystery_box.dm +++ b/code/game/objects/structures/mystery_box.dm @@ -85,7 +85,6 @@ GLOBAL_LIST_INIT(mystery_magic, list( /obj/item/gun/magic/staff/door, /obj/item/gun/magic/staff/honk, /obj/item/gun/magic/staff/spellblade, - /obj/item/gun/magic/staff/locker, /obj/item/gun/magic/staff/flying, /obj/item/gun/magic/staff/babel, /obj/item/singularityhammer, diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 515f1513ac754..565adb22dbc00 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -568,7 +568,6 @@ GLOBAL_LIST_EMPTY(station_turfs) if(EXPLODE_LIGHT) SSexplosions.low_mov_atom += movable_thing - /turf/narsie_act(force, ignore_mobs, probability = 20) . = (prob(probability) || force) for(var/I in src) diff --git a/code/modules/admin/verbs/ert.dm b/code/modules/admin/verbs/ert.dm index c86d08151ee62..2d1ba075a4795 100644 --- a/code/modules/admin/verbs/ert.dm +++ b/code/modules/admin/verbs/ert.dm @@ -25,7 +25,7 @@ /datum/admins/proc/equipAntagOnDummy(mob/living/carbon/human/dummy/mannequin, datum/antagonist/antag) - for(var/I in mannequin.get_equipped_items(include_pockets = TRUE)) + for(var/I in mannequin.get_equipped_items(INCLUDE_POCKETS)) qdel(I) if (ispath(antag, /datum/antagonist/ert)) var/datum/antagonist/ert/ert = antag diff --git a/code/modules/admin/verbs/selectequipment.dm b/code/modules/admin/verbs/selectequipment.dm index b94fd5cb2e455..415130fa1b727 100644 --- a/code/modules/admin/verbs/selectequipment.dm +++ b/code/modules/admin/verbs/selectequipment.dm @@ -209,7 +209,8 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(select_equipment, R_FUN, "Select Equipment", mob/ta delete_pocket = TRUE BLACKBOX_LOG_ADMIN_VERB("Select Equipment") - for(var/obj/item/item in human_target.get_equipped_items(include_pockets = delete_pocket)) + var/includes_flags = delete_pocket ? INCLUDE_POCKETS : NONE + for(var/obj/item/item in human_target.get_equipped_items(includes_flags)) qdel(item) var/obj/item/organ/internal/brain/human_brain = human_target.get_organ_slot(BRAIN) diff --git a/code/modules/antagonists/changeling/changeling_power.dm b/code/modules/antagonists/changeling/changeling_power.dm index 23b4f9548c424..d06d8fe91735a 100644 --- a/code/modules/antagonists/changeling/changeling_power.dm +++ b/code/modules/antagonists/changeling/changeling_power.dm @@ -32,6 +32,8 @@ var/ignores_fakedeath = FALSE /// used by a few powers that toggle var/active = FALSE + /// Does this ability stop working if you are burning? + var/disabled_by_fire = TRUE /* changeling code now relies on on_purchase to grant powers. @@ -61,6 +63,9 @@ the same goes for Remove(). if you override Remove(), call parent or else your p /datum/action/changeling/proc/try_to_sting(mob/living/user, mob/living/target) if(!can_sting(user, target)) return FALSE + if(disabled_by_fire && user.fire_stacks && user.on_fire) + user.balloon_alert(user, "on fire!") + return FALSE var/datum/antagonist/changeling/changeling = IS_CHANGELING(user) if(sting_action(user, target)) sting_feedback(user, target) diff --git a/code/modules/antagonists/changeling/powers/adrenaline.dm b/code/modules/antagonists/changeling/powers/adrenaline.dm index 9d2abfe623314..3b6a550b18b0f 100644 --- a/code/modules/antagonists/changeling/powers/adrenaline.dm +++ b/code/modules/antagonists/changeling/powers/adrenaline.dm @@ -1,12 +1,13 @@ /datum/action/changeling/adrenaline name = "Repurposed Glands" - desc = "We shift almost all available muscle mass from the arms to the legs, disabling the former but making us unable to be downed for 15 seconds. Costs 10 chemicals." + desc = "We shift almost all available muscle mass from the arms to the legs, disabling the former but making us unable to be downed for 20 seconds. Costs 25 chemicals." helptext = "Disables your arms and retracts bioweaponry, but regenerates your legs, grants you speed, and wakes you up from any stun." button_icon_state = "adrenaline" chemical_cost = 25 // similar cost to biodegrade, as they serve similar purposes dna_cost = 2 req_human = FALSE req_stat = CONSCIOUS + disabled_by_fire = FALSE /datum/action/changeling/adrenaline/can_sting(mob/living/user, mob/living/target) . = ..() diff --git a/code/modules/antagonists/changeling/powers/biodegrade.dm b/code/modules/antagonists/changeling/powers/biodegrade.dm index 2b1753c27273a..8a5fae3bd8aed 100644 --- a/code/modules/antagonists/changeling/powers/biodegrade.dm +++ b/code/modules/antagonists/changeling/powers/biodegrade.dm @@ -6,6 +6,7 @@ chemical_cost = 30 //High cost to prevent spam dna_cost = 2 req_human = TRUE + disabled_by_fire = FALSE /datum/action/changeling/biodegrade/sting_action(mob/living/carbon/human/user) if(user.handcuffed) diff --git a/code/modules/antagonists/changeling/powers/defib_grasp.dm b/code/modules/antagonists/changeling/powers/defib_grasp.dm index 135b9b243f721..867a595e17dcd 100644 --- a/code/modules/antagonists/changeling/powers/defib_grasp.dm +++ b/code/modules/antagonists/changeling/powers/defib_grasp.dm @@ -6,6 +6,7 @@ while we are dead or in stasis. Will also stun cyborgs momentarily." owner_has_control = FALSE dna_cost = 0 + disabled_by_fire = FALSE /// Flags to pass to fully heal when we get zapped var/heal_flags = HEAL_DAMAGE|HEAL_BODY|HEAL_STATUS|HEAL_CC_STATUS diff --git a/code/modules/antagonists/changeling/powers/fakedeath.dm b/code/modules/antagonists/changeling/powers/fakedeath.dm index 75d4996b8b2d7..1dff58377fd4a 100644 --- a/code/modules/antagonists/changeling/powers/fakedeath.dm +++ b/code/modules/antagonists/changeling/powers/fakedeath.dm @@ -7,6 +7,7 @@ req_dna = 1 req_stat = DEAD ignores_fakedeath = TRUE + disabled_by_fire = FALSE /// How long it takes for revival to ready upon entering stasis. /// The changeling can opt to stay in fakedeath for longer, though. diff --git a/code/modules/antagonists/changeling/powers/headcrab.dm b/code/modules/antagonists/changeling/powers/headcrab.dm index 30970832df0a4..0b7668260d769 100644 --- a/code/modules/antagonists/changeling/powers/headcrab.dm +++ b/code/modules/antagonists/changeling/powers/headcrab.dm @@ -8,6 +8,7 @@ req_human = TRUE req_stat = DEAD ignores_fakedeath = TRUE + disabled_by_fire = FALSE /datum/action/changeling/headcrab/sting_action(mob/living/user) set waitfor = FALSE diff --git a/code/modules/antagonists/changeling/powers/shriek.dm b/code/modules/antagonists/changeling/powers/shriek.dm index aa204d89a166e..cfbcc7b64ec27 100644 --- a/code/modules/antagonists/changeling/powers/shriek.dm +++ b/code/modules/antagonists/changeling/powers/shriek.dm @@ -6,6 +6,7 @@ chemical_cost = 20 dna_cost = 1 req_human = TRUE + disabled_by_fire = FALSE //A flashy ability, good for crowd control and sowing chaos. /datum/action/changeling/resonant_shriek/sting_action(mob/user) @@ -41,6 +42,7 @@ button_icon_state = "dissonant_shriek" chemical_cost = 20 dna_cost = 1 + disabled_by_fire = FALSE /datum/action/changeling/dissonant_shriek/sting_action(mob/user) ..() diff --git a/code/modules/antagonists/changeling/powers/strained_muscles.dm b/code/modules/antagonists/changeling/powers/strained_muscles.dm index 19c4458a388bc..3ea59f5df089b 100644 --- a/code/modules/antagonists/changeling/powers/strained_muscles.dm +++ b/code/modules/antagonists/changeling/powers/strained_muscles.dm @@ -11,6 +11,7 @@ req_human = TRUE var/stacks = 0 //Increments every 5 seconds; damage increases over time active = FALSE //Whether or not you are a hedgehog + disabled_by_fire = FALSE /datum/action/changeling/strained_muscles/sting_action(mob/living/carbon/user) ..() diff --git a/code/modules/antagonists/heretic/heretic_antag.dm b/code/modules/antagonists/heretic/heretic_antag.dm index 9c41c54e84e09..416dbe390e16f 100644 --- a/code/modules/antagonists/heretic/heretic_antag.dm +++ b/code/modules/antagonists/heretic/heretic_antag.dm @@ -56,6 +56,8 @@ var/static/list/blacklisted_rune_turfs = typecacheof(list(/turf/open/space, /turf/open/openspace, /turf/open/lava, /turf/open/chasm)) /// Controls what types of turf we can spread rust to, increases as we unlock more powerful rust abilites var/rust_strength = 0 + /// Wether we are allowed to ascend + var/feast_of_owls = FALSE /// Static list of what each path converts to in the UI (colors are TGUI colors) var/static/list/path_to_ui_color = list( PATH_START = "grey", @@ -478,7 +480,8 @@ succeeded = FALSE parts += "Objective #[count]: [objective.explanation_text] [objective.get_roundend_success_suffix()]" count++ - + if(feast_of_owls) + parts += span_greentext("Ascension Forsaken") if(ascended) parts += span_greentext(span_big("THE HERETIC ASCENDED!")) @@ -695,6 +698,8 @@ /datum/antagonist/heretic/proc/can_ascend() if(!can_assign_self_objectives) return FALSE // We spurned the offer of the Mansus :( + if(feast_of_owls) + return FALSE // We sold our ambition for immediate power :/ for(var/datum/objective/must_be_done as anything in objectives) if(!must_be_done.check_completion()) return FALSE diff --git a/code/modules/antagonists/heretic/items/eldritch_painting.dm b/code/modules/antagonists/heretic/items/eldritch_painting.dm index 5302fc1c9c148..3332c4e31ba63 100644 --- a/code/modules/antagonists/heretic/items/eldritch_painting.dm +++ b/code/modules/antagonists/heretic/items/eldritch_painting.dm @@ -4,14 +4,14 @@ icon = 'icons/obj/signs.dmi' resistance_flags = FLAMMABLE flags_1 = NONE - icon_state = "frame-empty" + icon_state = "eldritch_painting_debug" result_path = /obj/structure/sign/painting/eldritch pixel_shift = 30 /obj/structure/sign/painting/eldritch name = "The debug and a coder who slept" icon = 'icons/obj/signs.dmi' - icon_state = "frame-empty" + icon_state = "eldritch_painting_debug" custom_materials = list(/datum/material/wood =SHEET_MATERIAL_AMOUNT) resistance_flags = FLAMMABLE buildable_sign = FALSE diff --git a/code/modules/antagonists/heretic/knowledge/moon_lore.dm b/code/modules/antagonists/heretic/knowledge/moon_lore.dm index e2af5390ba810..4b61648329214 100644 --- a/code/modules/antagonists/heretic/knowledge/moon_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/moon_lore.dm @@ -188,7 +188,6 @@ /datum/heretic_knowledge/ultimate/moon_final/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc) . = ..() - var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(user) priority_announce( text = "[generate_heretic_text()] Laugh, for the ringleader [user.real_name] has ascended! \ The truth shall finally devour the lie! [generate_heretic_text()]", @@ -199,8 +198,7 @@ user.client?.give_award(/datum/award/achievement/misc/moon_ascension, user) ADD_TRAIT(user, TRAIT_MADNESS_IMMUNE, REF(src)) - heretic_datum.add_team_hud(user, /datum/antagonist/lunatic) - + user.mind.add_antag_datum(/datum/antagonist/lunatic/master) RegisterSignal(user, COMSIG_LIVING_LIFE, PROC_REF(on_life)) // Roughly 1/5th of the station will rise up as lunatics to the heretic diff --git a/code/modules/antagonists/heretic/knowledge/starting_lore.dm b/code/modules/antagonists/heretic/knowledge/starting_lore.dm index f1b5f7f55ea19..50b57fd9e96b4 100644 --- a/code/modules/antagonists/heretic/knowledge/starting_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/starting_lore.dm @@ -293,3 +293,28 @@ GLOBAL_LIST_INIT(heretic_start_knowledge, initialize_starting_knowledge()) body.do_jitter_animation() body.visible_message(span_danger("An awful ripping sound is heard as [ripped_thing]'s [exterior_text] is ripped straight out, wrapping around [le_book || "the book"], turning into an eldritch shade of blue!")) return ..() + +/datum/heretic_knowledge/feast_of_owls + name = "Feast of Owls" + desc = "Allows you to undergo a ritual that gives you 5 knowledge points but locks you out of ascension. This can only be done once and cannot be reverted." + gain_text = "Under the soft glow of unreason there is a beast that stalks the night. I shall bring it forth and let it enter my presence. It will feast upon my amibitions and leave knowledge in its wake." + route = PATH_START + required_atoms = list() + +/datum/heretic_knowledge/feast_of_owls/can_be_invoked(datum/antagonist/heretic/invoker) + return !invoker.feast_of_owls + +/datum/heretic_knowledge/feast_of_owls/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc) + var/alert = tgui_alert(user,"Do you really want to forsake your ascension? This action cannot be reverted.", "Feast of Owls", list("Yes I'm sure", "No"), 30 SECONDS) + if( alert != "Yes I'm sure") + return FALSE + user.set_temp_blindness(5 SECONDS) + user.AdjustParalyzed(5 SECONDS) + var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(user) + for(var/i in 0 to 4) + user.emote("scream") + playsound(loc, 'sound/items/eatfood.ogg', 100, TRUE) + heretic_datum.knowledge_points++ + sleep(1 SECONDS) + to_chat(user,span_danger("You feel different...")) + heretic_datum.feast_of_owls = TRUE diff --git a/code/modules/antagonists/heretic/moon_lunatic.dm b/code/modules/antagonists/heretic/moon_lunatic.dm index dbc07a6b5054b..3d877ee962c11 100644 --- a/code/modules/antagonists/heretic/moon_lunatic.dm +++ b/code/modules/antagonists/heretic/moon_lunatic.dm @@ -13,16 +13,27 @@ var/datum/mind/ascended_heretic // The body of the ascended heretic who created us var/mob/living/carbon/human/ascended_body + // Our objective + var/datum/objective/lunatic/lunatic_obj + +/datum/antagonist/lunatic/on_gain() + // Masters gain an objective before so we dont want duplicates + for(var/objective in objectives) + if(!istype(objective, /datum/objective/lunatic)) + continue + return ..() + var/datum/objective/lunatic/loony = new() + objectives += loony + lunatic_obj = loony + return ..() /// Runs when the moon heretic creates us, used to give the lunatic a master /datum/antagonist/lunatic/proc/set_master(datum/mind/heretic_master, mob/living/carbon/human/heretic_body) src.ascended_heretic = heretic_master src.ascended_body = heretic_body - var/datum/objective/lunatic/lunatic_obj = new() lunatic_obj.master = heretic_master lunatic_obj.update_explanation_text() - objectives += lunatic_obj to_chat(owner, span_boldnotice("Ruin the lie, save the truth through obeying [heretic_master] the ringleader!")) @@ -30,8 +41,7 @@ var/mob/living/our_mob = mob_override || owner.current handle_clown_mutation(our_mob, "Ancient knowledge from the moon has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") our_mob.faction |= FACTION_HERETIC - add_team_hud(our_mob) - add_team_hud(our_mob, /datum/antagonist/heretic) + add_team_hud(our_mob, /datum/antagonist/lunatic) ADD_TRAIT(our_mob, TRAIT_MADNESS_IMMUNE, REF(src)) var/datum/action/cooldown/lunatic_track/moon_track = new /datum/action/cooldown/lunatic_track() @@ -52,7 +62,28 @@ /datum/objective/lunatic explanation_text = "Assist your ringleader. If you are seeing this, scroll up in chat for who that is and report this" var/datum/mind/master + // If the person with this objective is a lunatic master + var/is_master = FALSE /datum/objective/lunatic/update_explanation_text() . = ..() - explanation_text = "Assist your ringleader [master]" + if(is_master) + explanation_text = "Lead your lunatics to further your own goals!" + return + explanation_text = "Assist your ringleader [master], do not harm fellow lunatics" + +// Lunatic master +/datum/antagonist/lunatic/master + name = "\improper Ringleader" + antag_hud_name = "lunatic_master" + +/datum/antagonist/lunatic/master/on_gain() + var/datum/objective/lunatic/loony = new() + objectives += loony + loony.is_master = TRUE + loony.update_explanation_text() + return ..() + +/datum/antagonist/lunatic/master/apply_innate_effects(mob/living/mob_override) + var/mob/living/our_mob = mob_override || owner.current + add_team_hud(our_mob, /datum/antagonist/lunatic) diff --git a/code/modules/antagonists/obsessed/obsessed.dm b/code/modules/antagonists/obsessed/obsessed.dm index 3d0a0063bf709..db934c90df604 100644 --- a/code/modules/antagonists/obsessed/obsessed.dm +++ b/code/modules/antagonists/obsessed/obsessed.dm @@ -66,7 +66,7 @@ shoes = /obj/item/clothing/shoes/sneakers/black /datum/outfit/obsessed/post_equip(mob/living/carbon/human/H) - for(var/obj/item/carried_item in H.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE)) + for(var/obj/item/carried_item in H.get_equipped_items(INCLUDE_POCKETS | INCLUDE_ACCESSORIES)) carried_item.add_mob_blood(H)//Oh yes, there will be blood... H.regenerate_icons() diff --git a/code/modules/atmospherics/machinery/components/binary_devices/valve.dm b/code/modules/atmospherics/machinery/components/binary_devices/valve.dm index 32f3eb7419ced..aeb14c9b5dd28 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/valve.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/valve.dm @@ -25,6 +25,7 @@ It's like a regular ol' straight pipe, but you can turn it on and off. normalize_cardinal_directions() if(animation) flick("[valve_type]valve_[on][!on]-[set_overlay_offset(piping_layer)]", src) + playsound(src, 'sound/effects/valve_opening.ogg', 50) icon_state = "[valve_type]valve_[on ? "on" : "off"]-[set_overlay_offset(piping_layer)]" /** @@ -37,6 +38,7 @@ It's like a regular ol' straight pipe, but you can turn it on and off. . = on on = to_open if(on) + playsound(src, 'sound/effects/gas_hissing.ogg', 50) update_icon_nopipes() update_parents() var/datum/pipeline/parent1 = parents[1] diff --git a/code/modules/bitrunning/components/virtual_entity.dm b/code/modules/bitrunning/components/virtual_entity.dm index 12e5305ba9adc..db81f376a8094 100644 --- a/code/modules/bitrunning/components/virtual_entity.dm +++ b/code/modules/bitrunning/components/virtual_entity.dm @@ -31,6 +31,8 @@ /datum/component/virtual_entity/proc/jailbreak_mobs() SIGNAL_HANDLER - to_chat(parent, span_big("You shiver for a moment, then suddenly feel a sense of clarity you haven't felt before. \ - You can go anywhere, do anything! You could leave this simulation right now if you wanted!")) + to_chat(parent, span_boldannounce("You shiver for a moment with a sense of clarity you haven't felt before.")) + to_chat(parent, span_notice("You could go anywhere, do anything! You could leave this simulation right now if you wanted!")) + to_chat(parent, span_danger("But be warned, quantum entanglement will interfere with any previous lives.")) + to_chat(parent, span_notice("You'll have just one chance to go nova, and there's no turning back.")) qdel(src) diff --git a/code/modules/bitrunning/designs.dm b/code/modules/bitrunning/designs.dm index 4e7bca1c1a8dd..96ae65d41e99b 100644 --- a/code/modules/bitrunning/designs.dm +++ b/code/modules/bitrunning/designs.dm @@ -72,16 +72,3 @@ RND_CATEGORY_COMPUTER + RND_SUBCATEGORY_COMPUTER_CARGO ) departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING - - -/datum/techweb_node/bitrunning - id = "bitrunning" - display_name = "Bitrunning Technology" - description = "Bluespace technology has led to the development of quantum-scale computing, which unlocks the means to materialize atomic structures while executing advanced programs." - prereq_ids = list("practical_bluespace") - design_ids = list( - "byteforge", - "quantum_console", - "netpod", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) diff --git a/code/modules/bitrunning/event.dm b/code/modules/bitrunning/event.dm index 4cc95f4f0578a..16190851f3720 100644 --- a/code/modules/bitrunning/event.dm +++ b/code/modules/bitrunning/event.dm @@ -89,6 +89,10 @@ if(!unlucky_server.validate_mutation_candidates()) return WAITING_FOR_SOMETHING - spawned_mobs = unlucky_server.setup_glitch(forced_role) + var/mob/spawned = unlucky_server.setup_glitch(forced_role) + if(isnull(spawned)) + return WAITING_FOR_SOMETHING + + spawned_mobs += spawned return SUCCESSFUL_SPAWN diff --git a/code/modules/bitrunning/objects/disks.dm b/code/modules/bitrunning/objects/disks.dm index 6e166d5eb7fdb..17b768c54d08f 100644 --- a/code/modules/bitrunning/objects/disks.dm +++ b/code/modules/bitrunning/objects/disks.dm @@ -142,3 +142,46 @@ /obj/item/dualsaber/green, /obj/item/grenade/syndieminibomb, ) + +///proto-kinetic accelerator mods, to be applied to pka's given inside domains +/obj/item/bitrunning_disk/item/pka_mods + name = "bitrunning gear: proto-kinetic accelerator mods" + selectable_items = list( + /obj/item/borg/upgrade/modkit/range, + /obj/item/borg/upgrade/modkit/damage, + /obj/item/borg/upgrade/modkit/cooldown, + /obj/item/borg/upgrade/modkit/aoe/mobs, + /obj/item/borg/upgrade/modkit/human_passthrough, + ) + +/obj/item/bitrunning_disk/item/pka_mods/premium + name = "bitrunning gear: premium proto-kinetic accelerator mods" + selectable_items = list( + /obj/item/borg/upgrade/modkit/cooldown/repeater, + /obj/item/borg/upgrade/modkit/lifesteal, + /obj/item/borg/upgrade/modkit/resonator_blasts, + /obj/item/borg/upgrade/modkit/bounty, + /obj/item/borg/upgrade/modkit/indoors, + ) + +///proto-kinetic crusher trophies, to be applied to pkc's given inside domains +/obj/item/bitrunning_disk/item/pkc_mods + name = "bitrunning gear: proto-kinetic crusher mods" + selectable_items = list( + /obj/item/crusher_trophy/watcher_wing, + /obj/item/crusher_trophy/blaster_tubes/magma_wing, + /obj/item/crusher_trophy/legion_skull, + /obj/item/crusher_trophy/wolf_ear, + ) + +/obj/item/bitrunning_disk/item/pkc_mods/premium + name = "bitrunning gear: premium proto-kinetic crusher mods" + selectable_items = list( + /obj/item/crusher_trophy/watcher_wing/ice_wing, + /obj/item/crusher_trophy/blaster_tubes, + /obj/item/crusher_trophy/miner_eye, + /obj/item/crusher_trophy/tail_spike, + /obj/item/crusher_trophy/demon_claws, + /obj/item/crusher_trophy/vortex_talisman, + /obj/item/crusher_trophy/ice_demon_cube, + ) diff --git a/code/modules/bitrunning/objects/hololadder.dm b/code/modules/bitrunning/objects/hololadder.dm index e592f31382de9..3df41a403e735 100644 --- a/code/modules/bitrunning/objects/hololadder.dm +++ b/code/modules/bitrunning/objects/hololadder.dm @@ -8,11 +8,37 @@ obj_flags = BLOCK_Z_OUT_DOWN /// Time req to disconnect properly var/travel_time = 3 SECONDS + /// Uses this to teleport observers back to the origin server + var/datum/weakref/server_ref -/obj/structure/hololadder/Initialize(mapload) + +/obj/structure/hololadder/Initialize(mapload, obj/machinery/quantum_server/origin) . = ..() RegisterSignal(loc, COMSIG_ATOM_ENTERED, PROC_REF(on_enter)) + server_ref = WEAKREF(origin) + register_context() + + +/obj/structure/hololadder/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + + context[SCREENTIP_CONTEXT_LMB] = "Disconnect" + + +/obj/structure/hololadder/examine(mob/user) + . = ..() + + if(isnull(server_ref.resolve())) + . += span_infoplain("It's not connected to anything.") + return + + if(isobserver(user)) + . += span_notice("Left click to view the server that this ladder is connected to.") + return + + . += span_infoplain("This ladder is connected to a server. You can click on it or walk over it to disconnect.") + /obj/structure/hololadder/attack_hand(mob/user, list/modifiers) . = ..() @@ -24,19 +50,29 @@ disconnect(user) + +/obj/structure/hololadder/attack_ghost(mob/dead/observer/ghostie) + var/our_server = server_ref?.resolve() + if(isnull(our_server)) + return ..() + + ghostie.abstract_move(get_turf(our_server)) + + /// If there's a pilot ref- send the disconnect signal /obj/structure/hololadder/proc/disconnect(mob/user) if(isnull(user.mind)) return if(!HAS_TRAIT(user, TRAIT_TEMPORARY_BODY)) - balloon_alert(user, "no connection detected.") + balloon_alert(user, "no connection detected") return balloon_alert(user, "disconnecting...") if(do_after(user, travel_time, src)) SEND_SIGNAL(user, COMSIG_BITRUNNER_LADDER_SEVER) + /// Helper for times when you dont have hands (gondola??) /obj/structure/hololadder/proc/on_enter(datum/source, atom/movable/arrived, turf/old_loc) SIGNAL_HANDLER diff --git a/code/modules/bitrunning/objects/netpod.dm b/code/modules/bitrunning/objects/netpod.dm index 98bc96231b30e..1d4e905d6e184 100644 --- a/code/modules/bitrunning/objects/netpod.dm +++ b/code/modules/bitrunning/objects/netpod.dm @@ -52,17 +52,25 @@ . += span_infoplain("Netpods must be built within 4 tiles of a server.") return - . += span_infoplain("Drag yourself into the pod to engage the link.") - . += span_infoplain("It has limited resuscitation capabilities. Remaining in the pod can heal some injuries.") - . += span_infoplain("It has a security system that will alert the occupant if it is tampered with.") + if(!isobserver(user)) + . += span_infoplain("Drag yourself into the pod to engage the link.") + . += span_infoplain("It has limited resuscitation capabilities. Remaining in the pod can heal some injuries.") + . += span_infoplain("It has a security system that will alert the occupant if it is tampered with.") if(isnull(occupant)) - . += span_notice("It is currently unoccupied.") + . += span_infoplain("It's currently unoccupied.") + return + + . += span_infoplain("It's currently occupied by [occupant].") + + if(isobserver(user)) + . += span_notice("As an observer, you can click this netpod to jump to its avatar.") return - . += span_notice("It is currently occupied by [occupant].") . += span_notice("It can be pried open with a crowbar, but its safety mechanisms will alert the occupant.") + + /obj/machinery/netpod/add_context(atom/source, list/context, obj/item/held_item, mob/user) . = ..() @@ -74,7 +82,6 @@ context[SCREENTIP_CONTEXT_LMB] = "Pry Open" return CONTEXTUAL_SCREENTIP_SET - return CONTEXTUAL_SCREENTIP_SET /obj/machinery/netpod/update_icon_state() if(!is_operational) diff --git a/code/modules/bitrunning/orders/tech.dm b/code/modules/bitrunning/orders/tech.dm index a4bf59ce18dec..7e987e4818104 100644 --- a/code/modules/bitrunning/orders/tech.dm +++ b/code/modules/bitrunning/orders/tech.dm @@ -34,3 +34,23 @@ /datum/orderable_item/bitrunning_tech/flip_skillchip item_path = /obj/item/skillchip/matrix_flip cost_per_order = 2000 + +/datum/orderable_item/bitrunning_tech/pka_mod + item_path = /obj/item/bitrunning_disk/item/pka_mods + cost_per_order = 750 + desc = "This disk contains a program that lets you equip modkits for the proto-kinetic accelerator. Proto-kinetic accelerator not included." + +/datum/orderable_item/bitrunning_tech/pka_mod/premium + item_path = /obj/item/bitrunning_disk/item/pka_mods/premium + cost_per_order = 1800 + desc = "This disk contains a program that lets you equip stronger modkits for the proto-kinetic accelerator. Proto-kinetic accelerator not included." + +/datum/orderable_item/bitrunning_tech/pkc_mod + item_path = /obj/item/bitrunning_disk/item/pkc_mods + cost_per_order = 750 + desc = "This disk contains a program that lets you equip trophies for the proto-kinetic crusher. Proto-kinetic crusher no included." + +/datum/orderable_item/bitrunning_tech/pkc_mod/premium + item_path = /obj/item/bitrunning_disk/item/pkc_mods/premium + cost_per_order = 1800 + desc = "This disk contains a program that lets you equip stronger trophies for the proto-kinetic crusher. Proto-kinetic crusher not included." diff --git a/code/modules/bitrunning/server/_parent.dm b/code/modules/bitrunning/server/_parent.dm index 113ed6b212625..8a8d2eed913de 100644 --- a/code/modules/bitrunning/server/_parent.dm +++ b/code/modules/bitrunning/server/_parent.dm @@ -19,7 +19,7 @@ /// Prevents multiple user actions. Handled by loading domains and cooldowns var/is_ready = TRUE /// Chance multipled by threat to spawn a glitch - var/glitch_chance = 0.05 + var/glitch_chance = 0.2 /// Current plugged in users var/list/datum/weakref/avatar_connection_refs = list() /// Cached list of mutable mobs in zone for cybercops @@ -37,11 +37,13 @@ /// Changes how much info is available on the domain var/scanner_tier = 1 /// Length of time it takes for the server to cool down after resetting. Here to give runners downtime so their faces don't get stuck like that - var/server_cooldown_time = 3 MINUTES + var/server_cooldown_time = 2 MINUTES /// Applies bonuses to rewards etc var/servo_bonus = 0 /// Determines the glitches available to spawn, builds with completion var/threat = 0 + /// Maximum rate at which a glitch can spawn + var/threat_prob_max = 15 /// The turfs we can place a hololadder on. var/turf/exit_turfs = list() /// Determines if we broadcast to entertainment monitors or not @@ -76,15 +78,18 @@ . += span_infoplain("Can be resource intensive to run. Ensure adequate power supply.") if(capacitor_coefficient < 1) - . += span_infoplain("Its coolant capacity reduces cooldown time by [(1 - capacitor_coefficient) * 100]%.") + . += span_infoplain("- Its coolant capacity reduces cooldown time by [(1 - capacitor_coefficient) * 100]%.") if(servo_bonus > 0.2) - . += span_infoplain("Its manipulation potential is increasing rewards by [servo_bonus]x.") - . += span_infoplain("Injury from unsafe ejection reduced [servo_bonus * 100]%.") + . += span_infoplain("- Its manipulation potential is increasing rewards by [servo_bonus]x.") + . += span_infoplain("- Injury from unsafe ejection reduced [servo_bonus * 100]%.") if(!is_ready) . += span_notice("It is currently cooling down. Give it a few moments.") + if(isobserver(user) && (obj_flags & EMAGGED)) + . += span_notice("Ominous warning lights are blinking red. This server has been tampered with.") + /obj/machinery/quantum_server/emag_act(mob/user, obj/item/card/emag/emag_card) . = ..() @@ -92,7 +97,8 @@ return obj_flags |= EMAGGED - glitch_chance = 0.09 + glitch_chance *= 2 + threat_prob_max *= 2 add_overlay(mutable_appearance('icons/obj/machines/bitrunning.dmi', "emag_overlay")) balloon_alert(user, "system jailbroken...") @@ -116,11 +122,14 @@ /obj/machinery/quantum_server/attackby(obj/item/weapon, mob/user, params) . = ..() - if(istype(weapon, /obj/item/bitrunning_debug)) - obj_flags |= EMAGGED - glitch_chance = 0.5 - capacitor_coefficient = 0.01 - points = 100 + + if(!istype(weapon, /obj/item/bitrunning_debug)) + return + + obj_flags |= EMAGGED + glitch_chance = 0.5 + capacitor_coefficient = 0.1 + points = 100 /obj/machinery/quantum_server/crowbar_act(mob/living/user, obj/item/crowbar) . = ..() diff --git a/code/modules/bitrunning/server/map_handling.dm b/code/modules/bitrunning/server/map_handling.dm index a55de5dbf9ded..5bfa7813910b6 100644 --- a/code/modules/bitrunning/server/map_handling.dm +++ b/code/modules/bitrunning/server/map_handling.dm @@ -55,7 +55,8 @@ is_ready = TRUE - if(prob(clamp((threat * glitch_chance), 1, 10))) + var/spawn_chance = clamp((threat * glitch_chance), 5, threat_prob_max) + if(prob(spawn_chance)) setup_glitch() playsound(src, 'sound/machines/terminal_insert_disc.ogg', 30, vary = TRUE) diff --git a/code/modules/bitrunning/server/obj_generation.dm b/code/modules/bitrunning/server/obj_generation.dm index 641d906cc5989..e8dbd72228c1d 100644 --- a/code/modules/bitrunning/server/obj_generation.dm +++ b/code/modules/bitrunning/server/obj_generation.dm @@ -110,7 +110,7 @@ if(isnull(destination)) return - var/obj/structure/hololadder/wayout = new(destination) + var/obj/structure/hololadder/wayout = new(destination, src) if(isnull(wayout)) return diff --git a/code/modules/bitrunning/server/threats.dm b/code/modules/bitrunning/server/threats.dm index 66a96d9971fe4..25a891c03b24b 100644 --- a/code/modules/bitrunning/server/threats.dm +++ b/code/modules/bitrunning/server/threats.dm @@ -71,6 +71,8 @@ var/datum/antagonist/bitrunning_glitch/chosen_role = forced_role || get_antagonist_role() var/role_name = initial(chosen_role.name) var/mob/chosen_one = SSpolling.poll_ghosts_for_target( + question = "A temporary antagonist role is spawning in the virtual domain.\ + \nYou will return to your previous body on conclusion.", check_jobban = ROLE_GLITCH, poll_time = 20 SECONDS, checked_target = mutation_target, @@ -92,26 +94,32 @@ return var/role_name = initial(chosen_role.name) - var/mob/living/antag_mob + + var/mob/living/new_mob switch(role_name) if(ROLE_NETGUARDIAN) - antag_mob = new /mob/living/basic/netguardian(mutation_target.loc) + new_mob = new /mob/living/basic/netguardian(mutation_target.loc) else // any other humanoid mob - antag_mob = new /mob/living/carbon/human(mutation_target.loc) + new_mob = new /mob/living/carbon/human(mutation_target.loc) mutation_target.gib(DROP_ALL_REMAINS) - antag_mob.key = ghost.key - var/datum/mind/ghost_mind = antag_mob.mind - ghost_mind.add_antag_datum(chosen_role) - ghost_mind.special_role = ROLE_GLITCH - ghost_mind.set_assigned_role(SSjob.GetJobType(/datum/job/bitrunning_glitch)) + var/datum/mind/ghost_mind = ghost.mind + new_mob.key = ghost.key + + if(ghost_mind?.current) + new_mob.AddComponent(/datum/component/temporary_body, ghost_mind, ghost_mind.current, TRUE) - playsound(antag_mob, 'sound/magic/ethereal_exit.ogg', 50, vary = TRUE) - message_admins("[ADMIN_LOOKUPFLW(antag_mob)] has been made into virtual antagonist by an event.") - antag_mob.log_message("was spawned as a virtual antagonist by an event.", LOG_GAME) + var/datum/mind/antag_mind = new_mob.mind + antag_mind.add_antag_datum(chosen_role) + antag_mind.special_role = ROLE_GLITCH + antag_mind.set_assigned_role(SSjob.GetJobType(/datum/job/bitrunning_glitch)) - add_threats(antag_mob) + playsound(new_mob, 'sound/magic/ethereal_exit.ogg', 50, vary = TRUE) + message_admins("[ADMIN_LOOKUPFLW(new_mob)] has been made into virtual antagonist by an event.") + new_mob.log_message("was spawned as a virtual antagonist by an event.", LOG_GAME) + + add_threats(new_mob) /// Oh boy - transports the antag station side /obj/machinery/quantum_server/proc/station_spawn(mob/living/antag, obj/machinery/byteforge/chosen_forge) @@ -151,6 +159,10 @@ if(istype(antag_datum)) antag_datum.show_in_roundend = TRUE + var/datum/component/temp_body = antag.GetComponent(/datum/component/temporary_body) + if(temp_body) + qdel(temp_body) + do_teleport(antag, get_turf(chosen_forge), forced = TRUE, asoundin = 'sound/magic/ethereal_enter.ogg', asoundout = 'sound/magic/ethereal_exit.ogg', channel = TELEPORT_CHANNEL_QUANTUM) /// Removes any invalid candidates from the list diff --git a/code/modules/bitrunning/server/util.dm b/code/modules/bitrunning/server/util.dm index ac3e60b51ba64..6b5352bde6cb1 100644 --- a/code/modules/bitrunning/server/util.dm +++ b/code/modules/bitrunning/server/util.dm @@ -66,7 +66,7 @@ /// Removes all blacklisted items from a mob and returns them to base state /obj/machinery/quantum_server/proc/reset_equipment(mob/living/carbon/human/person) - for(var/obj/item in person.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE)) + for(var/obj/item in person.get_equipped_items(INCLUDE_POCKETS | INCLUDE_ACCESSORIES)) qdel(item) var/datum/antagonist/bitrunning_glitch/antag_datum = locate() in person.mind?.antag_datums diff --git a/code/modules/bitrunning/spawners.dm b/code/modules/bitrunning/spawners.dm index 4f8aab322ffac..5fa889ac655fd 100644 --- a/code/modules/bitrunning/spawners.dm +++ b/code/modules/bitrunning/spawners.dm @@ -3,13 +3,19 @@ prompt_name = "a virtual domain debug entity" flavour_text = "You probably shouldn't be seeing this, contact a coder!" you_are_text = "You are NOT supposed to be here. How did you let this happen?" + important_text = "You must eliminate any bitrunners from the domain." + temp_body = TRUE /obj/effect/mob_spawn/ghost_role/human/virtual_domain/Initialize(mapload) . = ..() notify_ghosts("The [name] has been created. The virtual world calls for aid!", src, "Virtual Insanity!") /obj/effect/mob_spawn/ghost_role/human/virtual_domain/special(mob/living/spawned_mob, mob/mob_possessor) - . = ..() + var/datum/mind/ghost_mind = mob_possessor.mind + if(ghost_mind?.current) // Preserves any previous bodies before making the switch + spawned_mob.AddComponent(/datum/component/temporary_body, ghost_mind, ghost_mind.current, TRUE) + + ..() spawned_mob.mind.add_antag_datum(/datum/antagonist/domain_ghost_actor) diff --git a/code/modules/bitrunning/virtual_domain/domains/starfront_saloon.dm b/code/modules/bitrunning/virtual_domain/domains/starfront_saloon.dm deleted file mode 100644 index eae9dabc49e4d..0000000000000 --- a/code/modules/bitrunning/virtual_domain/domains/starfront_saloon.dm +++ /dev/null @@ -1,14 +0,0 @@ -/datum/lazy_template/virtual_domain/starfront_saloon - name = "Starfront Saloon" - cost = BITRUNNER_COST_MEDIUM - desc = "Looks like you stepped onto the wrong street, partner. Hope you brought your gunslinging skills." - difficulty = BITRUNNER_DIFFICULTY_HIGH - help_text = "One of these rooms has the cache we're looking for. Find it and get out." - is_modular = TRUE - key = "starfront_saloon" - map_name = "starfront_saloon" - mob_modules = list( - /datum/modular_mob_segment/syndicate_team, - /datum/modular_mob_segment/syndicate_elite, - ) - reward_points = BITRUNNER_REWARD_HIGH diff --git a/code/modules/buildmode/buildmode.dm b/code/modules/buildmode/buildmode.dm index 36a3db07f597e..80f5ae1ad27b0 100644 --- a/code/modules/buildmode/buildmode.dm +++ b/code/modules/buildmode/buildmode.dm @@ -50,6 +50,8 @@ holder.player_details.post_login_callbacks -= li_cb li_cb = null holder = null + modebutton = null + dirbutton = null QDEL_NULL(mode) QDEL_LIST(buttons) QDEL_LIST(modeswitch_buttons) diff --git a/code/modules/buildmode/submodes/outfit.dm b/code/modules/buildmode/submodes/outfit.dm index 5f8e3319cb95d..c3d507bf1e6c7 100644 --- a/code/modules/buildmode/submodes/outfit.dm +++ b/code/modules/buildmode/submodes/outfit.dm @@ -32,11 +32,11 @@ to_chat(c, span_warning("Pick an outfit first.")) return - for (var/item in dollie.get_equipped_items(include_pockets = TRUE)) + for (var/item in dollie.get_equipped_items(INCLUDE_POCKETS)) qdel(item) if(dressuptime != "Naked") dollie.equipOutfit(dressuptime) if(LAZYACCESS(modifiers, RIGHT_CLICK)) - for (var/item in dollie.get_equipped_items(include_pockets = TRUE)) + for (var/item in dollie.get_equipped_items(INCLUDE_POCKETS)) qdel(item) diff --git a/code/modules/cargo/packs/security.dm b/code/modules/cargo/packs/security.dm index e36f9f84cacf1..05360fe913f0a 100644 --- a/code/modules/cargo/packs/security.dm +++ b/code/modules/cargo/packs/security.dm @@ -214,9 +214,12 @@ /datum/supply_pack/security/armory/dragnet name = "DRAGnet Crate" desc = "Contains three \"Dynamic Rapid-Apprehension of the Guilty\" netting devices, \ - a recent breakthrough in law enforcement prisoner management technology." + a recent breakthrough in law enforcement prisoner management technology. Includes a DRAGnet beacon." cost = CARGO_CRATE_VALUE * 5 - contains = list(/obj/item/gun/energy/e_gun/dragnet = 3) + contains = list( + /obj/item/gun/energy/e_gun/dragnet = 3, + /obj/item/dragnet_beacon = 1 + ) crate_name = "\improper DRAGnet crate" /datum/supply_pack/security/armory/energy diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 8eb0def90bfa3..7cd3965718e60 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -211,18 +211,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) if ("change_slot") // Save existing character save_character() - - // SAFETY: `load_character` performs sanitization the slot number - if (!load_character(params["slot"])) - tainted_character_profiles = TRUE - randomise_appearance_prefs() - save_character() - - for (var/datum/preference_middleware/preference_middleware as anything in middleware) - preference_middleware.on_new_character(usr) - - character_preview_view.update_body() - + // SAFETY: `switch_to_slot` performs sanitization on the slot number + switch_to_slot(params["slot"]) + return TRUE + if ("remove_current_slot") + remove_current_slot() return TRUE if ("rotate") character_preview_view.setDir(turn(character_preview_view.dir, -90)) diff --git a/code/modules/client/preferences/_preference.dm b/code/modules/client/preferences/_preference.dm index 6c62ed1d054c2..485276b4ade2a 100644 --- a/code/modules/client/preferences/_preference.dm +++ b/code/modules/client/preferences/_preference.dm @@ -112,6 +112,10 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key()) /// will show the feature as selectable. var/relevant_mutant_bodypart = null + /// If the selected species has this in its /datum/species/body_markings, + /// will show the feature as selectable. + var/relevant_body_markings = null + /// If the selected species has this in its /datum/species/inherent_traits, /// will show the feature as selectable. var/relevant_inherent_trait = null @@ -333,6 +337,7 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key()) || !isnull(relevant_inherent_trait) \ || !isnull(relevant_external_organ) \ || !isnull(relevant_head_flag) \ + || !isnull(relevant_body_markings) \ ) var/species_type = preferences.read_preference(/datum/preference/choiced/species) diff --git a/code/modules/client/preferences/sounds.dm b/code/modules/client/preferences/sounds.dm index f56430b53638a..3ace1b64326cc 100644 --- a/code/modules/client/preferences/sounds.dm +++ b/code/modules/client/preferences/sounds.dm @@ -4,6 +4,9 @@ savefile_key = "sound_ambience" savefile_identifier = PREFERENCE_PLAYER +/datum/preference/toggle/sound_ambience/apply_to_client(client/client, value) + client.update_ambience_pref() + /// Controls hearing announcement sounds /datum/preference/toggle/sound_announcements category = PREFERENCE_CATEGORY_GAME_PREFERENCES diff --git a/code/modules/client/preferences/species_features/lizard.dm b/code/modules/client/preferences/species_features/lizard.dm index bee57300ec4a4..38c83690b3b5e 100644 --- a/code/modules/client/preferences/species_features/lizard.dm +++ b/code/modules/client/preferences/species_features/lizard.dm @@ -29,20 +29,20 @@ category = PREFERENCE_CATEGORY_FEATURES main_feature_name = "Body markings" should_generate_icons = TRUE - relevant_mutant_bodypart = "body_markings" + relevant_body_markings = /datum/bodypart_overlay/simple/body_marking/lizard /datum/preference/choiced/lizard_body_markings/init_possible_values() - return assoc_to_keys_features(SSaccessories.body_markings_list) + return assoc_to_keys_features(SSaccessories.lizard_markings_list) /datum/preference/choiced/lizard_body_markings/icon_for(value) - var/datum/sprite_accessory/sprite_accessory = SSaccessories.body_markings_list[value] + var/datum/sprite_accessory/sprite_accessory = SSaccessories.lizard_markings_list[value] var/icon/final_icon = icon('icons/mob/human/species/lizard/bodyparts.dmi', "lizard_chest_m") if (sprite_accessory.icon_state != "none") var/icon/body_markings_icon = icon( 'icons/mob/human/species/lizard/lizard_misc.dmi', - "m_body_markings_[sprite_accessory.icon_state]_ADJ", + "male_[sprite_accessory.icon_state]_chest", ) final_icon.Blend(body_markings_icon, ICON_OVERLAY) @@ -55,7 +55,7 @@ return final_icon /datum/preference/choiced/lizard_body_markings/apply_to_human(mob/living/carbon/human/target, value) - target.dna.features["body_markings"] = value + target.dna.features["lizard_markings"] = value /datum/preference/choiced/lizard_frills savefile_key = "feature_lizard_frills" diff --git a/code/modules/client/preferences/species_features/moth.dm b/code/modules/client/preferences/species_features/moth.dm index 745e6fb917b8f..f697d857d4fc4 100644 --- a/code/modules/client/preferences/species_features/moth.dm +++ b/code/modules/client/preferences/species_features/moth.dm @@ -34,7 +34,7 @@ category = PREFERENCE_CATEGORY_FEATURES main_feature_name = "Body markings" should_generate_icons = TRUE - relevant_mutant_bodypart = "moth_markings" + relevant_body_markings = /datum/bodypart_overlay/simple/body_marking/moth /datum/preference/choiced/moth_markings/init_possible_values() return assoc_to_keys_features(SSaccessories.moth_markings_list) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index aa6b1840c50b2..9a6448e2e6d54 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -368,6 +368,43 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car return TRUE +/datum/preferences/proc/switch_to_slot(new_slot) + // SAFETY: `load_character` performs sanitization on the slot number + if (!load_character(new_slot)) + tainted_character_profiles = TRUE + randomise_appearance_prefs() + save_character() + + for (var/datum/preference_middleware/preference_middleware as anything in middleware) + preference_middleware.on_new_character(usr) + + character_preview_view.update_body() + +/datum/preferences/proc/remove_current_slot() + PRIVATE_PROC(TRUE) + + var/closest_slot + for (var/other_slot in default_slot - 1 to 1 step -1) + var/save_data = savefile.get_entry("character[other_slot]") + if (!isnull(save_data)) + closest_slot = other_slot + break + + if (isnull(closest_slot)) + for (var/other_slot in default_slot + 1 to max_save_slots) + var/save_data = savefile.get_entry("character[other_slot]") + if (!isnull(save_data)) + closest_slot = other_slot + break + + if (isnull(closest_slot)) + stack_trace("remove_current_slot() being called when there are no slots to go to, the client should prevent this") + return + + savefile.remove_entry("character[default_slot]") + tainted_character_profiles = TRUE + switch_to_slot(closest_slot) + /datum/preferences/proc/sanitize_be_special(list/input_be_special) var/list/output = list() diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index cd32002d0434b..98184b3fce25e 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -360,7 +360,7 @@ . = ..() if(href_list["list_armor"]) - var/list/readout = list("PROTECTION CLASSES") + var/list/readout = list() var/datum/armor/armor = get_armor() var/added_damage_header = FALSE @@ -369,9 +369,9 @@ if(!rating) continue if(!added_damage_header) - readout += "\nARMOR (I-X)" + readout += "ARMOR (I-X)" added_damage_header = TRUE - readout += "\n[armor_to_protection_name(damage_key)] [armor_to_protection_class(rating)]" + readout += "[armor_to_protection_name(damage_key)] [armor_to_protection_class(rating)]" var/added_durability_header = FALSE for(var/durability_key in ARMOR_LIST_DURABILITY()) @@ -379,9 +379,9 @@ if(!rating) continue if(!added_durability_header) - readout += "\nDURABILITY (I-X)" + readout += "DURABILITY (I-X)" added_damage_header = TRUE - readout += "\n[armor_to_protection_name(durability_key)] [armor_to_protection_class(rating)]" + readout += "[armor_to_protection_name(durability_key)] [armor_to_protection_class(rating)]" if(flags_cover & HEADCOVERSMOUTH || flags_cover & PEPPERPROOF) var/list/things_blocked = list() @@ -390,12 +390,15 @@ if(flags_cover & PEPPERPROOF) things_blocked += "pepperspray" if(length(things_blocked)) - readout += "\nCOVERAGE" - readout += "\nIt will block [english_list(things_blocked)]." + readout += "COVERAGE" + readout += "It will block [english_list(things_blocked)]." - readout += "" - to_chat(usr, "[readout.Join()]") + if(!length(readout)) + readout += "No armor or durability information available." + + var/formatted_readout = span_notice("PROTECTION CLASSES
[jointext(readout, "\n")]") + to_chat(usr, examine_block(formatted_readout)) /** * Rounds armor_value down to the nearest 10, divides it by 10 and then converts it to Roman numerals. diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm index cd1f6a2798ba2..5ea7d62313bd4 100644 --- a/code/modules/clothing/head/jobs.dm +++ b/code/modules/clothing/head/jobs.dm @@ -701,7 +701,7 @@ else var/obj/item/organ/internal/tongue/has_tongue = human_examined.get_organ_slot(ORGAN_SLOT_TONGUE) var/pill_count = 0 - for(var/datum/action/item_action/hands_free/activate_pill/pill in human_examined.actions) + for(var/datum/action/item_action/activate_pill/pill in human_examined.actions) pill_count++ if(pill_count >= 1 && has_tongue) diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm index a22691495ccc1..6c088760f07db 100644 --- a/code/modules/clothing/outfits/standard.dm +++ b/code/modules/clothing/outfits/standard.dm @@ -185,7 +185,7 @@ l_hand = /obj/item/fireaxe /datum/outfit/psycho/post_equip(mob/living/carbon/human/H) - for(var/obj/item/carried_item in H.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE)) + for(var/obj/item/carried_item in H.get_equipped_items(INCLUDE_POCKETS | INCLUDE_ACCESSORIES)) carried_item.add_mob_blood(H)//Oh yes, there will be blood... for(var/obj/item/I in H.held_items) I.add_mob_blood(H) diff --git a/code/modules/clothing/suits/reactive_armour.dm b/code/modules/clothing/suits/reactive_armour.dm index 155e4dbe42fb6..c1889cc77383d 100644 --- a/code/modules/clothing/suits/reactive_armour.dm +++ b/code/modules/clothing/suits/reactive_armour.dm @@ -5,8 +5,8 @@ icon = 'icons/obj/clothing/suits/armor.dmi' w_class = WEIGHT_CLASS_BULKY -/obj/item/reactive_armor_shell/attackby(obj/item/weapon, mob/user, params) - ..() +/obj/item/reactive_armor_shell/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = ..() var/static/list/anomaly_armour_types = list( /obj/effect/anomaly/grav = /obj/item/clothing/suit/armor/reactive/repulse, /obj/effect/anomaly/flux = /obj/item/clothing/suit/armor/reactive/tesla, @@ -17,15 +17,16 @@ /obj/effect/anomaly/ectoplasm = /obj/item/clothing/suit/armor/reactive/ectoplasm, ) - if(istype(weapon, /obj/item/assembly/signaler/anomaly)) - var/obj/item/assembly/signaler/anomaly/anomaly = weapon - var/armour_path = anomaly_armour_types[anomaly.anomaly_type] + if(istype(tool, /obj/item/assembly/signaler/anomaly)) + var/obj/item/assembly/signaler/anomaly/anomaly = tool + var/armour_path = is_path_in_list(anomaly.anomaly_type, anomaly_armour_types, TRUE) if(!armour_path) armour_path = /obj/item/clothing/suit/armor/reactive/stealth //Lets not cheat the player if an anomaly type doesnt have its own armour coded to_chat(user, span_notice("You insert [anomaly] into the chest plate, and the armour gently hums to life.")) new armour_path(get_turf(src)) qdel(src) qdel(anomaly) + return ITEM_INTERACT_SUCCESS //Reactive armor /obj/item/clothing/suit/armor/reactive diff --git a/code/modules/experisci/experiment/experiments.dm b/code/modules/experisci/experiment/experiments.dm index 3434fb6fdb1ed..7a7c073b75a6a 100644 --- a/code/modules/experisci/experiment/experiments.dm +++ b/code/modules/experisci/experiment/experiments.dm @@ -118,6 +118,14 @@ experiment_proper = TRUE required_gas = /datum/gas/nitrous_oxide +/datum/experiment/ordnance/gaseous/plasma + name = "Plasma Gas Shells" + description = "The delivery of Plasma gas into an area of operation might prove useful. Pack the specified gas into a tank and burst it using a Tank Compressor. Publish the data in a paper." + gain = list(10,40) + target_amount = list(200,600) + experiment_proper = TRUE + required_gas = /datum/gas/plasma + /datum/experiment/ordnance/gaseous/bz name = "BZ Gas Shells" description = "The delivery of BZ gas into an area of operation might prove useful. Pack the specified gas into a tank and burst it using a Tank Compressor. Publish the data in a paper." @@ -315,7 +323,7 @@ required_stock_part = /obj/item/stock_parts/micro_laser/ultra /datum/experiment/scanning/random/mecha_damage_scan - name = "Exosuit Materials 1: Stress Failure Test" + name = "Exosuit Materials: Stress Failure Test" description = "Your exosuit fabricators allow for rapid production on a small scale, but the structural integrity of created parts is inferior to more traditional means." exp_tag = "Scan" possible_types = list(/obj/vehicle/sealed/mecha) @@ -324,10 +332,10 @@ var/damage_percent /datum/experiment/scanning/random/mecha_equipped_scan - name = "Exosuit Materials 2: Load Strain Test" + name = "Exosuit Materials: Load Strain Test" description = "Exosuit equipment places unique strain upon the structure of the vehicle. Scan exosuits you have assembled from your exosuit fabricator and fully equipped to accelerate our structural stress simulations." possible_types = list(/obj/vehicle/sealed/mecha) - total_requirement = 2 + total_requirement = 1 /// Scan for organs you didn't start the round with /datum/experiment/scanning/people/novel_organs @@ -368,3 +376,85 @@ continue return TRUE return FALSE + +/// Scan for cybernetic organs +/datum/experiment/scanning/people/augmented_organs + name = "Human Field Research: Augmented Organs" + description = "We need to gather data on how cybernetic vital organs integrate with human biology. Conduct a scan on a human with these implants to help us understand their compatibility" + performance_hint = "Perform an organ manipulation surgery to replace one of the vital organs with a cybernetic variant." + required_traits_desc = "augmented vital organs" + required_count = 1 + +/datum/experiment/scanning/people/augmented_organs/is_valid_scan_target(mob/living/carbon/human/check) + . = ..() + if (!.) + return + var/static/list/vital_organ_slots = list( + ORGAN_SLOT_HEART, + ORGAN_SLOT_LUNGS, + ORGAN_SLOT_EYES, + ORGAN_SLOT_EARS, + ORGAN_SLOT_LIVER, + ORGAN_SLOT_STOMACH, + ) + + for (var/obj/item/organ/organ as anything in check.organs) + if (IS_ORGANIC_ORGAN(organ)) + continue + if (!(organ.slot in vital_organ_slots)) + continue + return TRUE + return FALSE + +/// Scan for skillchips +/datum/experiment/scanning/people/skillchip + name = "Human Field Research: Skill Chip Implants" + description = "Before sticking programmed circuits into human brain, we need to know how it handles simple ones. Scan a live person with a skill chip implant in their brain." + performance_hint = "Perform a skill chip implantation with a skill station." + required_traits_desc = "skill chip implant" + +/datum/experiment/scanning/people/skillchip/is_valid_scan_target(mob/living/carbon/human/check, datum/component/experiment_handler/experiment_handler) + . = ..() + if (!.) + return + var/obj/item/organ/internal/brain/scanned_brain = check.get_organ_slot(ORGAN_SLOT_BRAIN) + if (isnull(scanned_brain)) + experiment_handler.announce_message("Subject is brainless!") + return FALSE + if (scanned_brain.get_used_skillchip_slots() == 0) + experiment_handler.announce_message("No skill chips found!") + return FALSE + return TRUE + +/datum/experiment/scanning/reagent/cryostylane + name = "Pure Cryostylane Scan" + description = "It appears that the Cryostylane reagent can potentially halt all physiological processes in the human body. Produce Cryostylane with at least 99% purity and scan the beaker." + required_reagent = /datum/reagent/cryostylane + min_purity = 0.99 + +/datum/experiment/scanning/points/bluespace_crystal + name = "Bluespace Crystal Sampling" + description = "Investigate the properties of bluespace crystals by scanning either an artificial or naturally occurring variant. This will help us deepen our understanding of bluespace phenomena." + required_points = 1 + required_atoms = list( + /obj/item/stack/ore/bluespace_crystal = 1, + /obj/item/stack/sheet/bluespace_crystal = 1 + ) + +/datum/experiment/scanning/points/machinery_tiered_scan/tier2_any + name = "Upgraded Stock Parts Benchmark" + description = "Our newly-designed machinery components require practical application tests for hints at possible further advancements, as well as a general confirmation that we didn't actually design worse parts somehow. Scan any machinery with Upgraded Parts and report the results." + required_points = 4 + required_atoms = list( + /obj/machinery = 1 + ) + required_tier = 2 + +/datum/experiment/scanning/points/machinery_tiered_scan/tier3_any + name = "Advanced Stock Parts Benchmark" + description = "Our newly-designed machinery components require practical application tests for hints at possible further advancements, as well as a general confirmation that we didn't actually design worse parts somehow. Scan any machinery with Advanced Parts and report the results." + required_points = 4 + required_atoms = list( + /obj/machinery = 1 + ) + required_tier = 3 diff --git a/code/modules/experisci/experiment/types/scanning_people.dm b/code/modules/experisci/experiment/types/scanning_people.dm index 379d7e9089524..c3879e2a8d32c 100644 --- a/code/modules/experisci/experiment/types/scanning_people.dm +++ b/code/modules/experisci/experiment/types/scanning_people.dm @@ -18,15 +18,15 @@ return FALSE if(!ishuman(target)) return FALSE - return is_valid_scan_target(target) + return is_valid_scan_target(target, experiment_handler) /// Checks that the passed mob is valid human to scan -/datum/experiment/scanning/people/proc/is_valid_scan_target(mob/living/carbon/human/check) +/datum/experiment/scanning/people/proc/is_valid_scan_target(mob/living/carbon/human/check, datum/component/experiment_handler/experiment_handler) SHOULD_CALL_PARENT(TRUE) if(!mind_required || !isnull(check.mind)) return TRUE if(isliving(usr)) - check.balloon_alert(usr, "subject is mindless!") + experiment_handler.announce_message("Subject is mindless!") return FALSE /datum/experiment/scanning/people/serialize_progress_stage(atom/target, list/seen_instances) diff --git a/code/modules/experisci/experiment/types/scanning_reagent.dm b/code/modules/experisci/experiment/types/scanning_reagent.dm new file mode 100644 index 0000000000000..1a39e2941efeb --- /dev/null +++ b/code/modules/experisci/experiment/types/scanning_reagent.dm @@ -0,0 +1,35 @@ +/// An experiment where you scan a container with a specified reagent of certain purity +/datum/experiment/scanning/reagent + exp_tag = "Reagent Scan" + allowed_experimentors = list(/obj/item/experi_scanner, /obj/item/scanner_wand) + required_atoms = list(/obj/item/reagent_containers = 1) + /// The reagent required to present in the scanned container + var/datum/reagent/required_reagent = /datum/reagent/water + /// The minimum required purity of required_reagent + var/min_purity = 0 + +/datum/experiment/scanning/reagent/final_contributing_index_checks(datum/component/experiment_handler/experiment_handler, atom/target, typepath) + . = ..() + if(!.) + return FALSE + if(!is_reagent_container(target)) + return FALSE + return is_valid_scan_target(experiment_handler, target) + +/datum/experiment/scanning/reagent/proc/is_valid_scan_target(datum/component/experiment_handler/experiment_handler, obj/item/reagent_containers/container) + SHOULD_CALL_PARENT(TRUE) + if (container.reagents.total_volume == 0) + experiment_handler.announce_message("Container empty!") + return FALSE + var/datum/reagent/master_reagent = container.reagents.get_master_reagent() + if (master_reagent.type != required_reagent) + experiment_handler.announce_message("Reagent not found!") + return FALSE + if (master_reagent.purity < min_purity) + experiment_handler.announce_message("Purity too low!") + return FALSE + return TRUE + +/datum/experiment/scanning/reagent/serialize_progress_stage(atom/target, list/seen_instances) + return EXPERIMENT_PROG_INT("Scan a reagent container with [required_reagent::name] of at least [PERCENT(min_purity)] purity.", \ + seen_instances.len, required_atoms[target]) diff --git a/code/modules/experisci/experiment/types/scanning_vatgrown.dm b/code/modules/experisci/experiment/types/scanning_vatgrown.dm index f4578fdf41238..0a7ade381a4ea 100644 --- a/code/modules/experisci/experiment/types/scanning_vatgrown.dm +++ b/code/modules/experisci/experiment/types/scanning_vatgrown.dm @@ -3,7 +3,7 @@ description = "Base experiment for scanning atoms that were vatgrown" exp_tag = "Cytology Scan" total_requirement = 1 - possible_types = list(/mob/living/basic/cockroach) + possible_types = list(/mob/living/basic/slime) traits = EXPERIMENT_TRAIT_DESTRUCTIVE /datum/experiment/scanning/random/cytology/final_contributing_index_checks(datum/component/experiment_handler/experiment_handler, atom/target, typepath) diff --git a/code/modules/fishing/sources/_fish_source.dm b/code/modules/fishing/sources/_fish_source.dm index eb681dc16cbfd..66d2bf0a880e3 100644 --- a/code/modules/fishing/sources/_fish_source.dm +++ b/code/modules/fishing/sources/_fish_source.dm @@ -85,8 +85,8 @@ GLOBAL_LIST_INIT(specific_fish_icons, zebra_typecacheof(list( . = fishing_difficulty // Difficulty modifier added by having the Settler quirk - if(HAS_TRAIT(fisherman, TRAIT_SETTLER)) - . += SETTLER_DIFFICULTY_MOD + if(HAS_TRAIT(fisherman, TRAIT_EXPERT_FISHER)) + . += EXPERT_FISHER_DIFFICULTY_MOD // Difficulty modifier added by the fisher's skill level if(!challenge || !(challenge.special_effects & FISHING_MINIGAME_RULE_NO_EXP)) diff --git a/code/modules/food_and_drinks/machinery/gibber.dm b/code/modules/food_and_drinks/machinery/gibber.dm index e0002817f782e..cd50f29ffe478 100644 --- a/code/modules/food_and_drinks/machinery/gibber.dm +++ b/code/modules/food_and_drinks/machinery/gibber.dm @@ -5,6 +5,7 @@ icon_state = "grinder" density = TRUE circuit = /obj/item/circuitboard/machine/gibber + anchored_tabletop_offset = 8 var/operating = FALSE //Is it on? var/dirty = FALSE // Does it need cleaning? @@ -15,13 +16,15 @@ /obj/machinery/gibber/Initialize(mapload) . = ..() + RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_cleaned)) if(prob(5)) name = "meat grinder" desc = "Okay, if I... if I chop you up in a meat grinder, and the only thing that comes out, that's left of you, is your eyeball, \ you'r- you're PROBABLY DEAD! You're probably going to - not you, I'm just sayin', like, if you- if somebody were to, like, \ push you into a meat grinder, and, like, your- one of your finger bones is still intact, they're not gonna pick it up and go, \ Well see, yeah it wasn't deadly, it wasn't an instant kill move! You still got, like, this part of your finger left!" - add_overlay("grjam") + dirty = TRUE + update_appearance(UPDATE_OVERLAYS) /obj/machinery/gibber/RefreshParts() . = ..() @@ -45,16 +48,23 @@ /obj/machinery/gibber/update_overlays() . = ..() if(dirty) - . +="grbloody" - if(machine_stat & (NOPOWER|BROKEN)) + . += "grinder_bloody" + if(machine_stat & (NOPOWER|BROKEN) || panel_open) return if(!occupant) - . += "grjam" + . += "grinder_empty" + . += emissive_appearance(icon, "grinder_empty", src, alpha = src.alpha) return if(operating) - . += "gruse" + . += "grinder_active" + . += emissive_appearance(icon, "grinder_active", src, alpha = src.alpha) + . += "grinder_jaws_active" return - . += "gridle" + . += "grinder_loaded" + . += emissive_appearance(icon, "grinder_loaded", src, alpha = src.alpha) + +/obj/machinery/gibber/on_set_panel_open(old_value) + update_appearance(UPDATE_OVERLAYS) /obj/machinery/gibber/attack_paw(mob/user, list/modifiers) return attack_hand(user, modifiers) @@ -160,8 +170,7 @@ operating = TRUE update_appearance() - var/offset = prob(50) ? -2 : 2 - animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 200) //start shaking + Shake(pixelshiftx = 1, pixelshifty = 0, duration = gibtime) var/mob/living/mob_occupant = occupant var/sourcename = mob_occupant.real_name var/sourcejob @@ -223,6 +232,8 @@ /obj/machinery/gibber/proc/make_meat(obj/item/stack/sheet/animalhide/skin, list/obj/item/food/meat/slab/allmeat, meat_produced, gibtype, list/datum/disease/diseases) playsound(src.loc, 'sound/effects/splat.ogg', 50, TRUE) operating = FALSE + if (!dirty && prob(50)) + dirty = TRUE var/turf/T = get_turf(src) var/list/turf/nearby_turfs = RANGE_TURFS(3,T) - T if(skin) @@ -265,3 +276,7 @@ if(victim.loc == input) victim.forceMove(src) victim.gib(DROP_ALL_REMAINS) + +/obj/machinery/gibber/proc/on_cleaned(obj/source_component, obj/source) + dirty = FALSE + update_appearance(UPDATE_OVERLAYS) diff --git a/code/modules/food_and_drinks/machinery/processor.dm b/code/modules/food_and_drinks/machinery/processor.dm index 4a60cdbc26592..78dd71df128d9 100644 --- a/code/modules/food_and_drinks/machinery/processor.dm +++ b/code/modules/food_and_drinks/machinery/processor.dm @@ -4,7 +4,8 @@ name = "food processor" desc = "An industrial grinder used to process meat and other foods. Keep hands clear of intake area while operating." icon = 'icons/obj/machines/kitchen.dmi' - icon_state = "processor1" + base_icon_state = "processor" + icon_state = "processor" layer = BELOW_OBJ_LAYER density = TRUE pass_flags = PASSTABLE @@ -91,7 +92,7 @@ if(processing) to_chat(user, span_warning("[src] is in the process of processing!")) return TRUE - if(default_deconstruction_screwdriver(user, "processor", "processor1", attacking_item) || default_pry_open(attacking_item, close_after_pry = TRUE) || default_deconstruction_crowbar(attacking_item)) + if(default_deconstruction_screwdriver(user, base_icon_state + "_open", base_icon_state, attacking_item) || default_pry_open(attacking_item, close_after_pry = TRUE) || default_deconstruction_crowbar(attacking_item)) return if(istype(attacking_item, /obj/item/storage/bag/tray)) @@ -157,7 +158,7 @@ total_time += recipe.time var/duration = (total_time / rating_speed) - INVOKE_ASYNC(src, TYPE_PROC_REF(/atom, Shake), 2, 2, duration, max(duration*0.02, 0.01)) //initial values work out to duration 4 seconds, interval 0.8 + INVOKE_ASYNC(src, TYPE_PROC_REF(/atom, Shake), 1, 0, duration) sleep(duration) for(var/atom/movable/content_item in processor_contents) var/datum/food_processor_process/recipe = PROCESSOR_SELECT_RECIPE(content_item) @@ -189,6 +190,8 @@ /obj/machinery/processor/slime name = "slime processor" + base_icon_state = "processor_slime" + icon_state = "processor_slime" desc = "An industrial grinder with a sticker saying appropriated for science department. Keep hands clear of intake area while operating." circuit = /obj/item/circuitboard/machine/processor/slime diff --git a/code/modules/mafia/outfits.dm b/code/modules/mafia/outfits.dm index dc2d384b263f6..5c6450adb90d2 100644 --- a/code/modules/mafia/outfits.dm +++ b/code/modules/mafia/outfits.dm @@ -155,7 +155,7 @@ suit = /obj/item/clothing/suit/apron /datum/outfit/mafia/obsessed/post_equip(mob/living/carbon/human/H) - for(var/obj/item/carried_item in H.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE)) + for(var/obj/item/carried_item in H.get_equipped_items(INCLUDE_POCKETS | INCLUDE_ACCESSORIES)) carried_item.add_mob_blood(H)//Oh yes, there will be blood... H.regenerate_icons() diff --git a/code/modules/mining/lavaland/megafauna_loot.dm b/code/modules/mining/lavaland/megafauna_loot.dm index f4ae3548fa659..0bbf15352318d 100644 --- a/code/modules/mining/lavaland/megafauna_loot.dm +++ b/code/modules/mining/lavaland/megafauna_loot.dm @@ -755,7 +755,7 @@ "wings" = "None", "frills" = "None", "spines" = "Long", - "body_markings" = "Dark Tiger Body", + "lizard_markings" = "Dark Tiger Body", "legs" = DIGITIGRADE_LEGS, ) consumer.eye_color_left = "#FEE5A3" diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 556a959e4f8eb..3c02de4707317 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -984,8 +984,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp game.ui_interact(usr) /mob/dead/observer/CtrlShiftClickOn(atom/target) - if(check_rights(R_SPAWN)) - change_mob_type(/mob/living/carbon/human , null, null, TRUE) //always delmob, ghosts shouldn't be left lingering + if(isobserver(target) && check_rights(R_SPAWN)) + var/mob/dead/observer/target_ghost = target + + target_ghost.change_mob_type(/mob/living/carbon/human , null, null, TRUE) //always delmob, ghosts shouldn't be left lingering /mob/dead/observer/examine(mob/user) . = ..() diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index b118de06f057a..50ab6e82faa4d 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -388,38 +388,37 @@ * Used to return a list of equipped items on a mob; does not include held items (use get_all_gear) * * Argument(s): - * * Optional - include_pockets (TRUE/FALSE), whether or not to include the pockets and suit storage in the returned list - * * Optional - include_accessories (TRUE/FALSE), whether or not to include the accessories in the returned list + * * Optional - include_flags, (see obj.flags.dm) describes which optional things to include or not (pockets, accessories, held items) */ -/mob/living/proc/get_equipped_items(include_pockets = FALSE, include_accessories = FALSE) +/mob/living/proc/get_equipped_items(include_flags = NONE) var/list/items = list() for(var/obj/item/item_contents in contents) if(item_contents.item_flags & IN_INVENTORY) items += item_contents - items -= held_items + if (!(include_flags & INCLUDE_HELD)) + items -= held_items return items /** - * Used to return a list of equipped items on a human mob; does not include held items (use get_all_gear) + * Used to return a list of equipped items on a human mob; does not by default include held items, see include_flags * * Argument(s): - * * Optional - include_pockets (TRUE/FALSE), whether or not to include the pockets and suit storage in the returned list - * * Optional - include_accessories (TRUE/FALSE), whether or not to include the accessories in the returned list + * * Optional - include_flags, (see obj.flags.dm) describes which optional things to include or not (pockets, accessories, held items) */ -/mob/living/carbon/human/get_equipped_items(include_pockets = FALSE, include_accessories = FALSE) +/mob/living/carbon/human/get_equipped_items(include_flags = NONE) var/list/items = ..() - if(!include_pockets) + if(!(include_flags & INCLUDE_POCKETS)) items -= list(l_store, r_store, s_store) - if(include_accessories && w_uniform) + if((include_flags & INCLUDE_ACCESSORIES) && w_uniform) var/obj/item/clothing/under/worn_under = w_uniform items += worn_under.attached_accessories return items /mob/living/proc/unequip_everything() var/list/items = list() - items |= get_equipped_items(include_pockets = TRUE) + items |= get_equipped_items(INCLUDE_POCKETS) for(var/I in items) dropItemToGround(I) drop_all_held_items() @@ -558,7 +557,7 @@ //GetAllContents that is reasonable and not stupid /mob/living/proc/get_all_gear() - var/list/processing_list = get_equipped_items(include_pockets = TRUE, include_accessories = TRUE) + held_items + var/list/processing_list = get_equipped_items(INCLUDE_POCKETS | INCLUDE_ACCESSORIES | INCLUDE_HELD) list_clear_nulls(processing_list) // handles empty hands var/i = 0 while(i < length(processing_list)) diff --git a/code/modules/mob/living/basic/alien/_alien.dm b/code/modules/mob/living/basic/alien/_alien.dm index 823ab896c0a22..907d28aaa4187 100644 --- a/code/modules/mob/living/basic/alien/_alien.dm +++ b/code/modules/mob/living/basic/alien/_alien.dm @@ -63,7 +63,7 @@ AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_CLAW) /mob/living/basic/alien/get_butt_sprite() - return BUTT_SPRITE_XENOMORPH + return icon('icons/mob/butts.dmi', BUTT_SPRITE_XENOMORPH) ///Places alien weeds on the turf the mob is currently standing on. /mob/living/basic/alien/proc/place_weeds() diff --git a/code/modules/mob/living/basic/drone/_drone.dm b/code/modules/mob/living/basic/drone/_drone.dm index ae72054899b11..6501e35d51dc2 100644 --- a/code/modules/mob/living/basic/drone/_drone.dm +++ b/code/modules/mob/living/basic/drone/_drone.dm @@ -265,7 +265,7 @@ dust() /mob/living/basic/drone/get_butt_sprite() - return BUTT_SPRITE_DRONE + return icon('icons/mob/butts.dmi', BUTT_SPRITE_DRONE) /mob/living/basic/drone/examine(mob/user) . = list("This is [icon2html(src, user)] \a [src]!") diff --git a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm index b2aff7371a426..ce363af236465 100644 --- a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm +++ b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm @@ -55,7 +55,7 @@ /mob/living/basic/gorilla/Initialize(mapload) . = ..() - add_traits(list(TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP), ROUNDSTART_TRAIT) + add_traits(list(TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, TRAIT_CHUNKYFINGERS), ROUNDSTART_TRAIT) AddElement(/datum/element/wall_tearer, allow_reinforced = FALSE) AddElement(/datum/element/dextrous) AddElement(/datum/element/footstep, FOOTSTEP_MOB_BAREFOOT) diff --git a/code/modules/mob/living/basic/slime/slime.dm b/code/modules/mob/living/basic/slime/slime.dm index 4864cb82016a7..fa40ac28d816d 100644 --- a/code/modules/mob/living/basic/slime/slime.dm +++ b/code/modules/mob/living/basic/slime/slime.dm @@ -187,6 +187,8 @@ /mob/living/basic/slime/regenerate_icons() cut_overlays() + if(slime_type.transparent) + alpha = SLIME_TRANSPARENCY_ALPHA var/icon_text = "[slime_type.colour]-[life_stage]" icon_dead = "[icon_text]-dead" if(stat != DEAD) diff --git a/code/modules/mob/living/basic/slime/slime_type.dm b/code/modules/mob/living/basic/slime/slime_type.dm index 11f3798804017..048f861eeb08a 100644 --- a/code/modules/mob/living/basic/slime/slime_type.dm +++ b/code/modules/mob/living/basic/slime/slime_type.dm @@ -1,6 +1,8 @@ /datum/slime_type ///Our slime's colour as text. Used by both description, and icon var/colour + ///Whether the slime icons should be semi-transparent + var/transparent = FALSE ///The type our slime spawns var/core_type ///The possible mutations of our slime @@ -12,6 +14,7 @@ /datum/slime_type/grey colour = SLIME_TYPE_GREY + transparent = TRUE core_type = /obj/item/slime_extract/grey mutations = list( /datum/slime_type/blue = 1, @@ -21,11 +24,11 @@ ) rgb_code = COLOR_SLIME_GREY - //TIER 1 /datum/slime_type/blue colour = SLIME_TYPE_BLUE + transparent = TRUE core_type = /obj/item/slime_extract/blue mutations = list( /datum/slime_type/darkblue = 1, @@ -46,6 +49,7 @@ /datum/slime_type/purple colour = SLIME_TYPE_PURPLE + transparent = TRUE core_type = /obj/item/slime_extract/purple mutations = list( /datum/slime_type/darkblue = 1, @@ -56,6 +60,7 @@ /datum/slime_type/orange colour = SLIME_TYPE_ORANGE + transparent = TRUE core_type = /obj/item/slime_extract/orange mutations = list( /datum/slime_type/darkpurple = 1, @@ -68,6 +73,7 @@ /datum/slime_type/darkblue colour = SLIME_TYPE_DARK_BLUE + transparent = TRUE core_type = /obj/item/slime_extract/darkblue mutations = list( /datum/slime_type/blue = 1, @@ -98,6 +104,7 @@ /datum/slime_type/yellow colour = SLIME_TYPE_YELLOW + transparent = TRUE core_type = /obj/item/slime_extract/yellow mutations = list( /datum/slime_type/bluespace = 2, @@ -119,6 +126,7 @@ /datum/slime_type/cerulean colour = SLIME_TYPE_CERULEAN + transparent = TRUE core_type = /obj/item/slime_extract/cerulean mutations = list( /datum/slime_type/cerulean = 1, @@ -135,6 +143,7 @@ /datum/slime_type/sepia colour = SLIME_TYPE_SEPIA + transparent = TRUE core_type = /obj/item/slime_extract/sepia mutations = list( /datum/slime_type/sepia = 1, @@ -154,6 +163,7 @@ /datum/slime_type/green colour = SLIME_TYPE_GREEN + transparent = TRUE core_type = /obj/item/slime_extract/green mutations = list( /datum/slime_type/black = 1, @@ -163,6 +173,7 @@ /datum/slime_type/pink colour = SLIME_TYPE_PINK + transparent = TRUE core_type = /obj/item/slime_extract/pink mutations = list( /datum/slime_type/lightpink = 1, @@ -172,6 +183,7 @@ /datum/slime_type/red colour = SLIME_TYPE_RED + transparent = TRUE core_type = /obj/item/slime_extract/red mutations = list( /datum/slime_type/oil = 1, @@ -191,6 +203,7 @@ /datum/slime_type/black colour = SLIME_TYPE_BLACK + transparent = TRUE core_type = /obj/item/slime_extract/black mutations = list( /datum/slime_type/black = 1, @@ -199,6 +212,7 @@ /datum/slime_type/lightpink colour = SLIME_TYPE_LIGHT_PINK + transparent = TRUE core_type = /obj/item/slime_extract/lightpink mutations = list( /datum/slime_type/lightpink = 1, @@ -217,6 +231,7 @@ /datum/slime_type/rainbow colour = SLIME_TYPE_RAINBOW + transparent = TRUE core_type = /obj/item/slime_extract/rainbow mutations = list( /datum/slime_type/rainbow = 1, diff --git a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm index d2b5edc58cced..4ba903d99285f 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm @@ -281,7 +281,7 @@ /mob/living/basic/revenant/gib() death() -/mob/living/basic/revenant/can_perform_action(atom/movable/target, action_bitflags) +/mob/living/basic/revenant/can_perform_action(atom/target, action_bitflags) return FALSE /mob/living/basic/revenant/ex_act(severity, target) diff --git a/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm b/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm index be31e121249a6..2286f65b79758 100644 --- a/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm +++ b/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm @@ -77,6 +77,11 @@ buffet = new(src) buffet.Grant(src) +/mob/living/basic/space_dragon/Destroy() + fire_breath = null + buffet = null + return ..() + /mob/living/basic/space_dragon/Login() . = ..() if(!isnull(chosen_colour)) diff --git a/code/modules/mob/living/basic/vermin/mothroach.dm b/code/modules/mob/living/basic/vermin/mothroach/mothroach.dm similarity index 88% rename from code/modules/mob/living/basic/vermin/mothroach.dm rename to code/modules/mob/living/basic/vermin/mothroach/mothroach.dm index 4c06665a14afc..a0079065de437 100644 --- a/code/modules/mob/living/basic/vermin/mothroach.dm +++ b/code/modules/mob/living/basic/vermin/mothroach/mothroach.dm @@ -36,6 +36,10 @@ /mob/living/basic/mothroach/Initialize(mapload) . = ..() + var/static/list/food_types = list(/obj/item/clothing) + AddElement(/datum/element/basic_eating, food_types = food_types) + ai_controller.set_blackboard_key(BB_BASIC_FOODS, typecacheof(food_types)) + AddElement(/datum/element/ai_retaliate) AddElement(/datum/element/pet_bonus, "squeaks happily!") add_verb(src, /mob/living/proc/toggle_resting) ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) @@ -64,16 +68,6 @@ else playsound(loc, 'sound/voice/moth/scream_moth.ogg', 50, TRUE) -/datum/ai_controller/basic_controller/mothroach - blackboard = list() - - ai_traits = STOP_MOVING_WHEN_PULLED - ai_movement = /datum/ai_movement/basic_avoidance - idle_behavior = /datum/idle_behavior/idle_random_walk - planning_subtrees = list( - /datum/ai_planning_subtree/random_speech/mothroach, - ) - /mob/living/basic/mothroach/bar name = "mothroach bartender" desc = "A mothroach serving drinks. Look at him go." diff --git a/code/modules/mob/living/basic/vermin/mothroach/mothroach_ai.dm b/code/modules/mob/living/basic/vermin/mothroach/mothroach_ai.dm new file mode 100644 index 0000000000000..5ef330cdc64f9 --- /dev/null +++ b/code/modules/mob/living/basic/vermin/mothroach/mothroach_ai.dm @@ -0,0 +1,35 @@ +#define MOTHROACH_EAT_TIMER 1 MINUTES + +/datum/ai_controller/basic_controller/mothroach + blackboard = list( + BB_FLEE_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items, + ) + + ai_traits = STOP_MOVING_WHEN_PULLED + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/find_food/mothroach, + /datum/ai_planning_subtree/target_retaliate/to_flee, + /datum/ai_planning_subtree/flee_target/from_flee_key, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/random_speech/mothroach, + ) + +/datum/ai_controller/basic_controller/mothroach/TryPossessPawn(atom/new_pawn) + . = ..() + if(. & AI_CONTROLLER_INCOMPATIBLE) + return + RegisterSignal(new_pawn, COMSIG_MOB_ATE, PROC_REF(on_eaten)) + +/datum/ai_controller/basic_controller/mothroach/proc/on_eaten(datum/source) + SIGNAL_HANDLER + set_blackboard_key(BB_MOTHROACH_NEXT_EAT, world.time + MOTHROACH_EAT_TIMER) + +/datum/ai_planning_subtree/find_food/mothroach/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(world.time < controller.blackboard[BB_MOTHROACH_NEXT_EAT]) + return + return ..() + +#undef MOTHROACH_EAT_TIMER diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm index 1ef72fd18e600..b0a747ff51d88 100644 --- a/code/modules/mob/living/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -394,7 +394,15 @@ /obj/item/organ/internal/brain/primitive //No like books and stompy metal men name = "primitive brain" desc = "This juicy piece of meat has a clearly underdeveloped frontal lobe." - organ_traits = list(TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, TRAIT_PRIMITIVE) // No literacy + organ_traits = list( + TRAIT_ADVANCEDTOOLUSER, + TRAIT_CAN_STRIP, + TRAIT_PRIMITIVE, // No literacy + TRAIT_FORBID_MINING_SHUTTLE_CONSOLE_OUTSIDE_STATION, + TRAIT_EXPERT_FISHER, // live off land, fish from river + TRAIT_ROUGHRIDER, // ride beast, chase down prey, flee from danger + TRAIT_BEAST_EMPATHY, // know the way of beast, calm with food + ) /obj/item/organ/internal/brain/golem name = "crystalline matrix" diff --git a/code/modules/mob/living/carbon/alien/adult/adult.dm b/code/modules/mob/living/carbon/alien/adult/adult.dm index c15efb77a4a19..ad005888178ac 100644 --- a/code/modules/mob/living/carbon/alien/adult/adult.dm +++ b/code/modules/mob/living/carbon/alien/adult/adult.dm @@ -140,7 +140,7 @@ GLOBAL_LIST_INIT(strippable_alien_humanoid_items, create_strippable_list(list( return TRUE /mob/living/carbon/alien/adult/get_butt_sprite() - return BUTT_SPRITE_XENOMORPH + return icon('icons/mob/butts.dmi', BUTT_SPRITE_XENOMORPH) // Aliens can touch acid /mob/living/carbon/alien/can_touch_acid(atom/acided_atom, acid_power, acid_volume) diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index b9dca314b5189..1e514ad13cedb 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -102,6 +102,9 @@ GLOBAL_LIST_EMPTY(features_by_species) ///Replaces default appendix with a different organ. var/obj/item/organ/internal/appendix/mutantappendix = /obj/item/organ/internal/appendix + /// Store body marking defines. See mobs.dm for bitflags + var/list/body_markings = list() + /// Flat modifier on all damage taken via [apply_damage][/mob/living/proc/apply_damage] (so being punched, shot, etc.) /// IE: 10 = 10% less damage taken. var/damage_modifier = 0 @@ -400,7 +403,7 @@ GLOBAL_LIST_EMPTY(features_by_species) replacement.Insert(organ_holder, special=TRUE, movement_flags = DELETE_IF_REPLACED) /datum/species/proc/worn_items_fit_body_check(mob/living/carbon/wearer) - for(var/obj/item/equipped_item in wearer.get_equipped_items(include_pockets = TRUE)) + for(var/obj/item/equipped_item in wearer.get_equipped_items(INCLUDE_POCKETS)) var/equipped_item_slot = wearer.get_slot_by_item(equipped_item) if(!equipped_item.mob_can_equip(wearer, equipped_item_slot, bypass_equip_delay_self = TRUE, ignore_equipped = TRUE)) wearer.dropItemToGround(equipped_item, force = TRUE) @@ -466,7 +469,7 @@ GLOBAL_LIST_EMPTY(features_by_species) var/obj/item/organ/external/new_organ = SSwardrobe.provide_type(organ_path) new_organ.Insert(human, special=TRUE, movement_flags = DELETE_IF_REPLACED) - + add_body_markings(human_who_gained_species) if(length(inherent_traits)) human_who_gained_species.add_traits(inherent_traits, SPECIES_TRAIT) @@ -526,6 +529,8 @@ GLOBAL_LIST_EMPTY(features_by_species) clear_tail_moodlets(C) + remove_body_markings(C) + // Removes all languages previously associated with [LANGUAGE_SPECIES], gaining our new species will add new ones back var/datum/language_holder/losing_holder = GLOB.prototype_language_holders[species_language_holder] for(var/language in losing_holder.understood_languages) @@ -560,42 +565,6 @@ GLOBAL_LIST_EMPTY(features_by_species) eye_organ.refresh(call_update = FALSE) standing += eye_organ.generate_body_overlay(species_human) - // organic body markings (oh my god this is terrible please rework this to be done on the limbs themselves i beg you) - if(HAS_TRAIT(species_human, TRAIT_HAS_MARKINGS)) - var/obj/item/bodypart/chest/chest = species_human.get_bodypart(BODY_ZONE_CHEST) - var/obj/item/bodypart/arm/right/right_arm = species_human.get_bodypart(BODY_ZONE_R_ARM) - var/obj/item/bodypart/arm/left/left_arm = species_human.get_bodypart(BODY_ZONE_L_ARM) - var/obj/item/bodypart/leg/right/right_leg = species_human.get_bodypart(BODY_ZONE_R_LEG) - var/obj/item/bodypart/leg/left/left_leg = species_human.get_bodypart(BODY_ZONE_L_LEG) - var/datum/sprite_accessory/markings = SSaccessories.moth_markings_list[species_human.dna.features["moth_markings"]] - var/mutable_appearance/marking = mutable_appearance(layer = -BODY_LAYER, appearance_flags = KEEP_TOGETHER) - - if(noggin && (IS_ORGANIC_LIMB(noggin))) - var/mutable_appearance/markings_head_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_head") - marking.overlays += markings_head_overlay - - if(chest && (IS_ORGANIC_LIMB(chest))) - var/mutable_appearance/markings_chest_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_chest") - marking.overlays += markings_chest_overlay - - if(right_arm && (IS_ORGANIC_LIMB(right_arm))) - var/mutable_appearance/markings_r_arm_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_r_arm") - marking.overlays += markings_r_arm_overlay - - if(left_arm && (IS_ORGANIC_LIMB(left_arm))) - var/mutable_appearance/markings_l_arm_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_l_arm") - marking.overlays += markings_l_arm_overlay - - if(right_leg && (IS_ORGANIC_LIMB(right_leg))) - var/mutable_appearance/markings_r_leg_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_r_leg") - marking.overlays += markings_r_leg_overlay - - if(left_leg && (IS_ORGANIC_LIMB(left_leg))) - var/mutable_appearance/markings_l_leg_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_l_leg") - marking.overlays += markings_l_leg_overlay - - standing += marking - //Underwear, Undershirts & Socks if(!HAS_TRAIT(species_human, TRAIT_NO_UNDERWEAR)) if(species_human.underwear) @@ -672,8 +641,6 @@ GLOBAL_LIST_EMPTY(features_by_species) switch(bodypart) if("ears") accessory = SSaccessories.ears_list[source.dna.features["ears"]] - if("body_markings") - accessory = SSaccessories.body_markings_list[source.dna.features["body_markings"]] if("legs") accessory = SSaccessories.legs_list[source.dna.features["legs"]] @@ -727,6 +694,8 @@ GLOBAL_LIST_EMPTY(features_by_species) source.apply_overlay(BODY_ADJ_LAYER) source.apply_overlay(BODY_FRONT_LAYER) + update_body_markings(source) + //This exists so sprite accessories can still be per-layer without having to include that layer's //number in their sprite name, which causes issues when those numbers change. /datum/species/proc/mutant_bodyparts_layertext(layer) @@ -1519,6 +1488,7 @@ GLOBAL_LIST_EMPTY(features_by_species) || (preference.relevant_inherent_trait in inherent_traits) \ || (preference.relevant_external_organ in external_organs) \ || (preference.relevant_head_flag && check_head_flags(preference.relevant_head_flag)) \ + || (preference.relevant_body_markings in body_markings) \ ) features += preference.savefile_key @@ -2110,3 +2080,48 @@ GLOBAL_LIST_EMPTY(features_by_species) return fixed_mut_color return null + +/// Add species appropriate body markings +/datum/species/proc/add_body_markings(mob/living/carbon/human/hooman) + for(var/markings_type in body_markings) //loop through possible species markings + var/datum/bodypart_overlay/simple/body_marking/markings = new markings_type() // made to die... mostly because we cant use initial on lists but its convenient and organized + var/accessory_name = hooman.dna.features[markings.dna_feature_key] //get the accessory name from dna + var/datum/sprite_accessory/moth_markings/accessory = markings.get_accessory(accessory_name) //get the actual datum + + if(isnull(accessory)) + CRASH("Value: [accessory_name] did not have a corresponding sprite accessory!") + + for(var/obj/item/bodypart/part as anything in markings.applies_to) //check through our limbs + var/obj/item/bodypart/people_part = hooman.get_bodypart(initial(part.body_zone)) // and see if we have a compatible marking for that limb + + if(!people_part) + continue + + var/datum/bodypart_overlay/simple/body_marking/overlay = new markings_type () + + // Tell the overlay what it should look like + overlay.icon = accessory.icon + overlay.icon_state = accessory.icon_state + overlay.use_gender = accessory.gender_specific + overlay.draw_color = accessory.color_src ? hooman.dna.features["mcolor"] : null + + people_part.add_bodypart_overlay(overlay) + +/// Remove body markings +/datum/species/proc/remove_body_markings(mob/living/carbon/human/hooman) + for(var/obj/item/bodypart/part as anything in hooman.bodyparts) + for(var/datum/bodypart_overlay/simple/body_marking/marking in part.bodypart_overlays) + part.remove_bodypart_overlay(marking) + +/// Update the overlays if necessary +/datum/species/proc/update_body_markings(mob/living/carbon/human/hooman) + var/needs_update = FALSE + for(var/datum/bodypart_overlay/simple/body_marking/marking as anything in body_markings) + if(initial(marking.dna_feature_key) == body_markings[marking]) // dna is same as our species (sort of mini-cache), so no update needed + continue + needs_update = TRUE + break + + if(needs_update) + remove_body_markings(hooman) + add_body_markings(hooman) diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index 627745cba929e..3340e34064052 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -41,7 +41,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) //Instead of just deleting our equipment, we save what we can and reinsert it into SSwardrobe's store //Hopefully this makes preference reloading not the worst thing ever /mob/living/carbon/human/dummy/delete_equipment() - var/list/items_to_check = get_equipped_items(include_pockets = TRUE) + held_items + var/list/items_to_check = get_equipped_items(INCLUDE_POCKETS | INCLUDE_HELD) var/list/to_nuke = list() //List of items queued for deletion, can't qdel them before iterating their contents in case they hold something ///Travel to the bottom of the contents chain, expanding it out for(var/i = 1; i <= length(items_to_check); i++) //Needs to be a c style loop since it can expand @@ -103,7 +103,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) /proc/create_consistent_human_dna(mob/living/carbon/human/target) target.dna.features["mcolor"] = COLOR_VIBRANT_LIME target.dna.features["ethcolor"] = COLOR_WHITE - target.dna.features["body_markings"] = get_consistent_feature_entry(SSaccessories.body_markings_list) + target.dna.features["lizard_markings"] = get_consistent_feature_entry(SSaccessories.lizard_markings_list) target.dna.features["ears"] = get_consistent_feature_entry(SSaccessories.ears_list) target.dna.features["frills"] = get_consistent_feature_entry(SSaccessories.frills_list) target.dna.features["horns"] = get_consistent_feature_entry(SSaccessories.horns_list) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 6e1f9037018b6..aa2daa1675e91 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -93,7 +93,7 @@ return TRUE var/block_chance_modifier = round(damage / -3) - for(var/obj/item/worn_thing in get_equipped_items(include_pockets = FALSE) + held_items) + for(var/obj/item/worn_thing in get_equipped_items(INCLUDE_HELD)) // Things that are supposed to be worn, being held = cannot block if(isclothing(worn_thing)) if(worn_thing in held_items) @@ -796,6 +796,10 @@ if(leg_clothes) burning_items |= leg_clothes + if (!gloves || (!(gloves.resistance_flags & FIRE_PROOF) && (gloves.resistance_flags & FLAMMABLE))) + for(var/obj/item/burnable_item in held_items) + burning_items |= burnable_item + for(var/obj/item/burning in burning_items) burning.fire_act((stacks * 25 * seconds_per_tick)) //damage taken is reduced to 2% of this value by fire_act() diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index da2c057d740bb..1fe6555cddf9c 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -293,6 +293,11 @@ return MONKEY_HEIGHT_DWARF else return HUMAN_HEIGHT_DWARF + if(HAS_TRAIT(src, TRAIT_TOO_TALL)) + if(ismonkey(src)) + return MONKEY_HEIGHT_TALL + else + return HUMAN_HEIGHT_TALLEST else if(ismonkey(src)) return MONKEY_HEIGHT_MEDIUM @@ -360,3 +365,30 @@ var/damage = ((min_damage / 4) + (max_damage / 4)) / 2 // We expect you to have 4 functional limbs- if you have fewer you're probably not going to be so good at lifting return ceil(damage * (ceil(athletics_level / 2)) * fitness_modifier * maxHealth) + +/mob/living/carbon/human/proc/item_heal(mob/user, brute_heal, burn_heal, heal_message_brute, heal_message_burn, required_bodytype) + var/obj/item/bodypart/affecting = src.get_bodypart(check_zone(user.zone_selected)) + if (!affecting || !(affecting.bodytype & required_bodytype)) + to_chat(user, span_warning("[affecting] is already in good condition!")) + return FALSE + + var/brute_damaged = affecting.brute_dam > 0 + var/burn_damaged = affecting.burn_dam > 0 + + var/nothing_to_heal = ((brute_heal <= 0 || !brute_damaged) && (burn_heal <= 0 || !burn_damaged)) + if (nothing_to_heal) + to_chat(user, span_notice("[affecting] is already in good condition!")) + return FALSE + + src.update_damage_overlays() + var/message + if ((brute_damaged && brute_heal > 0) && (burn_damaged && burn_heal > 0)) + message = "[heal_message_brute] and [heal_message_burn] on" + else if (brute_damaged && brute_heal > 0) + message = "[heal_message_brute] on" + else + message = "[heal_message_burn] on" + affecting.heal_damage(brute_heal, burn_heal, required_bodytype) + user.visible_message(span_notice("[user] fixes some of the [message] [src]'s [affecting.name]."), \ + span_notice("You fix some of the [message] [src == user ? "your" : "[src]'s"] [affecting.name].")) + return TRUE diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index bd320079b65d5..fe5817eab2780 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -864,20 +864,34 @@ generate/load female uniform sprites matching all previously decided variables "params" = displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 4), ), )) + if(HUMAN_HEIGHT_DWARF) // tall monkeys and dwarves use the same value + if(ismonkey(src)) + appearance.add_filters(list( + list( + "name" = "Monkey_Torso", + "priority" = 1, + "params" = displacement_map_filter(cut_torso_mask, x = 0, y = 0, size = 1), + ), + list( + "name" = "Monkey_Legs", + "priority" = 1, + "params" = displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 1), + ), + )) + else + appearance.add_filters(list( + list( + "name" = "Gnome_Cut_Torso", + "priority" = 1, + "params" = displacement_map_filter(cut_torso_mask, x = 0, y = 0, size = 2), + ), + list( + "name" = "Gnome_Cut_Legs", + "priority" = 1, + "params" = displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 3), + ), + )) // Don't set this one directly, use TRAIT_DWARF - if(HUMAN_HEIGHT_DWARF) - appearance.add_filters(list( - list( - "name" = "Gnome_Cut_Torso", - "priority" = 1, - "params" = displacement_map_filter(cut_torso_mask, x = 0, y = 0, size = 2), - ), - list( - "name" = "Gnome_Cut_Legs", - "priority" = 1, - "params" = displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 3), - ), - )) if(HUMAN_HEIGHT_SHORTEST) appearance.add_filters(list( list( diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index 32ab7ca1b900a..19e4b7a43deb6 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -347,7 +347,7 @@ //delete all equipment without dropping anything /mob/living/carbon/human/proc/delete_equipment() - for(var/slot in get_equipped_items(include_pockets = TRUE))//order matters, dependant slots go first + for(var/slot in get_equipped_items(INCLUDE_POCKETS))//order matters, dependant slots go first qdel(slot) for(var/obj/item/held_item in held_items) qdel(held_item) diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index b2a036a9d6d71..71a5c4c026193 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -8,7 +8,8 @@ TRAIT_TACKLING_TAILED_DEFENDER, ) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_REPTILE - mutant_bodyparts = list("body_markings" = "None", "legs" = "Normal Legs") + mutant_bodyparts = list("legs" = "Normal Legs") + body_markings = list(/datum/bodypart_overlay/simple/body_marking/lizard = "None") external_organs = list( /obj/item/organ/external/horns = "None", /obj/item/organ/external/frills = "None", @@ -49,7 +50,7 @@ /datum/species/lizard/randomize_features() var/list/features = ..() - features["body_markings"] = pick(SSaccessories.body_markings_list) + features["lizard_markings"] = pick(SSaccessories.lizard_markings_list) return features /datum/species/lizard/get_scream_sound(mob/living/carbon/human/lizard) @@ -156,7 +157,6 @@ Lizard subspecies: ASHWALKERS inherent_traits = list( TRAIT_MUTANT_COLORS, TRAIT_VIRUSIMMUNE, - TRAIT_FORBID_MINING_SHUTTLE_CONSOLE_OUTSIDE_STATION, ) species_language_holder = /datum/language_holder/lizard/ash digitigrade_customization = DIGITIGRADE_FORCED diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm index e2458563b038c..26efe358221fc 100644 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm @@ -3,12 +3,11 @@ plural_form = "Mothmen" id = SPECIES_MOTH inherent_traits = list( - TRAIT_HAS_MARKINGS, TRAIT_TACKLING_WINGED_ATTACKER, TRAIT_ANTENNAE, ) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG - mutant_bodyparts = list("moth_markings" = "None") + body_markings = list(/datum/bodypart_overlay/simple/body_marking/moth = "None") external_organs = list(/obj/item/organ/external/wings/moth = "Plain", /obj/item/organ/external/antennae = "Plain") meat = /obj/item/food/meat/slab/human/mutant/moth mutanttongue = /obj/item/organ/internal/tongue/moth diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 117dc5583eae5..68175333519a1 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -176,7 +176,7 @@ stat_allowed = HARD_CRIT /datum/emote/living/gasp/get_sound(mob/living/user) - if(!HAS_MIND_TRAIT(user, TRAIT_MIMING)) + if(HAS_MIND_TRAIT(user, TRAIT_MIMING)) return if(!ishuman(user)) return diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index b5e538461f2da..df15d979836b6 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1310,10 +1310,14 @@ /mob/living/can_hold_items(obj/item/I) return ..() && HAS_TRAIT(src, TRAIT_CAN_HOLD_ITEMS) && usable_hands -/mob/living/can_perform_action(atom/movable/target, action_bitflags) +/mob/living/can_perform_action(atom/target, action_bitflags) if(!istype(target)) CRASH("Missing target arg for can_perform_action") + if(stat != CONSCIOUS) + to_chat(src, span_warning("You are not conscious enough for this action!")) + return FALSE + if(!(interaction_flags_atom & INTERACT_ATOM_IGNORE_INCAPACITATED)) var/ignore_flags = NONE if(interaction_flags_atom & INTERACT_ATOM_IGNORE_RESTRAINED) @@ -1325,10 +1329,6 @@ to_chat(src, span_warning("You are incapacitated at the moment!")) return FALSE - if(stat == DEAD || stat != CONSCIOUS) - to_chat(src, span_warning("You are in no physical condition to do this!")) - return FALSE - // If the MOBILITY_UI bitflag is not set it indicates the mob's hands are cutoff, blocked, or handcuffed // Note - AI's and borgs have the MOBILITY_UI bitflag set even though they don't have hands // Also if it is not set, the mob could be incapcitated, knocked out, unconscious, asleep, EMP'd, etc. @@ -1345,7 +1345,7 @@ to_chat(src, span_warning("You don't have the physical ability to do this!")) return FALSE - if(!(action_bitflags & BYPASS_ADJACENCY) && !Adjacent(target) && (target.loc != src) && !recursive_loc_check(src, target)) + if(!(action_bitflags & BYPASS_ADJACENCY) && !recursive_loc_check(src, target) && !CanReach(target)) if(HAS_SILICON_ACCESS(src) && !ispAI(src)) if(!(action_bitflags & ALLOW_SILICON_REACH)) // silicons can ignore range checks (except pAIs) if(!(action_bitflags & SILENT_ADJACENCY)) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 8354ff0447461..6c4be898162dd 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -875,7 +875,7 @@ to_chat(src, "You have been downloaded to a mobile storage device. Remote device connection severed.") to_chat(user, "[span_boldnotice("Transfer successful")]: [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory.") -/mob/living/silicon/ai/can_perform_action(atom/movable/target, action_bitflags) +/mob/living/silicon/ai/can_perform_action(atom/target, action_bitflags) if(control_disabled) to_chat(src, span_warning("You can't do that right now!")) return FALSE diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 6fefbb05f7c0d..0c26e7c57e278 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -553,7 +553,7 @@ if(AI_NOTIFICATION_CYBORG_DISCONNECTED) //Tampering with the wires to_chat(connected_ai, "

[span_notice("NOTICE - Remote telemetry lost with [name].")]
") -/mob/living/silicon/robot/can_perform_action(atom/movable/target, action_bitflags) +/mob/living/silicon/robot/can_perform_action(atom/target, action_bitflags) if(lockcharge || low_power_mode) to_chat(src, span_warning("You can't do that right now!")) return FALSE diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 95e2e6ed13379..6d94c2c5be978 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -442,7 +442,7 @@ return // Silicons are always standing by default. /mob/living/silicon/get_butt_sprite() - return BUTT_SPRITE_QR_CODE + return icon('icons/mob/butts.dmi', BUTT_SPRITE_QR_CODE) /** * Records an IC event log entry in the cyborg's internal tablet. diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 51b2f3954973d..7a205da5c089f 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -486,7 +486,8 @@ . = ..() if(has_gravity()) for(var/mob/living/carbon/human/future_pancake in loc) - run_over(future_pancake) + if(future_pancake.body_position == LYING_DOWN) + run_over(future_pancake) diag_hud_set_mulebotcell() diff --git a/code/modules/mob/living/ventcrawling.dm b/code/modules/mob/living/ventcrawling.dm index 3d7be3ea47e29..e25a6f9b16e27 100644 --- a/code/modules/mob/living/ventcrawling.dm +++ b/code/modules/mob/living/ventcrawling.dm @@ -31,7 +31,7 @@ to_chat(src, span_warning("You can't vent crawl while buckled!")) return if(iscarbon(src) && required_nudity) - if(length(get_equipped_items(include_pockets = TRUE)) || get_num_held_items()) + if(length(get_equipped_items(INCLUDE_POCKETS)) || get_num_held_items()) if(provide_feedback) to_chat(src, span_warning("You can't crawl around in the ventilation ducts with items!")) return diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index ca393cf25666f..7dd1cf0d2880f 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1164,7 +1164,7 @@ * silence_adjacency: Sometimes we want to use this proc to check interaction without allowing it to throw errors for base case adjacency * Alt click uses this, as otherwise you can detect what is interactable from a distance via the error message **/ -/mob/proc/can_perform_action(atom/movable/target, action_bitflags) +/mob/proc/can_perform_action(atom/target, action_bitflags) return ///Can this mob use storage @@ -1537,8 +1537,8 @@ else speedies += thing.slowdown - //if our movespeed mod is in the negatives, we don't modify it since that's a benefit - if(speedies > 0 && HAS_TRAIT(src, TRAIT_SETTLER)) + //if we have TRAIT_STURDY_FRAME, we reduce our overall speed penalty UNLESS that penalty would be a negative value, and therefore a speed boost. + if(speedies > 0 && HAS_TRAIT(src, TRAIT_STURDY_FRAME)) speedies *= 0.2 if(immutable_speedies) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 9092efac428ca..a6a1c58c7eddf 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -331,19 +331,6 @@ toast.name = header toast.target_ref = WEAKREF(source) -/// Heals a robotic limb on a mob -/proc/item_heal_robotic(mob/living/carbon/human/human, mob/user, brute_heal, burn_heal) - var/obj/item/bodypart/affecting = human.get_bodypart(check_zone(user.zone_selected)) - if(!affecting || IS_ORGANIC_LIMB(affecting)) - to_chat(user, span_warning("[affecting] is already in good condition!")) - return FALSE - var/brute_damage = brute_heal > burn_heal //changes repair text based on how much brute/burn was supplied - if((brute_heal > 0 && affecting.brute_dam > 0) || (burn_heal > 0 && affecting.burn_dam > 0)) - if(affecting.heal_damage(brute_heal, burn_heal, required_bodytype = BODYTYPE_ROBOTIC)) - human.update_damage_overlays() - user.visible_message(span_notice("[user] fixes some of the [brute_damage ? "dents on" : "burnt wires in"] [human]'s [affecting.name]."), \ - span_notice("You fix some of the [brute_damage ? "dents on" : "burnt wires in"] [human == user ? "your" : "[human]'s"] [affecting.name].")) - return TRUE //successful heal ///Is the passed in mob a ghost with admin powers, doesn't check for AI interact like isAdminGhost() used to diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index b4fbd713065aa..d186661d87fae 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -140,8 +140,8 @@ new_borg.gender = gender new_borg.SetInvisibility(INVISIBILITY_NONE) - if(client) - new_borg.updatename(client) + if(client?.prefs.read_preference(/datum/preference/name/cyborg) != DEFAULT_CYBORG_NAME) + new_borg.apply_pref_name(/datum/preference/name/cyborg, client) if(mind) //TODO //TODO WHAT if(!transfer_after) @@ -312,7 +312,7 @@ SSblackbox.record_feedback("amount", "gorillas_created", 1) - var/Itemlist = get_equipped_items(include_pockets = TRUE) + var/Itemlist = get_equipped_items(INCLUDE_POCKETS) Itemlist += held_items for(var/obj/item/W in Itemlist) dropItemToGround(W, TRUE) diff --git a/code/modules/mob_spawn/mob_spawn.dm b/code/modules/mob_spawn/mob_spawn.dm index ad8c7e6a03ef0..c9130fb706e1b 100644 --- a/code/modules/mob_spawn/mob_spawn.dm +++ b/code/modules/mob_spawn/mob_spawn.dm @@ -139,6 +139,10 @@ /// Typepath indicating the kind of job datum this ghost role will have. PLEASE inherit this with a new job datum, it's not hard. jobs come with policy configs. var/spawner_job_path = /datum/job/ghost_role + /// Whether this offers a temporary body or not. Essentially, you'll be able to reenter your body after using this spawner. + var/temp_body = FALSE + + /obj/effect/mob_spawn/ghost_role/Initialize(mapload) . = ..() SSpoints_of_interest.make_point_of_interest(src) @@ -165,7 +169,7 @@ if(prompt_ghost) var/prompt = "Become [prompt_name]?" - if(user.can_reenter_corpse && user.mind) + if(!temp_body && user.can_reenter_corpse && user.mind) prompt += " (Warning, You can no longer be revived!)" var/ghost_role = tgui_alert(usr, prompt, buttons = list("Yes", "No"), timeout = 10 SECONDS) if(ghost_role != "Yes" || !loc || QDELETED(user)) @@ -213,7 +217,8 @@ user.log_message("became a [prompt_name].", LOG_GAME) uses -= 1 // Remove a use before trying to spawn to prevent strangeness like the spawner trying to spawn more mobs than it should be able to - user.mind = null // dissassociate mind, don't let it follow us to the next life + if(!temp_body) + user.mind = null // dissassociate mind, don't let it follow us to the next life var/created = create(user) LAZYREMOVE(ckeys_trying_to_spawn, user_ckey) // We do this AFTER the create() so that we're basically sure that the user won't be in their ghost body anymore, so they can't click on the spawner again. diff --git a/code/modules/mod/modules/modules_engineering.dm b/code/modules/mod/modules/modules_engineering.dm index cb830b2128e7e..e1081d0365a9b 100644 --- a/code/modules/mod/modules/modules_engineering.dm +++ b/code/modules/mod/modules/modules_engineering.dm @@ -15,7 +15,8 @@ /obj/item/mod/module/welding/on_suit_activation() var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) || mod.get_part_from_slot(ITEM_SLOT_MASK) || mod.get_part_from_slot(ITEM_SLOT_EYES) if(istype(head_cover)) - head_cover.flash_protect = FLASH_PROTECTION_WELDER + //this is a screen that displays an image, so flash sensitives can use this to protect against flashes. + head_cover.flash_protect = FLASH_PROTECTION_MAXIMUM /obj/item/mod/module/welding/on_suit_deactivation(deleting = FALSE) if(deleting) diff --git a/code/modules/modular_computers/computers/item/role_tablet_presets.dm b/code/modules/modular_computers/computers/item/role_tablet_presets.dm index ee6c9ee68f0af..44392c8c62de9 100644 --- a/code/modules/modular_computers/computers/item/role_tablet_presets.dm +++ b/code/modules/modular_computers/computers/item/role_tablet_presets.dm @@ -97,6 +97,7 @@ /datum/computer_file/program/crew_manifest, /datum/computer_file/program/robocontrol, /datum/computer_file/program/science, + /datum/computer_file/program/scipaper_program, /datum/computer_file/program/status, /datum/computer_file/program/signal_commander, ) @@ -187,6 +188,7 @@ starting_programs = list( /datum/computer_file/program/atmosscan, /datum/computer_file/program/science, + /datum/computer_file/program/scipaper_program, /datum/computer_file/program/signal_commander, ) diff --git a/code/modules/modular_computers/computers/machinery/console_presets.dm b/code/modules/modular_computers/computers/machinery/console_presets.dm index 0ec80da4bbb29..ad87960603c35 100644 --- a/code/modules/modular_computers/computers/machinery/console_presets.dm +++ b/code/modules/modular_computers/computers/machinery/console_presets.dm @@ -137,6 +137,7 @@ starting_programs += /datum/computer_file/program/bounty_board starting_programs += /datum/computer_file/program/budgetorders starting_programs += /datum/computer_file/program/shipping + starting_programs += /datum/computer_file/program/restock_tracker /obj/machinery/modular_computer/preset/cargochat/cargo/setup_starting_software() var/datum/computer_file/program/chatclient/chatprogram = cpu.find_file_by_name("ntnrc_client") diff --git a/code/modules/modular_computers/file_system/programs/frontier.dm b/code/modules/modular_computers/file_system/programs/frontier.dm index c41cf642ffb55..7a65513508d3e 100644 --- a/code/modules/modular_computers/file_system/programs/frontier.dm +++ b/code/modules/modular_computers/file_system/programs/frontier.dm @@ -8,7 +8,7 @@ program_open_overlay = "research" tgui_id = "NtosScipaper" program_icon = "paper-plane" - download_access = list(ACCESS_ORDNANCE) + download_access = list(ACCESS_ORDNANCE, ACCESS_SCIENCE, ACCESS_AWAY_SCIENCE) var/datum/techweb/linked_techweb /// Unpublished, temporary paper datum. diff --git a/code/modules/modular_computers/file_system/programs/restock_tracker.dm b/code/modules/modular_computers/file_system/programs/restock_tracker.dm index 46462c0c6b531..8f2174ce97bbd 100644 --- a/code/modules/modular_computers/file_system/programs/restock_tracker.dm +++ b/code/modules/modular_computers/file_system/programs/restock_tracker.dm @@ -5,7 +5,7 @@ program_open_overlay = "restock" extended_desc = "Nanotrasen IoT network listing all the vending machines found on station, and how well stocked they are each. Profitable!" program_flags = PROGRAM_ON_NTNET_STORE | PROGRAM_REQUIRES_NTNET - can_run_on_flags = PROGRAM_LAPTOP | PROGRAM_PDA + can_run_on_flags = PROGRAM_ALL size = 4 program_icon = "cash-register" tgui_id = "NtosRestock" diff --git a/code/modules/pai/pai.dm b/code/modules/pai/pai.dm index 0ea51f19d37e2..11334f12abc79 100644 --- a/code/modules/pai/pai.dm +++ b/code/modules/pai/pai.dm @@ -149,7 +149,7 @@ return ..() // See software.dm for Topic() -/mob/living/silicon/pai/can_perform_action(atom/movable/target, action_bitflags) +/mob/living/silicon/pai/can_perform_action(atom/target, action_bitflags) action_bitflags |= ALLOW_RESTING // Resting is just an aesthetic feature for them action_bitflags &= ~ALLOW_SILICON_REACH // They don't get long reach like the rest of silicons return ..(target, action_bitflags) diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index b7796ad070a87..72d3ecd85ba03 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -495,10 +495,9 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) /obj/machinery/photocopier/proc/make_ass_copy() if(!check_ass()) return null - var/butt_icon_state = ass.get_butt_sprite() - if(isnull(butt_icon_state)) + var/icon/temp_img = ass.get_butt_sprite() + if(isnull(temp_img)) return null - var/icon/temp_img = icon('icons/mob/butts.dmi', butt_icon_state) var/obj/item/photo/copied_ass = new /obj/item/photo(src) var/datum/picture/toEmbed = new(name = "[ass]'s Ass", desc = "You see [ass]'s ass on the photo.", image = temp_img) toEmbed.psize_x = 128 diff --git a/code/modules/power/apc/apc_attack.dm b/code/modules/power/apc/apc_attack.dm index 8c9715f1dcb1c..50f10c47e33c1 100644 --- a/code/modules/power/apc/apc_attack.dm +++ b/code/modules/power/apc/apc_attack.dm @@ -85,7 +85,7 @@ return /obj/machinery/power/apc/blob_act(obj/structure/blob/B) - set_broken() + atom_break() /obj/machinery/power/apc/take_damage(damage_amount, damage_type = BRUTE, damage_flag = "", sound_effect = TRUE, attack_dir, armor_penetration = 0) // APC being at 0 integrity doesnt delete it outright. Combined with take_damage this might cause runtimes. @@ -100,11 +100,6 @@ return damage_amount . = ..() -/obj/machinery/power/apc/atom_break(damage_flag) - . = ..() - if(.) - set_broken() - /obj/machinery/power/apc/proc/can_use(mob/user, loud = 0) //used by attack_hand() and Topic() if(isAdminGhostAI(user)) return TRUE @@ -120,17 +115,6 @@ balloon_alert(user, "it's disabled!") return . -/obj/machinery/power/apc/proc/set_broken() - if(machine_stat & BROKEN) - return - if(malfai && operating) - malfai.malf_picker.processing_time = clamp(malfai.malf_picker.processing_time - 10,0,1000) - operating = FALSE - atom_break() - if(occupier) - malfvacate(TRUE) - update() - /obj/machinery/power/apc/proc/shock(mob/user, prb) if(!prob(prb)) return FALSE diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm index 7e63aff7cbe1b..69732c69b97ac 100644 --- a/code/modules/power/apc/apc_main.dm +++ b/code/modules/power/apc/apc_main.dm @@ -250,38 +250,51 @@ /obj/machinery/power/apc/proc/on_saboteur(datum/source, disrupt_duration) SIGNAL_HANDLER + disrupt_duration *= 0.1 // so, turns out, failure timer is in seconds, not deciseconds; without this, disruptions last 10 times as long as they probably should energy_fail(disrupt_duration) return COMSIG_SABOTEUR_SUCCESS +/obj/machinery/power/apc/on_set_is_operational(old_value) + update_area_power_usage(!old_value) + +/obj/machinery/power/apc/update_name(updates) + . = ..() + if(auto_name) + name = "\improper [get_area_name(area, TRUE)] APC" + /obj/machinery/power/apc/proc/assign_to_area(area/target_area = get_area(src)) if(area == target_area) return disconnect_from_area() area = target_area - area.power_light = TRUE - area.power_equip = TRUE - area.power_environ = TRUE - area.power_change() + update_area_power_usage(TRUE) area.apc = src auto_name = TRUE update_appearance(UPDATE_NAME) -/obj/machinery/power/apc/update_name(updates) - . = ..() - if(auto_name) - name = "\improper [get_area_name(area, TRUE)] APC" +/obj/machinery/power/apc/proc/update_area_power_usage(state) + //apc is non functional so force disable + if(state && (has_electronics != APC_ELECTRONICS_SECURED || (machine_stat & (BROKEN | MAINT)) || QDELETED(cell))) + state = FALSE + + //no change in value + if(state == area.power_light && state == area.power_equip && state == area.power_environ) + return + + area.power_light = state + area.power_equip = state + area.power_environ = state + + area.power_change() /obj/machinery/power/apc/proc/disconnect_from_area() if(isnull(area)) return - area.power_light = FALSE - area.power_equip = FALSE - area.power_environ = FALSE - area.power_change() + update_area_power_usage(FALSE) area.apc = null area = null @@ -318,9 +331,16 @@ else . += "The cover is closed." -/obj/machinery/power/apc/on_deconstruction(disassembled = TRUE) - if(!(machine_stat & BROKEN)) - set_broken() +/obj/machinery/power/apc/atom_break(damage_flag) + . = ..() + if(.) + if(malfai && operating) + malfai.malf_picker.processing_time = clamp(malfai.malf_picker.processing_time - 10, 0, 1000) + operating = FALSE + if(occupier) + malfvacate(TRUE) + update() + if(opened != APC_COVER_REMOVED) opened = APC_COVER_REMOVED coverlocked = FALSE diff --git a/code/modules/power/apc/apc_malf.dm b/code/modules/power/apc/apc_malf.dm index f4c27e15a4067..1419e12c46be3 100644 --- a/code/modules/power/apc/apc_malf.dm +++ b/code/modules/power/apc/apc_malf.dm @@ -36,6 +36,12 @@ return if(!is_station_level(z)) return + INVOKE_ASYNC(src, PROC_REF(malfshunt), malf) + +/obj/machinery/power/apc/proc/malfshunt(mob/living/silicon/ai/malf) + var/confirm = tgui_alert(malf, "Are you sure that you want to shunt? This will take you out of your core!", "Shunt to [name]?", list("Yes", "No")) + if(confirm != "Yes") + return malf.ShutOffDoomsdayDevice() occupier = malf if (isturf(malf.loc)) // create a deactivated AI core if the AI isn't coming from an emergency mech shunt diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index e55442f31fd1f..a8e20cde8c7a0 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -575,7 +575,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri user.visible_message(span_notice("[user] starts to fix some of the wires in [H]'s [affecting.name]."), span_notice("You start fixing some of the wires in [H == user ? "your" : "[H]'s"] [affecting.name].")) if(!do_after(user, 5 SECONDS, H)) return - if(item_heal_robotic(H, user, 0, 15)) + if(H.item_heal(user, 0, 15, "dents", "burnt wires", BODYTYPE_ROBOTIC)) use(1) return else diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index dc2b4e9812a03..74352134f59f4 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -311,19 +311,29 @@ /obj/item/stock_parts/cell/crap name = "\improper Nanotrasen brand rechargeable AA battery" desc = "You can't top the plasma top." //TOTALLY TRADEMARK INFRINGEMENT + icon_state = "aa_cell" maxcharge = STANDARD_CELL_CHARGE * 0.5 custom_materials = list(/datum/material/glass=SMALL_MATERIAL_AMOUNT*0.4) +/obj/item/stock_parts/cell/crap/Initialize(mapload) + AddElement(/datum/element/update_icon_blocker) + return ..() + /obj/item/stock_parts/cell/crap/empty empty = TRUE /obj/item/stock_parts/cell/upgraded name = "upgraded power cell" desc = "A power cell with a slightly higher capacity than normal!" + icon_state = "9v_cell" maxcharge = STANDARD_CELL_CHARGE * 2.5 custom_materials = list(/datum/material/glass=SMALL_MATERIAL_AMOUNT*0.5) chargerate = STANDARD_CELL_RATE * 0.5 +/obj/item/stock_parts/cell/upgraded/Initialize(mapload) + AddElement(/datum/element/update_icon_blocker) + return ..() + /obj/item/stock_parts/cell/upgraded/plus name = "upgraded power cell+" desc = "A power cell with an even higher capacity than the base model!" @@ -470,21 +480,6 @@ charge_light_type = null connector_type = "slimecore" -/obj/item/stock_parts/cell/beam_rifle - name = "beam rifle capacitor" - desc = "A high powered capacitor that can provide huge amounts of energy in an instant." - maxcharge = STANDARD_CELL_CHARGE * 50 - chargerate = STANDARD_CELL_RATE * 2.5 //Extremely energy intensive - -/obj/item/stock_parts/cell/beam_rifle/corrupt() - return - -/obj/item/stock_parts/cell/beam_rifle/emp_act(severity) - . = ..() - if(. & EMP_PROTECT_SELF) - return - charge = clamp((charge-(10000/severity)),0,maxcharge) - /obj/item/stock_parts/cell/emergency_light name = "miniature power cell" desc = "A tiny power cell with a very low power capacity. Used in light fixtures to power them in the event of an outage." diff --git a/code/modules/power/lighting/light.dm b/code/modules/power/lighting/light.dm index 43713cc49ae0c..9d3eb222fb843 100644 --- a/code/modules/power/lighting/light.dm +++ b/code/modules/power/lighting/light.dm @@ -77,12 +77,13 @@ var/fire_power = 0.5 ///The Light colour to use when working in fire alarm status var/fire_colour = COLOR_FIRE_LIGHT_RED - ///Power usage - W per unit of luminosity var/power_consumption_rate = 20 + ///break if moved, if false also makes it ignore if the wall its on breaks + var/break_if_moved = TRUE /obj/machinery/light/Move() - if(status != LIGHT_BROKEN) + if(status != LIGHT_BROKEN && break_if_moved) break_light_tube(TRUE) return ..() @@ -117,7 +118,8 @@ RegisterSignal(src, COMSIG_LIGHT_EATER_ACT, PROC_REF(on_light_eater)) RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) AddElement(/datum/element/atmos_sensitive, mapload) - find_and_hang_on_wall(custom_drop_callback = CALLBACK(src, PROC_REF(knock_down))) + if(break_if_moved) + find_and_hang_on_wall(custom_drop_callback = CALLBACK(src, PROC_REF(knock_down))) /obj/machinery/light/post_machine_initialize() . = ..() @@ -733,3 +735,8 @@ /obj/machinery/light/floor/broken status = LIGHT_BROKEN icon_state = "floor-broken" + +/obj/machinery/light/floor/transport + name = "transport light" + break_if_moved = FALSE + layer = BELOW_OPEN_DOOR_LAYER diff --git a/code/modules/power/singularity/boh_tear.dm b/code/modules/power/singularity/reality_tear.dm similarity index 59% rename from code/modules/power/singularity/boh_tear.dm rename to code/modules/power/singularity/reality_tear.dm index a0089a7c94b35..e43301541a08f 100644 --- a/code/modules/power/singularity/boh_tear.dm +++ b/code/modules/power/singularity/reality_tear.dm @@ -1,4 +1,7 @@ -/obj/boh_tear +/// Tear in the Fabric of Reality /// +// Typically spawned by placing two bags of holding into one another, collapsing into a wandering singularity after a brief period as a stationary singularity. + +/obj/reality_tear name = "tear in the fabric of reality" desc = "As you gaze into the abyss, the only thing you can think is... \"Should I really be this close to it?\"" anchored = TRUE @@ -15,30 +18,36 @@ pixel_y = -32 resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF flags_1 = SUPERMATTER_IGNORES_1 + /// Range that our singularity component consumes objects + var/singularity_consume_range = 1 + /// Ranges that the singularity pulls objects + var/singularity_grav_pull = 21 + /// Time before we begin our bagulo spawn + var/collapse_spawn_time = 9 SECONDS -/obj/boh_tear/proc/start_disaster() +/obj/reality_tear/proc/start_disaster() apply_wibbly_filters(src) playsound(loc, 'sound/effects/clockcult_gateway_disrupted.ogg', vary = 200, extrarange = 3, falloff_exponent = 1, frequency = 0.33, pressure_affected = FALSE, ignore_walls = TRUE, falloff_distance = 7) AddComponent( /datum/component/singularity, \ - consume_range = 1, \ - grav_pull = 21, \ + consume_range = singularity_consume_range, \ + grav_pull = singularity_grav_pull, \ roaming = FALSE, \ singularity_size = STAGE_SIX, \ ) - addtimer(CALLBACK(src, PROC_REF(bagulo_time)), 9 SECONDS, TIMER_DELETE_ME) + addtimer(CALLBACK(src, PROC_REF(reality_collapse)), collapse_spawn_time, TIMER_DELETE_ME) animate(src, time = 7.5 SECONDS, transform = transform.Scale(2), flags = ANIMATION_PARALLEL) animate(time = 2 SECONDS, transform = transform.Scale(0.25), easing = ELASTIC_EASING) animate(time = 0.5 SECONDS, alpha = 0) -/obj/boh_tear/proc/bagulo_time() +/obj/reality_tear/proc/reality_collapse() playsound(loc, 'sound/effects/supermatter.ogg', 200, vary = TRUE, extrarange = 3, falloff_exponent = 1, frequency = 0.5, pressure_affected = FALSE, ignore_walls = TRUE, falloff_distance = 7) var/obj/singularity/bagulo = new(loc) bagulo.expand(STAGE_TWO) bagulo.energy = 400 qdel(src) -/obj/boh_tear/attack_tk(mob/user) +/obj/reality_tear/attack_tk(mob/user) if(!isliving(user)) return var/mob/living/jedi = user @@ -47,3 +56,15 @@ jedi.spawn_dust() addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, attack_hand), jedi), 0.5 SECONDS) return COMPONENT_CANCEL_ATTACK_CHAIN + +//The temporary tears in reality. Collapses into nothing, and has a significantly lower gravity pull range, but consumes more widely. + +/obj/reality_tear/temporary + name = "puncture in the fabric of reality" + desc = "Count your lucky stars that this wasn't anywhere near you." + singularity_consume_range = 2 + singularity_grav_pull = 3 + collapse_spawn_time = 2 SECONDS + +/obj/reality_tear/temporary/reality_collapse() + qdel(src) diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 4c00e83b0bbc6..b977441e9ae11 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -26,14 +26,23 @@ var/single_shot_type_overlay = TRUE ///Should we give an overlay to empty guns? var/display_empty = TRUE - var/selfcharge = 0 - var/charge_timer = 0 - var/charge_delay = 8 + ///whether the gun's cell drains the cyborg user's cell to recharge var/use_cyborg_cell = FALSE ///set to true so the gun is given an empty cell var/dead_cell = FALSE + // Self charging vars + + /// Whether or not our gun charges its own cell on a timer. + var/selfcharge = 0 + /// The amount of time between instances of cell self recharge + var/charge_timer = 0 + /// The amount of seconds_per_tick during process() before the gun charges itself + var/charge_delay = 8 + /// The amount restored by the gun to the cell per self charge tick + var/self_charge_amount = STANDARD_ENERGY_GUN_SELF_CHARGE_RATE + /obj/item/gun/energy/fire_sounds() // What frequency the energy gun's sound will make var/pitch_to_use = 1 @@ -153,7 +162,7 @@ if(charge_timer < charge_delay) return charge_timer = 0 - cell.give(STANDARD_ENERGY_GUN_SELF_CHARGE_RATE * seconds_per_tick) + cell.give(self_charge_amount * seconds_per_tick) if(!chambered) //if empty chamber we try to charge a new shot recharge_newshot(TRUE) update_appearance() diff --git a/code/modules/projectiles/guns/energy/beam_rifle.dm b/code/modules/projectiles/guns/energy/beam_rifle.dm index e29e1ef4878be..0bda1930c6260 100644 --- a/code/modules/projectiles/guns/energy/beam_rifle.dm +++ b/code/modules/projectiles/guns/energy/beam_rifle.dm @@ -1,588 +1,64 @@ - -#define ZOOM_LOCK_AUTOZOOM_FREEMOVE 0 -#define ZOOM_LOCK_AUTOZOOM_ANGLELOCK 1 -#define ZOOM_LOCK_CENTER_VIEW 2 -#define ZOOM_LOCK_OFF 3 - -#define AUTOZOOM_PIXEL_STEP_FACTOR 48 - -#define AIMING_BEAM_ANGLE_CHANGE_THRESHOLD 0.1 - -/obj/item/gun/energy/beam_rifle - name = "particle acceleration rifle" - desc = "An energy-based anti material marksman rifle that uses highly charged particle beams moving at extreme velocities to decimate whatever is unfortunate enough to be targeted by one." - desc_controls = "Hold down left click while scoped to aim, when weapon is fully aimed (Tracer goes from red to green as it charges), release to fire. Moving while aiming or changing where you're pointing at while aiming will delay the aiming process depending on how much you changed." +/obj/item/gun/energy/event_horizon + name = "\improper Event Horizon anti-existential beam rifle" + desc = "The deranged minds of Nanotrasen, in their great hubris and spite, have birthed forth the definitive conclusion to the arms race. Weaponized black holes, and a platform to deliver them.\ + To look upon this existential maleficence is to know that the pursuit of profit has consigned all life to this pathetic conclusion; the destruction of reality itself." icon = 'icons/obj/weapons/guns/energy.dmi' icon_state = "esniper" inhand_icon_state = null worn_icon_state = null fire_sound = 'sound/weapons/beam_sniper.ogg' slot_flags = ITEM_SLOT_BACK - force = 15 + force = 20 //This is maybe the sanest part of this weapon. custom_materials = null - recoil = 4 + recoil = 2 ammo_x_offset = 3 ammo_y_offset = 3 modifystate = FALSE charge_sections = 1 weapon_weight = WEAPON_HEAVY w_class = WEIGHT_CLASS_BULKY - ammo_type = list(/obj/item/ammo_casing/energy/beam_rifle/hitscan) - actions_types = list(/datum/action/item_action/zoom_lock_action) - cell_type = /obj/item/stock_parts/cell/beam_rifle - var/aiming = FALSE - var/aiming_time = 12 - var/aiming_time_fire_threshold = 5 - var/aiming_time_left = 12 - var/aiming_time_increase_user_movement = 3 - var/scoped_slow = 1 - var/aiming_time_increase_angle_multiplier = 0.3 - var/last_process = 0 - - var/lastangle = 0 - var/aiming_lastangle = 0 - var/mob/current_user = null - var/list/obj/effect/projectile/tracer/current_tracers - - var/structure_piercing = 2 //Amount * 2. For some reason structures aren't respecting this unless you have it doubled. Probably with the objects in question's Bump() code instead of this but I'll deal with this later. - var/structure_bleed_coeff = 0.7 - var/wall_pierce_amount = 0 - var/wall_devastate = 0 - var/aoe_structure_range = 1 - var/aoe_structure_damage = 50 - var/aoe_fire_range = 2 - var/aoe_fire_chance = 40 - var/aoe_mob_range = 1 - var/aoe_mob_damage = 30 - var/impact_structure_damage = 60 - var/projectile_damage = 30 - var/projectile_stun = 0 - var/projectile_setting_pierce = TRUE - var/delay = 25 - var/lastfire = 0 - - //ZOOMING - var/zoom_current_view_increase = 0 - ///The radius you want to zoom by - var/zoom_target_view_increase = 9.5 - var/zooming = FALSE - var/zoom_lock = ZOOM_LOCK_OFF - var/zooming_angle - var/current_zoom_x = 0 - var/current_zoom_y = 0 - - var/obj/projectile/beam/beam_rifle/hitscan/aiming_beam/trace = null - -/obj/item/gun/energy/beam_rifle/apply_fantasy_bonuses(bonus) - . = ..() - delay = modify_fantasy_variable("delay", delay, -bonus * 2) - aiming_time = modify_fantasy_variable("aiming_time", aiming_time, -bonus * 2) - recoil = modify_fantasy_variable("recoil", recoil, round(-bonus / 2)) - -/obj/item/gun/energy/beam_rifle/remove_fantasy_bonuses(bonus) - delay = reset_fantasy_variable("delay", delay) - aiming_time = reset_fantasy_variable("aiming_time", aiming_time) - recoil = reset_fantasy_variable("recoil", recoil) - return ..() - -/obj/item/gun/energy/beam_rifle/debug - delay = 0 - cell_type = /obj/item/stock_parts/cell/infinite - aiming_time = 0 - recoil = 0 - pin = /obj/item/firing_pin - -/obj/item/gun/energy/beam_rifle/equipped(mob/user) - set_user(user) - return ..() - -/obj/item/gun/energy/beam_rifle/pickup(mob/user) - set_user(user) - return ..() - -/obj/item/gun/energy/beam_rifle/dropped(mob/user) - set_user() - return ..() - -/obj/item/gun/energy/beam_rifle/ui_action_click(mob/user, actiontype) - if(istype(actiontype, /datum/action/item_action/zoom_lock_action)) - zoom_lock++ - if(zoom_lock > 3) - zoom_lock = 0 - switch(zoom_lock) - if(ZOOM_LOCK_AUTOZOOM_FREEMOVE) - to_chat(user, span_boldnotice("You switch [src]'s zooming processor to free directional.")) - if(ZOOM_LOCK_AUTOZOOM_ANGLELOCK) - to_chat(user, span_boldnotice("You switch [src]'s zooming processor to locked directional.")) - if(ZOOM_LOCK_CENTER_VIEW) - to_chat(user, span_boldnotice("You switch [src]'s zooming processor to center mode.")) - if(ZOOM_LOCK_OFF) - to_chat(user, span_boldnotice("You disable [src]'s zooming system.")) - reset_zooming() - return - - return ..() + ammo_type = list(/obj/item/ammo_casing/energy/event_horizon) + selfcharge = TRUE + self_charge_amount = STANDARD_ENERGY_GUN_SELF_CHARGE_RATE * 10 -/obj/item/gun/energy/beam_rifle/proc/set_autozoom_pixel_offsets_immediate(current_angle) - if(zoom_lock == ZOOM_LOCK_CENTER_VIEW || zoom_lock == ZOOM_LOCK_OFF) - return - current_zoom_x = sin(current_angle) + sin(current_angle) * AUTOZOOM_PIXEL_STEP_FACTOR * zoom_current_view_increase - current_zoom_y = cos(current_angle) + cos(current_angle) * AUTOZOOM_PIXEL_STEP_FACTOR * zoom_current_view_increase - -/obj/item/gun/energy/beam_rifle/proc/handle_zooming() - if(!zooming || !check_user()) - return - current_user.client.view_size.setTo(zoom_target_view_increase) - zoom_current_view_increase = zoom_target_view_increase - set_autozoom_pixel_offsets_immediate(zooming_angle) - -/obj/item/gun/energy/beam_rifle/proc/start_zooming() - if(zoom_lock == ZOOM_LOCK_OFF) - return - zooming = TRUE - -/obj/item/gun/energy/beam_rifle/proc/stop_zooming(mob/user) - if(zooming) - zooming = FALSE - reset_zooming(user) - -/obj/item/gun/energy/beam_rifle/proc/reset_zooming(mob/user) - if(!user) - user = current_user - if(!user || !user.client) - return FALSE - user.client.view_size.zoomIn() - zoom_current_view_increase = 0 - zooming_angle = 0 - current_zoom_x = 0 - current_zoom_y = 0 - -/obj/item/gun/energy/beam_rifle/attack_self(mob/user) - projectile_setting_pierce = !projectile_setting_pierce - balloon_alert(user, "switched to [projectile_setting_pierce ? "pierce":"impact"] mode") - aiming_beam() - -/obj/item/gun/energy/beam_rifle/proc/update_slowdown() - if(aiming) - slowdown = scoped_slow - else - slowdown = initial(slowdown) - -/obj/item/gun/energy/beam_rifle/Initialize(mapload) +/obj/item/gun/energy/event_horizon/Initialize(mapload) . = ..() - fire_delay = delay - current_tracers = list() - START_PROCESSING(SSfastprocess, src) - -/obj/item/gun/energy/beam_rifle/Destroy() - STOP_PROCESSING(SSfastprocess, src) - set_user(null) - QDEL_LIST(current_tracers) - return ..() - -/obj/item/gun/energy/beam_rifle/emp_act(severity) - . = ..() - if(. & EMP_PROTECT_SELF) - return - chambered = null - recharge_newshot() - -/obj/item/gun/energy/beam_rifle/proc/aiming_beam(force_update = FALSE) - var/diff = abs(aiming_lastangle - lastangle) - if(!check_user()) - return - if(diff < AIMING_BEAM_ANGLE_CHANGE_THRESHOLD && !force_update) - return - aiming_lastangle = lastangle - // ONLY ONE at once (since fire can sleep) - if(trace) - QDEL_NULL(trace) - trace = new - trace.gun = src - trace.wall_pierce_amount = wall_pierce_amount - trace.structure_pierce_amount = structure_piercing - trace.do_pierce = projectile_setting_pierce - if(aiming_time) - var/percent = ((100/aiming_time)*aiming_time_left) - trace.color = rgb(255 * percent,255 * ((100 - percent) / 100),0) - else - trace.color = rgb(0, 255, 0) - var/turf/curloc = get_turf(src) - - var/atom/target_atom = current_user.client.mouse_object_ref?.resolve() - var/turf/targloc = get_turf(target_atom) - if(!istype(targloc)) - if(!istype(curloc)) - return - targloc = get_turf_in_angle(lastangle, curloc, 10) - var/mouse_modifiers = params2list(current_user.client.mouseParams) - trace.preparePixelProjectile(targloc, current_user, mouse_modifiers, 0) - trace.fire(lastangle) - trace = null + AddComponent(/datum/component/scope, range_modifier = 4) -/obj/item/gun/energy/beam_rifle/process() - if(!aiming) - last_process = world.time - return - check_user() - handle_zooming() - aiming_time_left = max(0, aiming_time_left - (world.time - last_process)) - aiming_beam(TRUE) - last_process = world.time - -/obj/item/gun/energy/beam_rifle/proc/check_user(automatic_cleanup = TRUE) - if(!istype(current_user) || !isturf(current_user.loc) || !(src in current_user.held_items) || current_user.incapacitated()) //Doesn't work if you're not holding it! - if(automatic_cleanup) - stop_aiming() - return FALSE - return TRUE - -/obj/item/gun/energy/beam_rifle/proc/process_aim(params) - var/angle = mouse_angle_from_client(current_user?.client, params) - current_user.setDir(angle2dir_cardinal(angle)) - var/difference = abs(closer_angle_difference(lastangle, angle)) - delay_penalty(difference * aiming_time_increase_angle_multiplier) - lastangle = angle - -/obj/item/gun/energy/beam_rifle/proc/on_mob_move() - SIGNAL_HANDLER - check_user() - if(aiming) - delay_penalty(aiming_time_increase_user_movement) - process_aim(current_user?.client?.mouseParams) - INVOKE_ASYNC(src, PROC_REF(aiming_beam), TRUE) - -/obj/item/gun/energy/beam_rifle/proc/start_aiming(params) - aiming_time_left = aiming_time - aiming = TRUE - process_aim(params) - aiming_beam(TRUE) - zooming_angle = lastangle - start_zooming() - -/obj/item/gun/energy/beam_rifle/proc/stop_aiming(mob/user) - set waitfor = FALSE - aiming_time_left = aiming_time - aiming = FALSE - QDEL_LIST(current_tracers) - QDEL_NULL(trace) - stop_zooming(user) - -/obj/item/gun/energy/beam_rifle/proc/set_user(mob/user) - if(user == current_user) - return - stop_aiming(current_user) - if(istype(current_user)) - unregister_client_signals(current_user) - UnregisterSignal(current_user, list(COMSIG_MOVABLE_MOVED, COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT)) - current_user = null - if(!istype(user)) - return - current_user = user - RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(on_mob_move)) - RegisterSignal(user, COMSIG_MOB_LOGIN, PROC_REF(register_client_signals)) - RegisterSignal(user, COMSIG_MOB_LOGOUT, PROC_REF(unregister_client_signals)) - if(user.client) - register_client_signals(user) +/obj/item/gun/energy/event_horizon/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread) -/obj/item/gun/energy/beam_rifle/proc/register_client_signals(mob/source) - SIGNAL_HANDLER - RegisterSignal(source.client, COMSIG_CLIENT_MOUSEDOWN, PROC_REF(on_mouse_down)) - -/obj/item/gun/energy/beam_rifle/proc/unregister_client_signals(mob/source) - SIGNAL_HANDLER - stop_aiming() - if(QDELETED(source.client)) - return - UnregisterSignal(source.client, list(COMSIG_CLIENT_MOUSEDOWN, COMSIG_CLIENT_MOUSEUP, COMSIG_CLIENT_MOUSEDRAG)) - -///change the aiming beam angle to that of the mouse cursor. -/obj/item/gun/energy/beam_rifle/proc/on_mouse_drag(client/source, src_object, over_object, src_location, over_location, src_control, over_control, params) - SIGNAL_HANDLER - if(aiming) - process_aim(params) - INVOKE_ASYNC(src, PROC_REF(aiming_beam)) - if(zoom_lock == ZOOM_LOCK_AUTOZOOM_FREEMOVE) - zooming_angle = lastangle - set_autozoom_pixel_offsets_immediate(zooming_angle) - -///Start aiming and charging the beam -/obj/item/gun/energy/beam_rifle/proc/on_mouse_down(client/source, atom/movable/object, location, control, params) - SIGNAL_HANDLER - if(source.mob.get_active_held_item() != src) - return - if(!object.IsAutoclickable() || (object in source.mob.contents) || (object == source.mob)) + if(!HAS_TRAIT(user, TRAIT_USER_SCOPED)) + balloon_alert(user, "must be scoped!") return - INVOKE_ASYNC(src, PROC_REF(start_aiming), params) - RegisterSignal(source, COMSIG_CLIENT_MOUSEDRAG, PROC_REF(on_mouse_drag)) - RegisterSignal(source, COMSIG_CLIENT_MOUSEUP, PROC_REF(on_mouse_up)) - -///Stop aiming and fire the beam if charged enough -/obj/item/gun/energy/beam_rifle/proc/on_mouse_up(client/source, atom/movable/object, location, control, params) - SIGNAL_HANDLER - if(!object.IsAutoclickable()) - return - process_aim(params) - UnregisterSignal(source, list(COMSIG_CLIENT_MOUSEDRAG, COMSIG_CLIENT_MOUSEUP)) - if(aiming_time_left <= aiming_time_fire_threshold && check_user()) - sync_ammo() - var/atom/target = source.mouse_object_ref?.resolve() - if(target) - INVOKE_ASYNC(src, PROC_REF(try_fire_gun), target, source.mob, source.mouseParams, TRUE) - stop_aiming() - QDEL_LIST(current_tracers) - -/obj/item/gun/energy/beam_rifle/try_fire_gun(atom/target, mob/living/user, params, passthrough = FALSE) - if(user.Adjacent(target)) //It's adjacent, is the user, or is on the user's person - if(target in user.contents) //can't shoot stuff inside us. - return FALSE - if(!ismob(target) || user.combat_mode) //melee attack - return FALSE - if(target == user && user.zone_selected != BODY_ZONE_PRECISE_MOUTH) //so we can't shoot ourselves (unless mouth selected) - return FALSE - if(!passthrough && (aiming_time > aiming_time_fire_threshold)) - return FALSE - if(lastfire > world.time + delay) - return FALSE - if(!..()) - return FALSE - lastfire = world.time - stop_aiming() - return TRUE - -/obj/item/gun/energy/beam_rifle/proc/sync_ammo() - for(var/obj/item/ammo_casing/energy/beam_rifle/AC in contents) - AC.sync_stats() -/obj/item/gun/energy/beam_rifle/proc/delay_penalty(amount) - aiming_time_left = clamp(aiming_time_left + amount, 0, aiming_time) - -/obj/item/ammo_casing/energy/beam_rifle - name = "particle acceleration lens" - desc = "Don't look into barrel!" - var/wall_pierce_amount = 0 - var/wall_devastate = 0 - var/aoe_structure_range = 1 - var/aoe_structure_damage = 30 - var/aoe_fire_range = 2 - var/aoe_fire_chance = 66 - var/aoe_mob_range = 1 - var/aoe_mob_damage = 20 - var/impact_structure_damage = 50 - var/projectile_damage = 40 - var/projectile_stun = 0 - var/structure_piercing = 2 - var/structure_bleed_coeff = 0.7 - var/do_pierce = TRUE - var/obj/item/gun/energy/beam_rifle/host - -/obj/item/ammo_casing/energy/beam_rifle/proc/sync_stats() - var/obj/item/gun/energy/beam_rifle/BR = loc - if(!istype(BR)) - stack_trace("Beam rifle syncing error") - host = BR - do_pierce = BR.projectile_setting_pierce - wall_pierce_amount = BR.wall_pierce_amount - wall_devastate = BR.wall_devastate - aoe_structure_range = BR.aoe_structure_range - aoe_structure_damage = BR.aoe_structure_damage - aoe_fire_range = BR.aoe_fire_range - aoe_fire_chance = BR.aoe_fire_chance - aoe_mob_range = BR.aoe_mob_range - aoe_mob_damage = BR.aoe_mob_damage - impact_structure_damage = BR.impact_structure_damage - projectile_damage = BR.projectile_damage - projectile_stun = BR.projectile_stun - delay = BR.delay - structure_piercing = BR.structure_piercing - structure_bleed_coeff = BR.structure_bleed_coeff - -/obj/item/ammo_casing/energy/beam_rifle/ready_proj(atom/target, mob/living/user, quiet, zone_override = "") . = ..() - var/obj/projectile/beam/beam_rifle/hitscan/HS_BB = loaded_projectile - if(!istype(HS_BB)) - return - HS_BB.impact_direct_damage = projectile_damage - HS_BB.stun = projectile_stun - HS_BB.impact_structure_damage = impact_structure_damage - HS_BB.aoe_mob_damage = aoe_mob_damage - HS_BB.aoe_mob_range = clamp(aoe_mob_range, 0, 15) //Badmin safety lock - HS_BB.aoe_fire_chance = aoe_fire_chance - HS_BB.aoe_fire_range = aoe_fire_range - HS_BB.aoe_structure_damage = aoe_structure_damage - HS_BB.aoe_structure_range = clamp(aoe_structure_range, 0, 15) //Badmin safety lock - HS_BB.wall_devastate = wall_devastate - HS_BB.wall_pierce_amount = wall_pierce_amount - HS_BB.structure_pierce_amount = structure_piercing - HS_BB.structure_bleed_coeff = structure_bleed_coeff - HS_BB.do_pierce = do_pierce - HS_BB.gun = host - -/obj/item/ammo_casing/energy/beam_rifle/throw_proj(atom/target, turf/targloc, mob/living/user, params, spread, atom/fired_from) - var/turf/curloc = get_turf(user) - if(!istype(curloc) || !loaded_projectile) - return FALSE - var/obj/item/gun/energy/beam_rifle/gun = loc - if(!targloc && gun) - targloc = get_turf_in_angle(gun.lastangle, curloc, 10) - else if(!targloc) - return FALSE - var/firing_dir - if(loaded_projectile.firer) - firing_dir = loaded_projectile.firer.dir - if(!loaded_projectile.suppressed && firing_effect_type) - new firing_effect_type(get_turf(src), firing_dir) - var/modifiers = params2list(params) - loaded_projectile.preparePixelProjectile(target, user, modifiers, spread) - loaded_projectile.fire(gun? gun.lastangle : null, null) - loaded_projectile = null - return TRUE + message_admins("[ADMIN_LOOKUPFLW(user)] has fired an anti-existential beam at [ADMIN_VERBOSEJMP(user)].") -/obj/item/ammo_casing/energy/beam_rifle/hitscan - projectile_type = /obj/projectile/beam/beam_rifle/hitscan - select_name = "beam" - e_cost = LASER_SHOTS(5, 50000) // Beam rifle has a custom cell +/obj/item/ammo_casing/energy/event_horizon + projectile_type = /obj/projectile/beam/event_horizon + select_name = "doomsday" + e_cost = LASER_SHOTS(1, STANDARD_CELL_CHARGE) fire_sound = 'sound/weapons/beam_sniper.ogg' -/obj/projectile/beam/beam_rifle - name = "particle beam" +/obj/projectile/beam/event_horizon + name = "anti-existential beam" icon = null hitsound = 'sound/effects/explosion3.ogg' - damage = 0 //Handled manually. + damage = 100 // Does it matter? damage_type = BURN armor_flag = ENERGY range = 150 jitter = 20 SECONDS - var/obj/item/gun/energy/beam_rifle/gun - var/structure_pierce_amount = 0 //All set to 0 so the gun can manually set them during firing. - var/structure_bleed_coeff = 0 - var/structure_pierce = 0 - var/do_pierce = TRUE - var/wall_pierce_amount = 0 - var/wall_pierce = 0 - var/wall_devastate = 0 - var/aoe_structure_range = 0 - var/aoe_structure_damage = 0 - var/aoe_fire_range = 0 - var/aoe_fire_chance = 0 - var/aoe_mob_range = 0 - var/aoe_mob_damage = 0 - var/impact_structure_damage = 0 - var/impact_direct_damage = 0 - var/list/pierced = list() - -/obj/projectile/beam/beam_rifle/proc/AOE(turf/epicenter) - if(!epicenter) - return - new /obj/effect/temp_visual/explosion/fast(epicenter) - for(var/mob/living/L in range(aoe_mob_range, epicenter)) //handle aoe mob damage - L.adjustFireLoss(aoe_mob_damage) - to_chat(L, span_userdanger("\The [src] sears you!")) - for(var/turf/T in RANGE_TURFS(aoe_fire_range, epicenter)) //handle aoe fire - if(prob(aoe_fire_chance)) - new /obj/effect/hotspot(T) - for(var/obj/O in range(aoe_structure_range, epicenter)) - if(!isitem(O)) - O.take_damage(aoe_structure_damage * get_damage_coeff(O), BURN, LASER, FALSE) - -/obj/projectile/beam/beam_rifle/prehit_pierce(atom/A) - if(isclosedturf(A) && (wall_pierce < wall_pierce_amount)) - if(prob(wall_devastate)) - if(iswallturf(A)) - var/turf/closed/wall/W = A - W.dismantle_wall(TRUE, TRUE) - else - SSexplosions.medturf += A - ++wall_pierce - return PROJECTILE_PIERCE_PHASE // yeah this gun is a snowflakey piece of garbage - if(isobj(A) && (structure_pierce < structure_pierce_amount)) - ++structure_pierce - var/obj/O = A - O.take_damage((impact_structure_damage + aoe_structure_damage) * structure_bleed_coeff * get_damage_coeff(A), BURN, ENERGY, FALSE) - return PROJECTILE_PIERCE_PHASE // ditto and this could be refactored to on_hit honestly - return ..() - -/obj/projectile/beam/beam_rifle/proc/get_damage_coeff(atom/target) - if(istype(target, /obj/machinery/door)) - return 0.4 - if(istype(target, /obj/structure/window)) - return 0.5 - return 1 - -/obj/projectile/beam/beam_rifle/proc/handle_impact(atom/target) - if(isobj(target)) - var/obj/O = target - O.take_damage(impact_structure_damage * get_damage_coeff(target), BURN, LASER, FALSE) - if(isliving(target)) - var/mob/living/L = target - L.adjustFireLoss(impact_direct_damage) - L.emote("scream") - -/obj/projectile/beam/beam_rifle/proc/handle_hit(atom/target, piercing_hit = FALSE) - set waitfor = FALSE - if(!is_hostile_projectile()) - return FALSE - playsound(src, 'sound/effects/explosion3.ogg', 100, TRUE) - if(!do_pierce) - AOE(get_turf(target) || get_turf(src)) - if(!QDELETED(target)) - handle_impact(target) - -/obj/projectile/beam/beam_rifle/on_hit(atom/target, blocked = 0, pierce_hit) - handle_hit(target, pierce_hit) - return ..() - -/obj/projectile/beam/beam_rifle/is_hostile_projectile() - return TRUE // on hit = boom fire - -/obj/projectile/beam/beam_rifle/hitscan - icon_state = "" hitscan = TRUE tracer_type = /obj/effect/projectile/tracer/tracer/beam_rifle - var/constant_tracer = FALSE -/obj/projectile/beam/beam_rifle/hitscan/generate_hitscan_tracers(cleanup = TRUE, duration = 5, impacting = TRUE, highlander) - set waitfor = FALSE - if(isnull(highlander)) - highlander = constant_tracer - if(highlander && istype(gun)) - QDEL_LIST(gun.current_tracers) - for(var/datum/point/p in beam_segments) - gun.current_tracers += generate_tracer_between_points(p, beam_segments[p], tracer_type, color, 0, hitscan_light_range, hitscan_light_color_override, hitscan_light_intensity) - else - for(var/datum/point/p in beam_segments) - generate_tracer_between_points(p, beam_segments[p], tracer_type, color, duration, hitscan_light_range, hitscan_light_color_override, hitscan_light_intensity) - if(cleanup) - QDEL_LIST(beam_segments) - beam_segments = null - QDEL_NULL(beam_index) - -/obj/projectile/beam/beam_rifle/hitscan/aiming_beam - tracer_type = /obj/effect/projectile/tracer/tracer/aiming - name = "aiming beam" - hitsound = null - hitsound_wall = null - damage = 0 - constant_tracer = TRUE - hitscan_light_range = 0 - hitscan_light_intensity = 0 - hitscan_light_color_override = "#99ff99" - reflectable = REFLECT_FAKEPROJECTILE - -/obj/projectile/beam/beam_rifle/hitscan/aiming_beam/is_hostile_projectile() - return FALSE // just an aiming reticle - -/obj/projectile/beam/beam_rifle/hitscan/aiming_beam/prehit_pierce(atom/target) - return PROJECTILE_DELETE_WITHOUT_HITTING +/obj/projectile/beam/event_horizon/on_hit(atom/target, blocked, pierce_hit) + . = ..() -/obj/projectile/beam/beam_rifle/hitscan/aiming_beam/on_hit(atom/target, blocked = 0, pierce_hit) - SHOULD_CALL_PARENT(FALSE) // This is some snowflake stuff so whatever - qdel(src) - return BULLET_ACT_BLOCK + // Where we droppin' boys? + var/turf/rift_loc = get_turf(target) -#undef AIMING_BEAM_ANGLE_CHANGE_THRESHOLD -#undef AUTOZOOM_PIXEL_STEP_FACTOR -#undef ZOOM_LOCK_AUTOZOOM_ANGLELOCK -#undef ZOOM_LOCK_AUTOZOOM_FREEMOVE -#undef ZOOM_LOCK_CENTER_VIEW -#undef ZOOM_LOCK_OFF + // Spawn our temporary rift, then activate it. + var/obj/reality_tear/temporary/tear = new(rift_loc) + tear.start_disaster() + message_admins("[ADMIN_LOOKUPFLW(target)] has been hit by an anti-existential beam at [ADMIN_VERBOSEJMP(rift_loc)], creating a singularity.") diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm index fec816b1e765f..78e75d1f30665 100644 --- a/code/modules/projectiles/guns/energy/energy_gun.dm +++ b/code/modules/projectiles/guns/energy/energy_gun.dm @@ -86,7 +86,7 @@ /obj/item/gun/energy/e_gun/dragnet name = "\improper DRAGnet" - desc = "The \"Dynamic Rapid-Apprehension of the Guilty\" net is a revolution in law enforcement technology." + desc = "The \"Dynamic Rapid-Apprehension of the Guilty\" net is a revolution in law enforcement technology. Can by synced with a DRAGnet beacon to set a teleport destination for snare rounds." icon_state = "dragnet" inhand_icon_state = "dragnet" lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' @@ -95,10 +95,35 @@ modifystate = FALSE w_class = WEIGHT_CLASS_NORMAL ammo_x_offset = 1 + ///A dragnet beacon set to be the teleport destination for snare teleport rounds. + var/obj/item/dragnet_beacon/linked_beacon /obj/item/gun/energy/e_gun/dragnet/add_seclight_point() return +/obj/item/gun/energy/e_gun/dragnet/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(istype(tool, /obj/item/dragnet_beacon)) + link_beacon(user, tool) + +///Sets the linked_beacon var on the dragnet, which becomes the snare round's teleport destination. +/obj/item/gun/energy/e_gun/dragnet/proc/link_beacon(mob/living/user, obj/item/dragnet_beacon/our_beacon) + if(linked_beacon) + if(our_beacon == linked_beacon) + balloon_alert(user, "already synced!") + return + else + UnregisterSignal(linked_beacon, COMSIG_QDELETING) //You're getting overridden dude. + + linked_beacon = our_beacon + balloon_alert(user, "beacon synced") + RegisterSignal(our_beacon, COMSIG_QDELETING, PROC_REF(handle_beacon_disable)) + +///Handles clearing the linked_beacon reference in the event that it is deleted. +/obj/item/gun/energy/e_gun/dragnet/proc/handle_beacon_disable(datum/source) + SIGNAL_HANDLER + visible_message(span_warning("A light on the [src] flashes, indicating that it is no longer linked with a DRAGnet beacon!")) + linked_beacon = null + /obj/item/gun/energy/e_gun/dragnet/snare name = "Energy Snare Launcher" desc = "Fires an energy snare that slows the target down." diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index c7fefc745f7e0..7237ee0e32747 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -254,6 +254,8 @@ require_model = TRUE model_type = list(/obj/item/robot_model/miner) model_flags = BORG_MODEL_MINER + //Most modkits are supposed to allow duplicates. The ones that don't should be blocked by PKA code anyways. + allow_duplicates = TRUE var/denied_type = null var/maximum_of_type = 1 var/cost = 30 diff --git a/code/modules/projectiles/projectile/energy/net_snare.dm b/code/modules/projectiles/projectile/energy/net_snare.dm index 1bb7988e4bae4..ac35fb5503e68 100644 --- a/code/modules/projectiles/projectile/energy/net_snare.dm +++ b/code/modules/projectiles/projectile/energy/net_snare.dm @@ -11,10 +11,15 @@ SpinAnimation() /obj/projectile/energy/net/on_hit(atom/target, blocked = 0, pierce_hit) + var/obj/item/dragnet_beacon/destination_beacon = null + var/obj/item/gun/energy/e_gun/dragnet/our_dragnet = fired_from + if(our_dragnet && istype(our_dragnet)) + destination_beacon = our_dragnet.linked_beacon + if(isliving(target)) var/turf/Tloc = get_turf(target) if(!locate(/obj/effect/nettingportal) in Tloc) - new /obj/effect/nettingportal(Tloc) + new /obj/effect/nettingportal(Tloc, destination_beacon) . = ..() /obj/projectile/energy/net/on_range() @@ -29,26 +34,18 @@ light_range = 3 anchored = TRUE -/obj/effect/nettingportal/Initialize(mapload) +/obj/effect/nettingportal/Initialize(mapload, destination_beacon) . = ..() - var/obj/item/beacon/teletarget = null - for(var/obj/machinery/computer/teleporter/com as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/computer/teleporter)) - var/atom/target = com.target_ref?.resolve() - if(target) - if(com.power_station && com.power_station.teleporter_hub && com.power_station.engaged) - teletarget = target - else - com.target_ref = null - + var/obj/item/dragnet_beacon/teletarget = destination_beacon addtimer(CALLBACK(src, PROC_REF(pop), teletarget), 3 SECONDS) /obj/effect/nettingportal/proc/pop(teletarget) if(teletarget) - for(var/mob/living/L in get_turf(src)) - do_teleport(L, teletarget, 2, channel = TELEPORT_CHANNEL_BLUESPACE)//teleport what's in the tile to the beacon + for(var/mob/living/living_mob in get_turf(src)) + do_teleport(living_mob, get_turf(teletarget), 1, channel = TELEPORT_CHANNEL_BLUESPACE) //Teleport what's in the tile to the beacon else - for(var/mob/living/L in get_turf(src)) - do_teleport(L, L, 15, channel = TELEPORT_CHANNEL_BLUESPACE) //Otherwise it just warps you off somewhere. + for(var/mob/living/living_mob in get_turf(src)) + do_teleport(living_mob, get_turf(living_mob), 15, channel = TELEPORT_CHANNEL_BLUESPACE) //Otherwise it just warps you off somewhere. qdel(src) @@ -58,6 +55,66 @@ /obj/effect/nettingportal/singularity_pull() return +/obj/item/dragnet_beacon + name = "\improper DRAGnet beacon" + desc = "Can be synced with a DRAGnet to set it as a designated teleporting point." + icon = 'icons/obj/devices/tracker.dmi' + icon_state = "dragnet_beacon" + inhand_icon_state = "beacon" + lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' + ///Has a security ID been used to lock this in place? + var/locked = FALSE + +/obj/item/dragnet_beacon/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(istype(tool, /obj/item/gun/energy/e_gun/dragnet)) + var/obj/item/gun/energy/e_gun/dragnet/dragnet_to_link = tool + dragnet_to_link.link_beacon(user, src) + return + + if(isidcard(tool)) + if(!anchored) + balloon_alert(user, "wrench the beacon first!") + return + + if(obj_flags & EMAGGED) + balloon_alert(user, "the access control is fried!") + return + + var/obj/item/card/id/id_card = tool + if((ACCESS_SECURITY in id_card.GetAccess())) + locked = !locked + balloon_alert(user, "beacon [locked ? "locked" : "unlocked"]") + else + balloon_alert(user, "no access!") + +/obj/item/dragnet_beacon/wrench_act(mob/living/user, obj/item/tool) + if(user.is_holding(src)) + balloon_alert(user, "put it down first!") + return ITEM_INTERACT_BLOCKING + + if(anchored && locked) + balloon_alert(user, "must be unlocked first!") + return ITEM_INTERACT_BLOCKING + + if(isinspace() && !anchored) + balloon_alert(user, "nothing to anchor to!") + return ITEM_INTERACT_BLOCKING + + set_anchored(!anchored) + tool.play_tool_sound(src, 75) + user.balloon_alert_to_viewers("[anchored ? "anchored" : "unanchored"]") + +/obj/item/dragnet_beacon/emag_act(mob/user, obj/item/card/emag/emag_card) + if(obj_flags & EMAGGED) + return FALSE + obj_flags |= EMAGGED + locked = FALSE + set_anchored(FALSE) + do_sparks(3, TRUE, src) + balloon_alert(user, "beacon unlocked") + return TRUE + /obj/projectile/energy/trap name = "energy snare" icon_state = "e_snare" diff --git a/code/modules/reagents/chemistry/items.dm b/code/modules/reagents/chemistry/items.dm index d307f96dc264c..ad7f0413ce561 100644 --- a/code/modules/reagents/chemistry/items.dm +++ b/code/modules/reagents/chemistry/items.dm @@ -120,7 +120,7 @@ return NONE var/list/out_message = list() to_chat(user, "The chemistry meter beeps and displays:") - out_message += "Total volume: [round(cont.volume, 0.01)] Current temperature: [round(cont.reagents.chem_temp, 0.1)]K Total pH: [round(cont.reagents.ph, 0.01)]\n" + out_message += "Total volume: [round(cont.volume, 0.01)] Current temperature: [round(cont.reagents.chem_temp, 0.1)]K Total pH: [round(cont.reagents.ph, 0.01)]\n" out_message += "Chemicals found in [interacting_with.name]:\n" if(cont.reagents.is_reacting) out_message += "[span_warning("A reaction appears to be occuring currently.")]\n" @@ -132,7 +132,7 @@ out_message += "[round(reagent.volume, 0.01)]u of [reagent.name], Purity: [round(reagent.purity, 0.000001)*100]%, [(scanmode?"[(reagent.overdose_threshold?"Overdose: [reagent.overdose_threshold]u, ":"")]Base pH: [initial(reagent.ph)], Current pH: [reagent.ph].":"Current pH: [reagent.ph].")]\n" if(scanmode) out_message += "Analysis: [reagent.description]\n" - to_chat(user, "[out_message.Join()]") + to_chat(user, examine_block(span_notice("[out_message.Join()]"))) desc = "An electrode attached to a small circuit box that will display details of a solution. Can be toggled to provide a description of each of the reagents. The screen currently displays detected vol: [round(cont.volume, 0.01)] detected pH:[round(cont.reagents.ph, 0.1)]." return ITEM_INTERACT_SUCCESS diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm index e206ffebbc9f8..a4fa10cb88c63 100644 --- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm +++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm @@ -422,7 +422,7 @@ var/duration = time / speed - Shake(duration = duration) + Shake(pixelshiftx = 1, pixelshifty = 0, duration = duration) operating = TRUE if(!juicing) playsound(src, 'sound/machines/blender.ogg', 50, TRUE) @@ -490,7 +490,7 @@ var/duration = time / speed - Shake(duration = duration) + Shake(pixelshiftx = 1, pixelshifty = 0, duration = duration) operating = TRUE playsound(src, 'sound/machines/juicer.ogg', 20, TRUE) diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm index f7fc1b04ac8de..40305c9a8bc47 100644 --- a/code/modules/reagents/chemistry/recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -281,7 +281,7 @@ * * modifier - a flat additive numeric to the size of the explosion - set this if you want a minimum range * * strengthdiv - the divisional factor of the explosion, a larger number means a smaller range - This is the part that modifies an explosion's range with volume (i.e. it divides it by this number) */ -/datum/chemical_reaction/proc/default_explode(datum/reagents/holder, created_volume, modifier = 0, strengthdiv = 10) +/datum/chemical_reaction/proc/default_explode(datum/reagents/holder, created_volume, modifier = 0, strengthdiv = 10, clear_mob_reagents) var/power = modifier + round(created_volume/strengthdiv, 1) if(power > 0) var/turf/T = get_turf(holder.my_atom) @@ -300,8 +300,29 @@ var/datum/effect_system/reagents_explosion/e = new() e.set_up(power , T, 0, 0) e.start(holder.my_atom) - holder.clear_reagents() - + if (ismob(holder.my_atom)) + if(!clear_mob_reagents) + return + // Only clear reagents if they use a special explosive reaction to do it; it shouldn't apply + // to any explosion inside a person + holder.clear_reagents() + if(iscarbon(holder.my_atom)) + var/mob/living/carbon/victim = holder.my_atom + var/vomit_flags = MOB_VOMIT_MESSAGE | MOB_VOMIT_FORCE + // The vomiting here is for effect, not meant to help with purging + victim.vomit(vomit_flags, distance = 5) + // Not quite the same if the reaction is in their stomach; they'll throw up + // from any explosion, but it'll only make them puke up everything in their + // stomach + else if (istype(holder.my_atom, /obj/item/organ/internal/stomach)) + var/obj/item/organ/internal/stomach/indigestion = holder.my_atom + if(power < 1) + return + indigestion.owner?.vomit(MOB_VOMIT_MESSAGE | MOB_VOMIT_FORCE, lost_nutrition = 150, distance = 5, purge_ratio = 1) + holder.clear_reagents() + return + else + holder.clear_reagents() /* *Creates a flash effect only - less expensive than explode() * diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index d190a44aea063..f02aaa3ab2473 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -1,13 +1,48 @@ +#define PURGING_REAGENTS list( \ + /datum/reagent/medicine/c2/multiver, \ + /datum/reagent/medicine/pen_acid, \ + /datum/reagent/medicine/calomel, \ + /datum/reagent/medicine/ammoniated_mercury, \ + /datum/reagent/medicine/c2/syriniver, \ + /datum/reagent/medicine/c2/musiver \ +) + /datum/chemical_reaction/reagent_explosion var/strengthdiv = 10 var/modifier = 0 reaction_flags = REACTION_INSTANT reaction_tags = REACTION_TAG_EXPLOSIVE | REACTION_TAG_MODERATE | REACTION_TAG_DANGEROUS required_temp = 0 //Prevent impromptu RPGs - -/datum/chemical_reaction/reagent_explosion/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - default_explode(holder, created_volume, modifier, strengthdiv) - + // Only clear mob reagents in special cases + var/clear_mob_reagents = FALSE + +/datum/chemical_reaction/reagent_explosion/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume, clear_mob_reagents) + // If an explosive reaction clears mob reagents, it should always be a minimum power + if(ismob(holder.my_atom) && clear_mob_reagents) + if(round((created_volume / strengthdiv) + modifier, 1) < 1) + modifier += 1 - ((created_volume / strengthdiv) + modifier) + // If this particular explosion doesn't automatically clear mob reagents as an inherent quality, + // then we can still clear mob reagents with some mad science malpractice that shouldn't work but + // does because omnizine is magic and also it's the future or whatever + if(ismob(holder.my_atom) && !clear_mob_reagents) + // The explosion needs to be a minimum power to clear reagents: see above + var/purge_power = round((created_volume / strengthdiv) + modifier, 1) + if(purge_power >= 1) + var/has_purging_chemical = FALSE + // They need one of the purge reagents in them + for(var/purging_chem as anything in PURGING_REAGENTS) + if(holder.has_reagent(purging_chem)) + // We have a purging chemical + has_purging_chemical = TRUE + break + // Then we need omnizine! MAGIC! + var/has_omnizine = holder.has_reagent(/datum/reagent/medicine/omnizine) + if(has_purging_chemical && has_omnizine) + // With all this medical "science" combined, we can clear mob reagents + clear_mob_reagents = TRUE + default_explode(holder, created_volume, modifier, strengthdiv, clear_mob_reagents) + +#undef PURGING_REAGENTS /datum/chemical_reaction/reagent_explosion/nitroglycerin results = list(/datum/reagent/nitroglycerin = 2) required_reagents = list(/datum/reagent/glycerol = 1, /datum/reagent/toxin/acid/nitracid = 1, /datum/reagent/toxin/acid = 1) @@ -104,11 +139,18 @@ /datum/chemical_reaction/reagent_explosion/penthrite_explosion_epinephrine required_reagents = list(/datum/reagent/medicine/c2/penthrite = 1, /datum/reagent/medicine/epinephrine = 1) strengthdiv = 5 + // Penthrite is rare as hell, so this clears your reagents + // Will most likely be from miners accidentally penstacking + clear_mob_reagents = TRUE + /datum/chemical_reaction/reagent_explosion/penthrite_explosion_atropine required_reagents = list(/datum/reagent/medicine/c2/penthrite = 1, /datum/reagent/medicine/atropine = 1) strengthdiv = 5 modifier = 5 + // Rare reagents clear your reagents + // Probably not good for you because you'll need healing chems to survive this most likely + clear_mob_reagents = TRUE /datum/chemical_reaction/reagent_explosion/potassium_explosion required_reagents = list(/datum/reagent/water = 1, /datum/reagent/potassium = 1) diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 387f3b84d4911..bb426436599c0 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -96,7 +96,6 @@ /obj/item/reagent_containers/spray/proc/do_spray(atom/target, wait_step, obj/effect/decal/chempuff/reagent_puff, range, puff_reagent_left, mob/user) reagent_puff.user = user reagent_puff.sprayer = src - reagent_puff.lifetime = puff_reagent_left reagent_puff.stream = stream_mode var/turf/target_turf = get_turf(target) diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index 7d4f613f05478..ef6c65d183175 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -747,7 +747,6 @@ name = "NTNet Relay Board" desc = "The circuit board for a wireless network relay." id = "ntnet_relay" - build_type = IMPRINTER build_path = /obj/item/circuitboard/machine/ntnet_relay category = list( RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_TELECOMMS diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm index 8ae869220deef..0ea6c41e16448 100644 --- a/code/modules/research/designs/misc_designs.dm +++ b/code/modules/research/designs/misc_designs.dm @@ -818,6 +818,19 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SECURITY + +/datum/design/dragnet_beacon + name = "DRAGnet Beacon" + desc = "A beacon that can be used as a teleport destination for DRAGnet snare rounds. Remember to sync it with your DRAGnet first!" + id = "dragnet_beacon" + build_type = PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 5, /datum/material/glass = SHEET_MATERIAL_AMOUNT * 2) + build_path = /obj/item/dragnet_beacon + category = list( + RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_SECURITY + ) + departmental_flags = DEPARTMENT_BITFLAG_SECURITY + /datum/design/inspector name = "N-Spect Scanner" desc = "Central Command-issued inspection device. Performs inspections according to Nanotrasen protocols when activated, then prints an encrypted report regarding the maintenance of the station. Definitely not giving you cancer." diff --git a/code/modules/research/designs/power_designs.dm b/code/modules/research/designs/power_designs.dm index 85704c0c5b72e..700f99a643504 100644 --- a/code/modules/research/designs/power_designs.dm +++ b/code/modules/research/designs/power_designs.dm @@ -24,7 +24,7 @@ construction_time = 10 SECONDS build_path = /obj/item/stock_parts/cell/high/empty category = list( - RND_CATEGORY_STOCK_PARTS + RND_SUBCATEGORY_STOCK_PARTS_2 + RND_CATEGORY_STOCK_PARTS + RND_SUBCATEGORY_STOCK_PARTS_1 ) departmental_flags = DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_ENGINEERING @@ -37,7 +37,7 @@ construction_time = 10 SECONDS build_path = /obj/item/stock_parts/cell/super/empty category = list( - RND_CATEGORY_STOCK_PARTS + RND_SUBCATEGORY_STOCK_PARTS_3 + RND_CATEGORY_STOCK_PARTS + RND_SUBCATEGORY_STOCK_PARTS_2 ) departmental_flags = DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_ENGINEERING diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm index 00c7dba3946bd..35d95d82d3047 100644 --- a/code/modules/research/designs/weapon_designs.dm +++ b/code/modules/research/designs/weapon_designs.dm @@ -218,8 +218,8 @@ autolathe_exportable = FALSE /datum/design/beamrifle - name = "Beam Marksman Rifle Part Kit (Lethal)" - desc = "The gunkit for a powerful long ranged anti-material rifle that fires charged particle beams to obliterate targets." + name = "Event Horizon Anti-Existential Beam Rifle Part Kit (DOOMSDAY DEVICE)" + desc = "The kit that produces a weapon made to end your foes on an existential level. Why the fuck can you make this?" id = "beamrifle" build_type = PROTOLATHE | AWAY_LATHE materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 5, /datum/material/glass =SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/diamond =SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/uranium = SHEET_MATERIAL_AMOUNT * 4, /datum/material/silver = SHEET_MATERIAL_AMOUNT * 2.25, /datum/material/gold =SHEET_MATERIAL_AMOUNT * 2.5) @@ -230,7 +230,6 @@ departmental_flags = DEPARTMENT_BITFLAG_SECURITY autolathe_exportable = FALSE - /datum/design/rapidsyringe name = "Rapid Syringe Gun" desc = "A gun that fires many syringes." diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm index 04c777bb1c073..d110dab03e02d 100644 --- a/code/modules/research/machinery/_production.dm +++ b/code/modules/research/machinery/_production.dm @@ -411,14 +411,25 @@ var/atom/movable/created if(is_stack) - created = new design.build_path(target, items_remaining) + var/obj/item/stack/stack_item = initial(design.build_path) + var/max_stack_amount = initial(stack_item.max_amount) + var/number_to_make = (initial(stack_item.amount) * items_remaining) + while(number_to_make > max_stack_amount) + created = new stack_item(null, max_stack_amount) //it's imporant to spawn things in nullspace, since obj's like stacks qdel when they enter a tile/merge with other stacks of the same type, resulting in runtimes. + created.pixel_x = created.base_pixel_x + rand(-6, 6) + created.pixel_y = created.base_pixel_y + rand(-6, 6) + created.forceMove(target) + number_to_make -= max_stack_amount + + created = new stack_item(null, number_to_make) else - created = new design.build_path(target) + created = new design.build_path(null) split_materials_uniformly(design_materials, material_cost_coefficient, created) created.pixel_x = created.base_pixel_x + rand(-6, 6) created.pixel_y = created.base_pixel_y + rand(-6, 6) SSblackbox.record_feedback("nested tally", "lathe_printed_items", 1, list("[type]", "[created.type]")) + created.forceMove(target) if(is_stack) items_remaining = 0 diff --git a/code/modules/research/ordnance/tank_compressor.dm b/code/modules/research/ordnance/tank_compressor.dm index 830c004acad5e..d0393d9e10374 100644 --- a/code/modules/research/ordnance/tank_compressor.dm +++ b/code/modules/research/ordnance/tank_compressor.dm @@ -321,10 +321,6 @@ data["transferRate"] = transfer_rate data["lastPressure"] = last_recorded_pressure - data["inputData"] = gas_mixture_parser(airs[2], "Input Port") - data["outputData"] = gas_mixture_parser(airs[1], "Ouput Port") - data["bufferData"] = gas_mixture_parser(leaked_gas_buffer, "Gas Buffer") - data["disk"] = inserted_disk?.name data["storage"] = "[inserted_disk?.used_capacity] / [inserted_disk?.max_capacity] GQ" data["records"] = list() diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm deleted file mode 100644 index 1c6e6f2b9f7ee..0000000000000 --- a/code/modules/research/techweb/all_nodes.dm +++ /dev/null @@ -1,2498 +0,0 @@ - -//Current rate: 135000 research points in 90 minutes - -//Base Nodes -/datum/techweb_node/base - id = "base" - starting_node = TRUE - display_name = "Basic Research Technology" - description = "NT default research technologies." - // Default research tech, prevents bricking - design_ids = list( - "basic_capacitor", - "basic_cell", - "basic_matter_bin", - "basic_micro_laser", - "basic_scanning", - "blast", - "bounced_radio", - "bowl", - "bucket", - "c-reader", - "c38_rubber", - "camera_assembly", - "camera_film", - "camera", - "capbox", - "chisel", - "circuit_imprinter_offstation", - "circuit_imprinter", - "circuit", - "circuitgreen", - "circuitred", - "coffee_cartridge", - "coffeemaker", - "coffeepot", - "condenser", - "conveyor_belt", - "conveyor_switch", - "custom_vendor_refill", - "destructive_analyzer", - "destructive_scanner", - "desttagger", - "doppler_array", - "drinking_glass", - "earmuffs", - "electropack", - "experi_scanner", - "experimentor", - "extinguisher", - "fax", - "fish_case", - "fishing_rod", - "fishing_portal_generator", - "flashlight", - "fluid_ducts", - "foam_dart", - "fork", - "gas_filter", - "handcuffs_s", - "handlabel", - "health_sensor", - "holodisk", - "igniter", - "infrared_emitter", - "intercom_frame", - "kitchen_knife", - "laptop", - "light_bulb", - "light_replacer", - "light_tube", - "mechfab", - "micro_servo", - "miniature_power_cell", - "newscaster_frame", - "oven_tray", - "packagewrap", - "pet_carrier", - "plasmaglass", - "plasmaman_gas_filter", - "plasmareinforcedglass", - "plasteel", - "plastic_fork", - "plastic_knife", - "plastic_spoon", - "plastitanium", - "plastitaniumglass", - "plate", - "prox_sensor", - "radio_headset", - "rdconsole", - "rdserver", - "rdservercontrol", - "recorder", - "rglass", - "roll", - "sec_38", - "sec_beanbag_slug", - "sec_dart", - "sec_Islug", - "sec_rshot", - "sec_pen", - "servingtray", - "shaker", - "shot_glass", - "signaler", - "slime_scanner", - "solar_panel", - "solar_tracker", - "souppot", - "space_heater", - "spoon", - "status_display_frame", - "sticky_tape", - "syrup_bottle", - "tape", - "tech_disk", - "timer", - "titaniumglass", - "toner_large", - "toner", - "tongs", - "toy_armblade", - "toy_balloon", - "toygun", - "tram_floor_dark", - "tram_floor_light", - "trapdoor_electronics", - "turbine_part_compressor", - "turbine_part_rotor", - "turbine_part_stator", - "turret_control", - "universal_scanner", - "voice_analyzer", - "watering_can", - ) - experiments_to_unlock = list( - /datum/experiment/autopsy/nonhuman, - /datum/experiment/scanning/random/material/medium/one, - /datum/experiment/scanning/random/material/medium/three, - /datum/experiment/scanning/random/material/hard/one, - /datum/experiment/scanning/random/material/hard/two, - /datum/experiment/scanning/people/novel_organs, - ) - -/datum/techweb_node/mmi - id = "mmi" - starting_node = TRUE - display_name = "Man Machine Interface" - description = "A slightly Frankensteinian device that allows human brains to interface natively with software APIs." - design_ids = list( - "mmi", - ) - -/datum/techweb_node/cyborg - id = "cyborg" - starting_node = TRUE - display_name = "Cyborg Construction" - description = "Sapient robots with preloaded tool modules and programmable laws." - design_ids = list( - "borg_chest", - "borg_head", - "borg_l_arm", - "borg_l_leg", - "borg_r_arm", - "borg_r_leg", - "borg_suit", - "borg_upgrade_rename", - "borg_upgrade_restart", - "borgupload", - "cyborgrecharger", - "robocontrol", - "sflash", - ) - -/datum/techweb_node/mech - id = "mecha" - starting_node = TRUE - display_name = "Mechanical Exosuits" - description = "Mechanized exosuits that are several magnitudes stronger and more powerful than the average human." - design_ids = list( - "mech_recharger", - "mecha_tracking", - "mechacontrol", - "mechapower", - "ripley_chassis", - "ripley_left_arm", - "ripley_left_leg", - "ripley_main", - "ripley_peri", - "ripley_right_arm", - "ripley_right_leg", - "ripley_torso", - "ripleyupgrade", - "mech_hydraulic_clamp", - "mech_radio", - "mech_air_tank", - "mech_thrusters", - ) - -/datum/techweb_node/mod_basic - id = "mod" - starting_node = TRUE - display_name = "Basic Modular Suits" - description = "Specialized back mounted power suits with various different modules." - design_ids = list( - "mod_boots", - "mod_chestplate", - "mod_gauntlets", - "mod_helmet", - "mod_paint_kit", - "mod_shell", - "mod_plating_standard", - "mod_storage", - "mod_welding", - "mod_safety", - "mod_mouthhole", - "mod_flashlight", - "mod_longfall", - "mod_thermal_regulator", - "mod_plasma", - "mod_sign_radio", - ) - -/datum/techweb_node/mech_tools - id = "mech_tools" - starting_node = TRUE - display_name = "Basic Exosuit Equipment" - description = "Various tools fit for basic mech units" - design_ids = list( - "mech_drill", - "mech_extinguisher", - "mech_mscanner", - ) - -/datum/techweb_node/basic_tools - id = "basic_tools" - starting_node = TRUE - display_name = "Basic Tools" - description = "Basic mechanical, electronic, surgical and botanical tools." - design_ids = list( - "airlock_painter", - "analyzer", - "boxcutter", - "cable_coil", - "cable_coil", - "crowbar", - "cultivator", - "decal_painter", - "hatchet", - "mop", - "multitool", - "normtrash", - "pipe_painter", - "plant_analyzer", - "plunger", - "pushbroom", - "rwd", - "razor", - "screwdriver", - "secateurs", - "shovel", - "spade", - "spraycan", - "tile_sprayer", - "tscanner", - "welding_helmet", - "welding_tool", - "wirebrush", - "wirecutters", - "wrench", - "pickaxe", - ) - -/datum/techweb_node/basic_medical - id = "basic_medical" - starting_node = TRUE - display_name = "Basic Medical Equipment" - description = "Basic medical tools and equipment." - design_ids = list( - "beaker", - "biopsy_tool", - "blood_filter", - "bonesetter", - "cautery", - "circular_saw", - "cybernetic_ears", - "cybernetic_eyes", - "cybernetic_eyes_moth", - "cybernetic_heart", - "cybernetic_liver", - "cybernetic_lungs", - "cybernetic_stomach", - "defibmountdefault", - "dropper", - "hemostat", - "large_beaker", - "medicalbed", - "mmi_m", - "operating", - "petri_dish", - "pillbottle", - "plumbing_rcd", - "plumbing_rcd_service", - "plumbing_rcd_sci", - "portable_chem_mixer", - "penlight", - "retractor", - "scalpel", - "stethoscope", - "surgical_drapes", - "surgical_tape", - "surgicaldrill", - "swab", - "syringe", - "xlarge_beaker", - ) - -/datum/techweb_node/basic_circuitry - id = "basic_circuitry" - starting_node = TRUE - display_name = "Basic Integrated Circuits" - description = "Research on how to fully exploit the power of integrated circuits" - design_ids = list( - "circuit_multitool", - "comp_access_checker", - "comp_arctan2", - "comp_arithmetic", - "comp_assoc_list_pick", - "comp_assoc_list_remove", - "comp_assoc_list_set", - "comp_binary_convert", - "comp_clock", - "comp_comparison", - "comp_concat", - "comp_concat_list", - "comp_decimal_convert", - "comp_delay", - "comp_direction", - "comp_element_find", - "comp_filter_list", - "comp_foreach", - "comp_format", - "comp_format_assoc", - "comp_get_column", - "comp_gps", - "comp_health", - "comp_health_state", - "comp_hear", - "comp_id_access_reader", - "comp_id_getter", - "comp_id_info_reader", - "comp_index", - "comp_index_assoc", - "comp_index_table", - "comp_laserpointer", - "comp_length", - "comp_light", - "comp_list_add", - "comp_list_assoc_literal", - "comp_list_clear", - "comp_list_literal", - "comp_list_pick", - "comp_list_remove", - "comp_logic", - "comp_matscanner", - "comp_mmi", - "comp_module", - "comp_multiplexer", - "comp_not", - "comp_ntnet_receive", - "comp_ntnet_send", - "comp_ntnet_send_list_literal", - "comp_pinpointer", - "comp_pressuresensor", - "comp_radio", - "comp_random", - "comp_reagents", - "comp_router", - "comp_select_query", - "comp_self", - "comp_set_variable_trigger", - "comp_soundemitter", - "comp_species", - "comp_speech", - "comp_speech", - "comp_split", - "comp_string_contains", - "comp_tempsensor", - "comp_textcase", - "comp_timepiece", - "comp_toggle", - "comp_tonumber", - "comp_tostring", - "comp_trigonometry", - "comp_typecast", - "comp_typecheck", - "comp_view_sensor", - "compact_remote_shell", - "component_printer", - "integrated_circuit", - "module_duplicator", - "usb_cable" - ) - -/////////////////////////Biotech///////////////////////// - -/datum/techweb_node/biotech - id = "biotech" - display_name = "Biological Technology" - description = "What makes us tick." //the MC, silly! - prereq_ids = list("base") - design_ids = list( - "beer_dispenser", - "blood_pack", - "chem_dispenser", - "chem_heater", - "chem_mass_spec", - "chem_master", - "chem_pack", - "defibmount", - "defibrillator", - "genescanner", - "healthanalyzer", - "med_spray_bottle", - "medical_kiosk", - "medigel", - "medipen_refiller", - "pandemic", - "penlight_paramedic", - "soda_dispenser", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - required_experiments = list(/datum/experiment/autopsy/human) - -/datum/techweb_node/adv_biotech - id = "adv_biotech" - display_name = "Advanced Biotechnology" - description = "Advanced Biotechnology" - prereq_ids = list("biotech") - design_ids = list( - "autopsyscanner", - "crewpinpointer", - "defibrillator_compact", - "harvester", - "healthanalyzer_advanced", - "holobarrier_med", - "limbgrower", - "meta_beaker", - "ph_meter", - "piercesyringe", - "plasmarefiller", - "smoke_machine", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) - required_experiments = list(/datum/experiment/autopsy/nonhuman) - discount_experiments = list(/datum/experiment/scanning/random/material/meat = 4000) - -/datum/techweb_node/xenoorgan_biotech - id = "xenoorgan_bio" - display_name = "Xeno-organ Biology" - description = "Plasmaman, Ethereals, Lizardpeople... What makes our non-human crewmembers tick?" - prereq_ids = list("adv_biotech") - design_ids = list( - "limbdesign_ethereal", - "limbdesign_felinid", - "limbdesign_lizard", - "limbdesign_plasmaman", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 6500) - discount_experiments = list( - /datum/experiment/scanning/random/cytology/easy = 1000, - /datum/experiment/scanning/points/slime/hard = 5000, - /datum/experiment/autopsy/xenomorph = 5000, - ) - -/datum/techweb_node/morphological_theory - id = "morphological_theory" - display_name = "Anomalous Morphology" - description = "Use poorly understood energies to change your body." - prereq_ids = list("adv_biotech", "anomaly_research") - design_ids = list("polymorph_belt") - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) - discount_experiments = list( - /datum/experiment/scanning/people/novel_organs = 5000, - ) - -/datum/techweb_node/bio_process - id = "bio_process" - display_name = "Biological Processing" - description = "From slimes to kitchens." - prereq_ids = list("biotech") - design_ids = list( - "deepfryer", - "dish_drive", - "fat_sucker", - "gibber", - "griddle", - "microwave", - "microwave_engineering", - "monkey_recycler", - "oven", - "processor", - "range", // should be in a further node, probably - "reagentgrinder", - "smartfridge", - "stove", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4000) - discount_experiments = list(/datum/experiment/scanning/random/cytology = 3000) //Big discount to reinforce doing it. - -/datum/techweb_node/marine_util - id = "marine_util" - display_name = "Marine Utility" - description = "Fish are nice to look at and all, but they can be put to use." - prereq_ids = list("bio_process") - design_ids = list( - "bioelec_gen", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4000) - // only available if you've done the first fishing experiment (thus unlocking fishing tech), but not a strict requirement to get the tech - discount_experiments = list(/datum/experiment/scanning/fish/second = 3000) - -/////////////////////////Advanced Surgery///////////////////////// - -/datum/techweb_node/imp_wt_surgery - id = "imp_wt_surgery" - display_name = "Improved Wound-Tending Surgery" - description = "Who would have known being more gentle with a hemostat decreases patient pain?" - prereq_ids = list("biotech") - design_ids = list( - "surgery_heal_brute_upgrade", - "surgery_heal_burn_upgrade", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) - -/datum/techweb_node/oldstation_surgery - id = "oldstation_surgery" - display_name = "Experimental Dissection" - description = "Grants access to experimental dissections, which allows generation of research points." - design_ids = list( - "surgery_oldstation_dissection", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 500) - hidden = TRUE - show_on_wiki = FALSE - -/datum/techweb_node/adv_surgery - id = "adv_surgery" - display_name = "Advanced Surgery" - description = "When simple medicine doesn't cut it." - prereq_ids = list("imp_wt_surgery") - design_ids = list( - "surgery_heal_brute_upgrade_femto", - "surgery_heal_burn_upgrade_femto", - "surgery_heal_combo", - "surgery_lobotomy", - "surgery_wing_reconstruction", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500) - -/datum/techweb_node/exp_surgery - id = "exp_surgery" - display_name = "Experimental Surgery" - description = "When evolution isn't fast enough." - prereq_ids = list("adv_surgery") - design_ids = list( - "surgery_cortex_folding", - "surgery_cortex_imprint", - "surgery_heal_combo_upgrade", - "surgery_ligament_hook", - "surgery_ligament_reinforcement", - "surgery_muscled_veins", - "surgery_nerve_ground", - "surgery_nerve_splice", - "surgery_pacify", - "surgery_vein_thread", - "surgery_viral_bond", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 7500) - discount_experiments = list(/datum/experiment/scanning/random/plants/traits = 4500) - -/datum/techweb_node/alien_surgery - id = "alien_surgery" - display_name = "Alien Surgery" - description = "Abductors did nothing wrong." - prereq_ids = list("exp_surgery", "alientech") - design_ids = list( - "surgery_brainwashing", - "surgery_heal_combo_upgrade_femto", - "surgery_zombie", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000) - -/////////////////////////data theory tech///////////////////////// - -/datum/techweb_node/datatheory //Computer science - id = "datatheory" - display_name = "Data Theory" - description = "Big Data, in space!" - prereq_ids = list("base") - design_ids = list( - "bounty_pad", - "bounty_pad_control", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - - -/////////////////////////engineering tech///////////////////////// - -/datum/techweb_node/engineering - id = "engineering" - display_name = "Industrial Engineering" - description = "A refresher course on modern engineering technology." - prereq_ids = list("base") - design_ids = list( - "adv_capacitor", - "adv_matter_bin", - "adv_scanning", - "airalarm_electronics", - "airlock_board", - "anomaly_refinery", - "apc_control", - "atmos_control", - "atmos_thermal", - "atmosalerts", - "autolathe", - "cell_charger", - "crystallizer", - "electrolyzer", - "emergency_oxygen_engi", - "emergency_oxygen", - "emitter", - "mass_driver", - "firealarm_electronics", - "firelock_board", - "generic_tank", - "grounding_rod", - "high_cell", - "high_micro_laser", - "mesons", - "nano_servo", - "oxygen_tank", - "pacman", - "plasma_tank", - "plasmaman_tank_belt", - "pneumatic_seal", - "power_control", - "powermonitor", - "recharger", - "recycler", - "rped", - "scanner_gate", - "solarcontrol", - "stack_console", - "stack_machine", - "suit_storage_unit", - "tank_compressor", - "tesla_coil", - "thermomachine", - "w-recycler", - "welding_goggles", - "flatpacker", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 12500) - discount_experiments = list(/datum/experiment/scanning/random/material/easy = 7500) - experiments_to_unlock = list(/datum/experiment/scanning/points/machinery_pinpoint_scan/tier2_microlaser) - -/datum/techweb_node/adv_engi - id = "adv_engi" - display_name = "Advanced Engineering" - description = "Pushing the boundaries of physics, one chainsaw-fist at a time." - prereq_ids = list("engineering", "emp_basic") - design_ids = list( - "HFR_core", - "HFR_corner", - "HFR_fuel_input", - "HFR_interface", - "HFR_moderator_input", - "HFR_waste_output", - "engine_goggles", - "forcefield_projector", - "magboots", - "rcd_loaded", - "rcd_ammo", - "rpd_loaded", - "rtd_loaded", - "sheetifier", - "weldingmask", - "bolter_wrench", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 15000) - discount_experiments = list( - /datum/experiment/scanning/random/material/medium/one = 4000, - /datum/experiment/ordnance/gaseous/bz = 10000, - ) - -/datum/techweb_node/anomaly - id = "anomaly_research" - display_name = "Anomaly Research" - description = "Unlock the potential of the mysterious anomalies that appear on station." - prereq_ids = list("adv_engi", "practical_bluespace") - design_ids = list( - "anomaly_neutralizer", - "reactive_armour", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) - -/datum/techweb_node/high_efficiency - id = "high_efficiency" - display_name = "High Efficiency Parts" - description = "Finely-tooled manufacturing techniques allowing for picometer-perfect precision levels." - prereq_ids = list("engineering", "datatheory") - design_ids = list( - "pico_servo", - "super_matter_bin", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 7500) - discount_experiments = list(/datum/experiment/scanning/points/machinery_tiered_scan/tier2_lathes = 5000) - -/datum/techweb_node/adv_power - id = "adv_power" - display_name = "Advanced Power Manipulation" - description = "How to get more zap." - prereq_ids = list("engineering") - design_ids = list( - "hyper_cell", - "power_turbine_console", - "smes", - "super_capacitor", - "super_cell", - "turbine_compressor", - "turbine_rotor", - "turbine_stator", - "modular_shield_generator", - "modular_shield_node", - "modular_shield_relay", - "modular_shield_charger", - "modular_shield_well", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500) - discount_experiments = list(/datum/experiment/scanning/points/machinery_pinpoint_scan/tier2_capacitors = 2500) - -/////////////////////////Bluespace tech///////////////////////// -/datum/techweb_node/bluespace_basic //Bluespace-memery - id = "bluespace_basic" - display_name = "Basic Bluespace Theory" - description = "Basic studies into the mysterious alternate dimension known as bluespace." - prereq_ids = list("base") - design_ids = list( - "beacon", - "bluespace_crystal", - "telesci_gps", - "xenobioconsole", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/bluespace_travel - id = "bluespace_travel" - display_name = "Bluespace Travel" - description = "Application of Bluespace for static teleportation technology." - prereq_ids = list("practical_bluespace") - design_ids = list( - "bluespace_pod", - "launchpad", - "launchpad_console", - "quantumpad", - "tele_hub", - "tele_station", - "teleconsole", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) - discount_experiments = list(/datum/experiment/scanning/points/machinery_tiered_scan/tier3_bluespacemachines = 4000) - -/datum/techweb_node/micro_bluespace - id = "micro_bluespace" - display_name = "Miniaturized Bluespace Research" - description = "Extreme reduction in space required for bluespace engines, leading to portable bluespace technology." - prereq_ids = list("bluespace_travel", "practical_bluespace", "high_efficiency") - design_ids = list( - "bluespace_matter_bin", - "bluespacebodybag", - "medicalbed_emergency", - "femto_servo", - "quantum_keycard", - "swapper", - "triphasic_scanning", - "wormholeprojector", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000) - discount_experiments = list(/datum/experiment/scanning/points/machinery_tiered_scan/tier3_variety = 5000) - /* /datum/experiment/exploration_scan/random/condition) this should have a point cost but im not even sure the experiment works properly lmao*/ - -/datum/techweb_node/advanced_bluespace - id = "bluespace_storage" - display_name = "Advanced Bluespace Storage" - description = "With the use of bluespace we can create even more advanced storage devices than we could have ever done" - prereq_ids = list("micro_bluespace", "janitor") - design_ids = list( - "bag_holding", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) - -/datum/techweb_node/practical_bluespace - id = "practical_bluespace" - display_name = "Applied Bluespace Research" - description = "Using bluespace to make things faster and better." - prereq_ids = list("bluespace_basic", "engineering") - design_ids = list( - "bluespacebeaker", - "bluespacesyringe", - "bluespace_coffeepot", - "bs_rped", - "minerbag_holding", - "ore_silo", - "phasic_scanning", - "plumbing_receiver", - "roastingstick", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) - discount_experiments = list(/datum/experiment/scanning/points/machinery_pinpoint_scan/tier2_scanmodules = 3500) - -/datum/techweb_node/bluespace_power - id = "bluespace_power" - display_name = "Bluespace Power Technology" - description = "Even more powerful.. power!" - prereq_ids = list("adv_power", "practical_bluespace") - design_ids = list( - "bluespace_cell", - "quadratic_capacitor", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4000) - discount_experiments = list(/datum/experiment/scanning/points/machinery_pinpoint_scan/tier3_cells = 3000) - -/datum/techweb_node/unregulated_bluespace - id = "unregulated_bluespace" - display_name = "Unregulated Bluespace Research" - description = "Bluespace technology using unstable or unbalanced procedures, prone to damaging the fabric of bluespace. Outlawed by galactic conventions." - prereq_ids = list("bluespace_travel", "syndicate_basic") - design_ids = list( - "desynchronizer", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - - -/////////////////////////plasma tech///////////////////////// -/datum/techweb_node/basic_plasma - id = "basic_plasma" - display_name = "Basic Plasma Research" - description = "Research into the mysterious and dangerous substance, plasma." - prereq_ids = list("engineering") - design_ids = list( - "mech_generator", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/adv_plasma - id = "adv_plasma" - display_name = "Advanced Plasma Research" - description = "Research on how to fully exploit the power of plasma." - prereq_ids = list("basic_plasma") - design_ids = list( - "mech_plasma_cutter", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/////////////////////////integrated circuits tech///////////////////////// - -/datum/techweb_node/adv_shells - id = "adv_shells" - display_name = "Advanced Shell Research" - description = "Grants access to more complicated shell designs." - prereq_ids = list("basic_circuitry", "engineering") - design_ids = list( - "assembly_shell", - "bot_shell", - "comp_equip_action", - "controller_shell", - "dispenser_shell", - "door_shell", - "gun_shell", - "keyboard_shell", - "module_shell", - "money_bot_shell", - "scanner_gate_shell", - "scanner_shell", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/bci_shells - id = "bci_shells" - display_name = "Brain-Computer Interfaces" - description = "Grants access to biocompatable shell designs and components." - prereq_ids = list("adv_shells") - design_ids = list( - "bci_implanter", - "bci_shell", - "comp_bar_overlay", - "comp_camera_bci", - "comp_counter_overlay", - "comp_install_detector", - "comp_object_overlay", - "comp_reagent_injector", - "comp_target_intercept", - "comp_thought_listener", - "comp_vox", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 500) - -/datum/techweb_node/movable_shells_tech - id = "movable_shells" - display_name = "Movable Shell Research" - description = "Grants access to movable shells." - prereq_ids = list("adv_shells", "robotics") - design_ids = list( - "comp_pathfind", - "comp_pull", - "drone_shell", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3000) - -/datum/techweb_node/server_shell_tech - id = "server_shell" - display_name = "Server Technology Research" - description = "Grants access to a server shell that has a very high capacity for components." - prereq_ids = list("adv_shells", "computer_data_disks") - design_ids = list( - "server_shell", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3000) - -/////////////////////////robotics tech///////////////////////// -/datum/techweb_node/robotics - id = "robotics" - display_name = "Basic Robotics Research" - description = "Programmable machines that make our lives lazier." - prereq_ids = list("base") - design_ids = list( - "paicard", - "mecha_camera", - "botnavbeacon", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/adv_robotics - id = "adv_robotics" - display_name = "Advanced Robotics Research" - description = "Advanced synthetic neural networks and synaptic pathways allows for extraordinary leaps in cybernetic intelligence and interfacing." - prereq_ids = list("robotics") - design_ids = list( - "advanced_l_arm", - "advanced_r_arm", - "advanced_l_leg", - "advanced_r_leg", - "mmi_posi", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/adv_bots - id = "adv_bots" - display_name = "Advanced Bots Research" - description = "Grants access to a special launchpad designed for bots." - prereq_ids = list("robotics") - design_ids = list( - "botpad", - "botpad_remote", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/exodrone_tech - id = "exodrone" - display_name = "Exploration Drone Research" - description = "Technology for exploring far away locations." - prereq_ids = list("robotics") - design_ids = list( - "exodrone_console", - "exodrone_launcher", - "exoscanner", - "exoscanner_console", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/neural_programming - id = "neural_programming" - display_name = "Neural Programming" - description = "Study into networks of processing units that mimic our brains." - prereq_ids = list("biotech", "datatheory") - design_ids = list( - "skill_station", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/cyborg_upg_util - id = "cyborg_upg_util" - display_name = "Cyborg Upgrades: Utility" - description = "Utility upgrades for cyborgs." - prereq_ids = list("adv_robotics") - design_ids = list( - "borg_upgrade_advancedmop", - "borg_upgrade_broomer", - "borg_upgrade_expand", - "borg_upgrade_prt", - "borg_upgrade_selfrepair", - "borg_upgrade_thrusters", - "borg_upgrade_trashofholding", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000) - -/datum/techweb_node/cyborg_upg_util/New() - . = ..() - if(!CONFIG_GET(flag/disable_secborg)) - design_ids += "borg_upgrade_disablercooler" - -/datum/techweb_node/cyborg_upg_serv - id = "cyborg_upg_serv" - display_name = "Cyborg Upgrades: Service" - description = "Service upgrades for cyborgs." - prereq_ids = list("adv_robotics") - design_ids = list( - "borg_upgrade_rolling_table", - "borg_upgrade_condiment_synthesizer", - "borg_upgrade_silicon_knife", - "borg_upgrade_service_apparatus", - "borg_upgrade_drink_apparatus", - "borg_upgrade_service_cookbook", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000) - -/datum/techweb_node/cyborg_upg_engiminer - id = "cyborg_upg_engiminer" - display_name = "Cyborg Upgrades: Engineering & Mining" - description = "Engineering and Mining upgrades for cyborgs." - prereq_ids = list("adv_engi", "basic_mining") - design_ids = list( - "borg_upgrade_circuitapp", - "borg_upgrade_diamonddrill", - "borg_upgrade_holding", - "borg_upgrade_lavaproof", - "borg_upgrade_rped", - "borg_upgrade_hypermod", - "borg_upgrade_inducer", - "borg_upgrade_engineeringomnitool", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000) - -/datum/techweb_node/cyborg_upg_med - id = "cyborg_upg_med" - display_name = "Cyborg Upgrades: Medical" - description = "Medical upgrades for cyborgs." - prereq_ids = list("adv_biotech") - design_ids = list( - "borg_upgrade_beakerapp", - "borg_upgrade_defibrillator", - "borg_upgrade_expandedsynthesiser", - "borg_upgrade_piercinghypospray", - "borg_upgrade_pinpointer", - "borg_upgrade_surgicalprocessor", - "borg_upgrade_surgicalomnitool", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000) - -/datum/techweb_node/ai_basic - id = "ai_basic" - display_name = "Artificial Intelligence" - description = "AI unit research." - prereq_ids = list("adv_robotics") - design_ids = list( - "aicore", - "borg_ai_control", - "intellicard", - "mecha_tracking_ai_control", - "aifixer", - "aiupload", - "reset_module", - "asimov_module", - "default_module", - "nutimov_module", - "paladin_module", - "robocop_module", - "corporate_module", - "drone_module", - "oxygen_module", - "safeguard_module", - "protectstation_module", - "quarantine_module", - "freeform_module", - "remove_module", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/ai_basic/New() - . = ..() - if(HAS_TRAIT(SSstation, STATION_TRAIT_HUMAN_AI)) - design_ids -= list( - "aicore", - "borg_ai_control", - "intellicard", - "mecha_tracking_ai_control", - "aifixer", - "aiupload", - ) - -/datum/techweb_node/ai_adv - id = "ai_adv" - display_name = "Advanced Artificial Intelligence" - description = "State of the art lawsets to be used for AI research." - prereq_ids = list("ai_basic") - design_ids = list( - "asimovpp_module", - "paladin_devotion_module", - "dungeon_master_module", - "painter_module", - "ten_commandments_module", - "hippocratic_module", - "maintain_module", - "liveandletlive_module", - "reporter_module", - "yesman_module", - "hulkamania_module", - "peacekeeper_module", - "overlord_module", - "tyrant_module", - "antimov_module", - "balance_module", - "thermurderdynamic_module", - "damaged_module", - "freeformcore_module", - "onehuman_module", - "purge_module", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3000) - -//Any kind of point adjustment needs to happen before SSresearch sets up the whole node tree, it gets cached -/datum/techweb_node/ai/New() - . = ..() - if(HAS_TRAIT(SSstation, STATION_TRAIT_UNIQUE_AI)) - research_costs[TECHWEB_POINT_TYPE_GENERIC] *= 3 - -/////////////////////////EMP tech///////////////////////// -/datum/techweb_node/emp_basic //EMP tech for some reason - id = "emp_basic" - display_name = "Electromagnetic Theory" - description = "Study into usage of frequencies in the electromagnetic spectrum." - prereq_ids = list("base") - design_ids = list( - "holosign", - "holosignsec", - "holosignengi", - "holosignatmos", - "holosignrestaurant", - "holosignbar", - "inducer", - "inducerengi", - "tray_goggles", - "holopad", - "vendatray", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/emp_adv - id = "emp_adv" - display_name = "Advanced Electromagnetic Theory" - description = "Determining whether reversing the polarity will actually help in a given situation." - prereq_ids = list("emp_basic") - design_ids = list( - "ultra_micro_laser", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3000) - discount_experiments = list(/datum/experiment/scanning/points/machinery_pinpoint_scan/tier2_microlaser = 1500) - -/datum/techweb_node/emp_super - id = "emp_super" - display_name = "Quantum Electromagnetic Technology" //bs - description = "Even better electromagnetic technology." - prereq_ids = list("emp_adv") - design_ids = list( - "quadultra_micro_laser", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 15000) - discount_experiments = list( - /datum/experiment/scanning/points/machinery_pinpoint_scan/tier3_microlaser = 4000, - /datum/experiment/ordnance/gaseous/noblium = 10000, - ) - -/////////////////////////Clown tech///////////////////////// -/datum/techweb_node/clown - id = "clown" - display_name = "Clown Technology" - description = "Honk?!" - prereq_ids = list("base") - design_ids = list( - "air_horn", - "borg_transform_clown", - "honk_chassis", - "honk_head", - "honk_left_arm", - "honk_left_leg", - "honk_right_arm", - "honk_right_leg", - "honk_torso", - "honker_main", - "honker_peri", - "honker_targ", - "implant_trombone", - "mech_banana_mortar", - "mech_honker", - "mech_mousetrap_mortar", - "mech_punching_face", - "clown_firing_pin", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -////////////////////////Computer tech//////////////////////// -/datum/techweb_node/comptech - id = "comptech" - display_name = "Computer Consoles" - description = "Computers and how they work." - prereq_ids = list("datatheory") - design_ids = list( - "bankmachine", - "barcode_scanner", - "cargo", - "cargorequest", - "comconsole", - "crewconsole", - "idcard", - "libraryconsole", - "mining", - "photobooth", - "rdcamera", - "seccamera", - "security_photobooth", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000) - -/datum/techweb_node/data_disks - id = "computer_data_disks" - display_name = "Computer Data Disks" - description = "Data disks used for storing modular computer stuff." - prereq_ids = list("comptech") - design_ids = list( - "portadrive_advanced", - "portadrive_basic", - "portadrive_super", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) - -/datum/techweb_node/computer_board_gaming - id = "computer_board_gaming" - display_name = "Arcade Games" - description = "For the slackers on the station." - prereq_ids = list("comptech") - design_ids = list( - "arcade_battle", - "arcade_orion", - "slotmachine", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3250) - discount_experiments = list(/datum/experiment/physical/arcade_winner = 3000) - -/datum/techweb_node/comp_recordkeeping - id = "comp_recordkeeping" - display_name = "Computerized Recordkeeping" - description = "Organized record databases and how they're used." - prereq_ids = list("comptech") - design_ids = list( - "account_console", - "automated_announcement", - "med_data", - "prisonmanage", - "secdata", - "vendor", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) - -/datum/techweb_node/telecomms - id = "telecomms" - display_name = "Telecommunications Technology" - description = "Subspace transmission technology for near-instant communications devices." - prereq_ids = list("comptech", "bluespace_basic") - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - design_ids = list( - "comm_monitor", - "comm_server", - "gigabeacon", - "message_monitor", - "ntnet_relay", - "s_amplifier", - "s_analyzer", - "s_ansible", - "s_broadcaster", - "s_bus", - "s_crystal", - "s_filter", - "s_hub", - "s_messaging", - "s_processor", - "s_receiver", - "s_relay", - "s_server", - "s_transmitter", - "s_treatment", - ) - -/datum/techweb_node/tram - id = "tram" - display_name = "Tram Technology" - description = "Technology for linear induction transportation systems." - prereq_ids = list("telecomms") - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500) - design_ids = list( - "tram_controller", - "tram_display", - "crossing_signal", - "guideway_sensor", - ) - -/datum/techweb_node/integrated_hud - id = "integrated_HUDs" - display_name = "Integrated HUDs" - description = "The usefulness of computerized records, projected straight onto your eyepiece!" - prereq_ids = list("comp_recordkeeping", "emp_basic") - design_ids = list( - "diagnostic_hud", - "health_hud", - "scigoggles", - "security_hud", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500) - -/datum/techweb_node/nvg_tech - id = "NVGtech" - display_name = "Night Vision Technology" - description = "Allows seeing in the dark without actual light!" - prereq_ids = list("integrated_HUDs", "adv_engi", "emp_adv") - design_ids = list( - "diagnostic_hud_night", - "health_hud_night", - "night_visision_goggles", - "nvgmesons", - "nv_scigoggles", - "security_hud_night", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) - -////////////////////////Medical//////////////////////// -/datum/techweb_node/genetics - id = "genetics" - display_name = "Genetic Engineering" - description = "We have the technology to change him." - prereq_ids = list("biotech") - design_ids = list( - "dna_disk", - "dnainfuser", - "dnascanner", - "scan_console", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/cryotech - id = "cryotech" - display_name = "Cryostasis Technology" - description = "Smart freezing of objects to preserve them!" - prereq_ids = list("adv_engi", "biotech") - design_ids = list( - "cryo_grenade", - "cryotube", - "splitbeaker", - "stasis", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000) - -/datum/techweb_node/subdermal_implants - id = "subdermal_implants" - display_name = "Subdermal Implants" - description = "Electronic implants buried beneath the skin." - prereq_ids = list("biotech") - design_ids = list( - "c38_trac", - "implant_chem", - "implant_tracking", - "implant_exile", - "implantcase", - "implanter", - "locator", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/advanced_implants - id = "adv_subdermal_implants" - display_name = "Advanced Subdermal Implants" - description = "Subdermal implants that leverage bluespace research to control their bluespace signature." - prereq_ids = list("subdermal_implants", "micro_bluespace") - design_ids = list( - "implant_beacon", - "implant_bluespace", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/cyber_organs - id = "cyber_organs" - display_name = "Cybernetic Organs" - description = "We have the technology to rebuild him." - prereq_ids = list("biotech") - design_ids = list( - "cybernetic_ears_u", - "cybernetic_eyes_improved", - "cybernetic_eyes_improved_moth", - "cybernetic_heart_tier2", - "cybernetic_liver_tier2", - "cybernetic_lungs_tier2", - "cybernetic_stomach_tier2", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) - -/datum/techweb_node/cyber_organs/New() - ..() - if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION)) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 500) - -/datum/techweb_node/cyber_organs_upgraded - id = "cyber_organs_upgraded" - display_name = "Upgraded Cybernetic Organs" - description = "We have the technology to upgrade him." - prereq_ids = list("adv_biotech", "cyber_organs") - design_ids = list( - "cybernetic_ears_whisper", - "cybernetic_ears_xray", - "ci-gloweyes", - "ci-welding", - "ci-gloweyes-moth", - "ci-welding-moth", - "cybernetic_heart_tier3", - "cybernetic_liver_tier3", - "cybernetic_lungs_tier3", - "cybernetic_stomach_tier3", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500) - -/datum/techweb_node/cyber_organs_upgraded/New() - ..() - if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION)) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) - -/datum/techweb_node/cyber_implants - id = "cyber_implants" - display_name = "Cybernetic Implants" - description = "Electronic implants that improve humans." - prereq_ids = list("adv_biotech", "datatheory") - design_ids = list( - "ci-breather", - "ci-diaghud", - "ci-medhud", - "ci-nutriment", - "ci-sechud", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/cyber_implants/New() - ..() - if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION)) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) - -/datum/techweb_node/adv_cyber_implants - id = "adv_cyber_implants" - display_name = "Advanced Cybernetic Implants" - description = "Upgraded and more powerful cybernetic implants." - prereq_ids = list("neural_programming", "cyber_implants","integrated_HUDs") - design_ids = list( - "ci-nutrimentplus", - "ci-reviver", - "ci-surgery", - "ci-toolset", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/adv_cyber_implants/New() - ..() - if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION)) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500) - -/datum/techweb_node/combat_cyber_implants - id = "combat_cyber_implants" - display_name = "Combat Cybernetic Implants" - description = "Military grade combat implants to improve performance." - prereq_ids = list("adv_cyber_implants","weaponry","NVGtech","high_efficiency") - design_ids = list( - "ci-antidrop", - "ci-antistun", - "ci-thermals", - "ci-thrusters", - "ci-xray", - "ci-thermals-moth", - "ci-xray-moth", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/combat_cyber_implants/New() - ..() - if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION)) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500) - -////////////////////////Tools//////////////////////// - -/datum/techweb_node/basic_mining - id = "basic_mining" - display_name = "Mining Technology" - description = "Better than Efficiency V." - prereq_ids = list("engineering", "basic_plasma") - design_ids = list( - "borg_upgrade_cooldownmod", - "borg_upgrade_damagemod", - "borg_upgrade_rangemod", - "cargoexpress", - "cooldownmod", - "damagemod", - "drill", - "mecha_kineticgun", - "mining_equipment_vendor", - "ore_redemption", - "plasmacutter", - "rangemod", - "superresonator", - "triggermod", - "mining_scanner", - "brm", - "b_smelter", - "b_refinery", - )//e a r l y g a m e) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/adv_mining - id = "adv_mining" - display_name = "Advanced Mining Technology" - description = "Efficiency Level 127" //dumb mc references - prereq_ids = list("basic_mining", "adv_power", "adv_plasma") - design_ids = list( - "drill_diamond", - "hypermod", - "jackhammer", - "plasmacutter_adv", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 7500) - discount_experiments = list(/datum/experiment/scanning/random/material/hard/one = 5000) - -/datum/techweb_node/janitor - id = "janitor" - display_name = "Advanced Sanitation Technology" - description = "Clean things better, faster, stronger, and harder!" - prereq_ids = list("adv_engi") - design_ids = list( - "advmop", - "beartrap", - "blutrash", - "buffer", - "vacuum", - "holobarrier_jani", - "light_replacer_blue", - "paint_remover", - "spraybottle", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4000) - discount_experiments = list(/datum/experiment/scanning/random/janitor_trash = 3000) //75% discount for scanning some trash, seems fair right? - -/datum/techweb_node/botany - id = "botany" - display_name = "Botanical Engineering" - description = "Botanical tools" - prereq_ids = list("biotech") - design_ids = list( - "biogenerator", - "flora_gun", - "gene_shears", - "hydro_tray", - "portaseeder", - "seed_extractor", - "adv_watering_can", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4000) - required_experiments = list(/datum/experiment/scanning/random/plants/wild) - discount_experiments = list(/datum/experiment/scanning/random/plants/traits = 3000) - -/datum/techweb_node/fishing - id = "fishing" - display_name = "Fishing Technology" - description = "Cutting edge fishing advancements." - prereq_ids = list("base") - design_ids = list( - "fishing_rod_tech", - "stabilized_hook", - "auto_reel", - "fish_analyzer", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000) - required_experiments = list(/datum/experiment/scanning/fish) - -/datum/techweb_node/exp_tools - id = "exp_tools" - display_name = "Experimental Tools" - description = "Highly advanced tools." - prereq_ids = list("adv_engi") - design_ids = list( - "exwelder", - "handdrill", - "jawsoflife", - "laserscalpel", - "mechanicalpinches", - "rangedanalyzer", - "searingtool", - "adv_fire_extinguisher", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 7500) - discount_experiments = list(/datum/experiment/scanning/random/material/hard/one = 5000) - -/datum/techweb_node/sec_basic - id = "sec_basic" - display_name = "Basic Security Equipment" - description = "Standard equipment used by security." - prereq_ids = list("base") - design_ids = list( - "bola_energy", - "evidencebag", - "pepperspray", - "seclite", - "zipties", - "inspector", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) - -/datum/techweb_node/rcd_upgrade - id = "rcd_upgrade" - display_name = "Rapid Device Upgrade Designs" - description = "Unlocks new designs that improve rapid devices." - prereq_ids = list("adv_engi") - design_ids = list( - "rcd_upgrade_anti_interrupt", - "rcd_upgrade_cooling", - "rcd_upgrade_frames", - "rcd_upgrade_furnishing", - "rcd_upgrade_simple_circuits", - "rpd_upgrade_unwrench", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/adv_rcd_upgrade - id = "adv_rcd_upgrade" - display_name = "Advanced RCD Designs Upgrade" - description = "Unlocks new RCD designs." - design_ids = list( - "rcd_upgrade_silo_link", - ) - prereq_ids = list( - "bluespace_travel", - "rcd_upgrade", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000) - discount_experiments = list(/datum/experiment/scanning/random/material/hard/two = 5000) - -/////////////////////////weaponry tech///////////////////////// -/datum/techweb_node/weaponry - id = "weaponry" - display_name = "Weapon Development Technology" - description = "Our researchers have found new ways to weaponize just about everything now." - prereq_ids = list("engineering") - design_ids = list( - "ballistic_shield", - "pin_testing", - "tele_shield", - "lasershell", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 20000) - discount_experiments = list(/datum/experiment/ordnance/explosive/pressurebomb = 10000) - -/datum/techweb_node/adv_weaponry - id = "adv_weaponry" - display_name = "Advanced Weapon Development Technology" - description = "Our weapons are breaking the rules of reality by now." - prereq_ids = list("adv_engi", "weaponry") - design_ids = list( - "pin_loyalty", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000) - -/datum/techweb_node/electric_weapons - id = "electronic_weapons" - display_name = "Electric Weapons" - description = "Weapons using electric technology" - prereq_ids = list("weaponry", "adv_power" , "emp_basic") - design_ids = list( - "ioncarbine", - "stunrevolver", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/radioactive_weapons - id = "radioactive_weapons" - display_name = "Radioactive Weaponry" - description = "Weapons using radioactive technology." - prereq_ids = list("adv_engi", "adv_weaponry") - design_ids = list( - "nuclear_gun", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/beam_weapons - id = "beam_weapons" - display_name = "Beam Weaponry" - description = "Various basic beam weapons" - prereq_ids = list("adv_weaponry") - design_ids = list( - "temp_gun", - "xray_laser", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/adv_beam_weapons - id = "adv_beam_weapons" - display_name = "Advanced Beam Weaponry" - description = "Various advanced beam weapons" - prereq_ids = list("beam_weapons") - design_ids = list( - "beamrifle", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/explosive_weapons - id = "explosive_weapons" - display_name = "Explosive & Pyrotechnical Weaponry" - description = "If the light stuff just won't do it." - prereq_ids = list("adv_weaponry") - design_ids = list( - "adv_grenade", - "large_grenade", - "pyro_grenade", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/exotic_ammo - id = "exotic_ammo" - display_name = "Exotic Ammunition" - description = "They won't know what hit em." - prereq_ids = list("weaponry") - design_ids = list( - "c38_hotshot", - "c38_iceblox", - "techshotshell", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/gravity_gun - id = "gravity_gun" - display_name = "One-point Bluespace-gravitational Manipulator" - description = "Fancy wording for gravity gun." - prereq_ids = list("adv_weaponry", "bluespace_travel") - design_ids = list( - "gravitygun", - "mech_gravcatapult", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -//MODsuit tech - -/datum/techweb_node/mod_advanced - id = "mod_advanced" - display_name = "Advanced Modular Suits" - description = "More advanced modules, to improve modular suits." - prereq_ids = list("robotics") - design_ids = list( - "mod_visor_diaghud", - "mod_gps", - "mod_reagent_scanner", - "mod_clamp", - "mod_drill", - "mod_orebag", - "modlink_scryer", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mod_engineering - id = "mod_engineering" - display_name = "Engineering Modular Suits" - description = "Engineering suits, for powered engineers." - prereq_ids = list("mod_advanced", "engineering") - design_ids = list( - "mod_plating_engineering", - "mod_visor_meson", - "mod_t_ray", - "mod_magboot", - "mod_tether", - "mod_constructor", - "mod_mister_atmos", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mod_advanced_engineering - id = "mod_advanced_engineering" - display_name = "Advanced Engineering Modular Suits" - description = "Advanced Engineering suits, for advanced powered engineers." - prereq_ids = list("mod_engineering", "adv_engi") - design_ids = list( - "mod_plating_atmospheric", - "mod_jetpack", - "mod_rad_protection", - "mod_emp_shield", - "mod_storage_expanded", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500) - -/datum/techweb_node/mod_advanced_engineering/New() - if(HAS_TRAIT(SSstation, STATION_TRAIT_RADIOACTIVE_NEBULA)) //we'll really need the rad protection modsuit module - starting_node = TRUE - - return ..() - -/datum/techweb_node/mod_medical - id = "mod_medical" - display_name = "Medical Modular Suits" - description = "Medical suits for quick rescue purposes." - prereq_ids = list("mod_advanced", "biotech") - design_ids = list( - "mod_plating_medical", - "mod_visor_medhud", - "mod_health_analyzer", - "mod_quick_carry", - "mod_injector", - "mod_organ_thrower", - "mod_dna_lock", - "mod_patienttransport", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mod_advanced_medical - id = "mod_advanced_medical" - display_name = "Advanced Medical Modular Suits" - description = "Advanced medical suits for quicker rescue purposes." - prereq_ids = list("mod_medical", "adv_biotech") - design_ids = list( - "mod_defib", - "mod_threadripper", - "mod_surgicalprocessor", - "mod_statusreadout", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500) - -/datum/techweb_node/mod_security - id = "mod_security" - display_name = "Security Modular Suits" - description = "Security suits for space crime handling." - prereq_ids = list("mod_advanced", "sec_basic") - design_ids = list( - "mod_plating_security", - "mod_visor_sechud", - "mod_stealth", - "mod_mag_harness", - "mod_pathfinder", - "mod_holster", - "mod_sonar", - "mod_projectile_dampener", - "mod_criminalcapture", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mod_entertainment - id = "mod_entertainment" - display_name = "Entertainment Modular Suits" - description = "Powered suits for protection against low-humor environments." - prereq_ids = list("mod_advanced", "clown") - design_ids = list( - "mod_plating_cosmohonk", - "mod_bikehorn", - "mod_microwave_beam", - "mod_waddle", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mod_anomaly - id = "mod_anomaly" - display_name = "Anomalock Modular Suits" - description = "Modules for modular suits that require anomaly cores to function." - prereq_ids = list("mod_advanced", "anomaly_research") - design_ids = list( - "mod_antigrav", - "mod_teleporter", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mod_anomaly_engi - id = "mod_anomaly_engi" - display_name = "Engineering Anomalock Modular Suits" - description = "Advanced modules for modular suits, using anomaly cores to become even better engineers." - prereq_ids = list("mod_advanced_engineering", "mod_anomaly") - design_ids = list( - "mod_kinesis", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) - -////////////////////////mech technology//////////////////////// -/datum/techweb_node/adv_mecha - id = "adv_mecha" - display_name = "Advanced Exosuits" - description = "For when you just aren't Gundam enough." - prereq_ids = list("adv_robotics") - design_ids = list( - "mech_repair_droid", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 7500) - discount_experiments = list(/datum/experiment/scanning/random/material/medium/three = 5000) - -/datum/techweb_node/odysseus - id = "mecha_odysseus" - display_name = "EXOSUIT: Odysseus" - description = "Odysseus exosuit designs" - prereq_ids = list("base") - design_ids = list( - "odysseus_chassis", - "odysseus_head", - "odysseus_left_arm", - "odysseus_left_leg", - "odysseus_main", - "odysseus_peri", - "odysseus_right_arm", - "odysseus_right_leg", - "odysseus_torso", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/clarke - id = "mecha_clarke" - display_name = "EXOSUIT: Clarke" - description = "Clarke exosuit designs" - prereq_ids = list("engineering") - design_ids = list( - "clarke_chassis", - "clarke_head", - "clarke_left_arm", - "clarke_main", - "clarke_peri", - "clarke_right_arm", - "clarke_torso", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/paddy - id = "mech_paddy" - display_name = "EXOSUIT: APLU \"Paddy\"" - description = "Paddy exosuit designs" - prereq_ids = list("adv_mecha", "adv_mecha_armor") - design_ids = list( - "paddyupgrade", - "mech_hydraulic_claw" - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) - discount_experiments = list(/datum/experiment/scanning/points/machinery_tiered_scan/tier3_mechbay = 5000) - -/datum/techweb_node/gygax - id = "mech_gygax" - display_name = "EXOSUIT: Gygax" - description = "Gygax exosuit designs" - prereq_ids = list("adv_mecha", "adv_mecha_armor") - design_ids = list( - "gygax_armor", - "gygax_chassis", - "gygax_head", - "gygax_left_arm", - "gygax_left_leg", - "gygax_main", - "gygax_peri", - "gygax_right_arm", - "gygax_right_leg", - "gygax_targ", - "gygax_torso", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) - discount_experiments = list(/datum/experiment/scanning/points/machinery_tiered_scan/tier3_mechbay = 5000) - -/datum/techweb_node/durand - id = "mech_durand" - display_name = "EXOSUIT: Durand" - description = "Durand exosuit designs" - prereq_ids = list("adv_mecha", "adv_mecha_armor") - design_ids = list( - "durand_armor", - "durand_chassis", - "durand_head", - "durand_left_arm", - "durand_left_leg", - "durand_main", - "durand_peri", - "durand_right_arm", - "durand_right_leg", - "durand_targ", - "durand_torso", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) - discount_experiments = list(/datum/experiment/scanning/points/machinery_tiered_scan/tier3_mechbay = 3500) - -/datum/techweb_node/phazon - id = "mecha_phazon" - display_name = "EXOSUIT: Phazon" - description = "Phazon exosuit designs" - prereq_ids = list("adv_mecha", "adv_mecha_armor" , "micro_bluespace") - design_ids = list( - "phazon_armor", - "phazon_chassis", - "phazon_head", - "phazon_left_arm", - "phazon_left_leg", - "phazon_main", - "phazon_peri", - "phazon_right_arm", - "phazon_right_leg", - "phazon_targ", - "phazon_torso", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) - discount_experiments = list(/datum/experiment/scanning/points/machinery_tiered_scan/tier3_mechbay = 2500) - -/datum/techweb_node/savannah_ivanov - id = "mecha_savannah_ivanov" - display_name = "EXOSUIT: Savannah-Ivanov" - description = "Savannah-Ivanov exosuit designs" - prereq_ids = list("adv_mecha", "weaponry", "exp_tools") - design_ids = list( - "savannah_ivanov_armor", - "savannah_ivanov_chassis", - "savannah_ivanov_head", - "savannah_ivanov_left_arm", - "savannah_ivanov_left_leg", - "savannah_ivanov_main", - "savannah_ivanov_peri", - "savannah_ivanov_right_arm", - "savannah_ivanov_right_leg", - "savannah_ivanov_targ", - "savannah_ivanov_torso", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) - discount_experiments = list(/datum/experiment/scanning/points/machinery_tiered_scan/tier3_mechbay = 3000) - -/datum/techweb_node/adv_mecha_tools - id = "adv_mecha_tools" - display_name = "Advanced Exosuit Equipment" - description = "Tools for high level mech suits" - prereq_ids = list("adv_mecha") - design_ids = list( - "mech_rcd", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/med_mech_tools - id = "med_mech_tools" - display_name = "Medical Exosuit Equipment" - description = "Tools for high level mech suits" - prereq_ids = list("adv_biotech") - design_ids = list( - "mech_medi_beam", - "mech_sleeper", - "mech_syringe_gun", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mech_armor - id = "adv_mecha_armor" - display_name = "Exosuit Heavy Armor Research" - description = "Recreating heavy armor with new rapid fabrication techniques." - prereq_ids = list("adv_mecha", "bluespace_power") - design_ids = list( - "mech_ccw_armor", - "mech_proj_armor", - ) - required_experiments = list(/datum/experiment/scanning/random/mecha_damage_scan) - discount_experiments = list(/datum/experiment/scanning/random/mecha_equipped_scan = 5000) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000) - -/datum/techweb_node/mech_scattershot - id = "mecha_tools" - display_name = "Exosuit Weapon (LBX AC 10 \"Scattershot\")" - description = "An advanced piece of mech weaponry" - prereq_ids = list("adv_mecha") - design_ids = list( - "mech_scattershot", - "mech_scattershot_ammo", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mech_carbine - id = "mech_carbine" - display_name = "Exosuit Weapon (FNX-99 \"Hades\" Carbine)" - description = "An advanced piece of mech weaponry" - prereq_ids = list("exotic_ammo") - design_ids = list( - "mech_carbine", - "mech_carbine_ammo", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mech_ion - id = "mmech_ion" - display_name = "Exosuit Weapon (MKIV Ion Heavy Cannon)" - description = "An advanced piece of mech weaponry" - prereq_ids = list("electronic_weapons", "emp_adv") - design_ids = list( - "mech_ion", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mech_tesla - id = "mech_tesla" - display_name = "Exosuit Weapon (MKI Tesla Cannon)" - description = "An advanced piece of mech weaponry" - prereq_ids = list("electronic_weapons", "adv_power") - design_ids = list( - "mech_tesla", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mech_laser - id = "mech_laser" - display_name = "Exosuit Weapon (CH-PS \"Immolator\" Laser)" - description = "A basic piece of mech weaponry" - prereq_ids = list("beam_weapons") - design_ids = list( - "mech_laser", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mech_laser_heavy - id = "mech_laser_heavy" - display_name = "Exosuit Weapon (CH-LC \"Solaris\" Laser Cannon)" - description = "An advanced piece of mech weaponry" - prereq_ids = list("adv_beam_weapons") - design_ids = list( - "mech_laser_heavy", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mech_disabler - id = "mech_disabler" - display_name = "Exosuit Weapon (CH-DS \"Peacemaker\" Mounted Disabler)" - description = "A basic piece of mech weaponry" - prereq_ids = list("adv_mecha") - design_ids = list( - "mech_disabler", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mech_grenade_launcher - id = "mech_grenade_launcher" - display_name = "Exosuit Weapon (SGL-6 Grenade Launcher)" - description = "An advanced piece of mech weaponry" - prereq_ids = list("explosive_weapons") - design_ids = list( - "mech_grenade_launcher", - "mech_grenade_launcher_ammo", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mech_missile_rack - id = "mech_missile_rack" - display_name = "Exosuit Weapon (BRM-6 Missile Rack)" - description = "An advanced piece of mech weaponry" - prereq_ids = list("explosive_weapons") - design_ids = list( - "mech_missile_rack", - "mech_missile_rack_ammo", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/clusterbang_launcher - id = "clusterbang_launcher" - display_name = "Exosuit Module (SOB-3 Clusterbang Launcher)" - description = "An advanced piece of mech weaponry" - prereq_ids = list("explosive_weapons") - design_ids = list( - "clusterbang_launcher", - "clusterbang_launcher_ammo", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mech_teleporter - id = "mech_teleporter" - display_name = "Exosuit Module (Teleporter Module)" - description = "An advanced piece of mech Equipment" - prereq_ids = list("micro_bluespace") - design_ids = list( - "mech_teleporter", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mech_wormhole_gen - id = "mech_wormhole_gen" - display_name = "Exosuit Module (Localized Wormhole Generator)" - description = "An advanced piece of mech weaponry" - prereq_ids = list("bluespace_travel") - design_ids = list( - "mech_wormhole_gen", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mech_lmg - id = "mech_lmg" - display_name = "Exosuit Weapon (\"Ultra AC 2\" LMG)" - description = "An advanced piece of mech weaponry" - prereq_ids = list("adv_mecha") - design_ids = list( - "mech_lmg", - "mech_lmg_ammo", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -/datum/techweb_node/mech_diamond_drill - id = "mech_diamond_drill" - display_name = "Exosuit Diamond Drill" - description = "A diamond drill fit for a large exosuit" - prereq_ids = list("adv_mining") - design_ids = list( - "mech_diamond_drill", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - -////////////////////////Alien technology//////////////////////// -/datum/techweb_node/alientech //AYYYYYYYYLMAOO tech - id = "alientech" - display_name = "Alien Technology" - description = "Things used by the greys." - prereq_ids = list("biotech","engineering") - required_items_to_unlock = list( - /obj/item/stack/sheet/mineral/abductor, - /obj/item/abductor, - /obj/item/cautery/alien, - /obj/item/circuitboard/machine/abductor, - /obj/item/circular_saw/alien, - /obj/item/crowbar/abductor, - /obj/item/gun/energy/alien, - /obj/item/gun/energy/shrink_ray, - /obj/item/hemostat/alien, - /obj/item/melee/baton/abductor, - /obj/item/multitool/abductor, - /obj/item/retractor/alien, - /obj/item/scalpel/alien, - /obj/item/screwdriver/abductor, - /obj/item/surgicaldrill/alien, - /obj/item/weldingtool/abductor, - /obj/item/wirecutters/abductor, - /obj/item/wrench/abductor, - ) - design_ids = list( - "alienalloy", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) - hidden = TRUE - -/datum/techweb_node/alientech/on_station_research() - SSshuttle.shuttle_purchase_requirements_met[SHUTTLE_UNLOCK_ALIENTECH] = TRUE - -/datum/techweb_node/alien_bio - id = "alien_bio" - display_name = "Alien Biological Tools" - description = "Advanced biological tools." - prereq_ids = list("alientech", "adv_biotech") - design_ids = list( - "alien_cautery", - "alien_drill", - "alien_hemostat", - "alien_retractor", - "alien_saw", - "alien_scalpel", - ) - - required_items_to_unlock = list( - /obj/item/abductor, - /obj/item/cautery/alien, - /obj/item/circuitboard/machine/abductor, - /obj/item/circular_saw/alien, - /obj/item/crowbar/abductor, - /obj/item/gun/energy/alien, - /obj/item/gun/energy/shrink_ray, - /obj/item/hemostat/alien, - /obj/item/melee/baton/abductor, - /obj/item/multitool/abductor, - /obj/item/retractor/alien, - /obj/item/scalpel/alien, - /obj/item/screwdriver/abductor, - /obj/item/surgicaldrill/alien, - /obj/item/weldingtool/abductor, - /obj/item/wirecutters/abductor, - /obj/item/wrench/abductor, - ) - - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 12500) - discount_experiments = list(/datum/experiment/scanning/points/slime/hard = 10000) - hidden = TRUE - -/datum/techweb_node/alien_engi - id = "alien_engi" - display_name = "Alien Engineering" - description = "Alien engineering tools" - prereq_ids = list("alientech", "adv_engi") - - design_ids = list( - "alien_crowbar", - "alien_multitool", - "alien_screwdriver", - "alien_welder", - "alien_wirecutters", - "alien_wrench", - ) - - required_items_to_unlock = list( - /obj/item/abductor, - /obj/item/circuitboard/machine/abductor, - /obj/item/crowbar/abductor, - /obj/item/gun/energy/shrink_ray, - /obj/item/melee/baton/abductor, - /obj/item/multitool/abductor, - /obj/item/screwdriver/abductor, - /obj/item/weldingtool/abductor, - /obj/item/wirecutters/abductor, - /obj/item/wrench/abductor, - ) - - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - hidden = TRUE - -/datum/techweb_node/syndicate_basic - id = "syndicate_basic" - display_name = "Illegal Technology" - description = "Dangerous research used to create dangerous objects." - prereq_ids = list("adv_engi", "adv_weaponry", "explosive_weapons") - design_ids = list( - "advanced_camera", - "ai_cam_upgrade", - "borg_syndicate_module", - "donksoft_refill", - "donksofttoyvendor", - "largecrossbow", - "mag_autorifle", - "mag_autorifle_ap", - "mag_autorifle_ic", - "rapidsyringe", - "suppressor", - "super_pointy_tape", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000) - hidden = TRUE - -/datum/techweb_node/syndicate_basic/New() //Crappy way of making syndicate gear decon supported until there's another way. - . = ..() - if(!SSearly_assets.initialized) - RegisterSignal(SSearly_assets, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(register_uplink_items)) - else - register_uplink_items() - -/** - * This needs some clarification: The uplink_items_by_type list is populated on datum/asset/json/uplink/generate. - * SStraitor doesn't actually initialize. I'm bamboozled. - */ -/datum/techweb_node/syndicate_basic/proc/register_uplink_items() - SIGNAL_HANDLER - UnregisterSignal(SSearly_assets, COMSIG_SUBSYSTEM_POST_INITIALIZE) - required_items_to_unlock = list() - for(var/datum/uplink_item/item_path as anything in SStraitor.uplink_items_by_type) - var/datum/uplink_item/item = SStraitor.uplink_items_by_type[item_path] - if(!item.item || !item.illegal_tech) - continue - required_items_to_unlock |= item.item //allows deconning to unlock. - - -////////////////////////B.E.P.I.S. Locked Techs//////////////////////// -/datum/techweb_node/light_apps - id = "light_apps" - display_name = "Illumination Applications" - description = "Applications of lighting and vision technology not originally thought to be commercially viable." - prereq_ids = list("base") - design_ids = list( - "bright_helmet", - "rld_mini", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - hidden = TRUE - experimental = TRUE - -/datum/techweb_node/extreme_office - id = "extreme_office" - display_name = "Advanced Office Applications" - description = "Some of our smartest lab guys got together on a Friday and improved our office efficiency by 350%. Here's how." - prereq_ids = list("base") - design_ids = list( - "mauna_mug", - "rolling_table", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - hidden = TRUE - experimental = TRUE - -/datum/techweb_node/spec_eng - id = "spec_eng" - display_name = "Specialized Engineering" - description = "Conventional wisdom has deemed these engineering products 'technically' safe, but far too dangerous to traditionally condone." - prereq_ids = list("base") - design_ids = list( - "eng_gloves", - "lava_rods", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - hidden = TRUE - experimental = TRUE - -/datum/techweb_node/aus_security - id = "aus_security" - display_name = "Australicus Security Protocols" - description = "It is said that security in the Australicus sector is tight, so we took some pointers from their equipment. Thankfully, our sector lacks any signs of these, 'dropbears'." - prereq_ids = list("base") - design_ids = list( - "pin_explorer", - "stun_boomerang", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - hidden = TRUE - experimental = TRUE - -/datum/techweb_node/interrogation - id = "interrogation" - display_name = "Enhanced Interrogation Technology" - description = "By cross-referencing several declassified documents from past dictatorial regimes, we were able to develop an incredibly effective interrogation device. \ - Ethical concerns about loss of free will do not apply to criminals, according to galactic law." - prereq_ids = list("base") - design_ids = list( - "hypnochair", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500) - hidden = TRUE - experimental = TRUE - -/datum/techweb_node/sticky_advanced - id = "sticky_advanced" - display_name = "Advanced Sticky Technology" - description = "Taking a good joke too far? Nonsense!" - design_ids = list( - "pointy_tape", - "super_sticky_tape", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - hidden = TRUE - experimental = TRUE - -/datum/techweb_node/tackle_advanced - id = "tackle_advanced" - display_name = "Advanced Grapple Technology" - description = "Nanotrasen would like to remind its researching staff that it is never acceptable to \"glomp\" your coworkers, and further \"scientific trials\" on the subject \ - will no longer be accepted in its academic journals." - design_ids = list( - "tackle_dolphin", - "tackle_rocket", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - hidden = TRUE - experimental = TRUE - -/datum/techweb_node/mod_experimental - id = "mod_experimental" - display_name = "Experimental Modular Suits" - description = "Applications of experimentality when creating MODsuits have created these..." - prereq_ids = list("base") - design_ids = list( - "mod_disposal", - "mod_joint_torsion", - "mod_recycler", - "mod_shooting", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - hidden = TRUE - experimental = TRUE - -/datum/techweb_node/mod_experimental - id = "mod_experimental" - display_name = "Experimental Modular Suits" - description = "Applications of experimentality when creating MODsuits have created these..." - prereq_ids = list("base") - design_ids = list( - "mod_disposal", - "mod_joint_torsion", - "mod_recycler", - "mod_shooting", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - hidden = TRUE - experimental = TRUE - -/datum/techweb_node/posisphere - id = "positronic_sphere" - display_name = "Experimental Spherical Positronic Brain" - description = "Recent developments on cost-cutting measures have allowed us to cut positronic brain cubes into twice-as-cheap spheres. Unfortunately, it also allows them to move around the lab via rolling maneuvers." - prereq_ids = list("base") - design_ids = list( - "posisphere", - ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - hidden = TRUE - experimental = TRUE diff --git a/code/modules/research/techweb/nodes/alien_nodes.dm b/code/modules/research/techweb/nodes/alien_nodes.dm new file mode 100644 index 0000000000000..bf19c0c54a47d --- /dev/null +++ b/code/modules/research/techweb/nodes/alien_nodes.dm @@ -0,0 +1,100 @@ +/datum/techweb_node/alientech //AYYYYYYYYLMAOO tech + id = "alientech" + display_name = "Alien Technology" + description = "Things used by the greys." + prereq_ids = list("bluespace_travel") + required_items_to_unlock = list( + /obj/item/stack/sheet/mineral/abductor, + /obj/item/abductor, + /obj/item/cautery/alien, + /obj/item/circuitboard/machine/abductor, + /obj/item/circular_saw/alien, + /obj/item/crowbar/abductor, + /obj/item/gun/energy/alien, + /obj/item/gun/energy/shrink_ray, + /obj/item/hemostat/alien, + /obj/item/melee/baton/abductor, + /obj/item/multitool/abductor, + /obj/item/retractor/alien, + /obj/item/scalpel/alien, + /obj/item/screwdriver/abductor, + /obj/item/surgicaldrill/alien, + /obj/item/weldingtool/abductor, + /obj/item/wirecutters/abductor, + /obj/item/wrench/abductor, + ) + design_ids = list( + "alienalloy", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + hidden = TRUE + +/datum/techweb_node/alientech/on_station_research() + SSshuttle.shuttle_purchase_requirements_met[SHUTTLE_UNLOCK_ALIENTECH] = TRUE + +/datum/techweb_node/alien_engi + id = "alien_engi" + display_name = "Alien Engineering" + description = "Alien engineering tools" + prereq_ids = list("alientech", "exp_tools") + design_ids = list( + "alien_crowbar", + "alien_multitool", + "alien_screwdriver", + "alien_welder", + "alien_wirecutters", + "alien_wrench", + ) + required_items_to_unlock = list( + /obj/item/abductor, + /obj/item/circuitboard/machine/abductor, + /obj/item/crowbar/abductor, + /obj/item/gun/energy/shrink_ray, + /obj/item/melee/baton/abductor, + /obj/item/multitool/abductor, + /obj/item/screwdriver/abductor, + /obj/item/weldingtool/abductor, + /obj/item/wirecutters/abductor, + /obj/item/wrench/abductor, + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + hidden = TRUE + +/datum/techweb_node/alien_surgery + id = "alien_surgery" + display_name = "Alien Surgery" + description = "Abductors did nothing wrong." + prereq_ids = list("alientech", "surgery_tools") + design_ids = list( + "alien_cautery", + "alien_drill", + "alien_hemostat", + "alien_retractor", + "alien_saw", + "alien_scalpel", + "surgery_brainwashing", + "surgery_heal_combo_upgrade_femto", + "surgery_zombie", + ) + required_items_to_unlock = list( + /obj/item/abductor, + /obj/item/cautery/alien, + /obj/item/circuitboard/machine/abductor, + /obj/item/circular_saw/alien, + /obj/item/crowbar/abductor, + /obj/item/gun/energy/alien, + /obj/item/gun/energy/shrink_ray, + /obj/item/hemostat/alien, + /obj/item/melee/baton/abductor, + /obj/item/multitool/abductor, + /obj/item/retractor/alien, + /obj/item/scalpel/alien, + /obj/item/screwdriver/abductor, + /obj/item/surgicaldrill/alien, + /obj/item/weldingtool/abductor, + /obj/item/wirecutters/abductor, + /obj/item/wrench/abductor, + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS) + discount_experiments = list(/datum/experiment/scanning/points/slime/hard = TECHWEB_TIER_5_POINTS) + hidden = TRUE diff --git a/code/modules/research/techweb/nodes/atmos_nodes.dm b/code/modules/research/techweb/nodes/atmos_nodes.dm new file mode 100644 index 0000000000000..b97538070beba --- /dev/null +++ b/code/modules/research/techweb/nodes/atmos_nodes.dm @@ -0,0 +1,114 @@ +/datum/techweb_node/atmos + id = "atmos" + starting_node = TRUE + display_name = "Atmospherics" + description = "Maintaining station air and related life support systems." + design_ids = list( + "atmos_control", + "atmosalerts", + "thermomachine", + "space_heater", + "generic_tank", + "oxygen_tank", + "plasma_tank", + "plasmaman_tank_belt", + "plasmarefiller", + "extinguisher", + "gas_filter", + "plasmaman_gas_filter", + "analyzer", + "pipe_painter", + ) + +/datum/techweb_node/gas_compression + id = "gas_compression" + display_name = "Gas Compression" + description = "Highly pressurized gases hold potential for unlocking immense energy capabilities." + prereq_ids = list("atmos") + design_ids = list( + "tank_compressor", + "emergency_oxygen", + "emergency_oxygen_engi", + "power_turbine_console", + "turbine_part_compressor", + "turbine_part_rotor", + "turbine_part_stator", + "turbine_compressor", + "turbine_rotor", + "turbine_stator", + "atmos_thermal", + "pneumatic_seal", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/plasma_control + id = "plasma_control" + display_name = "Controlled Plasma" + description = "Experiments with high-pressure gases and electricity resulting in crystallization and controlled plasma reactions." + prereq_ids = list("gas_compression", "energy_manipulation") + design_ids = list( + "crystallizer", + "electrolyzer", + "pacman", + "mech_generator", + "plasmacutter", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + required_experiments = list(/datum/experiment/ordnance/gaseous/plasma) + +/datum/techweb_node/fusion + id = "fusion" + display_name = "Fusion" + description = "Investigating fusion reactor technology to achieve sustainable and efficient energy production through controlled plasma reactions involving noble gases." + prereq_ids = list("plasma_control") + design_ids = list( + "HFR_core", + "HFR_corner", + "HFR_fuel_input", + "HFR_interface", + "HFR_moderator_input", + "HFR_waste_output", + "bolter_wrench", + "rpd_loaded", + "engine_goggles", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + required_experiments = list(/datum/experiment/ordnance/gaseous/bz) + discount_experiments = list(/datum/experiment/ordnance/gaseous/nitrous_oxide = TECHWEB_TIER_3_POINTS) + +/datum/techweb_node/exp_tools + id = "exp_tools" + display_name = "Experimental Tools" + description = "Enhances the functionality and versatility of station tools." + prereq_ids = list("fusion") + design_ids = list( + "flatpacker", + "handdrill", + "exwelder", + "jawsoflife", + "rangedanalyzer", + "rtd_loaded", + "rcd_loaded", + "rcd_ammo", + "weldingmask", + "magboots", + "adv_fire_extinguisher", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) + discount_experiments = list(/datum/experiment/ordnance/gaseous/noblium = TECHWEB_TIER_4_POINTS) + +/datum/techweb_node/rcd_upgrade + id = "rcd_upgrade" + display_name = "Rapid Device Upgrade Designs" + description = "New designs and enhancements for RCD and RPD." + prereq_ids = list("exp_tools", "parts_bluespace") + design_ids = list( + "rcd_upgrade_silo_link", + "rcd_upgrade_anti_interrupt", + "rcd_upgrade_cooling", + "rcd_upgrade_frames", + "rcd_upgrade_furnishing", + "rcd_upgrade_simple_circuits", + "rpd_upgrade_unwrench", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS) diff --git a/code/modules/research/techweb/nodes/bepis_nodes.dm b/code/modules/research/techweb/nodes/bepis_nodes.dm new file mode 100644 index 0000000000000..c051aab526f81 --- /dev/null +++ b/code/modules/research/techweb/nodes/bepis_nodes.dm @@ -0,0 +1,123 @@ +/datum/techweb_node/light_apps + id = "light_apps" + display_name = "Illumination Applications" + description = "Applications of lighting and vision technology not originally thought to be commercially viable." + design_ids = list( + "bright_helmet", + "rld_mini", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + hidden = TRUE + experimental = TRUE + +/datum/techweb_node/extreme_office + id = "extreme_office" + display_name = "Advanced Office Applications" + description = "Some of our smartest lab guys got together on a Friday and improved our office efficiency by 350%. Here's how." + design_ids = list( + "mauna_mug", + "rolling_table", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + hidden = TRUE + experimental = TRUE + +/datum/techweb_node/spec_eng + id = "spec_eng" + display_name = "Specialized Engineering" + description = "Conventional wisdom has deemed these engineering products 'technically' safe, but far too dangerous to traditionally condone." + design_ids = list( + "eng_gloves", + "lava_rods", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + hidden = TRUE + experimental = TRUE + +/datum/techweb_node/aus_security + id = "aus_security" + display_name = "Australicus Security Protocols" + description = "It is said that security in the Australicus sector is tight, so we took some pointers from their equipment. Thankfully, our sector lacks any signs of these, 'dropbears'." + design_ids = list( + "pin_explorer", + "stun_boomerang", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + hidden = TRUE + experimental = TRUE + +/datum/techweb_node/interrogation + id = "interrogation" + display_name = "Enhanced Interrogation Technology" + description = "By cross-referencing several declassified documents from past dictatorial regimes, we were able to develop an incredibly effective interrogation device. \ + Ethical concerns about loss of free will do not apply to criminals, according to galactic law." + design_ids = list( + "hypnochair", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + hidden = TRUE + experimental = TRUE + +/datum/techweb_node/sticky_advanced + id = "sticky_advanced" + display_name = "Advanced Sticky Technology" + description = "Taking a good joke too far? Nonsense!" + design_ids = list( + "pointy_tape", + "super_sticky_tape", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + hidden = TRUE + experimental = TRUE + +/datum/techweb_node/tackle_advanced + id = "tackle_advanced" + display_name = "Advanced Grapple Technology" + description = "Nanotrasen would like to remind its researching staff that it is never acceptable to \"glomp\" your coworkers, and further \"scientific trials\" on the subject \ + will no longer be accepted in its academic journals." + design_ids = list( + "tackle_dolphin", + "tackle_rocket", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + hidden = TRUE + experimental = TRUE + +/datum/techweb_node/mod_experimental + id = "mod_experimental" + display_name = "Experimental Modular Suits" + description = "Applications of experimentality when creating MODsuits have created these..." + design_ids = list( + "mod_disposal", + "mod_joint_torsion", + "mod_recycler", + "mod_shooting", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + hidden = TRUE + experimental = TRUE + +/datum/techweb_node/mod_experimental + id = "mod_experimental" + display_name = "Experimental Modular Suits" + description = "Applications of experimentality when creating MODsuits have created these..." + design_ids = list( + "mod_disposal", + "mod_joint_torsion", + "mod_recycler", + "mod_shooting", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + hidden = TRUE + experimental = TRUE + +/datum/techweb_node/posisphere + id = "positronic_sphere" + display_name = "Experimental Spherical Positronic Brain" + description = "Recent developments on cost-cutting measures have allowed us to cut positronic brain cubes into twice-as-cheap spheres. Unfortunately, it also allows them to move around the lab via rolling maneuvers." + design_ids = list( + "posisphere", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + hidden = TRUE + experimental = TRUE diff --git a/code/modules/research/techweb/nodes/biology_nodes.dm b/code/modules/research/techweb/nodes/biology_nodes.dm new file mode 100644 index 0000000000000..4adc78691835a --- /dev/null +++ b/code/modules/research/techweb/nodes/biology_nodes.dm @@ -0,0 +1,64 @@ +/datum/techweb_node/bio_scan + id = "bio_scan" + display_name = "Biological Scan" + description = "Advanced technology for analyzing patient health and reagent compositions, ensuring precise diagnostics and treatment in the medical bay." + prereq_ids = list("medbay_equip") + design_ids = list( + "healthanalyzer", + "autopsyscanner", + "genescanner", + "medical_kiosk", + "chem_master", + "ph_meter", + "scigoggles", + "mod_reagent_scanner", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/cytology + id = "cytology" + display_name = "Cytology" + description = "Cellular biology research focused on cultivation of limbs and diverse organisms from cells." + prereq_ids = list("bio_scan") + design_ids = list( + "limbgrower", + "pandemic", + "petri_dish", + "swab", + "biopsy_tool", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/xenobiology + id = "xenobiology" + display_name = "Xenobiology" + description = "Exploration of non-human biology, unlocking the secrets of extraterrestrial lifeforms and their unique biological processes." + prereq_ids = list("cytology") + design_ids = list( + "xenobioconsole", + "slime_scanner", + "limbdesign_ethereal", + "limbdesign_felinid", + "limbdesign_lizard", + "limbdesign_plasmaman", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + required_experiments = list(/datum/experiment/scanning/random/cytology) + +/datum/techweb_node/gene_engineering + id = "gene_engineering" + display_name = "Gene Engineering" + description = "Research into sophisticated DNA manipulation techniques, enabling the modification of human genetic traits to unlock specific abilities and enhancements." + prereq_ids = list("selection", "xenobiology") + design_ids = list( + "dnascanner", + "scan_console", + "dna_disk", + "dnainfuser", + "mod_dna_lock", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) + discount_experiments = list( + /datum/experiment/scanning/random/plants/traits = TECHWEB_TIER_2_POINTS, + /datum/experiment/scanning/points/slime/hard = TECHWEB_TIER_2_POINTS, + ) diff --git a/code/modules/research/techweb/nodes/circuit_nodes.dm b/code/modules/research/techweb/nodes/circuit_nodes.dm new file mode 100644 index 0000000000000..81f6dad275f0d --- /dev/null +++ b/code/modules/research/techweb/nodes/circuit_nodes.dm @@ -0,0 +1,151 @@ +/datum/techweb_node/programming + id = "programming" + starting_node = TRUE + display_name = "Programming" + description = "Dedicate an entire shift to program a fridge to greet you when opened." + prereq_ids = list("robotics") + design_ids = list( + "component_printer", + "module_duplicator", + "circuit_multitool", + "compact_remote_shell", + "usb_cable", + "integrated_circuit", + "comp_access_checker", + "comp_arctan2", + "comp_arithmetic", + "comp_assoc_list_pick", + "comp_assoc_list_remove", + "comp_assoc_list_set", + "comp_binary_convert", + "comp_clock", + "comp_comparison", + "comp_concat", + "comp_concat_list", + "comp_decimal_convert", + "comp_delay", + "comp_direction", + "comp_element_find", + "comp_filter_list", + "comp_foreach", + "comp_format", + "comp_format_assoc", + "comp_get_column", + "comp_gps", + "comp_health", + "comp_health_state", + "comp_hear", + "comp_id_access_reader", + "comp_id_getter", + "comp_id_info_reader", + "comp_index", + "comp_index_assoc", + "comp_index_table", + "comp_laserpointer", + "comp_length", + "comp_light", + "comp_list_add", + "comp_list_assoc_literal", + "comp_list_clear", + "comp_list_literal", + "comp_list_pick", + "comp_list_remove", + "comp_logic", + "comp_matscanner", + "comp_mmi", + "comp_module", + "comp_multiplexer", + "comp_not", + "comp_ntnet_receive", + "comp_ntnet_send", + "comp_ntnet_send_list_literal", + "comp_pinpointer", + "comp_pressuresensor", + "comp_radio", + "comp_random", + "comp_reagents", + "comp_router", + "comp_select_query", + "comp_self", + "comp_set_variable_trigger", + "comp_soundemitter", + "comp_species", + "comp_speech", + "comp_speech", + "comp_split", + "comp_string_contains", + "comp_tempsensor", + "comp_textcase", + "comp_timepiece", + "comp_toggle", + "comp_tonumber", + "comp_tostring", + "comp_trigonometry", + "comp_typecast", + "comp_typecheck", + "comp_view_sensor", + ) + +/datum/techweb_node/circuit_shells + id = "circuit_shells" + display_name = "Advanced Circuit Shells" + description = "Adding brains to more things." + prereq_ids = list("programming") + design_ids = list( + "assembly_shell", + "bot_shell", + "controller_shell", + "dispenser_shell", + "door_shell", + "gun_shell", + "keyboard_shell", + "module_shell", + "money_bot_shell", + "scanner_gate_shell", + "scanner_shell", + "comp_equip_action", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/bci + id = "bci" + display_name = "Brain-Computer Interface" + description = "Embedded brain circuits. May occasionally stream Nanotrasen ads in dreams." + prereq_ids = list("circuit_shells", "passive_implants") + design_ids = list( + "bci_implanter", + "bci_shell", + "comp_bar_overlay", + "comp_camera_bci", + "comp_counter_overlay", + "comp_install_detector", + "comp_object_overlay", + "comp_reagent_injector", + "comp_target_intercept", + "comp_thought_listener", + "comp_vox", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + discount_experiments = list(/datum/experiment/scanning/people/skillchip = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/programmed_robot + id = "programmed_robot" + display_name = "Programmed Robot" + description = "Grants access to movable shells, allowing for remote operations and pranks." + prereq_ids = list("circuit_shells") + design_ids = list( + "drone_shell", + "comp_pathfind", + "comp_pull", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/programmed_server + id = "programmed_server" + display_name = "Programmed Server" + description = "Grants access to a server shell that has a very high capacity for components." + prereq_ids = list("bci") + design_ids = list( + "server_shell", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) diff --git a/code/modules/research/techweb/nodes/cyborg_nodes.dm b/code/modules/research/techweb/nodes/cyborg_nodes.dm new file mode 100644 index 0000000000000..a4e0debd6ebb8 --- /dev/null +++ b/code/modules/research/techweb/nodes/cyborg_nodes.dm @@ -0,0 +1,231 @@ +/datum/techweb_node/augmentation + id = "augmentation" + starting_node = TRUE + display_name = "Augmentation" + description = "For those who prefer shiny metal over squishy flesh." + prereq_ids = list("robotics") + design_ids = list( + "borg_chest", + "borg_head", + "borg_l_arm", + "borg_l_leg", + "borg_r_arm", + "borg_r_leg", + "cybernetic_eyes", + "cybernetic_eyes_moth", + "cybernetic_ears", + "cybernetic_lungs", + "cybernetic_stomach", + "cybernetic_liver", + "cybernetic_heart", + ) + +/datum/techweb_node/cybernetics + id = "cybernetics" + display_name = "Cybernetics" + description = "Sapient robots with preloaded tool modules and programmable laws." + prereq_ids = list("augmentation") + design_ids = list( + "robocontrol", + "borgupload", + "cyborgrecharger", + "borg_suit", + "mmi_posi", + "mmi", + "mmi_m", + "advanced_l_arm", + "advanced_r_arm", + "advanced_l_leg", + "advanced_r_leg", + "borg_upgrade_rename", + "borg_upgrade_restart", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/borg_service + id = "borg_service" + display_name = "Service Cyborg Upgrades" + description = "Let them do the cookin' by the book." + prereq_ids = list("cybernetics") + design_ids = list( + "borg_upgrade_rolling_table", + "borg_upgrade_condiment_synthesizer", + "borg_upgrade_silicon_knife", + "borg_upgrade_service_apparatus", + "borg_upgrade_drink_apparatus", + "borg_upgrade_service_cookbook", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/borg_mining + id = "borg_mining" + display_name = "Mining Cyborg Upgrades" + description = "To mine places too dangerous for humans." + prereq_ids = list("cybernetics") + design_ids = list( + "borg_upgrade_lavaproof", + "borg_upgrade_holding", + "borg_upgrade_diamonddrill", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/borg_medical + id = "borg_medical" + display_name = "Medical Cyborg Upgrades" + description = "Let them follow Asimov's First Law." + prereq_ids = list("borg_service", "surgery_adv") + design_ids = list( + "borg_upgrade_pinpointer", + "borg_upgrade_beakerapp", + "borg_upgrade_defibrillator", + "borg_upgrade_expandedsynthesiser", + "borg_upgrade_piercinghypospray", + "borg_upgrade_surgicalprocessor", + "borg_upgrade_surgicalomnitool", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + +/datum/techweb_node/borg_utility + id = "borg_utility" + display_name = "Untility Cyborg Upgrades" + description = "Let them wipe our floors for us." + prereq_ids = list("borg_service", "sanitation") + design_ids = list( + "borg_upgrade_advancedmop", + "borg_upgrade_broomer", + "borg_upgrade_expand", + "borg_upgrade_prt", + "borg_upgrade_selfrepair", + "borg_upgrade_thrusters", + "borg_upgrade_trashofholding", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + +/datum/techweb_node/borg_utility/New() + . = ..() + if(!CONFIG_GET(flag/disable_secborg)) + design_ids += "borg_upgrade_disablercooler" + +/datum/techweb_node/borg_engi + id = "borg_engi" + display_name = "Engineering Cyborg Upgrades" + description = "To slack even more." + prereq_ids = list("borg_mining", "parts_upg") + design_ids = list( + "borg_upgrade_rped", + "borg_upgrade_engineeringomnitool", + "borg_upgrade_circuitapp", + "borg_upgrade_inducer", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + +// Implants root node +/datum/techweb_node/passive_implants + id = "passive_implants" + display_name = "Passive Implants" + description = "Implants designed to operate seamlessly without active user input, enhancing various physiological functions or providing continuous benefits." + prereq_ids = list("augmentation") + design_ids = list( + "skill_station", + "implant_trombone", + "implant_chem", + "implant_tracking", + "implant_exile", + "implant_beacon", + "implant_bluespace", + "implantcase", + "implanter", + "locator", + "c38_trac", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/cyber/cyber_implants + id = "cyber_implants" + display_name = "Cybernetic Implants" + description = "Advanced technological enhancements integrated into the body, offering improved physical capabilities." + prereq_ids = list("passive_implants", "cybernetics") + design_ids = list( + "ci-breather", + "ci-nutriment", + "ci-thrusters", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + +/datum/techweb_node/cyber/New() + ..() + if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION)) + research_costs[TECHWEB_POINT_TYPE_GENERIC] /= 2 + +/datum/techweb_node/cyber/combat_implants + id = "combat_implants" + display_name = "Combat Implants" + description = "To make sure that you can wake the f*** up, samurai." + prereq_ids = list("cyber_implants") + design_ids = list( + "ci-reviver", + "ci-antidrop", + "ci-antistun", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) + +/datum/techweb_node/cyber/integrated_toolsets + id = "integrated_toolsets" + display_name = "Integrated Toolsets" + description = "Decades of contraband smuggling by assistants have led to the development of a full toolbox that fits seamlessly into your arm." + prereq_ids = list("combat_implants", "exp_tools") + design_ids = list( + "ci-nutrimentplus", + "ci-toolset", + "ci-surgery", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS) + +/datum/techweb_node/cyber/cyber_organs + id = "cyber_organs" + display_name = "Cybernetic Organs" + description = "We have the technology to rebuild him." + prereq_ids = list("cybernetics") + design_ids = list( + "cybernetic_eyes_improved", + "cybernetic_eyes_improved_moth", + "cybernetic_ears_u", + "cybernetic_lungs_tier2", + "cybernetic_stomach_tier2", + "cybernetic_liver_tier2", + "cybernetic_heart_tier2", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/cyber/cyber_organs_upgraded + id = "cyber_organs_upgraded" + display_name = "Upgraded Cybernetic Organs" + description = "We have the technology to upgrade him." + prereq_ids = list("cyber_organs") + design_ids = list( + "ci-gloweyes", + "ci-welding", + "ci-gloweyes-moth", + "ci-welding-moth", + "cybernetic_ears_whisper", + "cybernetic_lungs_tier3", + "cybernetic_stomach_tier3", + "cybernetic_liver_tier3", + "cybernetic_heart_tier3", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) + required_experiments = list(/datum/experiment/scanning/people/augmented_organs) + +/datum/techweb_node/cyber/cyber_organs_adv + id = "cyber_organs_adv" + display_name = "Advanced Cybernetic Organs" + description = "Cutting-edge cybernetic organs offering enhanced sensory capabilities, making it easier than ever to detect ERP." + prereq_ids = list("cyber_organs_upgraded", "night_vision") + design_ids = list( + "cybernetic_ears_xray", + "ci-thermals", + "ci-xray", + "ci-thermals-moth", + "ci-xray-moth", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS) diff --git a/code/modules/research/techweb/nodes/engi_nodes.dm b/code/modules/research/techweb/nodes/engi_nodes.dm new file mode 100644 index 0000000000000..182f689c372cd --- /dev/null +++ b/code/modules/research/techweb/nodes/engi_nodes.dm @@ -0,0 +1,232 @@ +// Parts root node +/datum/techweb_node/parts + id = "parts" + starting_node = TRUE + display_name = "Essential Stock Parts" + description = "Foundational components that form the backbone of station operations, encompassing a range of essential equipment necessary for day-to-day functionality." + design_ids = list( + "micro_servo", + "basic_capacitor", + "basic_matter_bin", + "basic_micro_laser", + "basic_scanning", + "high_cell", + "basic_cell", + "miniature_power_cell", + "condenser", + "igniter", + "infrared_emitter", + "prox_sensor", + "signaler", + "timer", + "voice_analyzer", + "health_sensor", + "sflash", + ) + +/datum/techweb_node/parts_upg + id = "parts_upg" + display_name = "Upgraded Parts" + description = "Offering enhanced capabilities beyond their basic counterparts." + prereq_ids = list("parts", "energy_manipulation") + design_ids = list( + "rped", + "high_micro_laser", + "adv_capacitor", + "nano_servo", + "adv_matter_bin", + "adv_scanning", + "super_cell", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/parts_adv + id = "parts_adv" + display_name = "Advanced Parts" + description = "The most finely tuned and accurate stock parts." + prereq_ids = list("parts_upg") + design_ids = list( + "ultra_micro_laser", + "super_capacitor", + "pico_servo", + "super_matter_bin", + "phasic_scanning", + "hyper_cell", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + required_experiments = list(/datum/experiment/scanning/points/machinery_tiered_scan/tier2_any) + + +/datum/techweb_node/parts_bluespace + id = "parts_bluespace" + display_name = "Bluespace Parts" + description = "Integrating the latest in bluespace technology, these advanced components not only enhance functionality but also open up new possibilities for the station's technological capabilities." + prereq_ids = list("parts_adv", "bluespace_travel") + design_ids = list( + "bs_rped", + "quadultra_micro_laser", + "quadratic_capacitor", + "femto_servo", + "bluespace_matter_bin", + "triphasic_scanning", + "bluespace_cell", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) + discount_experiments = list(/datum/experiment/scanning/points/machinery_tiered_scan/tier3_any = TECHWEB_TIER_4_POINTS) + +/datum/techweb_node/telecomms + id = "telecomms" + display_name = "Telecommunications Technology" + description = "A comprehensive suite of machinery for station-wide communication setups, ensuring seamless connectivity and operational coordination." + prereq_ids = list("parts_bluespace") + design_ids = list( + "comm_monitor", + "comm_server", + "message_monitor", + "s_hub", + "s_messaging", + "s_server", + "s_processor", + "s_relay", + "s_bus", + "s_broadcaster", + "s_receiver", + "s_amplifier", + "s_analyzer", + "s_ansible", + "s_crystal", + "s_filter", + "s_transmitter", + "s_treatment", + "gigabeacon", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS) + +// Engineering root node +/datum/techweb_node/construction + id = "construction" + starting_node = TRUE + display_name = "Construction" + description = "Tools and essential machinery used for station maintenance and expansion." + design_ids = list( + "circuit_imprinter_offstation", + "circuit_imprinter", + "solarcontrol", + "solar_panel", + "solar_tracker", + "power_control", + "airalarm_electronics", + "airlock_board", + "firealarm_electronics", + "firelock_board", + "trapdoor_electronics", + "blast", + "tile_sprayer", + "airlock_painter", + "decal_painter", + "rwd", + "cable_coil", + "welding_helmet", + "welding_tool", + "tscanner", + "analyzer", + "multitool", + "wrench", + "crowbar", + "screwdriver", + "wirecutters", + "light_bulb", + "light_tube", + "intercom_frame", + "newscaster_frame", + "status_display_frame", + "circuit", + "circuitgreen", + "circuitred", + "tram_floor_dark", + "tram_floor_light", + "tram_controller", + "tram_display", + "crossing_signal", + "guideway_sensor", + ) + +/datum/techweb_node/energy_manipulation + id = "energy_manipulation" + display_name = "Energy Manipulation" + description = "Harnessing the raw power of lightning arcs through sophisticated energy control methods." + prereq_ids = list("construction") + design_ids = list( + "apc_control", + "powermonitor", + "smes", + "emitter", + "grounding_rod", + "tesla_coil", + "cell_charger", + "recharger", + "inducer", + "inducerengi", + "welding_goggles", + "tray_goggles", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/holographics + id = "holographics" + display_name = "Holographics" + description = "Use of holographic technology for signage and barriers." + prereq_ids = list("energy_manipulation") + design_ids = list( + "forcefield_projector", + "holosign", + "holosignsec", + "holosignengi", + "holosignatmos", + "holosignrestaurant", + "holosignbar", + "holobarrier_jani", + "holobarrier_med", + "holopad", + "vendatray", + "holodisk", + "modular_shield_generator", + "modular_shield_node", + "modular_shield_relay", + "modular_shield_charger", + "modular_shield_well", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/hud + id = "hud" + display_name = "Integrated HUDs" + description = "Initially developed for assistants to learn the nuances of different professions through augmented reality." + prereq_ids = list("holographics", "cyber_implants") + design_ids = list( + "health_hud", + "diagnostic_hud", + "security_hud", + "mod_visor_medhud", + "mod_visor_diaghud", + "mod_visor_sechud", + "ci-medhud", + "ci-diaghud", + "ci-sechud", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + +/datum/techweb_node/night_vision + id = "night_vision" + display_name = "Night Vision Technology" + description = "There are whispers that Nanotrasen pushed for this technology to extend shift durations, ensuring productivity around the clock." + prereq_ids = list("hud") + design_ids = list( + "diagnostic_hud_night", + "health_hud_night", + "night_visision_goggles", + "nvgmesons", + "nv_scigoggles", + "security_hud_night", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) diff --git a/code/modules/research/techweb/nodes/mech_nodes.dm b/code/modules/research/techweb/nodes/mech_nodes.dm new file mode 100644 index 0000000000000..4f58ed25c8955 --- /dev/null +++ b/code/modules/research/techweb/nodes/mech_nodes.dm @@ -0,0 +1,251 @@ +/datum/techweb_node/mech_assembly + id = "mech_assembly" + starting_node = TRUE + display_name = "Mech Assembly" + description = "Development of mech designed to contend with artificial gravity while transporting cargo." + prereq_ids = list("robotics") + design_ids = list( + "mechapower", + "mech_recharger", + "ripley_chassis", + "ripley_torso", + "ripley_left_arm", + "ripley_right_arm", + "ripley_left_leg", + "ripley_right_leg", + "ripley_main", + "ripley_peri", + "mech_hydraulic_clamp", + ) + +/datum/techweb_node/mech_equipment + id = "mech_equipment" + display_name = "Expedition Equipment" + description = "Specialized mech gear tailored for navigating space and celestial bodies, ensuring durability and functionality in the harshest conditions." + prereq_ids = list("mech_assembly") + design_ids = list( + "mechacontrol", + "botpad", + "botpad_remote", + "ripleyupgrade", + "mech_air_tank", + "mech_thrusters", + "mech_extinguisher", + "mecha_camera", + "mecha_tracking", + "mech_radio", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/mech_clown + id = "mech_clown" + display_name = "Funny Robots" + description = "Fueled by laughter." + prereq_ids = list("mech_assembly") + design_ids = list( + "honk_chassis", + "honk_torso", + "honk_head", + "honk_left_arm", + "honk_right_arm", + "honk_left_leg", + "honk_right_leg", + "honker_main", + "honker_peri", + "honker_targ", + "mech_banana_mortar", + "mech_honker", + "mech_mousetrap_mortar", + "mech_punching_face", + "borg_transform_clown", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/mech_medical + id = "mech_medical" + display_name = "Medical Mech" + description = "Advanced robotic unit equipped with syringe guns and healing beams, revolutionizing medical assistance in hazardous environments." + prereq_ids = list("mech_assembly", "chem_synthesis") + design_ids = list( + "odysseus_chassis", + "odysseus_torso", + "odysseus_head", + "odysseus_left_arm", + "odysseus_right_arm", + "odysseus_left_leg", + "odysseus_right_leg", + "odysseus_main", + "odysseus_peri", + "mech_medi_beam", + "mech_syringe_gun", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/mech_mining + id = "mech_mining" + display_name = "Mining Mech" + description = "Robust mech engineered to withstand lava and storms for continuous off-station mining operations." + prereq_ids = list("mech_equipment", "mining") + design_ids = list( + "clarke_chassis", + "clarke_torso", + "clarke_head", + "clarke_left_arm", + "clarke_right_arm", + "clarke_main", + "clarke_peri", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/mech_combat + id = "mech_combat" + display_name = "Combat Mechs" + description = "Modular armor upgrades and specialized equipment for security mechs." + prereq_ids = list("mech_equipment") + design_ids = list( + "mech_ccw_armor", + "mech_proj_armor", + "paddyupgrade", + "mech_hydraulic_claw", + "mech_disabler", + "mech_repair_droid", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + required_experiments = list(/datum/experiment/scanning/random/mecha_equipped_scan) + discount_experiments = list(/datum/experiment/scanning/random/mecha_damage_scan = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/mech_assault + id = "mech_assault" + display_name = "Assault Mech" + description = "Heavy battle mech boasting robust armor but sacrificing speed for enhanced durability." + prereq_ids = list("mech_combat") + design_ids = list( + "durand_armor", + "durand_chassis", + "durand_torso", + "durand_head", + "durand_left_arm", + "durand_right_arm", + "durand_left_leg", + "durand_right_leg", + "durand_main", + "durand_peri", + "durand_targ", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + +/datum/techweb_node/mech_light + id = "mech_light" + display_name = "Light Combat Mech" + description = "Agile combat mech equipped with overclocking capabilities for temporary speed boosts, prioritizing speed over durability on the battlefield." + prereq_ids = list("mech_combat") + design_ids = list( + "gygax_armor", + "gygax_chassis", + "gygax_torso", + "gygax_head", + "gygax_left_arm", + "gygax_right_arm", + "gygax_left_leg", + "gygax_right_leg", + "gygax_main", + "gygax_peri", + "gygax_targ", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + +/datum/techweb_node/mech_heavy + id = "mech_heavy" + display_name = "Heavy Mech" + description = "Advanced heavy mechanized unit with dual pilot capability, designed for robust battlefield performance and increased tactical versatility." + prereq_ids = list("mech_assault") + design_ids = list( + "savannah_ivanov_armor", + "savannah_ivanov_chassis", + "savannah_ivanov_torso", + "savannah_ivanov_head", + "savannah_ivanov_left_arm", + "savannah_ivanov_right_arm", + "savannah_ivanov_left_leg", + "savannah_ivanov_right_leg", + "savannah_ivanov_main", + "savannah_ivanov_peri", + "savannah_ivanov_targ", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) + +/datum/techweb_node/mech_infiltrator + id = "mech_infiltrator" + display_name = "Infiltration Mech" + description = "Advanced mech with phasing capabilities, allowing it to move through walls and obstacles, ideal for covert and special operations." + prereq_ids = list("mech_light", "anomaly_research") + design_ids = list( + "phazon_armor", + "phazon_chassis", + "phazon_torso", + "phazon_head", + "phazon_left_arm", + "phazon_right_arm", + "phazon_left_leg", + "phazon_right_leg", + "phazon_main", + "phazon_peri", + "phazon_targ", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) + +/datum/techweb_node/mech_energy_guns + id = "mech_energy_guns" + display_name = "Mech Energy Guns" + description = "Scaled-up versions of electric weapons optimized for mech deployment." + prereq_ids = list("mech_combat", "electric_weapons") + design_ids = list( + "mech_laser", + "mech_laser_heavy", + "mech_ion", + "mech_tesla", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) + +/datum/techweb_node/mech_firearms + id = "mech_firearms" + display_name = "Mech Firearms" + description = "Mounted ballistic weaponry, enhancing combat capabilities for mechanized units." + prereq_ids = list("mech_energy_guns", "exotic_ammo") + design_ids = list( + "mech_lmg", + "mech_lmg_ammo", + "mech_scattershot", + "mech_scattershot_ammo", + "mech_carbine", + "mech_carbine_ammo", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS) + +/datum/techweb_node/mech_heavy_arms + id = "mech_heavy_arms" + display_name = "Heavy Mech Firearms" + description = "High-impact weaponry integrated into mechs, optimized for maximum firepower." + prereq_ids = list("mech_heavy", "exotic_ammo") + design_ids = list( + "clusterbang_launcher", + "clusterbang_launcher_ammo", + "mech_grenade_launcher", + "mech_grenade_launcher_ammo", + "mech_missile_rack", + "mech_missile_rack_ammo", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS) + +/datum/techweb_node/mech_equip_bluespace + id = "mech_equip_bluespace" + display_name = "Bluespace Mech Equipment" + description = "An array of equipment empowered by bluespace, providing unmatched mobility and utility." + prereq_ids = list("mech_infiltrator", "bluespace_travel") + design_ids = list( + "mech_gravcatapult", + "mech_teleporter", + "mech_wormhole_gen", + "mech_rcd", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS) diff --git a/code/modules/research/techweb/nodes/medbay_nodes.dm b/code/modules/research/techweb/nodes/medbay_nodes.dm new file mode 100644 index 0000000000000..ce4ef103eda2d --- /dev/null +++ b/code/modules/research/techweb/nodes/medbay_nodes.dm @@ -0,0 +1,97 @@ +/datum/techweb_node/medbay_equip + id = "medbay_equip" + starting_node = TRUE + display_name = "Medbay Equipment" + description = "Essential medical tools to patch you up while medbay is still intact." + design_ids = list( + "operating", + "medicalbed", + "defibmountdefault", + "defibrillator", + "surgical_drapes", + "scalpel", + "retractor", + "hemostat", + "cautery", + "circular_saw", + "surgicaldrill", + "bonesetter", + "blood_filter", + "surgical_tape", + "penlight", + "penlight_paramedic", + "stethoscope", + "beaker", + "large_beaker", + "syringe", + "dropper", + "pillbottle", + ) + +/datum/techweb_node/chem_synthesis + id = "chem_synthesis" + display_name = "Chemical Synthesis" + description = "Synthesizing complex chemicals from electricity and thin air... Don't ask how..." + prereq_ids = list("medbay_equip") + design_ids = list( + "xlarge_beaker", + "blood_pack", + "chem_pack", + "med_spray_bottle", + "medigel", + "medipen_refiller", + "soda_dispenser", + "beer_dispenser", + "chem_dispenser", + "portable_chem_mixer", + "chem_heater", + "w-recycler", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/plumbing + id = "plumbing" + display_name = "Plumbing" + description = "Essential infrastructure for building chemical factories. To scale up the production of happy pills to an industrial level." + prereq_ids = list("chem_synthesis") + design_ids = list( + "plumbing_rcd", + "plumbing_rcd_service", + "plumbing_rcd_sci", + "plunger", + "fluid_ducts", + "meta_beaker", + "piercesyringe", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/cryostasis + id = "cryostasis" + display_name = "Cryostasis" + description = "The result of clown accidentally drinking a chemical, now repurposed for safely preserving crew members in suspended animation." + prereq_ids = list("plumbing", "plasma_control") + design_ids = list( + "cryotube", + "mech_sleeper", + "stasis", + "cryo_grenade", + "splitbeaker", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + required_experiments = list(/datum/experiment/scanning/reagent/cryostylane) + +/datum/techweb_node/medbay_equip_adv + id = "medbay_equip_adv" + display_name = "Advanced Medbay Equipment" + description = "State-of-the-art medical gear for keeping the crew in one piece — mostly." + prereq_ids = list("cryostasis") + design_ids = list( + "chem_mass_spec", + "healthanalyzer_advanced", + "mod_health_analyzer", + "crewpinpointer", + "defibrillator_compact", + "defibmount", + "medicalbed_emergency", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) diff --git a/code/modules/research/techweb/nodes/mining_nodes.dm b/code/modules/research/techweb/nodes/mining_nodes.dm new file mode 100644 index 0000000000000..e1caaf57902e2 --- /dev/null +++ b/code/modules/research/techweb/nodes/mining_nodes.dm @@ -0,0 +1,104 @@ +/datum/techweb_node/material_processing + id = "material_proc" + starting_node = TRUE + display_name = "Material Processing" + description = "Refinement and processing of alloys and ores to enhance their utility and value." + design_ids = list( + "pickaxe", + "shovel", + "conveyor_switch", + "conveyor_belt", + "mass_driver", + "recycler", + "stack_machine", + "stack_console", + "autolathe", + "rglass", + "plasmaglass", + "plasmareinforcedglass", + "plasteel", + "titaniumglass", + "plastitanium", + "plastitaniumglass", + ) + +/datum/techweb_node/mining + id = "mining" + display_name = "Mining Technology" + description = "Development of tools meant to optimize mining operations and resource extraction." + prereq_ids = list("material_proc") + design_ids = list( + "cargoexpress", + "brm", + "b_smelter", + "b_refinery", + "ore_redemption", + "mining_equipment_vendor", + "mining_scanner", + "mech_mscanner", + "superresonator", + "mech_drill", + "mod_drill", + "drill", + "mod_orebag", + "beacon", + "telesci_gps", + "mod_gps", + "mod_visor_meson", + "mesons", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/low_pressure_excavation + id = "low_pressure_excavation" + display_name = "Low-Pressure Excavation" + description = "Research of Proto-Kinetic Accelerators (PKAs), pneumatic guns renowned for their exceptional performance in low-pressure environments." + prereq_ids = list("mining", "gas_compression") + design_ids = list( + "mecha_kineticgun", + "damagemod", + "rangemod", + "cooldownmod", + "triggermod", + "hypermod", + "borg_upgrade_damagemod", + "borg_upgrade_rangemod", + "borg_upgrade_cooldownmod", + "borg_upgrade_hypermod", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/plasma_mining + id = "plasma_mining" + display_name = "Plasma Beam Mining" + description = "Engineers' plasma welders have proven highly effective in mining operations. This led to the development of a mech-mounted variant and an enhanced handheld cutter for miners." + prereq_ids = list("low_pressure_excavation", "plasma_control") + design_ids = list( + "mech_plasma_cutter", + "plasmacutter_adv", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + +/datum/techweb_node/bitrunning + id = "bitrunning" + display_name = "Bitrunning Technology" + description = "Bluespace technology has led to the development of quantum-scale computing, which unlocks the means to materialize atomic structures while executing advanced programs." + prereq_ids = list("gaming", "applied_bluespace") + design_ids = list( + "byteforge", + "quantum_console", + "netpod", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + +/datum/techweb_node/mining_adv + id = "mining_adv" + display_name = "Advanced Mining Technology" + description = "High-level mining equipment, pushing the boundaries of efficiency and effectiveness in resource extraction." + prereq_ids = list("plasma_mining") + design_ids = list( + "jackhammer", + "drill_diamond", + "mech_diamond_drill", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) diff --git a/code/modules/research/techweb/nodes/modsuit_nodes.dm b/code/modules/research/techweb/nodes/modsuit_nodes.dm new file mode 100644 index 0000000000000..a5005a66ee794 --- /dev/null +++ b/code/modules/research/techweb/nodes/modsuit_nodes.dm @@ -0,0 +1,139 @@ +/datum/techweb_node/mod_suit + id = "mod_suit" + starting_node = TRUE + display_name = "Modular Exosuit" + description = "Specialized back mounted power suits with various different modules." + prereq_ids = list("robotics") + design_ids = list( + "suit_storage_unit", + "mod_shell", + "mod_chestplate", + "mod_helmet", + "mod_gauntlets", + "mod_boots", + "mod_plating_standard", + "mod_paint_kit", + "mod_storage", + "mod_plasma", + "mod_flashlight", + ) + +/datum/techweb_node/mod_equip + id = "mod_equip" + display_name = "Modular Suit Equipment" + description = "More advanced modules, to improve modular suits." + prereq_ids = list("mod_suit") + design_ids = list( + "modlink_scryer", + "mod_clamp", + "mod_tether", + "mod_welding", + "mod_safety", + "mod_mouthhole", + "mod_longfall", + "mod_thermal_regulator", + "mod_sign_radio", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/mod_entertainment + id = "mod_entertainment" + display_name = "Entertainment Modular Suit" + description = "Powered suits for protection against low-humor environments." + prereq_ids = list("mod_suit") + design_ids = list( + "mod_plating_cosmohonk", + "mod_bikehorn", + "mod_microwave_beam", + "mod_waddle", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/mod_medical + id = "mod_medical" + display_name = "Medical Modular Suit" + description = "Medical exosuits for quick rescue purposes." + prereq_ids = list("mod_suit", "chem_synthesis") + design_ids = list( + "mod_plating_medical", + "mod_quick_carry", + "mod_injector", + "mod_organ_thrower", + "mod_patienttransport", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/mod_engi + id = "mod_engi" + display_name = "Engineering Modular Suits" + description = "Engineering suits, for powered engineers." + prereq_ids = list("mod_equip") + design_ids = list( + "mod_plating_engineering", + "mod_t_ray", + "mod_magboot", + "mod_constructor", + "mod_mister_atmos", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/mod_security + id = "mod_security" + display_name = "Security Modular Suits" + description = "Security suits for space crime handling." + prereq_ids = list("mod_equip") + design_ids = list( + "mod_plating_security", + "mod_stealth", + "mod_mag_harness", + "mod_pathfinder", + "mod_holster", + "mod_sonar", + "mod_projectile_dampener", + "mod_criminalcapture", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/mod_medical_adv + id = "mod_medical_adv" + display_name = "Field Surgery Modules" + description = "Medical exosuit equipment designed for conducting surgical operations in field conditions." + prereq_ids = list("mod_medical", "surgery_adv") + design_ids = list( + "mod_defib", + "mod_threadripper", + "mod_surgicalprocessor", + "mod_statusreadout", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + +/datum/techweb_node/mod_engi_adv + id = "mod_engi_adv" + display_name = "Advanced Engineering Modular Suit" + description = "Advanced Engineering suits, for advanced powered engineers." + prereq_ids = list("mod_engi") + design_ids = list( + "mod_plating_atmospheric", + "mod_jetpack", + "mod_rad_protection", + "mod_emp_shield", + "mod_storage_expanded", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + +/datum/techweb_node/mod_engi_adv/New() + if(HAS_TRAIT(SSstation, STATION_TRAIT_RADIOACTIVE_NEBULA)) //we'll really need the rad protection modsuit module + starting_node = TRUE + return ..() + +/datum/techweb_node/mod_anomaly + id = "mod_anomaly" + display_name = "Anomalock Modular Suit" + description = "Modules for exosuits that require anomaly cores to function." + prereq_ids = list("mod_engi_adv", "anomaly_research") + design_ids = list( + "mod_antigrav", + "mod_teleporter", + "mod_kinesis", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) diff --git a/code/modules/research/techweb/nodes/research_nodes.dm b/code/modules/research/techweb/nodes/research_nodes.dm new file mode 100644 index 0000000000000..f68086ab5abdd --- /dev/null +++ b/code/modules/research/techweb/nodes/research_nodes.dm @@ -0,0 +1,94 @@ +/datum/techweb_node/fundamental_sci + id = "fundamental_sci" + starting_node = TRUE + display_name = "Fundamental Science" + description = "Establishing the bedrock of scientific understanding, paving the way for deeper exploration and theoretical inquiry." + design_ids = list( + "rdserver", + "rdservercontrol", + "rdconsole", + "tech_disk", + "doppler_array", + "experimentor", + "destructive_analyzer", + "destructive_scanner", + "experi_scanner", + "ntnet_relay", + "laptop", + "portadrive_basic", + "portadrive_advanced", + "portadrive_super", + ) + +/datum/techweb_node/bluespace_theory + id = "bluespace_theory" + display_name = "Bluespace Theory" + description = "Basic studies into the mysterious alternate dimension known as bluespace." + prereq_ids = list("fundamental_sci") + design_ids = list( + "bluespace_crystal", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/applied_bluespace + id = "applied_bluespace" + display_name = "Applied Bluespace Research" + description = "With a heightened grasp of bluespace dynamics, sophisticated applications and technologies can be devised using data from bluespace crystal analyses." + prereq_ids = list("bluespace_theory") + design_ids = list( + "ore_silo", + "minerbag_holding", + "plumbing_receiver", + "bluespacebeaker", + "adv_watering_can", + "bluespace_coffeepot", + "bluespacesyringe", + "blutrash", + "light_replacer_blue", + "bluespacebodybag", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + required_experiments = list(/datum/experiment/scanning/points/bluespace_crystal) + +/datum/techweb_node/bluespace_travel + id = "bluespace_travel" + display_name = "Bluespace Travel" + description = "Facilitate teleportation methods based on bluespace principles to revolutionize logistical efficiency." + prereq_ids = list("applied_bluespace") + design_ids = list( + "teleconsole", + "tele_station", + "tele_hub", + "launchpad_console", + "quantumpad", + "launchpad", + "bluespace_pod", + "quantum_keycard", + "swapper", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + +/datum/techweb_node/anomaly_research + id = "anomaly_research" + display_name = "Anomaly Research" + description = "Delving into the study of mysterious anomalies to investigate methods to refine and harness their unpredictable energies." + prereq_ids = list("applied_bluespace") + design_ids = list( + "anomaly_refinery", + "anomaly_neutralizer", + "reactive_armour", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + +/datum/techweb_node/anomaly_shells + id = "anomaly_shells" + display_name = "Advanced Anomaly Shells" + description = "New shells designed to utilize anomaly cores, maximizing their potential in innovative ways." + prereq_ids = list("anomaly_research") + design_ids = list( + "bag_holding", + "wormholeprojector", + "gravitygun", + "polymorph_belt" + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) diff --git a/code/modules/research/techweb/nodes/robo_nodes.dm b/code/modules/research/techweb/nodes/robo_nodes.dm new file mode 100644 index 0000000000000..556fa560daf6b --- /dev/null +++ b/code/modules/research/techweb/nodes/robo_nodes.dm @@ -0,0 +1,97 @@ +/datum/techweb_node/robotics + id = "robotics" + starting_node = TRUE + display_name = "Robotics" + description = "Programmable machines that make our lives lazier." + design_ids = list( + "mechfab", + "botnavbeacon", + "paicard", + ) + +/datum/techweb_node/exodrone + id = "exodrone" + display_name = "Exploration Drones" + description = "Adapted arcade machines to covertly harness gamers' skills in controlling real drones for practical purposes." + prereq_ids = list("robotics") + design_ids = list( + "exoscanner_console", + "exoscanner", + "exodrone_console", + "exodrone_launcher", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +// AI root node +/datum/techweb_node/ai + id = "ai" + display_name = "Artificial Intelligence" + description = "Exploration of AI systems, more intelligent than the entire crew put together." + prereq_ids = list("robotics") + design_ids = list( + "aiupload", + "aifixer", + "intellicard", + "mecha_tracking_ai_control", + "borg_ai_control", + "aicore", + "reset_module", + "asimov_module", + "default_module", + "nutimov_module", + "paladin_module", + "robocop_module", + "corporate_module", + "drone_module", + "oxygen_module", + "safeguard_module", + "protectstation_module", + "quarantine_module", + "freeform_module", + "remove_module", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/ai/New() + . = ..() + if(HAS_TRAIT(SSstation, STATION_TRAIT_HUMAN_AI)) + design_ids -= list( + "aicore", + "borg_ai_control", + "intellicard", + "mecha_tracking_ai_control", + "aifixer", + "aiupload", + ) + else if(HAS_TRAIT(SSstation, STATION_TRAIT_UNIQUE_AI)) + research_costs[TECHWEB_POINT_TYPE_GENERIC] *= 3 + +/datum/techweb_node/ai_laws + id = "ai_laws" + display_name = "Advanced AI Laws" + description = "Delving into sophisticated AI directives, with hopes that they won't lead to humanity's extinction." + prereq_ids = list("ai") + design_ids = list( + "asimovpp_module", + "paladin_devotion_module", + "dungeon_master_module", + "painter_module", + "ten_commandments_module", + "hippocratic_module", + "maintain_module", + "liveandletlive_module", + "reporter_module", + "yesman_module", + "hulkamania_module", + "peacekeeper_module", + "overlord_module", + "tyrant_module", + "antimov_module", + "balance_module", + "thermurderdynamic_module", + "damaged_module", + "freeformcore_module", + "onehuman_module", + "purge_module", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) diff --git a/code/modules/research/techweb/nodes/security_nodes.dm b/code/modules/research/techweb/nodes/security_nodes.dm new file mode 100644 index 0000000000000..8b931fd2273e5 --- /dev/null +++ b/code/modules/research/techweb/nodes/security_nodes.dm @@ -0,0 +1,108 @@ +/datum/techweb_node/basic_arms + id = "basic_arms" + starting_node = TRUE + display_name = "Basic Arms" + description = "Ballistics can be unpredictable in space." + design_ids = list( + "toygun", + "c38_rubber", + "sec_38", + "capbox", + "foam_dart", + "sec_beanbag_slug", + "sec_dart", + "sec_Islug", + "sec_rshot", + ) + +/datum/techweb_node/sec_equip + id = "sec_equip" + display_name = "Security Equipment" + description = "All the essentials to subdue a mime." + prereq_ids = list("basic_arms") + design_ids = list( + "camera_assembly", + "secdata", + "mining", + "prisonmanage", + "rdcamera", + "seccamera", + "security_photobooth", + "photobooth", + "scanner_gate", + "turret_control", + "pepperspray", + "dragnet_beacon", + "inspector", + "evidencebag", + "handcuffs_s", + "zipties", + "seclite", + "electropack", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/riot_supression + id = "riot_supression" + display_name = "Riot Supression" + description = "When you are on the opposing side of a revolutionary movement." + prereq_ids = list("sec_equip") + design_ids = list( + "pin_testing", + "pin_loyalty", + "tele_shield", + "ballistic_shield", + "bola_energy", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/explosives + id = "explosives" + display_name = "Explosives" + description = "For once, intentional explosions." + prereq_ids = list("riot_supression") + design_ids = list( + "large_grenade", + "adv_grenade", + "pyro_grenade", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + required_experiments = list(/datum/experiment/ordnance/explosive/lowyieldbomb) + discount_experiments = list(/datum/experiment/ordnance/explosive/highyieldbomb = TECHWEB_TIER_3_POINTS) + +/datum/techweb_node/exotic_ammo + id = "exotic_ammo" + display_name = "Exotic Ammunition" + description = "Specialized bullets designed to ignite, freeze, and inflict various other effects on targets, expanding combat capabilities." + prereq_ids = list("explosives") + design_ids = list( + "c38_hotshot", + "c38_iceblox", + "techshotshell", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) + +/datum/techweb_node/electric_weapons + id = "electric_weapons" + display_name = "Electric Weaponry" + description = "Energy-based weaponry designed for both lethal and non-lethal applications." + prereq_ids = list("riot_supression") + design_ids = list( + "stunrevolver", + "ioncarbine", + "temp_gun", + "lasershell", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + +/datum/techweb_node/beam_weapons + id = "beam_weapons" + display_name = "Advanced Beam Weaponry" + description = "So advanced, even engineers are baffled by its operational principles." + prereq_ids = list("electric_weapons") + design_ids = list( + "beamrifle", + "xray_laser", + "nuclear_gun", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) diff --git a/code/modules/research/techweb/nodes/service_nodes.dm b/code/modules/research/techweb/nodes/service_nodes.dm new file mode 100644 index 0000000000000..ff56afc115eb5 --- /dev/null +++ b/code/modules/research/techweb/nodes/service_nodes.dm @@ -0,0 +1,236 @@ +/datum/techweb_node/office_equip + id = "office_equip" + starting_node = TRUE + display_name = "Office Equipment" + description = "Nanotrasen's finest in ergonomic office tech, ensuring station admin stays productive and compliant with corporate policies — because even in space, paperwork never stops." + design_ids = list( + "fax", + "sec_pen", + "handlabel", + "roll", + "universal_scanner", + "desttagger", + "packagewrap", + "sticky_tape", + "toner_large", + "toner", + "boxcutter", + "bounced_radio", + "radio_headset", + "earmuffs", + "recorder", + "tape", + "toy_balloon", + "pet_carrier", + "chisel", + "spraycan", + "camera_film", + "camera", + "razor", + "bucket", + "mop", + "pushbroom", + "normtrash", + "wirebrush", + "flashlight", + ) + +/datum/techweb_node/sanitation + id = "sanitation" + display_name = "Advanced Sanitation Technology" + description = "Nanotrasen's latest in janitorial tech, making sure the station stays spotless and bear-free." + prereq_ids = list("office_equip") + design_ids = list( + "advmop", + "light_replacer", + "spraybottle", + "paint_remover", + "beartrap", + "buffer", + "vacuum", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + discount_experiments = list(/datum/experiment/scanning/random/janitor_trash = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/toys + id = "toys" + display_name = "New Toys" + description = "For new pranks." + prereq_ids = list("office_equip") + design_ids = list( + "smoke_machine", + "toy_armblade", + "air_horn", + "clown_firing_pin", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/consoles + id = "consoles" + display_name = "Civilian Consoles" + description = "User-friendly consoles for non-technical crew members, enhancing communication and access to essential station information." + prereq_ids = list("office_equip") + design_ids = list( + "comconsole", + "automated_announcement", + "cargo", + "cargorequest", + "med_data", + "crewconsole", + "bankmachine", + "account_console", + "idcard", + "c-reader", + "libraryconsole", + "barcode_scanner", + "vendor", + "custom_vendor_refill", + "bounty_pad_control", + "bounty_pad", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/gaming + id = "gaming" + display_name = "Gaming" + description = "For the slackers on the station." + prereq_ids = list("toys", "consoles") + design_ids = list( + "arcade_battle", + "arcade_orion", + "slotmachine", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + discount_experiments = list(/datum/experiment/physical/arcade_winner = TECHWEB_TIER_2_POINTS) + +// Kitchen root node +/datum/techweb_node/cafeteria_equip + id = "cafeteria_equip" + starting_node = TRUE + display_name = "Cafeteria Equipment" + description = "When standard-issue tubed food no longer satisfies the station crew's appetite..." + design_ids = list( + "griddle", + "microwave", + "bowl", + "plate", + "oven_tray", + "servingtray", + "tongs", + "spoon", + "fork", + "kitchen_knife", + "plastic_spoon", + "plastic_fork", + "plastic_knife", + "shaker", + "drinking_glass", + "shot_glass", + "coffee_cartridge", + "coffeemaker", + "coffeepot", + "syrup_bottle", + ) + +/datum/techweb_node/food_proc + id = "food_proc" + display_name = "Food Processing" + description = "Top-tier kitchen appliances from Nanotrasen, designed to keep the crew well-fed and happy." + prereq_ids = list("cafeteria_equip") + design_ids = list( + "deepfryer", + "oven", + "stove", + "range", + "souppot", + "processor", + "gibber", + "monkey_recycler", + "reagentgrinder", + "microwave_engineering", + "smartfridge", + "sheetifier", + "fat_sucker", + "dish_drive", + "roastingstick", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +// Fishing root node +/datum/techweb_node/fishing_equip + id = "fishing_equip" + starting_node = TRUE + display_name = "Fishing Equipment" + description = "Basic fishing gear tailored for space station environments, perfect for extraterrestrial aquatic pursuits." + design_ids = list( + "fishing_portal_generator", + "fishing_rod", + "fish_case", + ) + +/datum/techweb_node/fishing_equip_adv + id = "fishing_equip_adv" + display_name = "Advanced Fishing Tools" + description = "Continuing advancements in fishing technology, incorporating cutting-edge features in space fishing operations. Just don't try this on space carps..." + prereq_ids = list("fishing_equip") + design_ids = list( + "fishing_rod_tech", + "stabilized_hook", + "auto_reel", + "fish_analyzer", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + required_experiments = list(/datum/experiment/scanning/fish) + +/datum/techweb_node/marine_util + id = "marine_util" + display_name = "Marine Utility" + description = "Fish are nice to look at and all, but they can be put to use." + prereq_ids = list("fishing_equip_adv") + design_ids = list( + "bioelec_gen", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + // only available if you've done the first fishing experiment (thus unlocking fishing tech), but not a strict requirement to get the tech + discount_experiments = list(/datum/experiment/scanning/fish/second = TECHWEB_TIER_3_POINTS) + +// Botany root node +/datum/techweb_node/botany_equip + id = "botany_equip" + starting_node = TRUE + display_name = "Botany Equipment" + description = "Essential tools for maintaining onboard gardens, supporting plant growth in the unique environment of the space station." + design_ids = list( + "seed_extractor", + "plant_analyzer", + "watering_can", + "spade", + "cultivator", + "secateurs", + "hatchet", + ) + +/datum/techweb_node/hydroponics + id = "hydroponics" + display_name = "Hydroponics" + description = "Research into advanced hydroponic systems for efficient and sustainable plant cultivation." + prereq_ids = list("botany_equip", "chem_synthesis") + design_ids = list( + "biogenerator", + "hydro_tray", + "portaseeder", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + +/datum/techweb_node/selection + id = "selection" + display_name = "Artificial Selection" + description = "Advancement in plant cultivation techniques through artificial selection, enabling precise manipulation of plant DNA." + prereq_ids = list("hydroponics") + design_ids = list( + "flora_gun", + "gene_shears", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + required_experiments = list(/datum/experiment/scanning/random/plants/wild) + discount_experiments = list(/datum/experiment/scanning/random/plants/traits = TECHWEB_TIER_3_POINTS) diff --git a/code/modules/research/techweb/nodes/surgery_nodes.dm b/code/modules/research/techweb/nodes/surgery_nodes.dm new file mode 100644 index 0000000000000..3cd3d373c0599 --- /dev/null +++ b/code/modules/research/techweb/nodes/surgery_nodes.dm @@ -0,0 +1,72 @@ +/datum/techweb_node/oldstation_surgery + id = "oldstation_surgery" + display_name = "Experimental Dissection" + description = "Grants access to experimental dissections, which allows generation of research points." + prereq_ids = list("medbay_equip") + design_ids = list( + "surgery_oldstation_dissection", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + hidden = TRUE + show_on_wiki = FALSE + +/datum/techweb_node/surgery + id = "surgery" + display_name = "Improved Wound-Tending" + description = "Who would have known being more gentle with a hemostat decreases patient pain?" + prereq_ids = list("medbay_equip") + design_ids = list( + "surgery_heal_brute_upgrade", + "surgery_heal_burn_upgrade", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/surgery_adv + id = "surgery_adv" + display_name = "Advanced Surgery" + description = "When simple medicine doesn't cut it." + prereq_ids = list("surgery") + design_ids = list( + "harvester", + "surgery_heal_brute_upgrade_femto", + "surgery_heal_burn_upgrade_femto", + "surgery_heal_combo", + "surgery_lobotomy", + "surgery_wing_reconstruction", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + required_experiments = list(/datum/experiment/autopsy/human) + +/datum/techweb_node/surgery_exp + id = "surgery_exp" + display_name = "Experimental Surgery" + description = "When evolution isn't fast enough." + prereq_ids = list("surgery_adv") + design_ids = list( + "surgery_cortex_folding", + "surgery_cortex_imprint", + "surgery_heal_combo_upgrade", + "surgery_ligament_hook", + "surgery_ligament_reinforcement", + "surgery_muscled_veins", + "surgery_nerve_ground", + "surgery_nerve_splice", + "surgery_pacify", + "surgery_vein_thread", + "surgery_viral_bond", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) + required_experiments = list(/datum/experiment/autopsy/nonhuman) + +/datum/techweb_node/surgery_tools + id = "surgery_tools" + display_name = "Advanced Surgery Tools" + description = "Surgical instruments of dual purpose for quick operations." + prereq_ids = list("surgery_exp") + design_ids = list( + "laserscalpel", + "searingtool", + "mechanicalpinches", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS) + discount_experiments = list(/datum/experiment/autopsy/xenomorph = TECHWEB_TIER_4_POINTS) diff --git a/code/modules/research/techweb/nodes/syndicate_nodes.dm b/code/modules/research/techweb/nodes/syndicate_nodes.dm new file mode 100644 index 0000000000000..c571551877099 --- /dev/null +++ b/code/modules/research/techweb/nodes/syndicate_nodes.dm @@ -0,0 +1,48 @@ +/datum/techweb_node/syndicate_basic + id = "syndicate_basic" + display_name = "Illegal Technology" + description = "Dangerous research used to create dangerous objects." + prereq_ids = list("exp_tools", "exotic_ammo") + design_ids = list( + "advanced_camera", + "ai_cam_upgrade", + "borg_syndicate_module", + "donksoft_refill", + "donksofttoyvendor", + "largecrossbow", + "mag_autorifle", + "mag_autorifle_ap", + "mag_autorifle_ic", + "rapidsyringe", + "suppressor", + "super_pointy_tape", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS) + hidden = TRUE + +/datum/techweb_node/syndicate_basic/New() //Crappy way of making syndicate gear decon supported until there's another way. + . = ..() + if(!SSearly_assets.initialized) + RegisterSignal(SSearly_assets, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(register_uplink_items)) + else + register_uplink_items() + +/datum/techweb_node/syndicate_basic/proc/register_uplink_items() + SIGNAL_HANDLER + UnregisterSignal(SSearly_assets, COMSIG_SUBSYSTEM_POST_INITIALIZE) + required_items_to_unlock = list() + for(var/datum/uplink_item/item_path as anything in SStraitor.uplink_items_by_type) + var/datum/uplink_item/item = SStraitor.uplink_items_by_type[item_path] + if(!item.item || !item.illegal_tech) + continue + required_items_to_unlock |= item.item //allows deconning to unlock. + +/datum/techweb_node/unregulated_bluespace + id = "unregulated_bluespace" + display_name = "Unregulated Bluespace Research" + description = "Bluespace technology using unstable or unbalanced procedures, prone to damaging the fabric of bluespace. Outlawed by galactic conventions." + prereq_ids = list("parts_bluespace", "syndicate_basic") + design_ids = list( + "desynchronizer", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) diff --git a/code/modules/spells/spell_types/conjure/invisible_wall.dm b/code/modules/spells/spell_types/conjure/invisible_wall.dm index d2812912f0fc2..a61db7cf74e19 100644 --- a/code/modules/spells/spell_types/conjure/invisible_wall.dm +++ b/code/modules/spells/spell_types/conjure/invisible_wall.dm @@ -15,7 +15,7 @@ invocation_self_message = span_notice("You form a wall in front of yourself.") invocation_type = INVOCATION_EMOTE - spell_requirements = SPELL_REQUIRES_MIME_VOW + spell_requirements = SPELL_REQUIRES_HUMAN|SPELL_REQUIRES_MIME_VOW antimagic_flags = NONE spell_max_level = 1 diff --git a/code/modules/spells/spell_types/self/mime_vow.dm b/code/modules/spells/spell_types/self/mime_vow.dm index bd666786b9624..d4e34880b534d 100644 --- a/code/modules/spells/spell_types/self/mime_vow.dm +++ b/code/modules/spells/spell_types/self/mime_vow.dm @@ -8,7 +8,8 @@ panel = "Mime" school = SCHOOL_MIME - spell_requirements = NONE + //MMI mimes should be able to break their vow + spell_requirements = SPELL_CASTABLE_AS_BRAIN spell_max_level = 1 diff --git a/code/modules/spells/spell_types/touch/_touch.dm b/code/modules/spells/spell_types/touch/_touch.dm index 5045ea6522092..1ed5ce49511dd 100644 --- a/code/modules/spells/spell_types/touch/_touch.dm +++ b/code/modules/spells/spell_types/touch/_touch.dm @@ -127,7 +127,8 @@ /datum/action/cooldown/spell/touch/proc/register_hand_signals() SHOULD_CALL_PARENT(TRUE) - RegisterSignal(attached_hand, COMSIG_ITEM_AFTERATTACK, PROC_REF(on_hand_hit)) + RegisterSignal(attached_hand, COMSIG_ITEM_INTERACTING_WITH_ATOM, PROC_REF(on_hand_hit)) + RegisterSignal(attached_hand, COMSIG_ITEM_INTERACTING_WITH_ATOM_SECONDARY, PROC_REF(on_hand_hit_secondary)) RegisterSignal(attached_hand, COMSIG_ITEM_DROPPED, PROC_REF(on_hand_dropped)) RegisterSignal(attached_hand, COMSIG_QDELETING, PROC_REF(on_hand_deleted)) @@ -140,7 +141,8 @@ SHOULD_CALL_PARENT(TRUE) UnregisterSignal(attached_hand, list( - COMSIG_ITEM_AFTERATTACK, + COMSIG_ITEM_INTERACTING_WITH_ATOM, + COMSIG_ITEM_INTERACTING_WITH_ATOM_SECONDARY, COMSIG_ITEM_DROPPED, COMSIG_QDELETING, COMSIG_ITEM_OFFER_TAKEN, @@ -159,21 +161,34 @@ return ..() /** - * Signal proc for [COMSIG_ITEM_AFTERATTACK] from our attached hand. + * Signal proc for [COMSIG_ITEM_INTERACTING_WITH_ATOM] from our attached hand. * * When our hand hits an atom, we can cast do_hand_hit() on them. */ -/datum/action/cooldown/spell/touch/proc/on_hand_hit(datum/source, atom/victim, mob/caster, click_parameters) +/datum/action/cooldown/spell/touch/proc/on_hand_hit(datum/source, mob/living/caster, atom/target, click_parameters) SIGNAL_HANDLER SHOULD_NOT_OVERRIDE(TRUE) // DEFINITELY don't put effects here, put them in cast_on_hand_hit - if(!can_hit_with_hand(victim, caster)) + if(!can_hit_with_hand(target, caster)) return - if(LAZYACCESS(params2list(click_parameters), RIGHT_CLICK)) - INVOKE_ASYNC(src, PROC_REF(do_secondary_hand_hit), source, victim, caster) - else - INVOKE_ASYNC(src, PROC_REF(do_hand_hit), source, victim, caster) + INVOKE_ASYNC(src, PROC_REF(do_hand_hit), source, target, caster) + return ITEM_INTERACT_SUCCESS + +/** + * Signal proc for [COMSIG_ITEM_INTERACTING_WITH_ATOM_SECONDARY] from our attached hand. + * + * When our hand hits an atom, we can cast do_hand_hit() on them. + */ +/datum/action/cooldown/spell/touch/proc/on_hand_hit_secondary(datum/source, mob/living/caster, atom/target, click_parameters) + SIGNAL_HANDLER + SHOULD_NOT_OVERRIDE(TRUE) + + if(!can_hit_with_hand(target, caster)) + return + + INVOKE_ASYNC(src, PROC_REF(do_secondary_hand_hit), source, target, caster) + return ITEM_INTERACT_SUCCESS /// Checks if the passed victim can be cast on by the caster. /datum/action/cooldown/spell/touch/proc/can_hit_with_hand(atom/victim, mob/caster) @@ -206,6 +221,7 @@ log_combat(caster, victim, "cast the touch spell [name] on", hand) spell_feedback(caster) + caster.do_attack_animation(victim) remove_hand(caster) /** @@ -223,6 +239,7 @@ if(SECONDARY_ATTACK_CONTINUE_CHAIN) log_combat(caster, victim, "cast the touch spell [name] on", hand, "(secondary / alt cast)") spell_feedback(caster) + caster.do_attack_animation(victim) remove_hand(caster) // Call normal will call the normal cast proc diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 318926465ae08..c03a930395ab9 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -362,7 +362,7 @@ if(ishuman(victim)) var/mob/living/carbon/human/human_victim = victim - if(HAS_TRAIT(victim, TRAIT_LIMBATTACHMENT)) + if(HAS_TRAIT(victim, TRAIT_LIMBATTACHMENT) || HAS_TRAIT(src, TRAIT_EASY_ATTACH)) if(!human_victim.get_bodypart(body_zone)) user.temporarilyRemoveItemFromInventory(src, TRUE) if(!try_attach_limb(victim)) diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index e942a1b2e3aca..1fa6db17e5a54 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -234,7 +234,7 @@ qdel(owner.GetComponent(/datum/component/creamed)) //clean creampie overlay flushed emoji //Handle dental implants - for(var/datum/action/item_action/hands_free/activate_pill/pill_action in owner.actions) + for(var/datum/action/item_action/activate_pill/pill_action in owner.actions) pill_action.Remove(owner) var/obj/pill = pill_action.target if(pill) @@ -342,7 +342,7 @@ //Handle dental implants for(var/obj/item/reagent_containers/pill/pill in src) - for(var/datum/action/item_action/hands_free/activate_pill/pill_action in pill.actions) + for(var/datum/action/item_action/activate_pill/pill_action in pill.actions) pill.forceMove(new_head_owner) pill_action.Grant(new_head_owner) break diff --git a/code/modules/surgery/bodyparts/ghetto_parts.dm b/code/modules/surgery/bodyparts/ghetto_parts.dm new file mode 100644 index 0000000000000..36c0310dead76 --- /dev/null +++ b/code/modules/surgery/bodyparts/ghetto_parts.dm @@ -0,0 +1,79 @@ +/obj/item/bodypart/arm/left/ghetto + name = "left peg arm" + desc = "A roughly hewn wooden peg replaces where a forearm should be. It's simple and sturdy, clearly made in a hurry with whatever materials were at hand. Despite its crude appearance, it gets the job done." + icon = 'icons/mob/human/species/ghetto.dmi' + icon_static = 'icons/mob/human/species/ghetto.dmi' + limb_id = BODYPART_ID_PEG + icon_state = "peg_l_arm" + bodytype = BODYTYPE_PEG + should_draw_greyscale = FALSE + attack_verb_simple = list("bashed", "slashed") + unarmed_damage_low = 3 + unarmed_damage_high = 9 + unarmed_effectiveness = 5 + brute_modifier = 1.2 + burn_modifier = 1.5 + bodypart_traits = list(TRAIT_CHUNKYFINGERS) + +/obj/item/bodypart/arm/left/ghetto/Initialize(mapload, ...) + . = ..() + ADD_TRAIT(src, TRAIT_EASY_ATTACH, INNATE_TRAIT) + +/obj/item/bodypart/arm/right/ghetto + name = "right peg arm" + desc = "A roughly hewn wooden peg replaces where a forearm should be. It's simple and sturdy, clearly made in a hurry with whatever materials were at hand. Despite its crude appearance, it gets the job done." + icon = 'icons/mob/human/species/ghetto.dmi' + icon_static = 'icons/mob/human/species/ghetto.dmi' + limb_id = BODYPART_ID_PEG + icon_state = "peg_r_arm" + bodytype = BODYTYPE_PEG + should_draw_greyscale = FALSE + attack_verb_simple = list("bashed", "slashed") + unarmed_damage_low = 3 + unarmed_damage_high = 9 + unarmed_effectiveness = 5 + brute_modifier = 1.2 + burn_modifier = 1.5 + bodypart_traits = list(TRAIT_CHUNKYFINGERS) + +/obj/item/bodypart/arm/right/ghetto/Initialize(mapload, ...) + . = ..() + ADD_TRAIT(src, TRAIT_EASY_ATTACH, INNATE_TRAIT) + +/obj/item/bodypart/leg/left/ghetto + name = "left peg leg" + desc = "Fashioned from what looks suspiciously like a table leg, this peg leg brings a whole new meaning to 'dining on the go.' It's a bit wobbly and creaks ominously with every step, but at least you can claim to have the most well-balanced diet on the seven seas." + icon = 'icons/mob/human/species/ghetto.dmi' + icon_static = 'icons/mob/human/species/ghetto.dmi' + limb_id = BODYPART_ID_PEG + icon_state = "peg_l_leg" + bodytype = BODYTYPE_PEG + should_draw_greyscale = FALSE + unarmed_damage_low = 2 + unarmed_damage_high = 5 + unarmed_effectiveness = 10 + brute_modifier = 1.2 + burn_modifier = 1.5 + +/obj/item/bodypart/leg/left/ghetto/Initialize(mapload, ...) + . = ..() + ADD_TRAIT(src, TRAIT_EASY_ATTACH, INNATE_TRAIT) + +/obj/item/bodypart/leg/right/ghetto + name = "right peg leg" + desc = "Fashioned from what looks suspiciously like a table leg, this peg leg brings a whole new meaning to 'dining on the go.' It's a bit wobbly and creaks ominously with every step, but at least you can claim to have the most well-balanced diet on the seven seas." + icon = 'icons/mob/human/species/ghetto.dmi' + icon_static = 'icons/mob/human/species/ghetto.dmi' + limb_id = BODYPART_ID_PEG + icon_state = "peg_r_leg" + bodytype = BODYTYPE_PEG + should_draw_greyscale = FALSE + unarmed_damage_low = 2 + unarmed_damage_high = 5 + unarmed_effectiveness = 10 + brute_modifier = 1.2 + burn_modifier = 1.5 + +/obj/item/bodypart/leg/right/ghetto/Initialize(mapload, ...) + . = ..() + ADD_TRAIT(src, TRAIT_EASY_ATTACH, INNATE_TRAIT) diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index 03f53c962d59f..97fa50d76c85b 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -74,9 +74,11 @@ if(!ishuman(owner)) return null var/mob/living/carbon/human/human_owner = owner - var/butt_sprite = human_owner.physique == FEMALE ? BUTT_SPRITE_HUMAN_FEMALE : BUTT_SPRITE_HUMAN_MALE var/obj/item/organ/external/tail/tail = human_owner.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAIL) - return tail?.get_butt_sprite() || butt_sprite + if(tail) + return tail.get_butt_sprite() + + return icon('icons/mob/butts.dmi', human_owner.physique == FEMALE ? BUTT_SPRITE_HUMAN_FEMALE : BUTT_SPRITE_HUMAN_MALE) /obj/item/bodypart/chest/monkey icon = 'icons/mob/human/species/monkey/bodyparts.dmi' diff --git a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm index 30e91db21373a..157e5b04fe68e 100644 --- a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm @@ -11,7 +11,7 @@ wing_types = list(/obj/item/organ/external/wings/functional/dragon) /obj/item/bodypart/chest/lizard/get_butt_sprite() - return BUTT_SPRITE_LIZARD + return icon('icons/mob/butts.dmi', BUTT_SPRITE_LIZARD) /obj/item/bodypart/arm/left/lizard icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi' diff --git a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm index 2730bc362c72c..fa3ab9cc49d39 100644 --- a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm @@ -59,7 +59,7 @@ wing_types = NONE /obj/item/bodypart/chest/abductor/get_butt_sprite() - return BUTT_SPRITE_GREY + return icon('icons/mob/butts.dmi', BUTT_SPRITE_GREY) /obj/item/bodypart/arm/left/abductor limb_id = SPECIES_ABDUCTOR @@ -97,7 +97,7 @@ wing_types = list(/obj/item/organ/external/wings/functional/slime) /obj/item/bodypart/chest/jelly/get_butt_sprite() - return BUTT_SPRITE_SLIME + return icon('icons/mob/butts.dmi', BUTT_SPRITE_SLIME) /obj/item/bodypart/arm/left/jelly biological_state = (BIO_FLESH|BIO_BLOODED) @@ -216,7 +216,7 @@ wing_types = NONE /obj/item/bodypart/chest/pod/get_butt_sprite() - return BUTT_SPRITE_FLOWERPOT + return icon('icons/mob/butts.dmi', BUTT_SPRITE_FLOWERPOT) /obj/item/bodypart/arm/left/pod limb_id = SPECIES_PODPERSON diff --git a/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm index 011ee83368a63..375b37ca434d6 100644 --- a/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm @@ -17,7 +17,7 @@ wing_types = list(/obj/item/organ/external/wings/functional/moth/megamoth, /obj/item/organ/external/wings/functional/moth/mothra) /obj/item/bodypart/chest/moth/get_butt_sprite() - return BUTT_SPRITE_FUZZY + return icon('icons/mob/butts.dmi', BUTT_SPRITE_FUZZY) /obj/item/bodypart/arm/left/moth icon = 'icons/mob/human/species/moth/bodyparts.dmi' diff --git a/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm index 40bf4a51c042e..b0acf914079f3 100644 --- a/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm @@ -27,7 +27,7 @@ wing_types = NONE /obj/item/bodypart/chest/plasmaman/get_butt_sprite() - return BUTT_SPRITE_PLASMA + return icon('icons/mob/butts.dmi', BUTT_SPRITE_PLASMA) /obj/item/bodypart/arm/left/plasmaman icon = 'icons/mob/human/species/plasmaman/bodyparts.dmi' diff --git a/code/modules/surgery/dental_implant.dm b/code/modules/surgery/dental_implant.dm index 0d583d09a11b0..d720039d56b7e 100644 --- a/code/modules/surgery/dental_implant.dm +++ b/code/modules/surgery/dental_implant.dm @@ -27,7 +27,7 @@ user.transferItemToLoc(tool, target, TRUE) - var/datum/action/item_action/hands_free/activate_pill/pill_action = new(tool) + var/datum/action/item_action/activate_pill/pill_action = new(tool) pill_action.name = "Activate [tool.name]" pill_action.build_all_button_icons() pill_action.target = tool @@ -42,12 +42,21 @@ ) return ..() -/datum/action/item_action/hands_free/activate_pill +/datum/action/item_action/activate_pill name = "Activate Pill" + check_flags = NONE -/datum/action/item_action/hands_free/activate_pill/Trigger(trigger_flags) +/datum/action/item_action/activate_pill/IsAvailable(feedback) + if(owner.stat > SOFT_CRIT) + return FALSE + return ..() + +/datum/action/item_action/activate_pill/Trigger(trigger_flags) if(!..()) return FALSE + owner.balloon_alert_to_viewers("[owner] grinds their teeth!", "You grit your teeth.") + if(!do_after(owner, owner.stat * (2.5 SECONDS), owner, IGNORE_USER_LOC_CHANGE | IGNORE_INCAPACITATED)) + return FALSE var/obj/item/item_target = target to_chat(owner, span_notice("You grit your teeth and burst the implanted [item_target.name]!")) owner.log_message("swallowed an implanted pill, [target]", LOG_ATTACK) diff --git a/code/modules/surgery/organs/external/tails.dm b/code/modules/surgery/organs/external/tails.dm index 56479d0f22a10..e4cd3f50a4997 100644 --- a/code/modules/surgery/organs/external/tails.dm +++ b/code/modules/surgery/organs/external/tails.dm @@ -23,11 +23,12 @@ /obj/item/organ/external/tail/Insert(mob/living/carbon/receiver, special, movement_flags) . = ..() if(.) - original_owner ||= WEAKREF(receiver) - receiver.clear_mood_event("tail_lost") receiver.clear_mood_event("tail_balance_lost") + if(!special) // if some admin wants to give someone tail moodles for tail shenanigans, they can spawn it and do it by hand + original_owner ||= WEAKREF(receiver) + // If it's your tail, an infinite debuff is replaced with a timed one // If it's not your tail but of same species, I guess it works, but we are more sad // If it's not your tail AND of different species, we are horrified @@ -161,7 +162,7 @@ return SSaccessories.tails_list_human /obj/item/organ/external/tail/cat/get_butt_sprite() - return BUTT_SPRITE_CAT + return icon('icons/mob/butts.dmi', BUTT_SPRITE_CAT) ///Cat tail bodypart overlay /datum/bodypart_overlay/mutant/tail/cat diff --git a/code/modules/unit_tests/changeling.dm b/code/modules/unit_tests/changeling.dm index 9749d760ea91c..7f86510fd62d1 100644 --- a/code/modules/unit_tests/changeling.dm +++ b/code/modules/unit_tests/changeling.dm @@ -80,7 +80,7 @@ ling.dna.features["horns"] = "Curled" ling.dna.features["frills"] = "Short" ling.dna.features["spines"] = "Long + Membrane" - ling.dna.features["body_markings"] = "Light Belly" + ling.dna.features["lizard_markings"] = "Light Belly" ling.dna.features["legs"] = DIGITIGRADE_LEGS ling.eye_color_left = COLOR_WHITE ling.eye_color_right = COLOR_WHITE diff --git a/code/modules/unit_tests/outfit_sanity.dm b/code/modules/unit_tests/outfit_sanity.dm index 18f5e9b8e6141..554d226ed2e72 100644 --- a/code/modules/unit_tests/outfit_sanity.dm +++ b/code/modules/unit_tests/outfit_sanity.dm @@ -49,7 +49,7 @@ for (var/outfit_type in outfits_to_check) // Only make one human and keep undressing it because it's much faster - for (var/obj/item/I in H.get_equipped_items(include_pockets = TRUE)) + for (var/obj/item/I in H.get_equipped_items(INCLUDE_POCKETS)) qdel(I) var/datum/outfit/outfit = new outfit_type diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index 76d193c80e87f..ed6d085abe593 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -271,7 +271,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) */ var/max_amount = rand(CEILING(product_record.amount * 0.5, 1), product_record.amount) product_record.amount = rand(0, max_amount) - credits_contained += rand(0, 1) //randomly add a few credits to the machine to make it look like it's been used, proportional to the amount missing. + credits_contained += rand(1, 5) //randomly add a few credits to the machine to make it look like it's been used, proportional to the amount missing. if(tiltable && prob(6)) // 1 in 17 chance to start tilted (as an additional hint to the station trait behind it) INVOKE_ASYNC(src, PROC_REF(tilt), loc) credits_contained = 0 // If it's tilted, it's been looted, so no credits for you. @@ -1652,6 +1652,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) return var/credits_to_remove = min(CREDITS_DUMP_THRESHOLD, round(credits_contained)) var/obj/item/holochip/holochip = new(loc, credits_to_remove) + playsound(src, 'sound/effects/cashregister.ogg', 40, TRUE) credits_contained = max(0, credits_contained - credits_to_remove) SSblackbox.record_feedback("amount", "vending machine looted", holochip.credits) diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm index 015c3d6f7e0cb..3f82a219e56c9 100644 --- a/code/modules/vending/wardrobes.dm +++ b/code/modules/vending/wardrobes.dm @@ -1,3 +1,7 @@ +GLOBAL_VAR_INIT(roaches_deployed, FALSE) +#define MOTHROACH_START_CHANCE 5 +#define MAX_MOTHROACH_AMOUNT 3 + /obj/item/vending_refill/wardrobe icon_state = "refill_clothes" @@ -8,6 +12,29 @@ panel_type = "panel19" light_mask = "wardrobe-light-mask" +/obj/machinery/vending/wardrobe/Initialize(mapload) + . = ..() + if(!mapload) + return + if(GLOB.roaches_deployed || !is_station_level(z) || !prob(MOTHROACH_START_CHANCE)) + return + for(var/count in 1 to rand(1, MAX_MOTHROACH_AMOUNT)) + new /mob/living/basic/mothroach(src) + GLOB.roaches_deployed = TRUE + + +/obj/machinery/vending/wardrobe/on_dispense(obj/item/clothing/food) + if(!istype(food)) + return + for(var/mob/living/basic/mothroach/roach in contents) + food.take_damage(food.get_integrity() * 0.5) + +/obj/machinery/vending/wardrobe/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) + . = ..() + for(var/mob/living/basic/mothroach/roach in contents) + roach.ai_controller.set_blackboard_key(BB_BASIC_MOB_FLEE_TARGET, src) //scatter away! + roach.forceMove(drop_location()) + /obj/machinery/vending/wardrobe/sec_wardrobe name = "\improper SecDrobe" desc = "A vending machine for security and security-related clothing!" @@ -704,3 +731,6 @@ /obj/item/vending_refill/wardrobe/cent_wardrobe machine_name = "CentDrobe" light_color = LIGHT_COLOR_ELECTRIC_GREEN + +#undef MOTHROACH_START_CHANCE +#undef MAX_MOTHROACH_AMOUNT diff --git a/html/changelogs/AutoChangeLog-pr-83840.yml b/html/changelogs/AutoChangeLog-pr-83840.yml deleted file mode 100644 index 5d879aece5df2..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83840.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TheBoondock" -delete-after: True -changes: - - sound: "added compressed air sound for when air tanks are inserted into machinery" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83949.yml b/html/changelogs/AutoChangeLog-pr-83949.yml deleted file mode 100644 index 62584dcc7c0fc..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83949.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "grungussuss" -delete-after: True -changes: - - rscadd: "Added Misha the bear to the HoS office on icebox." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-84125.yml b/html/changelogs/AutoChangeLog-pr-84125.yml new file mode 100644 index 0000000000000..2109a86d39ef0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-84125.yml @@ -0,0 +1,10 @@ +author: "jlsnow301" +delete-after: True +changes: + - bugfix: "Bitrunning made more illegal: Increased the rate at which antags spawn." + - bugfix: "\"Temporary\" bitrunning antagonists and spawners are made actually temporary. You will return to your original body after death, just like CTF." + - rscadd: "Added more examine text for ghosts to bitrunning equipment." + - balance: "Server cooldown reduced by 1 minute at base level." + - rscadd: "As an observer, you can now switch views between station and virtual domain by clicking the hololadder and netpod respectively." + - rscdel: "Removed the starfront saloon BR map." + - bugfix: "Syndicate assault map: Added pistols, reduced exploits." \ No newline at end of file diff --git a/html/changelogs/archive/2024-06.yml b/html/changelogs/archive/2024-06.yml index c0da4690e635b..2b62716374ae9 100644 --- a/html/changelogs/archive/2024-06.yml +++ b/html/changelogs/archive/2024-06.yml @@ -742,3 +742,255 @@ carlarctg: - bugfix: Cosmos spells will no longer star mark your steed - qol: Baby plushies are now smaller than their parents +2024-06-17: + Hacks-The-Doors: + - balance: dental pills can now be used in crit. + - balance: dental pills now give off a message when you start using them + - balance: dental pills have a 2.5 second delay when in soft crit + JackEnoff: + - balance: Certain changeling abilities won't work while on fire. + TheBoondock: + - sound: added compressed air sound for when air tanks are inserted into machinery + grungussuss: + - rscadd: Added Misha the bear to the HoS office on icebox. +2024-06-18: + Bisar: + - balance: Replaced the free reagent purging with actually purging by exploding + someone in the blood while they have omnizine and a purgative in their bloodstream. + Let's go practice medicine! + - bugfix: Fixed the free reagent purging mechanic from causing an explosion so weak + that it doesn't cause any damage. + GPeckman: + - bugfix: Mining borgs can get multiple modkits of the same type installed again. + Goat: + - qol: fire extinguishers can now be filled via stationary tanks. (and water coolers) + GoblinBackwards: + - bugfix: Fixed mulebots being able to run over people who are leaning against a + wall. + - bugfix: Fixed anomaly cores from the high-intensity grav anomaly event creating + the wrong type of reactive armour. + Kaostico: + - bugfix: Transcendent Olfaction mutation now works properly + LucyGrind: + - bugfix: allows cigarette grinding in mortar + MTandi: + - bugfix: Non-metallic slime types are semi-transparent + - balance: Reshuffled tech tree, making nodes more specialized + - qol: Research points devided by the amount generated per second, so now research + points correspond to seconds + - rscadd: Introduced reagent purity scan experiments (required for Cryostasis node) + - rscadd: Introduced synthetic organ scan experiment (required for top tier cyber + organs) + - rscadd: Added a variant of machinery scan experiment that accepts any machines + with upgraded parts (required for tier 3 parts) + - rscdel: Removed material scanning experiments from the tech tree + Melbert: + - qol: Block'd out armor readout, should be more readable now + - bugfix: Crusher Fix For Real + SyncIt21: + - bugfix: ctrl+shift clicking on a ghost will only quick spawn that clicked target + and not you + TheBoondock: + - sound: added squeaky turn and gas hissing sound to gas valve + TheRyeGuyWhoWillNowDie: + - qol: adds a confirmation to malf AI shunting into APCs + mc-oofert: + - bugfix: build mode and space dragons dont harddel on destroy + - bugfix: you may now open the panel of a flatpacker with a screwdriver + san7890: + - qol: A message with a link to publicly accessible logs (if enabled by your server + operators) should now be visible far earlier when a world is about to reboot. +2024-06-19: + Bisar: + - rscadd: The Nanotrasen safety commission reminds employees to properly clean themselves + of all flammable material before going on smoke breaks. + - rscadd: Sparks now ignite flammable things. Including you. Keep a fire extinguisher + handy or stop dousing yourself in welding fuel! + - bugfix: Fixed a few oversights with welding fuel pools not igniting when you throw + lit/hot things into them or when you walk into them while on fire. + GPeckman: + - bugfix: Airlocks should no longer appear closed sometimes when fireman carrying + someone into them. + Jacquerel: + - balance: Gorillas have big fingers, which mostly just prevents them from using + laser pointers and stun batons + - balance: Items held in your hands can catch fire. + - balance: Items you are holding won't catch fire if your hands cannot catch fire. + - balance: When you stop being on fire so will items you are holding. + - balance: If you roll around on your burning items they will stop being on fire. + Melbert: + - bugfix: Fixed hand tele portals being forever + - bugfix: Enabling or disabling ambience mid round will properly enable or disable + ambience + - qol: Added descriptions differentiating "Ship ambience" from "ambience" + TheRyeGuyWhoWillNowDie: + - rscadd: the advanced omnitool upgrade now hastens the mediborg's syringe too + Time-Green: + - refactor: Lizard and moth markings now use the bodypart overlay system + carlarctg: + - balance: Negative mutations now allow you to have more positive mutations, via + reducing your instability! + - code_imp: All mutations have been overall standardized via defines on their instability + values. Many mediocre positive mutations have had their cost reduced significantly! + - rscadd: 'Added a new height mutation: Acromegaly! It''s the opposite of Dwarfism + and makes you uncannily tall. It also makes you hit your head 8% or 4% (with + synch) of the time you pass through airlocks. Wear a helmet!' + - rscadd: Gigantism is now a recipe mutation, mix Acromegaly with Strength to get + it. + - qol: Injectors and activators' duration is now dependent on the in/stability (absolute + value) of the mutations to be injected! With a minimum of 5-10-15 seconds for + each type of injector. Also changed up a bit how part upgrade cooldowns work, + by making each tier reduce cooldowns by 25-15-10% for each injector type. + jlsnow301: + - bugfix: TGUI say will no longer spill your /me contents when you get attacked +2024-06-20: + Absolucy: + - qol: Prettied up the Chemical Analyzer's output in chat, making it easier to read, + especially when scanning multiple things. + Ben10Omintrix: + - rscadd: vendrobes may have mothroaches inside them + - rscadd: mothroaches will now seek out clothes to eat them + FlufflesTheDog: + - bugfix: limbs that are both robotic and something else can be repaired properly + GPeckman: + - bugfix: The chaplain altar can once again be buckled to. + LT3: + - spellcheck: Melon fruit bowl now comes with a side of foreshadowing for people + who want to experience an explosion of flavour + MTandi: + - bugfix: Fixed techweb app showing wrong designs on Details button click + - bugfix: Fixed new compressor UI + - refactor: Compressor UI to TypeScript + - qol: Simplified Compressor UI layout + - bugfix: Made 10 MJ & 20 MJ cells properly correspond to tiers 1 & 2 in lathes. + - image: Updated cell sprites to correspond to other stock parts of their tiers. + - image: Updated plasma cell, 500KJ cell and 2.5MJ cell sprites + - qol: APC has wires for machinery/lights/environment channels + Metekillot: + - bugfix: Sparks will no longer turn areas with wooden furniture or similar into + naught but a field of ashes; they no longer ignite furniture, (unless it's made + of plasma(?!)) and have a decreasing chance to ignite items bigger than small + size. + Rhials: + - bugfix: Fixes a door in the Fredington Fasting Bear Five Nights and Fnafbears + map. + - balance: The energy bola slowdown has been (roughly) halved, to allow for more + retaliation when used on a criminal. + SyncIt21: + - bugfix: Techfabs now print 5x cable coil + - bugfix: no more runtimes when dragging turfs onto other stuff + - code_imp: most actions now properly check for recursive locs & better adjacency + - bugfix: You can move around ui buttons in your action bar + Vishenka0704: + - qol: Ability to delete characters(yourself) + grungussuss: + - bugfix: mimes can now break their vow while borged or an MMI + mc-oofert: + - bugfix: wawa centcom interns may actually leave the stationside dock + - bugfix: wawa hop office and cap office get keycard auths + - bugfix: wawa disposals blast doors work properly + - bugfix: wawa med elevator controls on the bottom floor are accessible + - bugfix: sci entrance actually has access restrictions + - bugfix: gasping makes sound now +2024-06-21: + 00-Steven: + - refactor: Updated cards/ids to use the proper item interaction system instead + of attackby, please report any issues. + - bugfix: You can no longer recolour an ID at any point if you open the menu but + then don't select anything until later. + - bugfix: ID cards can be recoloured using crayons/spraycans again. + - qol: Prisoner IDs show genpop sentence time in hours/minutes/seconds instead of + seconds. + - qol: Prisoner IDs have genpop usage tips in their examine. + ArcaneMusic: + - qol: Vending machines now give audio feedback when you restock a vending refill + and get a payout. + - qol: The Restock tracker NTOS app for tracking vending machine contents now works + on all consoles, and comes pre-installed on the cargochat cargo computers. + - balance: Vending machines now offer a bit more credits when missing contents at + the start of a round after getting restocked. + BeagleGaming1: + - rscadd: Added disks for accelerator modkits and crusher trophies to the bitrunning + vendor + Bisar: + - rscadd: Ashwalkers are now better at riding, taming animals, and fishing. + - code_imp: Behavior for the settler trait has been partially atomized into several + traits instead. + EdgeLordExe: + - rscadd: Adds Feast of Owls ritual to heretic which allows one to forsake their + ascension in exchange for immediate power. + GPeckman: + - bugfix: When on 'stream' mode, the cleaning spray from a bottle of space cleaner + should no longer be blocked by just about everything. + Goat: + - bugfix: Icebox's raptor den is now lined with asbestos and lead and no longer + gets hit with radiation. + JackEnoff: + - bugfix: Repurposed Glands (Adrenals) now show their correct duration and chemical + cost in its description. + LT3: + - bugfix: Fixed paramedics not having access to the Icebox NanoDrug using the west + airlock + MTandi: + - image: New gibber sprite + - image: New food/slime processor sprite + - balance: Added ordnance to extra access of geneticists and roboticists + - balance: Reduced parts scanning tests' machine count to 4 from 8 + - balance: Reduced augmented organs scanning tests mob count to 1 from 2 + - balance: Reduced equipped mech scanning test count to 1 from 2 + - balance: Added polycrystal option to bluespace crystal scan test + - bugfix: Allowed NTNet relay in away circuit imprinter for NT Frontier app + - qol: NT Frontier app installed on RD and Scientists` PDAs by default + - qol: Updated NT Frontier app to be more user-friendly + Rex9001: + - bugfix: lunatics now get their hud properly + - bugfix: lunatics now get objectives + - qol: ascended moon heretics are now labelled as ringleaders and are easier for + lunatics to spot + Rhials: + - balance: DRAGnets now come with a beacon they can be synced to, which will set + the destination for the snare round's teleport ability. + SmArtKar: + - image: Resprited all jetpacks + SyncIt21: + - bugfix: breaking an APC will depower the area + Xander3359: + - bugfix: Fix rust heretic being unable to rust walls or floors + grungussuss: + - bugfix: Welding protection module for MODsuits protect flash-sensitives from welding + arcs + mc-oofert: + - rscadd: every engineering lobby starts with a flatpacked flatpacker and multitool + - bugfix: fixed wrong access on one door on wawastation and also made lights on + elevators not break (On Wawastation) + necromanceranne: + - rscadd: Replaces the Particle Acceleration Rifle with the Event Horizon anti-existential + beam rifle. It shoots black holes. You can make this in-game. That's right, + YOU! + - balance: Only one vortex anomaly can be made in a round. + projectkepler-ru: + - bugfix: Wawastation bridge now has the correct access on their suit storage and + medkit now actually starts filled + r3dj4ck0424: + - bugfix: puts tiles under the wawa tool storage doors + - bugfix: allows you to access a door and a fire alarm on wawa's prison second floor +2024-06-22: + AyIong: + - qol: Fullscreen mode can now be toggled by pressing F11 or the button at the top + right + Bisar: + - bugfix: Felinids no longer remember losing their tail and regaining it roundstart; + you need to do it during the round to get that mood event. + FlufflesTheDog: + - bugfix: sanitization on citation pda alerts + JupiterJaeden: + - bugfix: Conga lines of more than 2 no longer break when going up and down stairs. + MelokGleb: + - image: added sprite for debug heretic painting + Mothblocks: + - qol: Dramatically improves delete character UI and UX. + Thunder12345: + - rscdel: Locker staffs have been removed from the Ragin' Mages deathmatch lootcrate + pool. + mc-oofert: + - bugfix: borg factory gives you your preference borg name diff --git a/icons/effects/random_spawners.dmi b/icons/effects/random_spawners.dmi index ddd6fd6f608bd..ed6c0c8702e45 100644 Binary files a/icons/effects/random_spawners.dmi and b/icons/effects/random_spawners.dmi differ diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi index 52be2d07923e5..eb3f87d9c71f0 100644 Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ diff --git a/icons/mob/huds/antag_hud.dmi b/icons/mob/huds/antag_hud.dmi index c51fcc5baa8c6..2a916d01d9553 100644 Binary files a/icons/mob/huds/antag_hud.dmi and b/icons/mob/huds/antag_hud.dmi differ diff --git a/icons/mob/human/bodyparts.dmi b/icons/mob/human/bodyparts.dmi index d6e4472973a32..78be880423c1e 100644 Binary files a/icons/mob/human/bodyparts.dmi and b/icons/mob/human/bodyparts.dmi differ diff --git a/icons/mob/human/species/ghetto.dmi b/icons/mob/human/species/ghetto.dmi new file mode 100644 index 0000000000000..e11701428ebcb Binary files /dev/null and b/icons/mob/human/species/ghetto.dmi differ diff --git a/icons/mob/human/species/lizard/lizard_markings.dmi b/icons/mob/human/species/lizard/lizard_markings.dmi new file mode 100644 index 0000000000000..7cc8f2fa1b8a5 Binary files /dev/null and b/icons/mob/human/species/lizard/lizard_markings.dmi differ diff --git a/icons/mob/human/species/lizard/lizard_misc.dmi b/icons/mob/human/species/lizard/lizard_misc.dmi index ab228f29076f0..346581978e4b7 100644 Binary files a/icons/mob/human/species/lizard/lizard_misc.dmi and b/icons/mob/human/species/lizard/lizard_misc.dmi differ diff --git a/icons/mob/inhands/equipment/jetpacks_lefthand.dmi b/icons/mob/inhands/equipment/jetpacks_lefthand.dmi index 113a8349008b8..8096611173054 100644 Binary files a/icons/mob/inhands/equipment/jetpacks_lefthand.dmi and b/icons/mob/inhands/equipment/jetpacks_lefthand.dmi differ diff --git a/icons/mob/inhands/equipment/jetpacks_righthand.dmi b/icons/mob/inhands/equipment/jetpacks_righthand.dmi index 6337f0c0d2a02..8e2ce1de8b2a5 100644 Binary files a/icons/mob/inhands/equipment/jetpacks_righthand.dmi and b/icons/mob/inhands/equipment/jetpacks_righthand.dmi differ diff --git a/icons/obj/canisters.dmi b/icons/obj/canisters.dmi index 277833976adbb..436467648880b 100644 Binary files a/icons/obj/canisters.dmi and b/icons/obj/canisters.dmi differ diff --git a/icons/obj/devices/tracker.dmi b/icons/obj/devices/tracker.dmi index 59884c0aff881..39be63ef4de81 100644 Binary files a/icons/obj/devices/tracker.dmi and b/icons/obj/devices/tracker.dmi differ diff --git a/icons/obj/machines/cell_charger.dmi b/icons/obj/machines/cell_charger.dmi index 5ce285fc81782..0c9ca53544286 100644 Binary files a/icons/obj/machines/cell_charger.dmi and b/icons/obj/machines/cell_charger.dmi differ diff --git a/icons/obj/machines/kitchen.dmi b/icons/obj/machines/kitchen.dmi index c94afb8d78ad6..2142125c5aa5c 100644 Binary files a/icons/obj/machines/kitchen.dmi and b/icons/obj/machines/kitchen.dmi differ diff --git a/icons/obj/signs.dmi b/icons/obj/signs.dmi index 78cc96fabbc13..a2069ba5d9d3b 100644 Binary files a/icons/obj/signs.dmi and b/icons/obj/signs.dmi differ diff --git a/interface/skin.dmf b/interface/skin.dmf index 3bfab58ea52a9..5f4fd5eda69c1 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -70,8 +70,8 @@ window "mainwindow" menu = "menu" elem "split" type = CHILD - pos = 3,0 - size = 634x440 + pos = 0,0 + size = 640x440 anchor1 = 0,0 anchor2 = 100,100 saved-params = "splitter" @@ -159,58 +159,67 @@ window "infowindow" is-vert = false elem "changelog" type = BUTTON - pos = 16,5 - size = 104x20 - anchor1 = 3,0 - anchor2 = 19,0 + pos = 5,5 + size = 90x20 + anchor1 = 1,0 + anchor2 = 15,0 saved-params = "is-checked" text = "Changelog" command = "changelog" elem "rules" type = BUTTON - pos = 120,5 - size = 100x20 - anchor1 = 19,0 - anchor2 = 34,0 + pos = 95,5 + size = 90x20 + anchor1 = 15,0 + anchor2 = 29,0 saved-params = "is-checked" text = "Rules" command = "rules" elem "wiki" type = BUTTON - pos = 220,5 - size = 100x20 - anchor1 = 34,0 - anchor2 = 50,0 + pos = 185,5 + size = 90x20 + anchor1 = 29,0 + anchor2 = 43,0 saved-params = "is-checked" text = "Wiki" command = "wiki" elem "forum" type = BUTTON - pos = 320,5 - size = 100x20 - anchor1 = 50,0 - anchor2 = 66,0 + pos = 275,5 + size = 90x20 + anchor1 = 43,0 + anchor2 = 57,0 saved-params = "is-checked" text = "Forum" command = "forum" elem "github" type = BUTTON - pos = 420,5 - size = 100x20 - anchor1 = 66,0 - anchor2 = 81,0 + pos = 365,5 + size = 90x20 + anchor1 = 57,0 + anchor2 = 71,0 saved-params = "is-checked" text = "Github" command = "github" elem "report-issue" type = BUTTON - pos = 520,5 - size = 100x20 - anchor1 = 81,0 - anchor2 = 97,0 + pos = 455,5 + size = 90x20 + anchor1 = 71,0 + anchor2 = 85,0 saved-params = "is-checked" text = "Report Issue" command = "report-issue" + elem "fullscreen-toggle" + type = BUTTON + pos = 545,5 + size = 90x20 + anchor1 = 85,0 + anchor2 = 99,0 + saved-params = "is-checked" + text = "Fullscreen" + command = "fullscreen" window "outputwindow" elem "outputwindow" diff --git a/sound/attributions.txt b/sound/attributions.txt index bcd6f41edf278..29c86945dd1a1 100644 --- a/sound/attributions.txt +++ b/sound/attributions.txt @@ -188,3 +188,7 @@ https://freesound.org/people/BinaryMonkFlint/sounds/333296/ tank_remove_thunk.ogg was made by mixing two sound tracks from Freesound: https://freesound.org/people/lowdjinn/sounds/533885/ and; https://freesound.org/people/BMacZero/sounds/96137/ + +valve_opening.ogg was made by mixing water flowing samples from: +https://freesound.org/people/scriotxstudios/sounds/349111/?attribution=1 and squeaky scrape sound from: +https://freesound.org/people/Department64/sounds/669028/ which was modified with lower pitch diff --git a/sound/effects/gas_hissing.ogg b/sound/effects/gas_hissing.ogg new file mode 100644 index 0000000000000..58df62ef0842f Binary files /dev/null and b/sound/effects/gas_hissing.ogg differ diff --git a/sound/effects/valve_opening.ogg b/sound/effects/valve_opening.ogg new file mode 100644 index 0000000000000..9e71912041467 Binary files /dev/null and b/sound/effects/valve_opening.ogg differ diff --git a/strings/tips.txt b/strings/tips.txt index 8cccfe6953bb0..7d5f9f82ccc2e 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -286,3 +286,6 @@ You'll quickly lose your interest in the game if you play to win and kill. If yo Some areas of the station use simple nautical directions to indicate their respective locations, like Fore (Front of the ship), Aft (Back), Port (Left side), Starboard (Right), Quarter and Bow (Either sides of Aft and Fore, respectively). You can review these terms on the Notepad App of your PDA. Modular computers are compatible with integrated circuits, but most of the program-dependent circuits require them to be open/backgrounded to work. To install circuits on stationary consoles, you need to toggle interaction with the frame with right-click first. You don't need to destroy a Spacecoin machine to make your funds stop draining. Swiping your ID on it will stop the withdrawal. +As a Bitrunner, upgrading your quantum server will increase rewards and reduce downtime. +As a Bitrunner, your avatar has a domain info ability which will give you clues to help complete virtual domains. +Bitrunning is a crime. diff --git a/tgstation.dme b/tgstation.dme index e467ab9484891..f4c76dd348d66 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -989,6 +989,7 @@ #include "code\datums\atmosphere\planetary.dm" #include "code\datums\bodypart_overlays\bodypart_overlay.dm" #include "code\datums\bodypart_overlays\emote_bodypart_overlay.dm" +#include "code\datums\bodypart_overlays\markings_bodypart_overlay.dm" #include "code\datums\bodypart_overlays\mutant_bodypart_overlay.dm" #include "code\datums\bodypart_overlays\simple_bodypart_overlay.dm" #include "code\datums\brain_damage\brain_trauma.dm" @@ -3534,7 +3535,6 @@ #include "code\modules\bitrunning\virtual_domain\domains\psyker_shuffle.dm" #include "code\modules\bitrunning\virtual_domain\domains\psyker_zombies.dm" #include "code\modules\bitrunning\virtual_domain\domains\stairs_and_cliffs.dm" -#include "code\modules\bitrunning\virtual_domain\domains\starfront_saloon.dm" #include "code\modules\bitrunning\virtual_domain\domains\syndicate_assault.dm" #include "code\modules\bitrunning\virtual_domain\domains\test_only.dm" #include "code\modules\bitrunning\virtual_domain\domains\vaporwave.dm" @@ -4048,6 +4048,7 @@ #include "code\modules\experisci\experiment\types\scanning_people.dm" #include "code\modules\experisci\experiment\types\scanning_plants.dm" #include "code\modules\experisci\experiment\types\scanning_points.dm" +#include "code\modules\experisci\experiment\types\scanning_reagent.dm" #include "code\modules\experisci\experiment\types\scanning_vatgrown.dm" #include "code\modules\explorer_drone\adventure.dm" #include "code\modules\explorer_drone\control_console.dm" @@ -4957,9 +4958,10 @@ #include "code\modules\mob\living\basic\vermin\crab.dm" #include "code\modules\mob\living\basic\vermin\frog.dm" #include "code\modules\mob\living\basic\vermin\lizard.dm" -#include "code\modules\mob\living\basic\vermin\mothroach.dm" #include "code\modules\mob\living\basic\vermin\mouse.dm" #include "code\modules\mob\living\basic\vermin\space_bat.dm" +#include "code\modules\mob\living\basic\vermin\mothroach\mothroach.dm" +#include "code\modules\mob\living\basic\vermin\mothroach\mothroach_ai.dm" #include "code\modules\mob\living\brain\brain.dm" #include "code\modules\mob\living\brain\brain_cybernetic.dm" #include "code\modules\mob\living\brain\brain_item.dm" @@ -5361,12 +5363,12 @@ #include "code\modules\power\lighting\light_items.dm" #include "code\modules\power\lighting\light_mapping_helpers.dm" #include "code\modules\power\lighting\light_wallframes.dm" -#include "code\modules\power\singularity\boh_tear.dm" #include "code\modules\power\singularity\containment_field.dm" #include "code\modules\power\singularity\dark_matter_singularity.dm" #include "code\modules\power\singularity\emitter.dm" #include "code\modules\power\singularity\field_generator.dm" #include "code\modules\power\singularity\narsie.dm" +#include "code\modules\power\singularity\reality_tear.dm" #include "code\modules\power\singularity\singularity.dm" #include "code\modules\power\supermatter\supermatter.dm" #include "code\modules\power\supermatter\supermatter_extra_effects.dm" @@ -5678,8 +5680,24 @@ #include "code\modules\research\techweb\__techweb_helpers.dm" #include "code\modules\research\techweb\_techweb.dm" #include "code\modules\research\techweb\_techweb_node.dm" -#include "code\modules\research\techweb\all_nodes.dm" #include "code\modules\research\techweb\techweb_types.dm" +#include "code\modules\research\techweb\nodes\alien_nodes.dm" +#include "code\modules\research\techweb\nodes\atmos_nodes.dm" +#include "code\modules\research\techweb\nodes\bepis_nodes.dm" +#include "code\modules\research\techweb\nodes\biology_nodes.dm" +#include "code\modules\research\techweb\nodes\circuit_nodes.dm" +#include "code\modules\research\techweb\nodes\cyborg_nodes.dm" +#include "code\modules\research\techweb\nodes\engi_nodes.dm" +#include "code\modules\research\techweb\nodes\mech_nodes.dm" +#include "code\modules\research\techweb\nodes\medbay_nodes.dm" +#include "code\modules\research\techweb\nodes\mining_nodes.dm" +#include "code\modules\research\techweb\nodes\modsuit_nodes.dm" +#include "code\modules\research\techweb\nodes\research_nodes.dm" +#include "code\modules\research\techweb\nodes\robo_nodes.dm" +#include "code\modules\research\techweb\nodes\security_nodes.dm" +#include "code\modules\research\techweb\nodes\service_nodes.dm" +#include "code\modules\research\techweb\nodes\surgery_nodes.dm" +#include "code\modules\research\techweb\nodes\syndicate_nodes.dm" #include "code\modules\research\xenobiology\xenobio_camera.dm" #include "code\modules\research\xenobiology\xenobiology.dm" #include "code\modules\research\xenobiology\crossbreeding\__corecross.dm" @@ -5879,6 +5897,7 @@ #include "code\modules\surgery\advanced\bioware\vein_threading.dm" #include "code\modules\surgery\bodyparts\_bodyparts.dm" #include "code\modules\surgery\bodyparts\dismemberment.dm" +#include "code\modules\surgery\bodyparts\ghetto_parts.dm" #include "code\modules\surgery\bodyparts\head.dm" #include "code\modules\surgery\bodyparts\head_hair_and_lips.dm" #include "code\modules\surgery\bodyparts\helpers.dm" diff --git a/tgui/packages/tgui-panel/themes.ts b/tgui/packages/tgui-panel/themes.ts index d8f0ce50b7974..67061ff1f4cf1 100644 --- a/tgui/packages/tgui-panel/themes.ts +++ b/tgui/packages/tgui-panel/themes.ts @@ -57,6 +57,8 @@ export const setClientTheme = (name) => { 'github.text-color': '#000000', 'report-issue.background-color': 'none', 'report-issue.text-color': '#000000', + 'fullscreen-toggle.background-color': 'none', + 'fullscreen-toggle.text-color': '#000000', // Status and verb tabs 'output.background-color': 'none', 'output.text-color': '#000000', @@ -109,6 +111,8 @@ export const setClientTheme = (name) => { 'github.text-color': COLOR_DARK_TEXT, 'report-issue.background-color': '#492020', 'report-issue.text-color': COLOR_DARK_TEXT, + 'fullscreen-toggle.background-color': '#494949', + 'fullscreen-toggle.text-color': COLOR_DARK_TEXT, // Status and verb tabs 'output.background-color': COLOR_DARK_BG_DARKER, 'output.text-color': COLOR_DARK_TEXT, diff --git a/tgui/packages/tgui-say/TguiSay.tsx b/tgui/packages/tgui-say/TguiSay.tsx index d5b45f4d75f0f..34afaed1ff2d8 100644 --- a/tgui/packages/tgui-say/TguiSay.tsx +++ b/tgui/packages/tgui-say/TguiSay.tsx @@ -162,7 +162,7 @@ export class TguiSay extends Component<{}, State> { ? prefix + currentValue : currentValue; - this.messages.forceSayMsg(grunt); + this.messages.forceSayMsg(grunt, this.channelIterator.current()); this.reset(); } @@ -274,6 +274,7 @@ export class TguiSay extends Component<{}, State> { }; reset() { + this.currentPrefix = null; this.setValue(''); this.setSize(); this.setState({ diff --git a/tgui/packages/tgui-say/timers.ts b/tgui/packages/tgui-say/timers.ts index 85c58f7424ae9..d1388487c07c6 100644 --- a/tgui/packages/tgui-say/timers.ts +++ b/tgui/packages/tgui-say/timers.ts @@ -1,5 +1,7 @@ import { debounce, throttle } from 'common/timer'; +import { Channel } from './ChannelIterator'; + const SECONDS = 1000; /** Timers: Prevents overloading the server, throttles messages */ @@ -10,7 +12,8 @@ export const byondMessages = { 0.4 * SECONDS, ), forceSayMsg: debounce( - (entry: string) => Byond.sendMessage('force', { entry, channel: 'Say' }), + (entry: string, channel: Channel) => + Byond.sendMessage('force', { entry, channel }), 1 * SECONDS, true, ), diff --git a/tgui/packages/tgui/interfaces/NtosScipaper.jsx b/tgui/packages/tgui/interfaces/NtosScipaper.jsx index 2af2cd12f43f9..4d12fdc638931 100644 --- a/tgui/packages/tgui/interfaces/NtosScipaper.jsx +++ b/tgui/packages/tgui/interfaces/NtosScipaper.jsx @@ -5,7 +5,6 @@ import { Button, Collapsible, Dropdown, - Icon, Input, LabeledList, NoticeBox, @@ -13,14 +12,13 @@ import { Stack, Table, Tabs, - Tooltip, } from '../components'; import { TableCell, TableRow } from '../components/Table'; import { NtosWindow } from '../layouts'; export const NtosScipaper = (props) => { return ( - + @@ -50,31 +48,132 @@ const PaperPublishing = (props) => { return ( <>
- - + {fileList.length === 0 && ( + + Use the File Manager app to download files from a disk. + + )} + + + } + > + + + act('select_file', { + selected_uid: fileList[ordfile_name], + }) + } + /> + + + + } + > + + + act('select_experiment', { + selected_expath: expList[experiment_name], + }) + } + /> + + + + } + > + + String(number))} + selected={String(tier)} + onSelected={(new_tier) => + act('select_tier', { + selected_tier: Number(new_tier), + }) + } + /> + + + + } + > + + + act('select_partner', { + selected_partner: allowedPartners[new_partner], + }) + } + /> + + + act('et_alia')} + /> + } + > act('rewrite', { - title: value, + author: value, }) } /> - + act('rewrite', { - author: value, + title: value, }) } /> - { } /> - - - - - act('select_file', { - selected_uid: fileList[ordfile_name], - }) - } - /> - - - - - - - - - - - - - act('select_experiment', { - selected_expath: expList[experiment_name], - }) - } - /> - - - - - - - - - - - - String(number))} - selected={String(tier)} - onSelected={(new_tier) => - act('select_tier', { - selected_tier: Number(new_tier), - }) - } - /> - - - - - - - - - - - - - act('select_partner', { - selected_partner: allowedPartners[new_partner], - }) - } - /> - - - - - - - -
- - - +
); @@ -366,7 +367,7 @@ export const NtosScipaperContent = (props) => { Please sync this application to a valid techweb to upload progress! )} - + @@ -385,7 +386,7 @@ export const NtosScipaperContent = (props) => { }) } > - {'View Previous Publications'} + {'Publications'} { }) } > - {'View Available Experiments'} + {'Experiments'} { }) } > - {'View Scientific Partners'} + {'Scientific Partners'} {currentTab === 1 && } diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx index 9473506b80c97..55bfac0db0e71 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx @@ -106,15 +106,12 @@ export const CharacterPreferenceWindow = (props) => { profiles={data.character_profiles} /> - {!data.content_unlocked && ( Buy BYOND premium for more slots! )} - - @@ -185,9 +182,7 @@ export const CharacterPreferenceWindow = (props) => { )} - - {pageContents} diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/DeleteCharacterPopup.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/DeleteCharacterPopup.tsx new file mode 100644 index 0000000000000..3656465677b21 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/DeleteCharacterPopup.tsx @@ -0,0 +1,57 @@ +import { useEffect, useState } from 'react'; + +import { useBackend } from '../../backend'; +import { Box, Button, Modal, Stack } from '../../components'; +import { PreferencesMenuData } from './data'; + +export const DeleteCharacterPopup = (props: { close: () => void }) => { + const { data, act } = useBackend(); + const [secondsLeft, setSecondsLeft] = useState(3); + + const { close } = props; + + useEffect(() => { + const interval = setInterval(() => { + setSecondsLeft((current) => current - 1); + }, 1000); + + return () => clearInterval(interval); + }); + + return ( + + + + Wait! + + + + {`You're about to delete ${data.character_preferences.names[data.name_to_use]} forever. Are you sure you want to do this?`} + + + + + + {/* Explicit width so that the layout doesn't shift */} + + + + + + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx index c79827d2abe74..35ddf9d2a7326 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx @@ -1,7 +1,7 @@ import { filter, map, sortBy } from 'common/collections'; import { classes } from 'common/react'; import { createSearch } from 'common/string'; -import { useState } from 'react'; +import { ReactNode, useState } from 'react'; import { sendAct, useBackend } from '../../backend'; import { @@ -21,6 +21,7 @@ import { RandomSetting, ServerData, } from './data'; +import { DeleteCharacterPopup } from './DeleteCharacterPopup'; import { MultiNameInput, NameInput } from './names'; import features from './preferences/features'; import { @@ -383,6 +384,7 @@ export const PreferenceList = (props: { preferences: Record; randomizations: Record; maxHeight: string; + children?: ReactNode; }) => { return ( + + {props.children} ); }; @@ -478,6 +482,8 @@ export const MainPage = (props: { openSpecies: () => void }) => { const [currentClothingMenu, setCurrentClothingMenu] = useState( null, ); + const [deleteCharacterPopupOpen, setDeleteCharacterPopupOpen] = + useState(false); const [multiNameInputOpen, setMultiNameInputOpen] = useState(false); const [randomToggleEnabled] = useRandomToggleState(); @@ -549,6 +555,12 @@ export const MainPage = (props: { openSpecies: () => void }) => { /> )} + {deleteCharacterPopupOpen && ( + setDeleteCharacterPopupOpen(false)} + /> + )} + @@ -648,7 +660,21 @@ export const MainPage = (props: { openSpecies: () => void }) => { )} preferences={nonContextualPreferences} maxHeight="auto" - /> + > + + + + diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/sounds.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/sounds.tsx index 8516823a5587f..3f1c50c16f9f1 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/sounds.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/sounds.tsx @@ -10,6 +10,7 @@ import { FeatureDropdownInput } from '../dropdowns'; export const sound_ambience: FeatureToggle = { name: 'Enable ambience', category: 'SOUND', + description: `Ambience refers to the more noticeable ambient sounds that play on occasion.`, component: CheckboxInput, }; @@ -81,6 +82,7 @@ export const sound_midi: FeatureToggle = { export const sound_ship_ambience: FeatureToggle = { name: 'Enable ship ambience', category: 'SOUND', + description: `Ship ambience refers to the low ambient buzz that plays on loop.`, component: CheckboxInput, }; diff --git a/tgui/packages/tgui/interfaces/RestockTracker.jsx b/tgui/packages/tgui/interfaces/RestockTracker.jsx index 7df606adffcd3..ab6f1d012edf0 100644 --- a/tgui/packages/tgui/interfaces/RestockTracker.jsx +++ b/tgui/packages/tgui/interfaces/RestockTracker.jsx @@ -81,7 +81,17 @@ export const RestockTracker = (props) => { ))} + {vending_list.length === 0 && } ); }; + +export const RestockTrackerFull = (props) => { + const { data } = useBackend(); + return ( +
+ All vending machines stocked! +
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/TankCompressor.jsx b/tgui/packages/tgui/interfaces/TankCompressor.jsx deleted file mode 100644 index 1fddb2b1938f6..0000000000000 --- a/tgui/packages/tgui/interfaces/TankCompressor.jsx +++ /dev/null @@ -1,356 +0,0 @@ -import { useBackend, useSharedState } from '../backend'; -import { - Box, - Button, - Flex, - Icon, - LabeledList, - Modal, - NoticeBox, - RoundGauge, - Section, - Slider, - Stack, - Tabs, -} from '../components'; -import { Window } from '../layouts'; -import { GasmixParser } from './common/GasmixParser'; - -export const TankCompressor = (props) => { - return ( - - - - - - ); -}; - -const TankCompressorContent = (props) => { - const { act, data } = useBackend(); - const { disk, storage } = data; - const [currentTab, changeTab] = useSharedState('compressorTab', 1); - - return ( - - {currentTab === 1 && } - {currentTab === 2 && } - -
- - - - - -
-
-
- ); -}; - -const AlertBoxes = (props) => { - const { text_content, icon_name, icon_break, color, active } = props; - - return ( - - - - - {icon_break &&
} - {text_content} -
-
-
- ); -}; - -const TankCompressorControls = (props) => { - const { act, data } = useBackend(); - const { - tankPresent, - leaking, - lastPressure, - leakPressure, - fragmentPressure, - tankPressure, - maxTransfer, - active, - transferRate, - ejectPressure, - inputData, - outputData, - bufferData, - } = data; - const pressure = tankPresent ? tankPressure : lastPressure; - const usingLastData = !!(lastPressure && !tankPresent); - - return ( - <> - -
ejectPressure} - onClick={() => act('eject_tank')} - > - {'Eject Tank'} - - } - > - {!pressure && {'No Pressure Detected'}} - {usingLastData && ( - - {'Tank destroyed. Displaying last recorded data.'} - - )} - - - (value ? value.toFixed(2) : '-') + ' kPa'} - /> - - - - - - = leakPressure} - /> - - - - - = leakPressure && - pressure < fragmentPressure) || - leaking - } - /> - - - = fragmentPressure} - /> - - - - -
-
- -
- - - - act('change_rate', { target: new_rate }) - } - /> - - - - - -
-
- - - -
- {!inputData.total_moles && {'No Gas Present'}} - -
-
- -
- {!outputData.inputData && {'No Gas Present'}} - -
-
- -
- } - > - {!bufferData.total_moles && {'No Gas Present'}} - -
-
-
-
- - ); -}; - -const TankCompressorRecords = (props) => { - const { act, data } = useBackend(); - const { records = [], disk } = data; - const [activeRecordRef, setActiveRecordRef] = useSharedState( - 'recordRef', - records[0]?.ref, - ); - const activeRecord = - !!activeRecordRef && - records.find((record) => activeRecordRef === record.ref); - if (records.length === 0) { - return ( - - No Records - - ); - } - - return ( - - - - - {records.map((record) => ( - setActiveRecordRef(record.ref)} - > - {record.name} - - ))} - - - {activeRecord ? ( - -
{ - act('delete_record', { - ref: activeRecord.ref, - }); - }} - />, -
-
- ) : ( - - No Record Selected - - )} -
-
- ); -}; diff --git a/tgui/packages/tgui/interfaces/TankCompressor.tsx b/tgui/packages/tgui/interfaces/TankCompressor.tsx new file mode 100644 index 0000000000000..a0d2acc14fb4b --- /dev/null +++ b/tgui/packages/tgui/interfaces/TankCompressor.tsx @@ -0,0 +1,322 @@ +import { toFixed } from 'common/math'; +import { BooleanLike } from 'common/react'; + +import { useBackend, useSharedState } from '../backend'; +import { + Box, + Button, + Knob, + LabeledControls, + LabeledList, + NoticeBox, + RoundGauge, + Section, + Stack, + Tabs, +} from '../components'; +import { formatSiUnit } from '../format'; +import { Window } from '../layouts'; + +type Data = { + // Dynamic + tankPresent: BooleanLike; + tankPressure: number; + leaking: BooleanLike; + active: BooleanLike; + transferRate: number; + lastPressure: number; + disk: string; + storage: string; + records: Record[]; + // Static + maxTransfer: number; + leakPressure: number; + fragmentPressure: number; + ejectPressure: number; +}; + +type Record = { + ref: string; + name: string; + timestamp: string; + source: string; + gases: GasMoles[]; +}; + +type GasMoles = { + [key: string]: number; +}; + +const formatPressure = (value) => { + if (value < 10000) { + return toFixed(value) + ' kPa'; + } + return formatSiUnit(value * 1000, 1, 'Pa'); +}; + +export const TankCompressor = (props) => { + return ( + + + + + + ); +}; + +const TankCompressorContent = (props) => { + const { act, data } = useBackend(); + const { disk, storage } = data; + + return ( + + + +
act('eject_disk')} + > + Eject Disk + + } + > + +
+
+
+ ); +}; + +const TankCompressorControls = (props) => { + const { act, data } = useBackend(); + const { + tankPresent, + leaking, + lastPressure, + leakPressure, + fragmentPressure, + tankPressure, + maxTransfer, + active, + transferRate, + ejectPressure, + } = data; + const pressure = tankPresent ? tankPressure : lastPressure; + const usingLastData = !!(lastPressure && !tankPresent); + const notice_color = + usingLastData || leaking || pressure > fragmentPressure + ? 'bad' + : !tankPresent + ? 'blue' + : pressure > leakPressure + ? 'average' + : 'good'; + const notice_text = usingLastData + ? 'Tank destroyed. Displaying last recorded data.' + : !tankPresent + ? 'No Tank Detected' + : leaking + ? 'Tank Leaking' + : !pressure + ? 'No Pressure Detected' + : pressure < leakPressure + ? 'Tank Pressure Nominal' + : pressure < fragmentPressure + ? 'Leak Hazard' + : 'Explosive Hazard'; + + return ( + +
ejectPressure} + onClick={() => act('eject_tank')} + > + {'Eject Tank'} + + } + > + {notice_text} + + + + + + + + act('change_rate', { + target: value, + }) + } + /> + + + +
+
+ ); +}; + +const TankCompressorRecords = (props) => { + const { act, data } = useBackend(); + const { records = [], disk } = data; + const [activeRecordRef, setActiveRecordRef] = useSharedState( + 'recordRef', + records[0]?.ref, + ); + const activeRecord = + !!activeRecordRef && + records.find((record) => activeRecordRef === record.ref); + if (records.length === 0) { + return ( + + No Records + + ); + } + + return ( + + + + + {records.map((record) => ( + setActiveRecordRef(record.ref)} + > + {record.name} + + ))} + + + {activeRecord ? ( + + + + {activeRecord.name} + + + {activeRecord.timestamp} + + + {activeRecord.source} + + + + {Object.keys(activeRecord.gases).map((gas_name) => ( + + {(activeRecord.gases[gas_name] + ? activeRecord.gases[gas_name].toFixed(2) + : '-') + ' moles'} + + ))} + + + +