diff --git a/_maps/RandomRuins/StationRuins/GaxStation/ai_whale.dmm b/_maps/RandomRuins/StationRuins/GaxStation/ai_whale.dmm index ff3182149f64..4f99de8995cd 100644 --- a/_maps/RandomRuins/StationRuins/GaxStation/ai_whale.dmm +++ b/_maps/RandomRuins/StationRuins/GaxStation/ai_whale.dmm @@ -7,9 +7,6 @@ /turf/open/floor/plating, /area/tcommsat/computer) "aA" = ( -/obj/machinery/computer/ai_resource_distribution{ - dir = 8 - }, /obj/machinery/computer/security/telescreen{ dir = 8; name = "MiniSat Camera Monitor"; @@ -2206,7 +2203,7 @@ dir = 8; pixel_x = 24 }, -/obj/machinery/computer/ai_control_console{ +{ dir = 8 }, /turf/open/floor/plasteel/grimy, diff --git a/_maps/map_files/EclipseStation/EclipseStation.dmm b/_maps/map_files/EclipseStation/EclipseStation.dmm index 85baa543423e..879d1b12eb0a 100644 --- a/_maps/map_files/EclipseStation/EclipseStation.dmm +++ b/_maps/map_files/EclipseStation/EclipseStation.dmm @@ -45018,9 +45018,6 @@ /obj/structure/window/reinforced{ layer = 4.1 }, -/obj/machinery/computer/ai_resource_distribution{ - dir = 1 - }, /turf/open/floor/plasteel/dark, /area/ai_monitored/turret_protected/ai_upload) "bOT" = ( @@ -59457,7 +59454,7 @@ /area/crew_quarters/heads/hor) "cto" = ( /obj/structure/rack, -/obj/item/circuitboard/computer/ai_upload_download, +, /obj/item/disk/holodisk/tutorial/AICore, /turf/open/floor/plasteel, /area/crew_quarters/heads/hor) @@ -86278,9 +86275,6 @@ /turf/open/floor/plasteel, /area/hallway/primary/fore) "nsA" = ( -/obj/machinery/computer/ai_resource_distribution{ - dir = 4 - }, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /turf/open/floor/carpet, @@ -90567,7 +90561,7 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ dir = 1 }, -/obj/machinery/computer/ai_control_console{ +{ dir = 1 }, /turf/open/floor/plasteel/dark, diff --git a/_maps/map_files/GaxStation/GaxStation.dmm b/_maps/map_files/GaxStation/GaxStation.dmm index 74f61e2b2f10..4dfde9638ac4 100644 --- a/_maps/map_files/GaxStation/GaxStation.dmm +++ b/_maps/map_files/GaxStation/GaxStation.dmm @@ -65,7 +65,7 @@ /obj/structure/rack, /obj/item/aicard, /obj/item/disk/holodisk/tutorial/AICore, -/obj/item/circuitboard/computer/ai_upload_download, +, /obj/machinery/power/apc{ areastring = "/area/crew_quarters/heads/hor"; dir = 8; @@ -11064,9 +11064,6 @@ /turf/open/floor/plasteel, /area/security/main) "fvC" = ( -/obj/machinery/computer/ai_resource_distribution{ - dir = 4 - }, /turf/open/floor/plasteel/dark, /area/ai_monitored/secondarydatacore) "fvG" = ( @@ -18746,7 +18743,7 @@ /obj/machinery/computer/robotics{ dir = 8 }, -/obj/structure/sign/plaques/ai_password{ +{ pixel_x = 32 }, /turf/open/floor/carpet/exoticpurple, diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index 63cdf54eefe5..d152380c5be4 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -85994,7 +85994,7 @@ /obj/effect/turf_decal/tile/neutral, /obj/structure/table, /obj/item/hand_labeler, -/obj/item/circuitboard/computer/ai_upload_download, +, /turf/open/floor/plasteel/dark, /area/crew_quarters/heads/hor) "fMR" = ( @@ -91824,9 +91824,6 @@ dir = 8 }, /obj/effect/decal/cleanable/dirt, -/obj/machinery/computer/ai_resource_distribution{ - dir = 8 - }, /turf/open/floor/plasteel/dark, /area/ai_monitored/storage/satellite) "laJ" = ( @@ -92192,7 +92189,7 @@ dir = 1 }, /obj/effect/mapping_helpers/teleport_anchor, -/obj/structure/sign/plaques/ai_password{ +{ pixel_x = -32 }, /turf/open/floor/plasteel/showroomfloor, @@ -92215,7 +92212,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, -/obj/machinery/computer/ai_control_console{ +{ dir = 8 }, /turf/open/floor/plasteel/dark, diff --git a/_maps/map_files/Omegastation/omegastation.dmm b/_maps/map_files/Omegastation/omegastation.dmm index 416486332452..2d4ddd5f8ab0 100644 --- a/_maps/map_files/Omegastation/omegastation.dmm +++ b/_maps/map_files/Omegastation/omegastation.dmm @@ -43172,9 +43172,6 @@ /turf/open/floor/plasteel/white, /area/science/research) "tZB" = ( -/obj/machinery/computer/ai_resource_distribution{ - dir = 1 - }, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, diff --git a/_maps/map_files/YogStation/YogStation.dmm b/_maps/map_files/YogStation/YogStation.dmm index 13a8725706f1..53dc0e83aa69 100644 --- a/_maps/map_files/YogStation/YogStation.dmm +++ b/_maps/map_files/YogStation/YogStation.dmm @@ -220,12 +220,6 @@ }, /turf/open/floor/plasteel, /area/security/prison) -"abx" = ( -/obj/effect/decal/cleanable/dirt/dust, -/obj/effect/decal/cleanable/dirt/dust, -/obj/machinery/ai/server_cabinet/prefilled, -/turf/open/floor/circuit/green/telecomms, -/area/ai_monitored/turret_protected/ai) "aby" = ( /obj/machinery/atmospherics/components/unary/portables_connector/visible{ dir = 8 @@ -605,6 +599,16 @@ }, /turf/open/space/basic, /area/space) +"acX" = ( +/obj/structure/rack, +/obj/effect/turf_decal/stripes/line{ + dir = 9 + }, +/obj/structure/sign/plaques/cave{ + pixel_y = 32 + }, +/turf/open/floor/plasteel/white, +/area/crew_quarters/heads/hor) "acY" = ( /obj/structure/closet/bombcloset/security, /turf/open/floor/plasteel/showroomfloor, @@ -1217,6 +1221,12 @@ /obj/machinery/recharger, /turf/open/floor/plasteel/showroomfloor, /area/security/warden) +"agv" = ( +/obj/structure/ethernet_cable{ + icon_state = "1-2" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "agy" = ( /obj/structure/table, /obj/item/storage/firstaid/regular{ @@ -2543,6 +2553,21 @@ }, /turf/open/floor/carpet, /area/crew_quarters/fitness) +"aob" = ( +/obj/structure/sign/warning/electricshock{ + pixel_y = -32 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ + dir = 4 + }, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "aof" = ( /turf/closed/wall/r_wall, /area/maintenance/solars/starboard/fore) @@ -3389,18 +3414,6 @@ }, /turf/open/floor/plasteel/dark, /area/ai_monitored/security/armory) -"aue" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, -/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ - dir = 1 - }, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/open/floor/plating{ - icon_state = "platingdmg3" - }, -/area/maintenance/starboard/aft) "aug" = ( /obj/structure/table, /obj/item/storage/toolbox/electrical{ @@ -6021,6 +6034,14 @@ }, /turf/open/floor/plasteel/dark, /area/engine/engineering) +"aJj" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "aJk" = ( /obj/machinery/light, /obj/structure/table, @@ -6483,6 +6504,13 @@ /obj/machinery/vending/cigarette, /turf/open/floor/plasteel/dark, /area/hallway/secondary/entry) +"aLA" = ( +/obj/structure/window/reinforced, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "aLD" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ dir = 4 @@ -6660,22 +6688,6 @@ }, /turf/open/floor/plating, /area/maintenance/starboard/aft) -"aMD" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, -/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ - dir = 1 - }, -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/structure/cable{ - icon_state = "1-8" - }, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "aME" = ( /obj/machinery/atmospherics/components/binary/pump{ dir = 4; @@ -7820,15 +7832,6 @@ /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, /area/vacant_room/commissary) -"aSy" = ( -/obj/machinery/atmospherics/pipe/simple/cyan/hidden{ - dir = 4 - }, -/obj/structure/window/reinforced{ - dir = 8 - }, -/turf/open/floor/plasteel/dark/telecomms, -/area/ai_monitored/turret_protected/ai) "aSG" = ( /obj/structure/table, /obj/item/stack/sheet/glass/fifty, @@ -10633,6 +10636,14 @@ /obj/structure/closet/wardrobe/black, /turf/open/floor/plating, /area/maintenance/central) +"bkY" = ( +/obj/item/stack/cable_coil, +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/ethernet_cable{ + icon_state = "2-8" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "bkZ" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, @@ -10956,6 +10967,16 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/plasteel, /area/quartermaster/office) +"bnB" = ( +/obj/machinery/ai/networking{ + label = "Computer Science"; + roundstart_connection = "Main Core" + }, +/obj/structure/ethernet_cable{ + icon_state = "0-4" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "bnE" = ( /obj/machinery/door/airlock/research{ name = "Research Division Access"; @@ -13160,18 +13181,6 @@ "bCv" = ( /turf/closed/wall, /area/janitor) -"bCw" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ - dir = 1 - }, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "bCz" = ( /obj/machinery/vending/cigarette, /turf/open/floor/plasteel/dark, @@ -13973,22 +13982,16 @@ }, /turf/open/floor/plasteel, /area/engine/atmos_distro) -"bKB" = ( -/obj/structure/closet/emcloset, -/obj/structure/sign/warning/electricshock{ - pixel_y = -32 - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ - dir = 9 - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ - dir = 9 +"bKx" = ( +/obj/machinery/modular_computer/console/preset/netmin{ + dir = 1 }, -/obj/structure/cable{ - icon_state = "1-8" +/obj/effect/turf_decal/trimline/purple/filled/line, +/obj/structure/ethernet_cable{ + icon_state = "0-2" }, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "bKG" = ( /obj/machinery/requests_console{ department = "EVA"; @@ -14476,6 +14479,12 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/plasteel/white, /area/medical/virology) +"bOz" = ( +/obj/structure/ethernet_cable{ + icon_state = "1-4" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "bOH" = ( /obj/structure/sign/warning/docking, /obj/effect/spawner/structure/window/reinforced/shutter, @@ -14852,23 +14861,6 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/medical/virology) -"bRR" = ( -/obj/machinery/door/firedoor/border_only{ - dir = 1 - }, -/obj/machinery/door/firedoor/border_only, -/obj/machinery/door/airlock/research/glass{ - name = "Secondary AI Core"; - normalspeed = 0; - req_access_txt = "47" - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, -/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/open/floor/plasteel/dark, -/area/ai_monitored/secondarydatacore) "bSm" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ @@ -15045,6 +15037,13 @@ }, /turf/open/floor/plasteel/white, /area/medical/medbay/lobby) +"bUU" = ( +/obj/structure/ethernet_cable{ + icon_state = "1-2" + }, +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/plating, +/area/ai_monitored/secondarydatacore) "bUV" = ( /obj/machinery/vending/wardrobe/sec_wardrobe, /obj/machinery/light, @@ -15692,6 +15691,12 @@ }, /turf/open/space, /area/solar/port/aft) +"cde" = ( +/obj/machinery/atmospherics/pipe/simple/cyan/hidden{ + dir = 4 + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "cdh" = ( /obj/machinery/holopad, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ @@ -15865,10 +15870,6 @@ }, /turf/open/floor/plating, /area/maintenance/starboard/fore) -"ceR" = ( -/obj/effect/landmark/blobstart, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "ceW" = ( /obj/structure/rack, /obj/effect/spawner/lootdrop/techstorage/RnD_secure, @@ -17483,25 +17484,15 @@ }, /turf/open/floor/plasteel/dark/telecomms, /area/tcommsat/server) -"cyZ" = ( -/obj/machinery/door/firedoor/border_only{ - dir = 1 - }, -/obj/machinery/door/firedoor/border_only, -/obj/machinery/door/airlock/hatch{ - name = "Hardware Workshop"; - req_access_txt = "61" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 1 +"czb" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ + dir = 4 }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, -/obj/structure/cable{ - icon_state = "1-2" +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ + dir = 4 }, -/turf/open/floor/plasteel/grimy, -/area/tcommsat/computer) +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "czc" = ( /obj/machinery/door/airlock/highsecurity{ name = "AI Upload Access"; @@ -17967,6 +17958,20 @@ }, /turf/open/floor/plasteel, /area/quartermaster/miningdock) +"cGu" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "cGw" = ( /obj/machinery/meter, /obj/machinery/atmospherics/pipe/simple/supply/visible, @@ -18531,6 +18536,12 @@ }, /turf/open/floor/plasteel, /area/quartermaster/miningdock) +"cPu" = ( +/obj/effect/turf_decal/trimline/purple/filled/line, +/obj/machinery/portable_atmospherics/canister/nitrogen, +/obj/machinery/atmospherics/components/unary/portables_connector/visible, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "cPD" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ dir = 6 @@ -19092,16 +19103,6 @@ }, /turf/open/floor/plasteel/dark, /area/science/xenobiology) -"dbJ" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 6 - }, -/obj/structure/sign/plaques/ai_password{ - pixel_x = 32 - }, -/obj/machinery/papershredder, -/turf/open/floor/plasteel/white, -/area/crew_quarters/heads/hor) "dcc" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -19159,6 +19160,15 @@ /obj/effect/turf_decal/trimline/brown/filled/line, /turf/open/floor/plasteel, /area/quartermaster/miningdock) +"ddQ" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 1; + external_pressure_bound = 140; + plane = -2; + pressure_checks = 0 + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "dea" = ( /obj/structure/table, /obj/item/folder/yellow, @@ -19666,6 +19676,15 @@ }, /turf/open/floor/engine, /area/maintenance/disposal/incinerator) +"duc" = ( +/obj/structure/ethernet_cable{ + icon_state = "2-8" + }, +/obj/structure/ethernet_cable{ + icon_state = "2-4" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "dus" = ( /obj/structure/table/wood, /obj/item/flashlight/lantern, @@ -19834,6 +19853,26 @@ }, /turf/open/floor/plating, /area/maintenance/starboard/fore) +"dxO" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/machinery/computer/security/telescreen{ + dir = 1; + name = "Telecomms Camera Monitor"; + network = list("tcomms"); + pixel_x = 30; + pixel_y = -37 + }, +/obj/item/radio/intercom{ + dir = 1; + freerange = 1; + name = "Station Intercom (Telecomms)"; + pixel_x = 28; + pixel_y = -26 + }, +/turf/open/floor/plasteel/grimy, +/area/tcommsat/computer) "dxV" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/table, @@ -20000,13 +20039,6 @@ }, /turf/open/floor/plasteel/dark, /area/ai_monitored/nuke_storage) -"dBH" = ( -/obj/machinery/atmospherics/pipe/simple/general/visible{ - dir = 4 - }, -/obj/machinery/meter, -/turf/open/floor/circuit/telecomms/server, -/area/ai_monitored/secondarydatacore) "dBU" = ( /obj/machinery/light_switch{ pixel_x = 27 @@ -20161,15 +20193,6 @@ }, /turf/open/floor/plasteel/freezer, /area/crew_quarters/toilet) -"dFJ" = ( -/obj/structure/window/reinforced{ - dir = 1 - }, -/obj/structure/cable/white{ - icon_state = "4-8" - }, -/turf/open/floor/plasteel/dark/telecomms, -/area/ai_monitored/turret_protected/ai) "dFX" = ( /obj/machinery/door/airlock/maintenance{ name = "Security Maintenance"; @@ -20500,16 +20523,6 @@ }, /turf/open/floor/plasteel, /area/science/misc_lab) -"dMA" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, -/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ - dir = 1 - }, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "dMJ" = ( /obj/machinery/advanced_airlock_controller{ dir = 8; @@ -20815,6 +20828,13 @@ }, /turf/open/floor/plasteel, /area/quartermaster/qm) +"dTf" = ( +/obj/structure/frame/machine{ + anchored = 1; + state = 2 + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "dTu" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, @@ -21278,6 +21298,12 @@ }, /turf/open/floor/plasteel, /area/security/checkpoint/engineering) +"efW" = ( +/obj/structure/table, +/obj/item/storage/box/donkpockets, +/obj/effect/turf_decal/trimline/purple/filled/line, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "egc" = ( /obj/machinery/door/poddoor/preopen{ id = "atmos"; @@ -21392,6 +21418,13 @@ }, /turf/open/floor/plasteel, /area/construction/mining/aux_base) +"ehY" = ( +/obj/machinery/ai/server_cabinet/prefilled, +/obj/structure/ethernet_cable{ + icon_state = "0-8" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "eie" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 4 @@ -21950,6 +21983,13 @@ }, /turf/open/floor/plasteel, /area/engine/atmos_distro) +"euD" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 6 + }, +/obj/machinery/papershredder, +/turf/open/floor/plasteel/white, +/area/crew_quarters/heads/hor) "euJ" = ( /obj/machinery/door/airlock/maintenance_hatch, /obj/machinery/door/firedoor/border_only, @@ -22044,6 +22084,15 @@ /obj/effect/landmark/start/assistant, /turf/open/floor/wood, /area/library) +"exA" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "exB" = ( /obj/structure/chair/office/dark{ dir = 4 @@ -22503,6 +22552,18 @@ }, /turf/open/floor/plasteel/dark, /area/chapel/office) +"eFt" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/ai/networking{ + label = "Main Core"; + roundstart_connection = "Computer Science" + }, +/obj/structure/ethernet_cable{ + icon_state = "0-4" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "eFL" = ( /obj/machinery/camera{ c_tag = "Engineering Escape Pod"; @@ -23130,6 +23191,25 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, /turf/open/floor/plasteel, /area/janitor) +"eUd" = ( +/obj/machinery/door/firedoor/border_only{ + dir = 1 + }, +/obj/machinery/door/firedoor/border_only, +/obj/machinery/door/airlock/hatch{ + name = "Telecommunications"; + req_access_txt = "61" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plasteel/grimy, +/area/tcommsat/computer) "eUf" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ dir = 4 @@ -23548,6 +23628,17 @@ }, /turf/open/floor/plasteel/white, /area/science/research) +"fcx" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 27 + }, +/obj/structure/table, +/obj/item/stack/ethernet_coil, +/obj/effect/turf_decal/trimline/purple/filled/line{ + dir = 5 + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "fcB" = ( /obj/machinery/atmospherics/pipe/simple/yellow/visible, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ @@ -23559,17 +23650,6 @@ /obj/machinery/holopad, /turf/open/floor/plasteel, /area/engine/foyer) -"fdU" = ( -/obj/structure/rack, -/obj/effect/turf_decal/stripes/line{ - dir = 9 - }, -/obj/structure/sign/plaques/cave{ - pixel_y = 32 - }, -/obj/item/circuitboard/computer/ai_upload_download, -/turf/open/floor/plasteel/white, -/area/crew_quarters/heads/hor) "fen" = ( /obj/machinery/computer/upload/ai{ dir = 1 @@ -23620,6 +23700,18 @@ }, /turf/open/floor/plasteel/white, /area/medical/chemistry) +"feK" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/cable/white{ + icon_state = "4-8" + }, +/obj/structure/ethernet_cable{ + icon_state = "1-2" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "feV" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ dir = 4 @@ -23900,6 +23992,15 @@ /obj/effect/turf_decal/trimline/red/filled/corner, /turf/open/floor/plasteel, /area/security/brig) +"flr" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer4{ + dir = 8 + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "flC" = ( /obj/machinery/door/firedoor/border_only{ dir = 4 @@ -24117,18 +24218,6 @@ /obj/machinery/door/firedoor/border_only, /turf/open/floor/plating, /area/maintenance/starboard/aft) -"frD" = ( -/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer4{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer2{ - dir = 8 - }, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "frH" = ( /obj/machinery/light/small{ dir = 8 @@ -24840,18 +24929,6 @@ }, /turf/open/floor/plasteel/dark, /area/security/prison) -"fFO" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/machinery/computer/ai_resource_distribution{ - dir = 1 - }, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer4{ - dir = 1 - }, -/turf/open/floor/plasteel/dark, -/area/ai_monitored/secondarydatacore) "fFS" = ( /obj/structure/table/reinforced, /obj/machinery/door/firedoor/border_only{ @@ -24984,6 +25061,18 @@ /obj/effect/turf_decal/stripes/line, /turf/open/floor/plating, /area/storage/tech) +"fIh" = ( +/obj/machinery/power/apc{ + areastring = "/area/maintenance/starboard/aft"; + dir = 4; + name = "Starboard Quarter Maintenance APC"; + pixel_x = 24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "fIn" = ( /obj/machinery/computer/cargo{ dir = 4 @@ -25010,15 +25099,6 @@ }, /turf/open/floor/plating, /area/maintenance/port/aft) -"fIs" = ( -/obj/structure/window/reinforced{ - dir = 4 - }, -/obj/structure/cable/yellow{ - icon_state = "1-2" - }, -/turf/open/floor/plasteel/dark/telecomms, -/area/ai_monitored/turret_protected/ai) "fIu" = ( /obj/machinery/door/airlock/public/glass{ name = "Central Access" @@ -25032,13 +25112,6 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/aft_starboard) -"fIH" = ( -/obj/machinery/door/firedoor/border_only{ - dir = 1 - }, -/obj/machinery/door/firedoor/border_only, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "fIS" = ( /obj/machinery/atmospherics/pipe/simple/general/visible{ dir = 4 @@ -25882,6 +25955,14 @@ }, /turf/open/floor/plasteel, /area/quartermaster/storage) +"gcd" = ( +/obj/structure/table, +/obj/machinery/microwave, +/obj/effect/turf_decal/trimline/purple/filled/line{ + dir = 10 + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "gce" = ( /obj/effect/turf_decal/stripes/line, /obj/machinery/door/firedoor/border_only{ @@ -25983,12 +26064,6 @@ }, /turf/open/floor/wood, /area/library) -"gdI" = ( -/obj/machinery/atmospherics/pipe/simple/general/visible{ - dir = 10 - }, -/turf/open/floor/circuit/telecomms/server, -/area/ai_monitored/secondarydatacore) "gdU" = ( /obj/structure/cable/yellow{ icon_state = "4-8" @@ -26163,6 +26238,15 @@ }, /turf/open/floor/plating, /area/maintenance/starboard/aft) +"giM" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/cable/white{ + icon_state = "4-8" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "giP" = ( /obj/machinery/door/window/eastright{ base_state = "left"; @@ -26291,19 +26375,6 @@ }, /turf/open/floor/plasteel/dark, /area/bridge) -"goW" = ( -/obj/machinery/light{ - dir = 4 - }, -/obj/machinery/power/apc/highcap{ - areastring = "/area/ai_monitored/secondarydatacore"; - dir = 4; - name = "AI Secondary Datacore"; - pixel_x = 24 - }, -/obj/structure/cable, -/turf/open/floor/plasteel/dark, -/area/ai_monitored/secondarydatacore) "goZ" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -26322,6 +26393,18 @@ /obj/effect/spawner/structure/window, /turf/open/floor/plating, /area/maintenance/starboard/aft) +"gqo" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer2{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer4{ + dir = 8 + }, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "gqu" = ( /obj/machinery/door/firedoor/border_only{ dir = 1 @@ -26868,22 +26951,6 @@ }, /turf/open/floor/plasteel, /area/security/prison/hallway) -"gDs" = ( -/obj/machinery/doorButtons/access_button{ - idDoor = "secondary_aicore_interior"; - idSelf = "secondary_aicore_controller"; - name = "Secondary AI Core Access Button"; - pixel_x = -24; - pixel_y = 8; - req_one_access_txt = "30;70" - }, -/obj/structure/chair/office/light, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer2{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, -/turf/open/floor/plasteel/dark, -/area/ai_monitored/secondarydatacore) "gDD" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer2{ dir = 8 @@ -27420,6 +27487,10 @@ icon_state = "platingdmg3" }, /area/maintenance/port) +"gRT" = ( +/obj/machinery/atmospherics/pipe/manifold4w/cyan/hidden, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "gSd" = ( /obj/machinery/camera{ c_tag = "Research Division Access" @@ -27871,12 +27942,6 @@ /obj/effect/turf_decal/trimline/purple/filled/warning, /turf/open/floor/plasteel/white, /area/science/research) -"hbO" = ( -/obj/structure/window/reinforced{ - dir = 4 - }, -/turf/open/floor/plasteel/dark/telecomms, -/area/ai_monitored/turret_protected/ai) "hcu" = ( /obj/structure/table, /obj/item/storage/box/fancy/heart_box{ @@ -28527,6 +28592,12 @@ }, /turf/open/floor/plasteel, /area/hallway/secondary/entry) +"hnb" = ( +/obj/structure/ethernet_cable{ + icon_state = "2-4" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "hnh" = ( /obj/structure/cable{ icon_state = "4-8" @@ -29448,10 +29519,6 @@ }, /turf/open/floor/plasteel, /area/engine/atmos_distro) -"hJq" = ( -/obj/machinery/ai/data_core/primary, -/turf/open/floor/circuit/green/telecomms, -/area/ai_monitored/turret_protected/ai) "hJu" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/light/small{ @@ -29708,15 +29775,6 @@ }, /turf/open/floor/plasteel, /area/engine/engineering) -"hOU" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/machinery/computer/ai_server_console{ - dir = 1 - }, -/turf/open/floor/plasteel/dark, -/area/ai_monitored/secondarydatacore) "hPk" = ( /obj/machinery/holopad, /turf/open/floor/plasteel/white, @@ -30220,6 +30278,10 @@ }, /turf/open/floor/plasteel/grimy, /area/tcommsat/computer) +"hYR" = ( +/obj/effect/spawner/structure/window/reinforced/shutter, +/turf/open/floor/plating, +/area/space) "hYX" = ( /obj/structure/cable/yellow{ icon_state = "1-2" @@ -30230,19 +30292,6 @@ }, /turf/open/floor/plasteel/grimy, /area/ai_monitored/turret_protected/aisat_interior) -"hYY" = ( -/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer4{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer2{ - dir = 4 - }, -/obj/machinery/power/terminal{ - dir = 4 - }, -/obj/structure/cable, -/turf/open/floor/plasteel/dark, -/area/ai_monitored/secondarydatacore) "hZg" = ( /obj/machinery/power/smes/engineering{ charge = 5e+006; @@ -30502,20 +30551,6 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/central) -"ief" = ( -/obj/machinery/light{ - dir = 8 - }, -/obj/machinery/atmospherics/components/unary/vent_pump/siphon/on{ - dir = 4; - external_pressure_bound = 120 - }, -/obj/machinery/airalarm/tcomms{ - dir = 4; - pixel_x = -24 - }, -/turf/open/floor/circuit/telecomms/server, -/area/ai_monitored/secondarydatacore) "ieh" = ( /obj/effect/turf_decal/stripes/line, /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ @@ -30699,10 +30734,6 @@ }, /turf/open/floor/plasteel, /area/hydroponics) -"iiJ" = ( -/obj/machinery/ai/server_cabinet, -/turf/open/floor/circuit/green/telecomms/mainframe, -/area/ai_monitored/secondarydatacore) "iiO" = ( /obj/machinery/gulag_item_reclaimer{ pixel_y = 24 @@ -30778,10 +30809,6 @@ }, /turf/open/floor/plasteel, /area/hallway/secondary/exit) -"ikV" = ( -/obj/machinery/ai/server_cabinet/prefilled, -/turf/open/floor/circuit/green/telecomms, -/area/ai_monitored/turret_protected/ai) "ilk" = ( /obj/structure/closet/secure_closet/captains, /turf/open/floor/carpet/blue, @@ -31493,6 +31520,12 @@ }, /turf/open/floor/plasteel/dark, /area/bridge) +"izK" = ( +/obj/structure/ethernet_cable{ + icon_state = "4-8" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "izV" = ( /obj/item/radio/intercom{ name = "Station Intercom (General)"; @@ -32350,27 +32383,6 @@ /obj/effect/turf_decal/trimline/yellow/filled/line, /turf/open/floor/plasteel, /area/construction/mining/aux_base) -"iRV" = ( -/obj/structure/chair/office/dark{ - dir = 4 - }, -/obj/machinery/computer/security/telescreen{ - dir = 1; - name = "Telecomms Camera Monitor"; - network = list("tcomms"); - pixel_x = 30; - pixel_y = -37 - }, -/obj/item/radio/intercom{ - dir = 1; - freerange = 1; - name = "Station Intercom (Telecomms)"; - pixel_x = 28; - pixel_y = -26 - }, -/obj/effect/landmark/start/yogs/network_admin, -/turf/open/floor/plasteel/grimy, -/area/tcommsat/computer) "iRY" = ( /obj/structure/table, /obj/item/flashlight{ @@ -32536,10 +32548,6 @@ }, /turf/open/floor/plating, /area/medical/paramedic) -"iVk" = ( -/obj/structure/girder, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "iVn" = ( /obj/structure/closet/crate{ icon_state = "crateopen" @@ -32639,6 +32647,14 @@ /obj/structure/cable, /turf/open/floor/plasteel, /area/science/mixing) +"iWz" = ( +/obj/machinery/camera{ + c_tag = "Secondary AI Core"; + dir = 8; + network = list("ss13","rd") + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "iWF" = ( /obj/effect/spawner/structure/window/reinforced/shutter, /obj/structure/cable{ @@ -33046,6 +33062,16 @@ }, /turf/closed/wall/r_wall, /area/engine/atmos_distro) +"jgW" = ( +/obj/machinery/ai/data_core/primary, +/obj/structure/ethernet_cable{ + icon_state = "1-2" + }, +/obj/structure/ethernet_cable{ + icon_state = "0-2" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "jhc" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer2, @@ -33166,6 +33192,13 @@ }, /turf/open/floor/plasteel, /area/engine/engineering) +"jkO" = ( +/obj/structure/ethernet_cable{ + icon_state = "0-4" + }, +/obj/machinery/ai/server_cabinet, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "jld" = ( /obj/structure/rack, /obj/effect/spawner/lootdrop/techstorage/rnd, @@ -33884,12 +33917,6 @@ }, /turf/open/floor/plating, /area/maintenance/disposal/incinerator) -"jzm" = ( -/obj/structure/cable/yellow{ - icon_state = "2-4" - }, -/turf/open/floor/plasteel/dark/telecomms, -/area/ai_monitored/turret_protected/ai) "jzo" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer4{ dir = 1 @@ -34324,6 +34351,29 @@ /obj/effect/turf_decal/siding/wood, /turf/open/floor/wood, /area/library) +"jJv" = ( +/obj/machinery/doorButtons/access_button{ + idDoor = "secondary_aicore_interior"; + idSelf = "secondary_aicore_controller"; + name = "Secondary AI Core Access Button"; + pixel_x = -24; + pixel_y = 8; + req_one_access_txt = "30;70" + }, +/obj/effect/turf_decal/trimline/purple/filled/line{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ + dir = 5 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "jJy" = ( /obj/structure/chair{ dir = 4 @@ -34394,6 +34444,15 @@ }, /turf/open/floor/plasteel/cafeteria, /area/crew_quarters/heads/hor) +"jKp" = ( +/obj/machinery/atmospherics/pipe/simple/cyan/hidden{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "jKG" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer2, /turf/open/floor/plasteel, @@ -34549,20 +34608,13 @@ }, /turf/open/floor/plating, /area/hallway/secondary/exit) -"jPU" = ( -/obj/machinery/door/firedoor/border_only, -/obj/machinery/door/firedoor/border_only{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, -/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ - dir = 1 - }, -/obj/structure/cable{ - icon_state = "1-2" +"jPF" = ( +/obj/machinery/ai/data_core, +/obj/structure/ethernet_cable{ + icon_state = "0-8" }, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "jQg" = ( /obj/effect/turf_decal/arrows/white{ color = "#99ccff"; @@ -35087,6 +35139,13 @@ }, /turf/open/floor/circuit/telecomms/server, /area/ai_monitored/turret_protected/ai) +"kcA" = ( +/obj/structure/ethernet_cable{ + icon_state = "0-8" + }, +/obj/machinery/ai/server_cabinet/prefilled, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "kcH" = ( /obj/machinery/disposal/bin, /obj/structure/window/reinforced, @@ -35509,6 +35568,16 @@ }, /turf/open/floor/plasteel, /area/janitor) +"kkY" = ( +/obj/structure/ethernet_cable{ + icon_state = "1-4" + }, +/obj/structure/ethernet_cable{ + icon_state = "1-8" + }, +/obj/machinery/light, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "klD" = ( /obj/structure/sign/departments/minsky/medical/chemistry/chemical2, /turf/closed/wall, @@ -36428,12 +36497,6 @@ }, /turf/open/floor/carpet, /area/crew_quarters/fitness) -"kJz" = ( -/obj/machinery/atmospherics/pipe/manifold/general/visible{ - dir = 4 - }, -/turf/open/floor/circuit/telecomms/server, -/area/ai_monitored/secondarydatacore) "kJK" = ( /obj/structure/grille, /obj/structure/window{ @@ -36833,16 +36896,6 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/fore) -"kSZ" = ( -/obj/machinery/atmospherics/pipe/simple/cyan/hidden, -/obj/structure/window/reinforced{ - dir = 1 - }, -/obj/structure/cable/white{ - icon_state = "4-8" - }, -/turf/open/floor/plasteel/dark/telecomms, -/area/ai_monitored/turret_protected/ai) "kTm" = ( /obj/machinery/portable_atmospherics/canister/nitrogen, /obj/structure/window/reinforced{ @@ -37040,6 +37093,21 @@ /obj/structure/closet/firecloset, /turf/open/floor/plating, /area/maintenance/port/aft) +"kYZ" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/disposalpipe/segment{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ + dir = 5 + }, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "kZl" = ( /obj/structure/closet/l3closet, /turf/open/floor/plating, @@ -37143,12 +37211,6 @@ /obj/effect/turf_decal/trimline/yellow/filled/line, /turf/open/floor/plasteel, /area/hallway/primary/central) -"lbr" = ( -/obj/structure/cable/white{ - icon_state = "4-8" - }, -/turf/open/floor/plasteel/dark/telecomms, -/area/ai_monitored/turret_protected/ai) "lbE" = ( /obj/machinery/light, /obj/effect/turf_decal/trimline/blue/filled/corner{ @@ -37253,6 +37315,13 @@ "ldW" = ( /turf/template_noop, /area/maintenance/aft) +"lej" = ( +/obj/effect/turf_decal/trimline/purple/filled/line, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer2{ + dir = 1 + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "leo" = ( /obj/structure/window/reinforced{ dir = 4 @@ -37782,6 +37851,23 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/starboard) +"lpZ" = ( +/obj/machinery/door/firedoor/border_only{ + dir = 1 + }, +/obj/machinery/door/firedoor/border_only, +/obj/machinery/door/airlock/research/glass{ + name = "Computer Science"; + normalspeed = 0; + req_access_txt = "47" + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "lql" = ( /obj/structure/rack, /obj/item/storage/toolbox/electrical{ @@ -38123,6 +38209,21 @@ }, /turf/open/floor/plasteel, /area/quartermaster/office) +"lzq" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ + dir = 10 + }, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "lzt" = ( /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/trimline/yellow/filled/warning{ @@ -38396,11 +38497,6 @@ /obj/structure/chair/sofa/right, /turf/open/floor/wood, /area/medical/psych) -"lHO" = ( -/obj/item/stack/cable_coil, -/obj/effect/decal/cleanable/dirt/dust, -/turf/open/floor/circuit/green/telecomms, -/area/ai_monitored/turret_protected/ai) "lIb" = ( /obj/structure/sign/warning/electricshock{ pixel_y = 32 @@ -38453,6 +38549,15 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/engine, /area/science/xenobiology) +"lJK" = ( +/obj/effect/landmark/blobstart, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "lKd" = ( /obj/machinery/firealarm{ pixel_y = 28 @@ -38670,6 +38775,15 @@ }, /turf/open/floor/plasteel/white, /area/science/xenobiology) +"lQo" = ( +/obj/structure/ethernet_cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/cyan/hidden{ + dir = 4 + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "lQB" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ dir = 4 @@ -38782,6 +38896,9 @@ /obj/effect/turf_decal/trimline/blue/filled/line, /turf/open/floor/plasteel, /area/hallway/primary/starboard) +"lTx" = ( +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "lTC" = ( /obj/machinery/light, /obj/machinery/disposal/bin, @@ -39770,6 +39887,10 @@ }, /turf/open/floor/plasteel, /area/security/prison) +"mnp" = ( +/obj/machinery/atmospherics/pipe/manifold/cyan/hidden, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "mnN" = ( /obj/structure/chair{ dir = 4 @@ -40782,6 +40903,15 @@ /obj/effect/turf_decal/trimline/yellow/filled/line, /turf/open/floor/plasteel, /area/construction/mining/aux_base) +"mEQ" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "mFg" = ( /obj/machinery/airalarm{ dir = 4; @@ -41188,6 +41318,21 @@ }, /turf/open/floor/plasteel/white, /area/science/research) +"mQO" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ + dir = 4 + }, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "mQY" = ( /obj/effect/turf_decal/stripes/end{ dir = 4 @@ -41275,10 +41420,6 @@ }, /turf/open/floor/wood, /area/crew_quarters/heads/captain) -"mSg" = ( -/obj/machinery/atmospherics/pipe/manifold/general/visible, -/turf/open/floor/circuit/telecomms/server, -/area/ai_monitored/secondarydatacore) "mSl" = ( /obj/structure/closet/l3closet/scientist, /obj/effect/turf_decal/trimline/purple/filled/line{ @@ -41552,6 +41693,9 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/starboard) +"mYX" = ( +/turf/closed/wall/r_wall, +/area/maintenance/starboard/aft) "mZa" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ dir = 5 @@ -41882,6 +42026,21 @@ }, /turf/open/floor/plating, /area/science/robotics/lab) +"ncw" = ( +/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer4{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer2{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "ncA" = ( /obj/machinery/button/door{ desc = "A remote control-switch for shuttle construction storage."; @@ -43063,14 +43222,6 @@ }, /turf/open/floor/plasteel, /area/security/prison/hallway) -"nDW" = ( -/obj/structure/window/reinforced, -/obj/machinery/atmospherics/pipe/simple/cyan/hidden, -/obj/structure/cable/yellow{ - icon_state = "4-8" - }, -/turf/open/floor/plasteel/dark/telecomms, -/area/ai_monitored/turret_protected/ai) "nEu" = ( /obj/effect/turf_decal/loading_area{ dir = 1 @@ -43270,13 +43421,6 @@ }, /turf/open/floor/plating, /area/maintenance/aft) -"nJj" = ( -/obj/machinery/holopad, -/obj/machinery/door/firedoor/border_only{ - dir = 8 - }, -/turf/open/floor/plasteel/dark/telecomms, -/area/ai_monitored/turret_protected/ai) "nJl" = ( /obj/effect/turf_decal/pool{ dir = 8 @@ -43346,6 +43490,13 @@ }, /turf/closed/wall, /area/engine/atmos_distro) +"nKi" = ( +/obj/machinery/rack_creator, +/obj/effect/turf_decal/trimline/purple/filled/line{ + dir = 1 + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "nKv" = ( /obj/effect/turf_decal/bot_white/right, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer2, @@ -43499,6 +43650,18 @@ }, /turf/open/floor/plasteel/cafeteria, /area/crew_quarters/heads/cmo) +"nQz" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 8; + external_pressure_bound = 140; + plane = -2; + pressure_checks = 0 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "nQC" = ( /obj/effect/spawner/structure/window/reinforced/shutter, /obj/structure/cable{ @@ -43592,6 +43755,18 @@ }, /turf/open/floor/plasteel/white, /area/medical/storage) +"nSD" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ + dir = 9 + }, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "nSI" = ( /obj/machinery/atmospherics/pipe/simple/orange/visible{ dir = 4 @@ -43683,15 +43858,6 @@ }, /turf/open/floor/plasteel/white, /area/science/research) -"nTI" = ( -/obj/machinery/atmospherics/pipe/simple/cyan/hidden{ - dir = 8 - }, -/obj/structure/window/reinforced{ - dir = 8 - }, -/turf/open/floor/plasteel/dark/telecomms, -/area/ai_monitored/turret_protected/ai) "nTR" = ( /obj/item/cigbutt/roach, /turf/open/floor/plating, @@ -43773,6 +43939,10 @@ }, /turf/open/floor/plasteel/dark, /area/engine/engineering) +"nUE" = ( +/obj/structure/table, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "nUH" = ( /obj/effect/turf_decal/trimline/purple/filled/corner{ dir = 1 @@ -44522,6 +44692,16 @@ "omk" = ( /turf/template_noop, /area/maintenance/fore) +"omv" = ( +/obj/structure/window/reinforced, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/structure/ethernet_cable{ + icon_state = "1-2" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "omI" = ( /obj/item/instrument/piano_synth{ pixel_x = -10 @@ -45375,6 +45555,15 @@ /obj/effect/turf_decal/trimline/red/filled/line, /turf/open/floor/plasteel, /area/hallway/secondary/exit) +"oDB" = ( +/obj/machinery/door/firedoor/border_only{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "oDR" = ( /obj/machinery/disposal/bin, /obj/structure/disposalpipe/trunk{ @@ -45585,6 +45774,16 @@ }, /turf/open/floor/plasteel/dark, /area/engine/engine_smes) +"oJg" = ( +/obj/structure/ethernet_cable{ + icon_state = "1-8" + }, +/obj/structure/ethernet_cable{ + icon_state = "1-4" + }, +/obj/machinery/light, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "oJj" = ( /obj/structure/disposalpipe/segment, /turf/open/floor/plating, @@ -46595,20 +46794,6 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/medical/sleeper) -"piV" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ - dir = 1 - }, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/open/floor/plating{ - icon_state = "platingdmg3" - }, -/area/maintenance/starboard/aft) "pjc" = ( /obj/effect/turf_decal/arrows/white{ color = "#99ccff"; @@ -46630,6 +46815,17 @@ }, /turf/open/floor/plasteel, /area/security/main) +"pkn" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "pkC" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, @@ -47566,10 +47762,6 @@ }, /turf/open/space, /area/solar/port/aft) -"pDa" = ( -/obj/machinery/ai/data_core, -/turf/open/floor/circuit/green/telecomms/mainframe, -/area/ai_monitored/secondarydatacore) "pDq" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer4{ dir = 1 @@ -47863,6 +48055,19 @@ /obj/machinery/atmospherics/pipe/simple/yellow/visible, /turf/open/floor/plasteel, /area/engine/atmos_distro) +"pLx" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/siphon/on{ + dir = 1; + external_pressure_bound = 120; + plane = -2 + }, +/obj/machinery/camera{ + c_tag = "Secondary AI Core"; + dir = 4; + network = list("ss13","rd") + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "pLQ" = ( /obj/effect/landmark/event_spawn, /obj/machinery/atmospherics/pipe/manifold/scrubbers/visible{ @@ -48026,6 +48231,14 @@ /obj/item/stock_parts/subspace/treatment, /turf/open/floor/plasteel/white, /area/storage/tech) +"pPm" = ( +/obj/machinery/airalarm/tcomms{ + dir = 4; + pixel_x = -24 + }, +/obj/machinery/atmospherics/pipe/simple/cyan/hidden, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "pPs" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ dir = 4 @@ -48211,6 +48424,15 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, /turf/open/floor/plating, /area/maintenance/port/aft) +"pTp" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/cyan/hidden{ + dir = 8 + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "pTL" = ( /obj/structure/sign/departments/minsky/engineering/telecommmunications{ pixel_y = 32 @@ -48409,28 +48631,6 @@ }, /turf/open/floor/plasteel/dark, /area/security/courtroom) -"pYv" = ( -/obj/machinery/camera{ - c_tag = "Secondary AI Core"; - dir = 8; - network = list("ss13","rd") - }, -/obj/machinery/airalarm{ - pixel_y = 24 - }, -/obj/structure/extinguisher_cabinet{ - pixel_x = 27 - }, -/obj/machinery/power/smes/engineering{ - charge = 5e+006; - input_level = 25000; - output_level = 20000 - }, -/obj/structure/cable{ - icon_state = "0-2" - }, -/turf/open/floor/plasteel/dark, -/area/ai_monitored/secondarydatacore) "pYC" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, @@ -48653,6 +48853,14 @@ }, /turf/open/floor/plasteel, /area/hydroponics/garden) +"qdb" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/frame/machine{ + anchored = 1; + state = 2 + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "qdv" = ( /turf/open/floor/carpet, /area/crew_quarters/fitness) @@ -48883,6 +49091,11 @@ /obj/effect/turf_decal/trimline/blue/filled/warning, /turf/open/floor/plasteel/dark, /area/bridge) +"qiX" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/machinery/atmospherics/pipe/simple/cyan/hidden, +/turf/open/floor/plating, +/area/ai_monitored/secondarydatacore) "qjc" = ( /obj/structure/disposalpipe/sorting/mail{ sortType = 10 @@ -48935,18 +49148,6 @@ }, /turf/open/floor/plasteel/dark, /area/security/courtroom) -"qjZ" = ( -/obj/machinery/power/apc{ - areastring = "/area/maintenance/starboard/aft"; - dir = 1; - name = "Starboard Quarter Maintenance APC"; - pixel_y = 23 - }, -/obj/structure/cable{ - icon_state = "0-2" - }, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "qko" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ dir = 4 @@ -49633,16 +49834,6 @@ }, /turf/open/floor/wood, /area/lawoffice) -"qzd" = ( -/obj/machinery/airalarm{ - dir = 8; - pixel_x = 24 - }, -/obj/machinery/computer/ai_control_console{ - dir = 8 - }, -/turf/open/floor/plasteel/grimy, -/area/ai_monitored/turret_protected/aisat_interior) "qzt" = ( /obj/machinery/door/airlock/external{ name = "Engineering External Access"; @@ -49694,6 +49885,11 @@ }, /turf/open/space/basic, /area/ai_monitored/turret_protected/aisat_interior) +"qAr" = ( +/obj/effect/turf_decal/trimline/purple/filled/line, +/obj/machinery/atmospherics/components/unary/thermomachine/freezer/on, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "qAt" = ( /obj/structure/table, /obj/item/paper_bin{ @@ -50072,12 +50268,6 @@ }, /turf/open/floor/plating, /area/maintenance/solars/starboard/fore) -"qJg" = ( -/obj/structure/cable/yellow{ - icon_state = "4-8" - }, -/turf/open/floor/circuit/telecomms/server, -/area/ai_monitored/turret_protected/ai) "qJt" = ( /obj/machinery/door/firedoor/border_only{ dir = 1 @@ -50217,20 +50407,6 @@ }, /turf/open/floor/plating, /area/storage/tech) -"qLi" = ( -/obj/machinery/camera{ - c_tag = "MiniSat - Monitoring room"; - dir = 8; - network = list("minisat","ss13") - }, -/obj/machinery/newscaster/security_unit{ - pixel_x = 28 - }, -/obj/machinery/computer/ai_resource_distribution{ - dir = 8 - }, -/turf/open/floor/plasteel/grimy, -/area/ai_monitored/turret_protected/aisat_interior) "qLt" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -51281,6 +51457,18 @@ }, /turf/open/floor/plating, /area/construction) +"rjl" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ + dir = 4 + }, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "rjo" = ( /obj/machinery/atmospherics/pipe/simple/cyan/hidden{ dir = 4 @@ -51572,13 +51760,6 @@ /obj/machinery/light, /turf/open/floor/plasteel, /area/crew_quarters/dorms) -"rqW" = ( -/obj/structure/window/reinforced, -/obj/structure/cable/yellow{ - icon_state = "4-8" - }, -/turf/open/floor/plasteel/dark/telecomms, -/area/ai_monitored/turret_protected/ai) "rqZ" = ( /obj/machinery/door/poddoor{ id = "QMLoaddoor"; @@ -51935,6 +52116,22 @@ }, /turf/open/floor/plasteel/cafeteria, /area/crew_quarters/heads/cmo) +"rzU" = ( +/obj/machinery/power/terminal{ + dir = 4 + }, +/obj/structure/cable, +/obj/effect/turf_decal/trimline/purple/filled/warning{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer2{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer4{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "rAb" = ( /obj/structure/lattice/catwalk, /obj/machinery/atmospherics/components/binary/pump/layer2{ @@ -51985,6 +52182,15 @@ }, /turf/open/floor/plasteel, /area/engine/atmos_distro) +"rBx" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "rBz" = ( /obj/item/radio/intercom{ pixel_y = -27 @@ -52263,15 +52469,6 @@ /obj/machinery/teleport/station, /turf/open/floor/plating, /area/teleporter) -"rGM" = ( -/obj/machinery/door/firedoor/border_only{ - dir = 4 - }, -/obj/structure/cable/yellow{ - icon_state = "1-8" - }, -/turf/open/floor/plasteel/dark/telecomms, -/area/ai_monitored/turret_protected/ai) "rHf" = ( /turf/open/floor/engine/vacuum, /area/engine/atmos_distro) @@ -52474,6 +52671,32 @@ }, /turf/open/floor/plating, /area/maintenance/department/electrical) +"rKn" = ( +/obj/machinery/power/apc/highcap{ + areastring = "/area/ai_monitored/secondarydatacore"; + dir = 4; + name = "AI Secondary Datacore"; + pixel_x = 24 + }, +/obj/machinery/light{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/structure/table, +/obj/item/circuitboard/machine/server_cabinet, +/obj/item/circuitboard/machine/ai_data_core, +/obj/effect/turf_decal/trimline/purple/filled/line{ + dir = 4 + }, +/obj/machinery/camera{ + c_tag = "Secondary AI Core"; + dir = 8; + network = list("ss13","rd") + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "rKs" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, @@ -52588,6 +52811,13 @@ }, /turf/open/floor/plasteel, /area/hallway/secondary/entry) +"rOm" = ( +/obj/machinery/computer/ai_overclocking, +/obj/effect/turf_decal/trimline/purple/filled/line{ + dir = 1 + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "rOz" = ( /obj/structure/table, /obj/item/storage/belt/utility, @@ -54308,6 +54538,18 @@ }, /turf/open/floor/plasteel, /area/science/nanite) +"sDx" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ + dir = 10 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "sDG" = ( /obj/structure/closet{ name = "Evidence Closet" @@ -54317,6 +54559,12 @@ }, /turf/open/floor/plasteel, /area/security/brig) +"sDM" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "sEr" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ dir = 4 @@ -54702,6 +54950,16 @@ }, /turf/open/floor/plasteel, /area/crew_quarters/theatre) +"sKT" = ( +/obj/machinery/atmospherics/pipe/simple/cyan/hidden, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/cable/white{ + icon_state = "4-8" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "sKX" = ( /obj/structure/table, /obj/item/clothing/gloves/color/latex, @@ -54759,12 +55017,6 @@ }, /turf/open/floor/plasteel/dark, /area/bridge) -"sLZ" = ( -/obj/machinery/atmospherics/components/unary/thermomachine/freezer/on{ - dir = 4 - }, -/turf/open/floor/circuit/telecomms/server, -/area/ai_monitored/secondarydatacore) "sMh" = ( /obj/structure/filingcabinet, /obj/machinery/light_switch{ @@ -55391,6 +55643,15 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/starboard) +"sYO" = ( +/obj/machinery/atmospherics/pipe/simple/cyan/hidden{ + dir = 4 + }, +/obj/structure/ethernet_cable{ + icon_state = "1-2" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "sZn" = ( /obj/structure/table/wood, /obj/item/stamp/captain{ @@ -56292,12 +56553,26 @@ }, /turf/open/floor/plasteel/white, /area/medical/virology) +"trH" = ( +/obj/effect/turf_decal/trimline/purple/filled/line{ + dir = 6 + }, +/obj/item/twohanded/required/kirbyplants/random, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "tsu" = ( /obj/effect/turf_decal/trimline/red/filled/line{ dir = 1 }, /turf/open/floor/plasteel, /area/hallway/primary/fore) +"tsx" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/siphon/on{ + external_pressure_bound = 120; + plane = -2 + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "tsS" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, @@ -56421,12 +56696,6 @@ }, /turf/open/floor/plasteel/white, /area/science/mixing) -"twt" = ( -/obj/machinery/atmospherics/pipe/simple/general/visible{ - dir = 4 - }, -/turf/open/floor/circuit/telecomms/server, -/area/ai_monitored/secondarydatacore) "twv" = ( /obj/effect/spawner/structure/window, /obj/machinery/door/firedoor/border_only{ @@ -56451,6 +56720,15 @@ }, /turf/open/floor/plasteel, /area/security/prison) +"txn" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "txG" = ( /obj/machinery/light{ dir = 1 @@ -56787,6 +57065,13 @@ }, /turf/open/floor/plasteel, /area/maintenance/disposal/incinerator) +"tEQ" = ( +/obj/machinery/rnd/production/circuit_imprinter/department/netmin, +/obj/effect/turf_decal/trimline/purple/filled/line{ + dir = 1 + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "tEV" = ( /obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer2, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ @@ -57309,6 +57594,14 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/fore) +"tPR" = ( +/obj/structure/window/reinforced, +/obj/machinery/atmospherics/pipe/simple/cyan/hidden, +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "tPY" = ( /obj/machinery/light/small, /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ @@ -57346,17 +57639,6 @@ }, /turf/open/floor/plasteel, /area/clerk) -"tQv" = ( -/obj/machinery/light{ - dir = 4 - }, -/obj/machinery/atmospherics/components/unary/vent_pump/on{ - dir = 8; - external_pressure_bound = 140; - pressure_checks = 0 - }, -/turf/open/floor/circuit/telecomms/server, -/area/ai_monitored/secondarydatacore) "tQD" = ( /obj/structure/disposalpipe/segment, /turf/open/floor/plasteel, @@ -57621,9 +57903,6 @@ }, /turf/open/floor/plasteel, /area/engine/engineering) -"tXb" = ( -/turf/open/floor/circuit/green/telecomms/mainframe, -/area/ai_monitored/secondarydatacore) "tXk" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer2{ dir = 4 @@ -57861,6 +58140,10 @@ }, /turf/open/floor/circuit, /area/ai_monitored/turret_protected/ai_upload) +"uaD" = ( +/obj/structure/grille, +/turf/open/floor/plating, +/area/maintenance/starboard/aft) "uaL" = ( /obj/machinery/light/small{ dir = 1 @@ -59141,30 +59424,6 @@ }, /turf/open/floor/plasteel, /area/maintenance/disposal/incinerator) -"uFS" = ( -/obj/machinery/atmospherics/components/unary/portables_connector/visible{ - dir = 4 - }, -/obj/machinery/doorButtons/access_button{ - idDoor = "secondary_aicore_exterior"; - idSelf = "secondary_aicore_controller"; - name = "Secondary AI Core Access Button"; - pixel_x = -24; - pixel_y = 8; - req_one_access_txt = "30;70" - }, -/obj/machinery/doorButtons/airlock_controller{ - idExterior = "secondary_aicore_exterior"; - idInterior = "secondary_aicore_interior"; - idSelf = "secondary_aicore_controller"; - name = "Secondary AI Core Access Console"; - pixel_x = -26; - pixel_y = -6; - req_one_access_txt = "30;70" - }, -/obj/machinery/portable_atmospherics/canister/nitrogen, -/turf/open/floor/circuit/telecomms/server, -/area/ai_monitored/secondarydatacore) "uFW" = ( /obj/effect/landmark/event_spawn, /turf/open/floor/plating, @@ -59710,24 +59969,6 @@ /obj/item/stack/sheet/mineral/plasma, /turf/open/floor/plasteel/white, /area/medical/virology) -"uSq" = ( -/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer4{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer2{ - dir = 1 - }, -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/structure/cable{ - icon_state = "1-4" - }, -/obj/structure/cable{ - icon_state = "2-4" - }, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "uSG" = ( /obj/machinery/power/apc{ areastring = "/area/engine/foyer"; @@ -60551,6 +60792,28 @@ }, /turf/open/floor/plasteel, /area/maintenance/disposal/incinerator) +"vkE" = ( +/obj/machinery/camera{ + c_tag = "Secondary AI Core"; + dir = 8; + network = list("ss13","rd") + }, +/obj/machinery/airalarm{ + pixel_y = 24 + }, +/obj/machinery/power/smes/engineering{ + charge = 5e+006; + input_level = 25000; + output_level = 20000 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/effect/turf_decal/trimline/purple/filled/line{ + dir = 1 + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "vkJ" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -60760,6 +61023,12 @@ }, /turf/open/floor/plating, /area/maintenance/port/aft) +"vsl" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "vst" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ dir = 4 @@ -60875,6 +61144,18 @@ /obj/machinery/portable_atmospherics/canister/toxins, /turf/open/floor/plating, /area/construction/mining/aux_base) +"vuY" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "vvd" = ( /obj/structure/lattice/catwalk, /obj/structure/cable/yellow{ @@ -62529,6 +62810,13 @@ /obj/effect/landmark/start/assistant, /turf/open/floor/plasteel, /area/crew_quarters/fitness) +"wcX" = ( +/obj/machinery/airalarm{ + dir = 8; + pixel_x = 24 + }, +/turf/open/floor/plasteel/grimy, +/area/ai_monitored/turret_protected/aisat_interior) "wdb" = ( /obj/structure/door_assembly/door_assembly_mhatch, /turf/open/floor/plating, @@ -62572,14 +62860,6 @@ }, /turf/open/floor/plasteel, /area/quartermaster/office) -"wer" = ( -/obj/effect/decal/cleanable/dirt/dust, -/obj/structure/frame/machine{ - anchored = 1; - state = 2 - }, -/turf/open/floor/circuit/green/telecomms, -/area/ai_monitored/turret_protected/ai) "weD" = ( /obj/machinery/disposal/deliveryChute{ dir = 8 @@ -62753,6 +63033,12 @@ }, /turf/open/floor/plasteel, /area/security/prison) +"wjt" = ( +/obj/structure/cable/white{ + icon_state = "4-8" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "wjG" = ( /obj/structure/reagent_dispensers/water_cooler, /turf/open/floor/wood, @@ -62980,13 +63266,6 @@ }, /turf/open/floor/plasteel/white, /area/medical/chemistry) -"wnI" = ( -/obj/structure/frame/machine{ - anchored = 1; - state = 2 - }, -/turf/open/floor/circuit/green/telecomms/mainframe, -/area/ai_monitored/secondarydatacore) "wnN" = ( /obj/structure/table, /obj/item/storage/toolbox/mechanical{ @@ -64183,6 +64462,13 @@ }, /turf/open/floor/plasteel/white, /area/science/nanite) +"wOd" = ( +/obj/machinery/holopad, +/obj/machinery/door/firedoor/border_only{ + dir = 8 + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "wOj" = ( /obj/machinery/atmospherics/pipe/simple/orange/visible{ dir = 6 @@ -64433,6 +64719,14 @@ /obj/effect/turf_decal/trimline/brown/filled/warning, /turf/open/floor/plasteel, /area/quartermaster/sorting) +"wVN" = ( +/obj/structure/table, +/obj/item/storage/toolbox/mechanical, +/obj/effect/turf_decal/trimline/purple/filled/line{ + dir = 1 + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "wVP" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ dir = 4 @@ -64459,6 +64753,17 @@ /obj/machinery/light/small, /turf/open/floor/plating, /area/maintenance/aft) +"wVY" = ( +/obj/machinery/camera{ + c_tag = "MiniSat - Monitoring room"; + dir = 8; + network = list("minisat","ss13") + }, +/obj/machinery/newscaster/security_unit{ + pixel_x = 28 + }, +/turf/open/floor/plasteel/grimy, +/area/ai_monitored/turret_protected/aisat_interior) "wWl" = ( /obj/effect/turf_decal/stripes/line, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, @@ -65539,6 +65844,12 @@ /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer4, /turf/open/floor/plasteel, /area/engine/engineering) +"xAS" = ( +/obj/structure/ethernet_cable{ + icon_state = "1-8" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/secondarydatacore) "xAW" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cloth_curtain{ @@ -65773,6 +66084,12 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/wood, /area/library) +"xFQ" = ( +/obj/structure/cable/yellow{ + icon_state = "2-4" + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "xFW" = ( /obj/effect/landmark/stationroom/maint/fivexfour, /turf/template_noop, @@ -65984,6 +66301,15 @@ /obj/item/twohanded/required/kirbyplants/random, /turf/open/floor/carpet, /area/library) +"xLm" = ( +/obj/machinery/atmospherics/pipe/simple/cyan/hidden{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/open/floor/catwalk_floor/telecomms, +/area/ai_monitored/turret_protected/ai) "xLR" = ( /obj/structure/table, /obj/item/flashlight/lamp/green{ @@ -66224,6 +66550,19 @@ }, /turf/open/floor/plating, /area/maintenance/starboard) +"xRG" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/chair/office/light{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ + dir = 4 + }, +/obj/effect/landmark/start/yogs/network_admin, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/secondarydatacore) "xRO" = ( /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/trimline/yellow/filled/line{ @@ -66259,22 +66598,6 @@ }, /turf/open/floor/plating, /area/maintenance/port/aft) -"xTe" = ( -/obj/machinery/door/firedoor/border_only, -/obj/machinery/door/firedoor/border_only{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ - dir = 1 - }, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "xTZ" = ( /obj/structure/cloth_curtain{ color = "#99ccff" @@ -66338,13 +66661,6 @@ }, /turf/open/floor/plasteel/dark, /area/engine/atmos_distro) -"xUW" = ( -/obj/structure/frame/machine{ - anchored = 1; - state = 2 - }, -/turf/open/floor/circuit/green/telecomms, -/area/ai_monitored/turret_protected/ai) "xVm" = ( /obj/effect/turf_decal/trimline/purple/filled/corner{ dir = 4 @@ -97008,7 +97324,7 @@ dcc qsZ lFe rEb -cyZ +eUd kLA sYk rtp @@ -97519,7 +97835,7 @@ fPM wKU bVJ rzx -iRV +dxO aSV agz aJw @@ -107869,8 +108185,8 @@ kik eEZ jWq vmm -qzd -qLi +wcX +wVY mtW tiN gtB @@ -109405,11 +109721,11 @@ cva cva cva gQa -jzm -fIs -rGM -hbO -lbr +xFQ +txn +oDB +vsl +wjt yap cva cva @@ -109660,15 +109976,15 @@ pEf pEf cva cva -abx +eFt nLw -nDW +tPR enZ nSN xlV -dFJ +giM rjo -wer +qdb cva cva pEf @@ -109917,15 +110233,15 @@ pEf koy cva cva -lHO -rjo -rqW -rjo -hJq -sAu -dFJ -rjo -xlV +bkY +sYO +omv +sYO +jgW +agv +feK +sYO +bOz cva cva vUh @@ -110174,15 +110490,15 @@ pEf pEf cva cva -xUW +dTf rjo -rqW +aLA jTn nVK enZ -kSZ +sKT pyn -ikV +ehY cva cva pEf @@ -110433,11 +110749,11 @@ cva cva cva mWE -qJg -aSy -nJj -nTI -pnR +sDM +xLm +wOd +jKp +wjt kcr cva cva @@ -116796,7 +117112,7 @@ dRo kxz oaO bvK -fdU +acX bys bzM aDa @@ -116829,7 +117145,7 @@ atN atN atN atN -cOe +mYX fXS cOe gpq @@ -117081,11 +117397,11 @@ iKk oGM mwf oxg -uFS -sLZ -ief -tXb -oGM +tsx +pPm +pTp +pLx +bnB oGM fXS cOe @@ -117312,7 +117628,7 @@ eEA bvK bxm byu -dbJ +euD bCf aGs bvK @@ -117338,11 +117654,11 @@ rnA oGM mQY nlV -gdI -kJz -mSg -wnI -oGM +lTx +lTx +cde +hnb +oJg oGM fXS cOe @@ -117597,9 +117913,9 @@ fKM oGM oxg oxg -dBH -pDa -oGM +cde +izK +jPF oGM fXS cNW @@ -117849,14 +118165,14 @@ alj aXb xix uVI -bRR -hYY -gDs -fFO +lpZ +rzU +jJv +gcd oxg -twt -wnI -oGM +cde +izK +jkO oGM fXS bNA @@ -118107,13 +118423,13 @@ pWH pgx gxq oGM -pYv -goW -hOU +vkE +vuY +efW oxg -tQv -iiJ -oGM +cde +duc +kkY oGM fXS cOe @@ -118364,13 +118680,13 @@ aRv bQZ bQZ oGM -oGM -oGM -oGM -oGM -oGM -oGM -oGM +tEQ +sDx +lej +oxg +cde +izK +kcA oGM fXS cjE @@ -118618,17 +118934,17 @@ cOe cOe alZ aMC -cOe thv cOe -cOe -cOe -cOe -ezr oGM +nKi +xRG +bKx +bUU +lQo +xAS oGM oGM -cOe fXS cjD cjD @@ -118872,20 +119188,20 @@ lNU cNW qHY cNW -cNW +bNB cdR xHc -bNB -cNW -cOe -cOe cNW -iVk -cNW -cNW -ceR -fIH cOe +oGM +rOm +rBx +qAr +qiX +mnp +lTx +oGM +nUE mfN cjD bQq @@ -119128,22 +119444,22 @@ axl cNW cNW xSu -bMB cNW cNW -aMC -cNW cNW -cOe -cOe -bNB -cOe +aMC cNW -axl cOe -cNW -qjZ -uSq +oGM +wVN +flr +cPu +qiX +gRT +ddQ +oGM +bNA +ncw kQW iwk mNK @@ -119385,22 +119701,22 @@ cNZ cNZ bSm aWg -cNZ -cNZ -cNZ -aMD -dMA -jPU -dMA -aue -dMA -dMA -dMA -frD -piV -xTe -bCw -bKB +kYZ +bMB +cNW +mEQ +cNW +cOe +oGM +fcx +rKn +trH +oxg +nQz +iWz +oGM +cou +aob cjD shT clz @@ -119642,22 +119958,22 @@ nex cNW cNW cNW +mQO +cOe cNW +mEQ cNW -woo -cNW -cNW -cNW -cNW -cNW -cNW -cNW -cNW -umE -cNW -cNW -arG -cNW +cOe +oGM +oGM +oGM +oGM +oGM +oGM +oGM +oGM +cOe +rjl cjD cjD cjD @@ -119899,22 +120215,22 @@ iKq iKq eoH cNW -cou -cou -cae -cmo -cNW -iKq -iKq -cCG -cNW -ccW -hLb -jjr -cNW -iKq -iKq -hNs +lzq +exA +exA +cGu +aJj +aJj +aJj +aJj +aJj +aJj +aJj +gqo +aJj +pkn +lJK +nSD cNW gXs aaf @@ -120158,20 +120474,20 @@ iKq euJ cOe cOe -cae cOe -vKX -iKq -iKq -iKq -yeN +cNW +ezr cOe -wZs -jjr +cOe +axl cNW -iKq -iKq -iKq +bNB +cOe +czb +uaD +fIh +cOe +cdR cNW aaa aaa @@ -120413,22 +120729,22 @@ iKq iKq iKq cNW -chH cNW cNW +woo cNW cNW -iKq -iKq -iKq cNW -chH -cOe -tPY cNW -iKq -iKq -iKq +cNW +cNW +cNW +cNW +umE +cNW +cNW +arG +cNW cNW gXs gXs @@ -120670,22 +120986,22 @@ cNW bPp bPp cNW +cou +cou +cae +cmo cNW +iKq +iKq +cCG cNW -aaf -pEf -cNW -bPp -bPp -bPp -cNW -cNW -cNW -kRp +ccW +hLb +jjr cNW iKq iKq -iKq +hNs cNW aoV aaa @@ -120925,20 +121241,20 @@ aaf aaa aaa aaf -aaa -aaa -aoV -aaf -aaf -pEf -aaf -aaa -aaa -aaa -aaf -aaf +gXs cNW -szB +cOe +cOe +cae +cOe +vKX +iKq +iKq +iKq +yeN +cOe +wZs +jjr cNW iKq iKq @@ -121183,23 +121499,23 @@ aaa aaa aaf aaa -aaa -aoV -aaa -aaa -aag -aaf -aaa -aaa -aaa -aaa -aaf cNW -jSR +chH cNW cNW cNW cNW +iKq +iKq +iKq +cNW +chH +cOe +tPY +cNW +iKq +iKq +iKq cNW gXs gXs @@ -121290,199 +121606,8 @@ aaa aaa aaa aaa -"} -(211,1,1) = {" -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -afa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaf -aaf -aaa -aaf -aaf -aaf -aaa -aaf -gXs -gXs -aaa -aaa -aaf -aaa -aaf -aaa -aaa -aaa -aaf -aaa -aaa -aaa -aaa -aaa -pEf -aaf -aaa -aaa -aaa -aaa -aaf -aag -aag -aag -aoV -aaa -aaa -aoV -aaa -aaa -aaa -aoV -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +"} +(211,1,1) = {" aaa aaa aaa @@ -121547,8 +121672,6 @@ aaa aaa aaa aaa -"} -(212,1,1) = {" aaa aaa aaa @@ -121593,6 +121716,7 @@ aaa aaa aaa aaa +afa aaa aaa aaa @@ -121612,18 +121736,48 @@ aaa aaa aaa aaa +aaf +aaf aaa +aaf +aaf +aaf aaa +aaf +gXs +gXs aaa aaa +aaf aaa +aaf aaa aaa aaa +aaf aaa +cNW +cNW +cNW +aaf +pEf +cNW +hYR +bPp +bPp +cNW +cNW +cNW +kRp +cNW +iKq +iKq +iKq +cNW aaa aaa aaa +aoV aaa aaa aaa @@ -121677,31 +121831,24 @@ aaa aaa aaa aaa -aaf aaa aaa aaa -aaf aaa aaa -aaf aaa aaa aaa aaa -aaf aaa -aaf aaa aaa aaa -aag aaa aaa aaa aaa aaa -pEf aaa aaa aaa @@ -121709,7 +121856,6 @@ aaa aaa aaa aaa -aag aaa aaa aaa @@ -121717,6 +121863,8 @@ aaa aaa aaa aaa +"} +(212,1,1) = {" aaa aaa aaa @@ -121804,8 +121952,6 @@ aaa aaa aaa aaa -"} -(213,1,1) = {" aaa aaa aaa @@ -121847,24 +121993,44 @@ aaa aaa aaa aaa +aaf aaa aaa aaa +aaf aaa aaa +aaf aaa aaa aaa aaa +aaf aaa +aaf aaa aaa aaa +aag aaa aaa +aoV +aaf +aaf +pEf +aaf aaa aaa aaa +aaf +aaf +cNW +szB +cNW +iKq +iKq +iKq +cNW aaa aaa aaa @@ -121934,31 +122100,80 @@ aaa aaa aaa aaa -aaf aaa aaa aaa -aaf aaa aaa -aaf aaa aaa aaa aaa -aaf aaa -aaf aaa aaa aaa -aag aaa aaa aaa aaa aaa -pEf +aaa +aaa +"} +(213,1,1) = {" +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa aaa aaa aaa @@ -121966,24 +122181,113 @@ aaa aaa aaa aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaf +aaa +aaa +aaa aaf aaa aaa +aaf +aaa aaa aaa aaa +aaf aaa +aaf aaa aaa aaa +aag aaa aaa +aoV aaa aaa +aag +aaf aaa aaa aaa aaa +aaf +cNW +jSR +cNW +cNW +cNW +cNW +cNW aaa aaa aaa @@ -122061,8 +122365,6 @@ aaa aaa aaa aaa -"} -(214,1,1) = {" aaa aaa aaa @@ -122075,6 +122377,10 @@ aaa aaa aaa aaa +"} +(214,1,1) = {" +aaa +aaa aaa aaa aaa @@ -122191,44 +122497,54 @@ aaa aaa aaa aaa -aaf aaa aaa aaa -aaf aaa aaa -aag aaa aaa aaa aaa -aaf aaa aaf aaa aaa aaa +aaf +aaa +aaa aag aaa aaa aaa aaa +aaf aaa aaf aaa aaa aaa +aag +aaa aaa aaa aaa aaa +pEf aaf aaa aaa aaa aaa +aaf +aag +aag +aag +aoV +aaa aaa +aoV aaa aaa aaa @@ -122472,15 +122788,15 @@ aaa aaa aaa aaa +pEf aaa aaa aaa aaa -aae aaa aaa aaa -aaf +aag aaa aaa aaa @@ -122729,7 +123045,7 @@ aaa aaa aaa aaa -aaa +pEf aaa aaa aaa @@ -122986,6 +123302,7 @@ aaa aaa aaa aaa +aaf aaa aaa aaa @@ -122993,8 +123310,7 @@ aaa aaa aaa aaa -aaa -aaa +aaf aaa aaa aaa @@ -123247,11 +123563,11 @@ aaa aaa aaa aaa +aae aaa aaa aaa -aaa -aaa +aaf aaa aaa aaa @@ -123508,7 +123824,7 @@ aaa aaa aaa aaa -aaa +aaf aaa aaa aaa diff --git a/_maps/map_files/YogsDelta/YogsDelta.dmm b/_maps/map_files/YogsDelta/YogsDelta.dmm index 2273af75c1c4..760b2e907fde 100644 --- a/_maps/map_files/YogsDelta/YogsDelta.dmm +++ b/_maps/map_files/YogsDelta/YogsDelta.dmm @@ -66011,7 +66011,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, -/obj/machinery/computer/ai_control_console{ +{ dir = 1 }, /turf/open/floor/plasteel/dark, @@ -66054,9 +66054,6 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, -/obj/machinery/computer/ai_resource_distribution{ - dir = 1 - }, /turf/open/floor/plasteel/dark, /area/ai_monitored/turret_protected/aisat_interior) "cao" = ( @@ -81321,9 +81318,6 @@ /turf/open/floor/plating, /area/maintenance/port/aft) "cAD" = ( -/obj/machinery/computer/ai_resource_distribution{ - dir = 1 - }, /turf/open/floor/plasteel/dark, /area/ai_monitored/secondarydatacore) "cAE" = ( @@ -127272,7 +127266,7 @@ /obj/structure/table/reinforced, /obj/item/aicard, /obj/effect/turf_decal/bot, -/obj/item/circuitboard/computer/ai_upload_download, +, /obj/item/disk/holodisk/tutorial/AICore, /turf/open/floor/plasteel, /area/crew_quarters/heads/hor) diff --git a/code/__DEFINES/ai.dm b/code/__DEFINES/ai.dm index 85ea68c70876..11106b57a5ce 100644 --- a/code/__DEFINES/ai.dm +++ b/code/__DEFINES/ai.dm @@ -61,3 +61,24 @@ GLOBAL_LIST_INIT(ai_project_categories, list( #define MAX_AI_BITCOIN_MINED_PER_TICK 350 //Self explanatory, see MAX_AI_BITCOIN_MINED_PER_TICK * this = max money 1 AI can contribute per tick. (17,5 credits every 2 seconds, max 63k over 2 hours) #define AI_BITCOIN_PRICE 0.05 + + +//How much RAM and CPU a core needs locally to be functional +#define AI_CORE_CPU_REQUIREMENT 1 +#define AI_CORE_RAM_REQUIREMENT 1 + +//For network based research and tasks. Since each network are going to contribute to a "global" pool of research there's no point in making this more complicated or modular +//Adding an entry here automatically adds it to the UI and allows CPU to be allocated. Just use your define in the network process() to do stuff +#define AI_CRYPTO "Cryptocurrency Mining" + +GLOBAL_LIST_INIT(possible_ainet_activities, list( + "[AI_CRYPTO]" +)) + +GLOBAL_LIST_INIT(ainet_activity_tagline, list( + "[AI_CRYPTO]" = "Use CPU to generate credits!" +)) + +GLOBAL_LIST_INIT(ainet_activity_description, list( + "[AI_CRYPTO]" = "Using CPU to mine NTCoin should allow for a meager sum of passive credit income." +)) diff --git a/code/__DEFINES/footsteps.dm b/code/__DEFINES/footsteps.dm index b1af0b7cd6f5..a95acefa16f6 100644 --- a/code/__DEFINES/footsteps.dm +++ b/code/__DEFINES/footsteps.dm @@ -6,6 +6,7 @@ #define FOOTSTEP_GRASS "grass" #define FOOTSTEP_WATER "water" #define FOOTSTEP_LAVA "lava" +#define FOOTSTEP_CATWALK "catwalk" //barefoot sounds #define FOOTSTEP_WOOD_BAREFOOT "woodbarefoot" #define FOOTSTEP_WOOD_CLAW "woodclaw" @@ -71,6 +72,12 @@ GLOBAL_LIST_INIT(footstep, list( 'sound/effects/footstep/lava1.ogg', 'sound/effects/footstep/lava2.ogg', 'sound/effects/footstep/lava3.ogg'), 100, 0), + FOOTSTEP_CATWALK = list(list( + 'sound/effects/footstep/catwalk1.ogg', + 'sound/effects/footstep/catwalk2.ogg', + 'sound/effects/footstep/catwalk3.ogg', + 'sound/effects/footstep/catwalk4.ogg', + 'sound/effects/footstep/catwalk5.ogg'), 100, 1), )) //bare footsteps lists GLOBAL_LIST_INIT(barefootstep, list( diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index b7389061fba6..6f8bf703e1a9 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -28,6 +28,7 @@ #define LATTICE_LAYER 2.2 #define DISPOSAL_PIPE_LAYER 2.25 #define GAS_PIPE_HIDDEN_LAYER 2.35 //layer = initial(layer) + piping_layer / 1000 in atmospherics/update_icon() to determine order of pipe overlap +#define ETHERNET_LAYER 2.38 #define WIRE_LAYER 2.4 #define WIRE_TERMINAL_LAYER 2.45 #define UNDER_CATWALK 2.454 diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm index d9fdd3d79a75..8ae6027d1b3e 100644 --- a/code/__DEFINES/machines.dm +++ b/code/__DEFINES/machines.dm @@ -47,6 +47,7 @@ #define MC_CHARGE "CHARGE" #define MC_AI "AI" #define MC_SENSORS "SENSORS" +#define MC_AI_NETWORK "AINETWORK" //NTNet stuff, for modular computers // NTNet module-configuration values. Do not change these. If you need to add another use larger number (5..6..7 etc) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index b4455e63a8e1..e33fd3c38b8c 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -8,6 +8,10 @@ #define Z_TURFS(ZLEVEL) block(locate(1,1,ZLEVEL), locate(world.maxx, world.maxy, ZLEVEL)) #define CULT_POLL_WAIT 2400 +#define UNDERFLOOR_HIDDEN 0 +#define UNDERFLOOR_VISIBLE 1 +#define UNDERFLOOR_INTERACTABLE 2 + /proc/get_area_name(atom/X, format_text = FALSE, is_sensor = FALSE) var/area/A = isarea(X) ? X : get_area(X) if(!A) diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index 331f30de8bd1..eb469d6bd9e3 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -1,4 +1,5 @@ GLOBAL_LIST_EMPTY(cable_list) //Index for all cables, so that powernets don't have to look through the entire world all the time +GLOBAL_LIST_EMPTY(ethernet_cable_list) //Index for all ethernet cables, so that ainets don't have to look through the entire world all the time GLOBAL_LIST_EMPTY(portals) //list of all /obj/effect/portal GLOBAL_LIST_EMPTY(airlocks) //list of all airlocks GLOBAL_LIST_EMPTY(mechas_list) //list of all mechs. Used by hostile mobs target tracking. @@ -8,7 +9,7 @@ GLOBAL_LIST_EMPTY(navigation_computers) //list of all /obj/machinery/computer GLOBAL_LIST_EMPTY(syndicate_shuttle_boards) //important to keep track of for managing nukeops war declarations. GLOBAL_LIST_EMPTY(navbeacons) //list of all bot nagivation beacons, used for patrolling. GLOBAL_LIST_EMPTY(teleportbeacons) //list of all tracking beacons used by teleporters -GLOBAL_LIST_EMPTY(deliverybeacons) //list of all MULEbot delivery beacons. +GLOBAL_LIST_EMPTY(deliverybeacons) //lisAt of all MULEbot delivery beacons. GLOBAL_LIST_EMPTY(deliverybeacontags) //list of all tags associated with delivery beacons. GLOBAL_LIST_EMPTY(nuke_list) GLOBAL_LIST_EMPTY(alarmdisplay) //list of all machines or programs that can display station alerts diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 99bfb0a61c5b..50b3c4928858 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -256,6 +256,21 @@ SUBSYSTEM_DEF(job) return TRUE return FALSE +/datum/controller/subsystem/job/proc/FillNetminPosition() + var/datum/job/job = GetJob("Network Admin") + if(!job) + return + for(var/i = job.total_positions, i > 0, i--) + if(job.current_positions >= job.total_positions) //If we assign a netmin before this proc is run, (malf rework?) + return TRUE + for(var/level in level_order) + var/list/candidates = list() + candidates = FindOccupationCandidates(job, level) + if(candidates.len) + var/mob/dead/new_player/candidate = pick(candidates) + if(AssignRole(candidate, "Network Admin")) + break + /// Rolls a number of security based on the roundstart population /datum/controller/subsystem/job/proc/FillSecurityPositions() var/coeff = CONFIG_GET(number/min_security_scaling_coeff) @@ -339,7 +354,8 @@ SUBSYSTEM_DEF(job) //Check for an AI JobDebug("DO, Running AI Check") - FillAIPosition() + if(FillAIPosition()) + FillNetminPosition() JobDebug("DO, AI Check end") //Check for Security diff --git a/code/controllers/subsystem/machines.dm b/code/controllers/subsystem/machines.dm index 3c641fac1e62..b176fc561da5 100644 --- a/code/controllers/subsystem/machines.dm +++ b/code/controllers/subsystem/machines.dm @@ -5,9 +5,11 @@ SUBSYSTEM_DEF(machines) var/list/processing = list() var/list/currentrun = list() var/list/powernets = list() + var/list/ainets = list() /datum/controller/subsystem/machines/Initialize() makepowernets() + makeainets() fire() return ..() @@ -22,8 +24,22 @@ SUBSYSTEM_DEF(machines) NewPN.add_cable(PC) propagate_network(PC,PC.powernet) +/datum/controller/subsystem/machines/proc/makeainets() + for(var/datum/ai_network/AN in ainets) + qdel(AN) + ainets.Cut() + + for(var/obj/structure/ethernet_cable/EC in GLOB.ethernet_cable_list) + if(!EC.network) + var/datum/ai_network/NewAN = new() + NewAN.add_cable(EC) + propagate_ai_network(EC,EC.network) + + for(var/obj/machinery/ai/networking/N in GLOB.ai_networking_machines) + N.roundstart_connect() + /datum/controller/subsystem/machines/stat_entry(msg) - msg = "M:[length(processing)]|PN:[length(powernets)]" + msg = "M:[length(processing)]|PN:[length(powernets)]|AN:[length(ainets)]" return ..() @@ -58,8 +74,18 @@ SUBSYSTEM_DEF(machines) NewPN.add_cable(PC) propagate_network(PC,PC.powernet) +/datum/controller/subsystem/machines/proc/setup_template_ainets(list/cables) + for(var/A in cables) + var/obj/structure/ethernet_cable/PC = A + if(!PC.network) + var/datum/ai_network/NewPN = new() + NewPN.add_cable(PC) + propagate_ai_network(PC,PC.network) + /datum/controller/subsystem/machines/Recover() if (istype(SSmachines.processing)) processing = SSmachines.processing if (istype(SSmachines.powernets)) powernets = SSmachines.powernets + if (istype(SSmachines.ainets)) + ainets = SSmachines.ainets diff --git a/code/controllers/subsystem/minor_mapping.dm b/code/controllers/subsystem/minor_mapping.dm index d9e137bf2299..44f16d4890ff 100644 --- a/code/controllers/subsystem/minor_mapping.dm +++ b/code/controllers/subsystem/minor_mapping.dm @@ -39,7 +39,7 @@ SUBSYSTEM_DEF(minor_mapping) while(turfs.len && amount > 0) var/turf/T = pick_n_take(turfs) var/obj/item/storage/backpack/satchel/flat/S = new(T) - S.hide(intact=TRUE) + S.hide(intact=(T.underfloor_accessibility < UNDERFLOOR_VISIBLE)) amount-- diff --git a/code/game/machinery/Beacon.dm b/code/game/machinery/Beacon.dm index 8d849c8c145e..bb8c481f4c68 100644 --- a/code/game/machinery/Beacon.dm +++ b/code/game/machinery/Beacon.dm @@ -16,7 +16,7 @@ Beacon = new(T) Beacon.invisibility = INVISIBILITY_MAXIMUM - hide(T.intact) + hide(T.underfloor_accessibility < UNDERFLOOR_VISIBLE) /obj/machinery/bluespace_beacon/Destroy() QDEL_NULL(Beacon) diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index cce089a75e6a..da53b455f929 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -363,15 +363,6 @@ new /obj/item/card/id/captains_spare/temporary(loc) COOLDOWN_START(src, important_action_cooldown, IMPORTANT_ACTION_COOLDOWN) priority_announce("The emergency spare ID has been printed by [authorize_name].", "Emergency Spare ID Warning System", RANDOM_REPORT_SOUND) - if("printAIControlCode") - if(authenticated_as_non_silicon_head(usr)) - if(!COOLDOWN_FINISHED(src, important_action_cooldown)) - return - playsound(loc, 'sound/items/poster_being_created.ogg', 100, 1) - GLOB.ai_control_code = random_nukecode(6) - new /obj/item/paper/ai_control_code(loc) - COOLDOWN_START(src, important_action_cooldown, IMPORTANT_ACTION_COOLDOWN) - priority_announce("The AI Control Code been printed by [authorize_name]. All previous codes have been invalidated.", "Central Tech Support", RANDOM_REPORT_SOUND) /obj/machinery/computer/communications/ui_data(mob/user) diff --git a/code/game/machinery/magnet.dm b/code/game/machinery/magnet.dm index 0110312e5634..158db804d677 100644 --- a/code/game/machinery/magnet.dm +++ b/code/game/machinery/magnet.dm @@ -30,7 +30,7 @@ /obj/machinery/magnetic_module/Initialize() ..() var/turf/T = loc - hide(T.intact) + hide(T.underfloor_accessibility < UNDERFLOOR_VISIBLE) center = T SSradio.add_object(src, freq, RADIO_MAGNETS) return INITIALIZE_HINT_LATELOAD diff --git a/code/game/machinery/navbeacon.dm b/code/game/machinery/navbeacon.dm index c70c592003f2..58a1f425eaa9 100644 --- a/code/game/machinery/navbeacon.dm +++ b/code/game/machinery/navbeacon.dm @@ -27,7 +27,7 @@ set_codes() var/turf/T = loc - hide(T.intact) + hide(T.underfloor_accessibility < UNDERFLOOR_VISIBLE) if(codes["patrol"]) if(!GLOB.navbeacons["[z]"]) GLOB.navbeacons["[z]"] = list() @@ -86,8 +86,8 @@ /obj/machinery/navbeacon/attackby(obj/item/I, mob/user, params) var/turf/T = loc - if(T.intact) - return // prevent intraction when T-scanner revealed + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) + return // prevent intraction when T-scanner revealed if(I.tool_behaviour == TOOL_SCREWDRIVER) open = !open @@ -119,9 +119,8 @@ . = ..() var/ai = isAI(user) var/turf/T = loc - if(T.intact) - return // prevent intraction when T-scanner revealed - + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) + return // prevent intraction when T-scanner revealed if(!open && !ai) // can't alter controls if not open, unless you're an AI to_chat(user, span_warning("The beacon's control cover is closed!")) return diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm index 595356289b9b..dd3f0ef360df 100644 --- a/code/game/mecha/equipment/tools/work_tools.dm +++ b/code/game/mecha/equipment/tools/work_tools.dm @@ -450,7 +450,7 @@ if(!T.broken && !T.burnt) new T.floor_tile(T) T.make_plating() - return !new_turf.intact + return !(new_turf.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) /obj/item/mecha_parts/mecha_equipment/cable_layer/proc/layCable(var/turf/new_turf) if(equip_ready || !istype(new_turf) || !dismantleFloor(new_turf)) diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm index 3c8e2843d528..f94e0596c748 100644 --- a/code/game/objects/effects/effect_system/effects_foam.dm +++ b/code/game/objects/effects/effect_system/effects_foam.dm @@ -146,7 +146,7 @@ continue if(isturf(O.loc)) var/turf/T = O.loc - if(T.intact && O.level == 1) //hidden under the floor + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE && O.level == 1) //hidden under the floor continue if(lifetime % reagent_divisor) reagents.reaction(O, VAPOR, fraction) diff --git a/code/game/objects/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm index e83f4da302a0..e28dba3d7315 100644 --- a/code/game/objects/effects/effect_system/effects_smoke.dm +++ b/code/game/objects/effects/effect_system/effects_smoke.dm @@ -230,7 +230,7 @@ for(var/atom/movable/AM in T) if(AM.type == src.type) continue - if(T.intact && AM.level == 1) //hidden under the floor + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE && AM.level == 1) //hidden under the floor continue reagents.reaction(AM, TOUCH, fraction) diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm index df6723de0afb..06a848f31c88 100644 --- a/code/game/objects/effects/spawners/lootdrop.dm +++ b/code/game/objects/effects/spawners/lootdrop.dm @@ -534,7 +534,6 @@ name = "secure AI circuit board spawner" loot = list( /obj/item/circuitboard/computer/aiupload, - /obj/item/circuitboard/computer/ai_upload_download, /obj/item/circuitboard/computer/borgupload ) diff --git a/code/game/objects/items/RCL.dm b/code/game/objects/items/RCL.dm index da0e1b9891fb..dfe4938c9e6f 100644 --- a/code/game/objects/items/RCL.dm +++ b/code/game/objects/items/RCL.dm @@ -178,7 +178,7 @@ if(last) if(get_dist(last, user) == 1) //hacky, but it works var/turf/T = get_turf(user) - if(T.intact || !T.can_have_cabling()) + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE || !T.can_have_cabling()) last = null return if(get_dir(last, user) == last.d2) @@ -203,7 +203,7 @@ return T = get_turf(user) - if(T.intact || !T.can_have_cabling()) + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE || !T.can_have_cabling()) return for(var/obj/structure/cable/C in T) @@ -263,7 +263,7 @@ return var/turf/T = get_turf(user) - if(T.intact || !T.can_have_cabling()) + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE || !T.can_have_cabling()) return loaded.color = colors[current_color_index] diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm index 32ee802d8443..204d0b9ecc03 100644 --- a/code/game/objects/items/circuitboards/computer_circuitboards.dm +++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm @@ -393,20 +393,12 @@ name = "Shuttle Navigation Computer (Computer Board)" build_path = /obj/machinery/computer/camera_advanced/shuttle_docker/custom -/obj/item/circuitboard/computer/ai_upload_download - name = "AI Control Console (Computer Board)" - icon_state = "science" - build_path = /obj/machinery/computer/ai_control_console /obj/item/circuitboard/computer/ai_server_overview name = "AI Server Overview Console (Computer Board)" icon_state = "science" build_path = /obj/machinery/computer/ai_server_console -/obj/item/circuitboard/computer/ai_resource_distribution - name = "AI Resource Distribution Console (Computer Board)" - icon_state = "science" - build_path = /obj/machinery/computer/ai_resource_distribution //Security diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm index 449e9e660fa2..eef412632548 100644 --- a/code/game/objects/items/devices/powersink.dm +++ b/code/game/objects/items/devices/powersink.dm @@ -63,7 +63,7 @@ if(I.tool_behaviour == TOOL_SCREWDRIVER) if(mode == DISCONNECTED) var/turf/T = loc - if(isturf(T) && !T.intact) + if(isturf(T) && T.underfloor_accessibility >= UNDERFLOOR_INTERACTABLE) attached = locate() in T if(!attached) to_chat(user, span_warning("This device must be placed over an exposed, powered cable node!")) diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm index 0e4bd241045b..ea04b5bdac18 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -10,6 +10,7 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \ new/datum/stack_recipe("fore port spacepod frame", /obj/item/pod_parts/pod_frame/fore_port, 15, time = 30, one_per_turf = 0), \ new/datum/stack_recipe("fore starboard spacepod frame", /obj/item/pod_parts/pod_frame/fore_starboard, 15, time = 30, one_per_turf = 0), \ new/datum/stack_recipe("aft port spacepod frame", /obj/item/pod_parts/pod_frame/aft_port, 15, time = 30, one_per_turf = 0), \ + new/datum/stack_recipe("catwalk floor tile", /obj/item/stack/tile/catwalk_tile, 1, 4, 20), \ new/datum/stack_recipe("aft starboard spacepod frame", /obj/item/pod_parts/pod_frame/aft_starboard, 15, time = 30, one_per_turf = 0), \ // yogs end )) diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index 8f0808ac5bda..86c650ad937f 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -403,3 +403,52 @@ /obj/item/stack/tile/eighties/loaded amount = 15 + +//Catwalk Tiles +/obj/item/stack/tile/catwalk_tile //This is our base type, sprited to look maintenance-styled + name = "catwalk plating" + singular_name = "catwalk plating tile" + desc = "Flooring that shows its contents underneath. Engineers love it!" + icon_state = "maint_catwalk" + materials = list(/datum/material/iron=100) + turf_type = /turf/open/floor/catwalk_floor + merge_type = /obj/item/stack/tile/catwalk_tile //Just to be cleaner, these all stack with eachother + +/obj/item/stack/tile/catwalk_tile/sixty + amount = 60 + +/obj/item/stack/tile/catwalk_tile/iron + name = "iron catwalk floor" + singular_name = "iron catwalk floor tile" + icon_state = "iron_catwalk" + turf_type = /turf/open/floor/catwalk_floor/iron + +/obj/item/stack/tile/catwalk_tile/iron_white + name = "white catwalk floor" + singular_name = "white catwalk floor tile" + icon_state = "whiteiron_catwalk" + turf_type = /turf/open/floor/catwalk_floor/iron_white + +/obj/item/stack/tile/catwalk_tile/iron_dark + name = "dark catwalk floor" + singular_name = "dark catwalk floor tile" + icon_state = "darkiron_catwalk" + turf_type = /turf/open/floor/catwalk_floor/iron_dark + +/obj/item/stack/tile/catwalk_tile/flat_white + name = "flat white catwalk floor" + singular_name = "flat white catwalk floor tile" + icon_state = "flatwhite_catwalk" + turf_type = /turf/open/floor/catwalk_floor/flat_white + +/obj/item/stack/tile/catwalk_tile/titanium + name = "titanium catwalk floor" + singular_name = "titanium catwalk floor tile" + icon_state = "titanium_catwalk" + turf_type = /turf/open/floor/catwalk_floor/titanium + +/obj/item/stack/tile/catwalk_tile/iron_smooth //this is the greenish one + name = "smooth iron catwalk floor" + singular_name = "smooth iron catwalk floor tile" + icon_state = "smoothiron_catwalk" + turf_type = /turf/open/floor/catwalk_floor/iron_smooth diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 2a2405095db4..f8b76f338ac3 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -102,7 +102,7 @@ /obj/blob_act(obj/structure/blob/B) if(isturf(loc)) var/turf/T = loc - if(T.intact && level == 1) //the blob doesn't destroy thing below the floor + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE && level == 1) //the blob doesn't destroy thing below the floor return take_damage(400, BRUTE, MELEE, 0, get_dir(src, B)) @@ -213,7 +213,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e /obj/fire_act(exposed_temperature, exposed_volume) if(isturf(loc)) var/turf/T = loc - if(T.intact && level == 1) //fire can't damage things hidden below the floor. + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE && level == 1) //fire can't damage things hidden below the floor. return if(exposed_temperature && !(resistance_flags & FIRE_PROOF)) take_damage(clamp(0.02 * exposed_temperature, 0, 20), BURN, FIRE, 0) diff --git a/code/game/objects/structures/signs/signs_plaques.dm b/code/game/objects/structures/signs/signs_plaques.dm index 3220e0523054..216ba23cf52b 100644 --- a/code/game/objects/structures/signs/signs_plaques.dm +++ b/code/game/objects/structures/signs/signs_plaques.dm @@ -26,21 +26,6 @@ desc = "Next to the extremely long list of names and job titles, there is a drawing of a little child. The child appears to be retarded. Beneath the image, someone has scratched the word \"PACKETS\"." icon_state = "kiddieplaque" -/obj/structure/sign/plaques/ai_password - name = "\improper AI default password" - desc = "This plaque contains the default password for AI control consoles onboard this station." - var/control_code = "BUG" - -/obj/structure/sign/plaques/ai_password/Initialize(mapload) - . = ..() - control_code = GLOB.ai_control_code - -/obj/structure/sign/plaques/ai_password/examine(mob/living/user) - . = ..() - if(Adjacent(user)) - . += span_notice("The following digits are stamped into the plaque: [control_code]") - else - . += span_notice("You must be closer to read the code.") /obj/structure/sign/plaques/kiddie/badger name = "\improper Remembrance Plaque" diff --git a/code/game/turfs/openspace/openspace.dm b/code/game/turfs/openspace/openspace.dm index 1cf670c3da6e..0d861d897505 100644 --- a/code/game/turfs/openspace/openspace.dm +++ b/code/game/turfs/openspace/openspace.dm @@ -7,6 +7,8 @@ //mouse_opacity = MOUSE_OPACITY_TRANSPARENT var/can_cover_up = TRUE var/can_build_on = TRUE + overfloor_placed = FALSE + underfloor_accessibility = UNDERFLOOR_INTERACTABLE /turf/open/openspace/debug/update_multiz() ..() diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index 4101efd3ac69..dfe5b6c73072 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -16,9 +16,11 @@ var/icon_plating = "plating" thermal_conductivity = 0.040 heat_capacity = 10000 - intact = 1 + var/broken = 0 var/burnt = 0 + + overfloor_placed = TRUE var/floor_tile = null //tile that this floor drops var/list/broken_states var/list/burnt_states @@ -172,7 +174,7 @@ return 1 if(..()) return 1 - if(intact && istype(C, /obj/item/stack/tile)) + if(overfloor_placed && istype(C, /obj/item/stack/tile)) try_replace_tile(C, user, params) return 0 @@ -180,7 +182,7 @@ if(istype(I,/obj/item/jawsoflife/jimmy)) to_chat(user,"The [I] cannot pry tiles.") return - return intact ? pry_tile(I, user) : FALSE + return overfloor_placed ? pry_tile(I, user) : FALSE /turf/open/floor/proc/try_replace_tile(obj/item/stack/tile/T, mob/user, params) if(T.turf_type == type) diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index 4614d4f06669..cd086783fd72 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -10,7 +10,8 @@ /turf/open/floor/plating name = "plating" icon_state = "plating" - intact = FALSE + overfloor_placed = FALSE + underfloor_accessibility = UNDERFLOOR_INTERACTABLE baseturfs = /turf/baseturf_bottom footstep = FOOTSTEP_PLATING barefootstep = FOOTSTEP_HARD_BAREFOOT diff --git a/code/game/turfs/simulated/floor/plating/catwalk_plating.dm b/code/game/turfs/simulated/floor/plating/catwalk_plating.dm new file mode 100644 index 000000000000..0339cac2be89 --- /dev/null +++ b/code/game/turfs/simulated/floor/plating/catwalk_plating.dm @@ -0,0 +1,103 @@ +/** + * ## catwalk flooring + * + * They show what's underneath their catwalk flooring (pipes and the like) + * you can screwdriver it to interact with the underneath stuff without destroying the tile... + * unless you want to! + */ +/turf/open/floor/catwalk_floor //the base type, meant to look like a maintenance panel + icon = 'icons/turf/floors/catwalk_plating.dmi' + icon_state = "maint_above" + name = "catwalk floor" + desc = "Flooring that shows its contents underneath. Engineers love it!" + baseturfs = /turf/open/floor/plating + floor_tile = /obj/item/stack/tile/catwalk_tile + layer = CATWALK_LAYER + plane = GAME_PLANE + footstep = FOOTSTEP_CATWALK + overfloor_placed = TRUE + underfloor_accessibility = UNDERFLOOR_VISIBLE + var/covered = TRUE + var/catwalk_type = "maint" + var/static/list/catwalk_underlays = list() + +/turf/open/floor/catwalk_floor/Initialize(mapload) + . = ..() + if(!catwalk_underlays[catwalk_type]) + var/mutable_appearance/plating_underlay = mutable_appearance(icon, "[catwalk_type]_below", TURF_LAYER) + catwalk_underlays[catwalk_type] = plating_underlay + underlays += catwalk_underlays[catwalk_type] + update_icon() + +/turf/open/floor/catwalk_floor/examine(mob/user) + . = ..() + + if(covered) + . += span_notice("You can unscrew it to reveal the contents beneath.") + else + . += span_notice("You can screw it to hide the contents beneath.") + . += span_notice("There's a small crack on the edge of it.") + +/turf/open/floor/catwalk_floor/screwdriver_act(mob/living/user, obj/item/tool) + . = ..() + covered = !covered + if(!covered) + underfloor_accessibility = UNDERFLOOR_INTERACTABLE + layer = TURF_LAYER + plane = FLOOR_PLANE + icon_state = "[catwalk_type]_below" + else + underfloor_accessibility = UNDERFLOOR_VISIBLE + layer = CATWALK_LAYER + plane = GAME_PLANE + icon_state = "[catwalk_type]_above" + user.balloon_alert(user, "[!covered ? "cover removed" : "cover added"]") + tool.play_tool_sound(src) + update_icon() + +/turf/open/floor/catwalk_floor/crowbar_act(mob/user, obj/item/crowbar) + if(covered) + user.balloon_alert(user, "remove cover first!") + return FALSE + . = ..() + +//Reskins! More fitting with most of our tiles, and appear as a radial on the base type +/turf/open/floor/catwalk_floor/iron + name = "iron plated catwalk floor" + icon_state = "iron_above" + floor_tile = /obj/item/stack/tile/catwalk_tile/iron + catwalk_type = "iron" + + +/turf/open/floor/catwalk_floor/iron_white + name = "white plated catwalk floor" + icon_state = "whiteiron_above" + floor_tile = /obj/item/stack/tile/catwalk_tile/iron_white + catwalk_type = "whiteiron" + +/turf/open/floor/catwalk_floor/iron_dark + name = "dark plated catwalk floor" + icon_state = "darkiron_above" + floor_tile = /obj/item/stack/tile/catwalk_tile/iron_dark + catwalk_type = "darkiron" + +/turf/open/floor/catwalk_floor/flat_white + name = "white large plated catwalk floor" + icon_state = "flatwhite_above" + floor_tile = /obj/item/stack/tile/catwalk_tile/flat_white + catwalk_type = "flatwhite" + +/turf/open/floor/catwalk_floor/titanium + name = "titanium plated catwalk floor" + icon_state = "titanium_above" + floor_tile = /obj/item/stack/tile/catwalk_tile/titanium + catwalk_type = "titanium" + +/turf/open/floor/catwalk_floor/iron_smooth //the original green type + name = "smooth plated catwalk floor" + icon_state = "smoothiron_above" + floor_tile = /obj/item/stack/tile/catwalk_tile/iron_smooth + catwalk_type = "smoothiron" + +/turf/open/floor/catwalk_floor/telecomms + initial_gas_mix = TCOMMS_ATMOS diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index 537bf53e53ba..24e352f25198 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -2,7 +2,8 @@ icon = 'icons/turf/space.dmi' icon_state = "0" name = "\proper space" - intact = 0 + overfloor_placed = FALSE + underfloor_accessibility = UNDERFLOOR_INTERACTABLE temperature = TCMB thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index b54880c5725e..086d4712d2bc 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -4,7 +4,10 @@ GLOBAL_LIST_EMPTY(station_turfs) icon = 'icons/turf/floors.dmi' level = 1 - var/intact = 1 + /// If there's a tile over a basic floor that can be ripped out + var/overfloor_placed = FALSE + /// How accessible underfloor pieces such as wires, pipes, etc are on this turf. Can be HIDDEN, VISIBLE, or INTERACTABLE. + var/underfloor_accessibility = UNDERFLOOR_HIDDEN // baseturfs can be either a list or a single turf type. // In class definition like here it should always be a single type. @@ -201,6 +204,15 @@ GLOBAL_LIST_EMPTY(station_turfs) coil.place_turf(src, user) return TRUE + if(can_lay_cable() && istype(C, /obj/item/stack/ethernet_coil)) + var/obj/item/stack/ethernet_coil/coil = C + for(var/obj/structure/ethernet_cable/LC in src) + if(!LC.d1 || !LC.d2) + LC.attackby(C,user) + return + coil.place_turf(src, user) + return TRUE + else if(istype(C, /obj/item/twohanded/rcl)) handleRCL(C, user) @@ -328,7 +340,7 @@ GLOBAL_LIST_EMPTY(station_turfs) /turf/proc/levelupdate() for(var/obj/O in src) if(O.level == 1 && (O.flags_1 & INITIALIZED_1)) - O.hide(src.intact) + O.hide(underfloor_accessibility < UNDERFLOOR_VISIBLE) // override for space turfs, since they should never hide anything /turf/open/space/levelupdate() @@ -390,7 +402,7 @@ GLOBAL_LIST_EMPTY(station_turfs) //////////////////////////////////////////////////// /turf/singularity_act() - if(intact) + if(underfloor_accessibility < UNDERFLOOR_INTERACTABLE) for(var/obj/O in contents) //this is for deleting things like wires contained in the turf if(O.level != 1) continue @@ -403,7 +415,7 @@ GLOBAL_LIST_EMPTY(station_turfs) return TRUE /turf/proc/can_lay_cable() - return can_have_cabling() & !intact + return can_have_cabling() && underfloor_accessibility >= UNDERFLOOR_INTERACTABLE /turf/proc/visibilityChanged() GLOB.cameranet.updateVisibility(src) @@ -478,7 +490,7 @@ GLOBAL_LIST_EMPTY(station_turfs) acid_type = /obj/effect/acid/alien var/has_acid_effect = FALSE for(var/obj/O in src) - if(intact && O.level == 1) //hidden under the floor + if(underfloor_accessibility < UNDERFLOOR_INTERACTABLE && O.level == 1) //hidden under the floor continue if(istype(O, acid_type)) var/obj/effect/acid/A = O diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 014bd9421ab1..a24a4c04fd86 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -1123,3 +1123,11 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention) return if(alert(usr, "Are you absolutely sure you want to reload the configuration from the default path on the disk, wiping any in-round modificatoins?", "Really reset?", "No", "Yes") == "Yes") config.admin_reload() + +/client/proc/debug_ai_networks() + set category = "Misc.Server Debug" + set name = "Debug AI Networks" + set desc = "Displays a list of all AI networks to ALL admins" + if(!check_rights(R_DEBUG)) + return + _debug_ai_networks() diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 8b1368e57938..41d36ea8cdc5 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -76,6 +76,7 @@ GLOBAL_LIST_INIT(admin_verbs_debug_all, list( /client/proc/cmd_display_init_log, /client/proc/cmd_display_overlay_log, /client/proc/reload_configuration, + /client/proc/debug_ai_networks, /datum/admins/proc/create_or_modify_area, /client/proc/debug_typeof, // Yogs -- Adds a debug verb for getting the subtypes of something /client/proc/toggle_cdn diff --git a/code/modules/antagonists/blob/blob_report.dm b/code/modules/antagonists/blob/blob_report.dm index f0d46888c2f6..d8ee7857d635 100644 --- a/code/modules/antagonists/blob/blob_report.dm +++ b/code/modules/antagonists/blob/blob_report.dm @@ -29,15 +29,11 @@ floor += 1 if(iswallturf(T)) - var/turf/closed/wall/TW = T - if(TW.intact) - wall += 2 - else - wall += 1 + wall += 1 if(istype(T, /turf/closed/wall/r_wall)) var/turf/closed/wall/r_wall/TRW = T - if(TRW.intact) + if(TRW.d_state == INTACT) r_wall += 2 else r_wall += 1 diff --git a/code/modules/antagonists/revenant/revenant_abilities.dm b/code/modules/antagonists/revenant/revenant_abilities.dm index 70cad681d522..ba330090874a 100644 --- a/code/modules/antagonists/revenant/revenant_abilities.dm +++ b/code/modules/antagonists/revenant/revenant_abilities.dm @@ -244,7 +244,7 @@ if(!isplatingturf(T) && !istype(T, /turf/open/floor/engine/cult) && isfloorturf(T) && prob(15)) var/turf/open/floor/floor = T - if(floor.intact && floor.floor_tile) + if(floor.overfloor_placed && floor.floor_tile) new floor.floor_tile(floor) floor.broken = 0 floor.burnt = 0 diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm index 587100913ea5..9260e12a0304 100644 --- a/code/modules/atmospherics/machinery/atmosmachinery.dm +++ b/code/modules/atmospherics/machinery/atmosmachinery.dm @@ -191,7 +191,7 @@ GLOBAL_LIST_EMPTY(pipeimages) return ..() var/turf/T = get_turf(src) - if (level==1 && isturf(T) && T.intact) + if (level==1 && isturf(T) && T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) to_chat(user, span_warning("You must remove the plating first!")) return TRUE @@ -277,7 +277,7 @@ GLOBAL_LIST_EMPTY(pipeimages) pipe_color = obj_color setPipingLayer(set_layer) var/turf/T = get_turf(src) - level = T.intact ? 2 : 1 + level = (T.underfloor_accessibility < UNDERFLOOR_VISIBLE) ? 2 : 1 atmosinit() var/list/nodes = pipeline_expansion() for(var/obj/machinery/atmospherics/A in nodes) diff --git a/code/modules/atmospherics/machinery/pipes/layermanifold.dm b/code/modules/atmospherics/machinery/pipes/layermanifold.dm index 00285a5f77d1..fae5d24afd7d 100644 --- a/code/modules/atmospherics/machinery/pipes/layermanifold.dm +++ b/code/modules/atmospherics/machinery/pipes/layermanifold.dm @@ -106,7 +106,7 @@ normalize_cardinal_directions() findAllConnections() var/turf/T = loc // hide if turf is not intact - hide(T.intact) + hide(T.underfloor_accessibility < UNDERFLOOR_VISIBLE) /obj/machinery/atmospherics/pipe/layer_manifold/setPipingLayer() piping_layer = PIPING_LAYER_DEFAULT diff --git a/code/modules/atmospherics/machinery/pipes/pipes.dm b/code/modules/atmospherics/machinery/pipes/pipes.dm index cbd6f8a10b51..e4b411c75cb3 100644 --- a/code/modules/atmospherics/machinery/pipes/pipes.dm +++ b/code/modules/atmospherics/machinery/pipes/pipes.dm @@ -39,7 +39,7 @@ /obj/machinery/atmospherics/pipe/atmosinit() var/turf/T = loc // hide if turf is not intact - hide(T.intact) + hide(T.underfloor_accessibility < UNDERFLOOR_VISIBLE) ..() /obj/machinery/atmospherics/pipe/hide(i) diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index 2ef90774b114..a75b4aa34f62 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -18,6 +18,10 @@ #define HOLODECK_CD 25 #define HOLODECK_DMG_CD 500 +/// typecache for turfs that should be considered ok during floorchecks. +/// A linked turf being anything not in this typecache will cause the holodeck to perform an emergency shutdown. +GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf/open/floor/holofloor, /turf/closed))) + /obj/machinery/computer/holodeck name = "holodeck control console" desc = "A computer used to control a nearby holodeck." @@ -223,8 +227,9 @@ /obj/machinery/computer/holodeck/proc/floorcheck() for(var/turf/T in linked) - if(!T.intact || isspaceturf(T)) - return FALSE + if (is_type_in_typecache(T, GLOB.typecache_holodeck_linked_floorcheck_ok)) + continue + return FALSE return TRUE /obj/machinery/computer/holodeck/proc/nerf(active) diff --git a/code/modules/holodeck/turfs.dm b/code/modules/holodeck/turfs.dm index 67c87a60c5d3..d39e5c5a8b5c 100644 --- a/code/modules/holodeck/turfs.dm +++ b/code/modules/holodeck/turfs.dm @@ -122,7 +122,7 @@ /turf/open/floor/holofloor/carpet/update_icon() if(!..()) return 0 - if(intact) + if(overfloor_placed) queue_smooth(src) /turf/open/floor/holofloor/wood diff --git a/code/modules/jobs/job_types/ai.dm b/code/modules/jobs/job_types/ai.dm index fe094589de30..90aa7c304604 100644 --- a/code/modules/jobs/job_types/ai.dm +++ b/code/modules/jobs/job_types/ai.dm @@ -28,13 +28,13 @@ var/mob/living/silicon/ai/AI = H - AI.relocate(TRUE) + AI.relocate(TRUE, TRUE) + + var/total_available_cpu = 1 - AI.ai_network.resources.total_cpu_assigned() + var/total_available_ram = AI.ai_network.resources.total_ram() - AI.ai_network.resources.total_ram_assigned() - var/total_available_cpu = 1 - GLOB.ai_os.total_cpu_assigned() - var/total_available_ram = GLOB.ai_os.total_ram - GLOB.ai_os.total_ram_assigned() - - GLOB.ai_os.set_cpu(AI, total_available_cpu) - GLOB.ai_os.add_ram(AI, total_available_ram) + AI.ai_network.resources.set_cpu(AI, total_available_cpu) + AI.ai_network.resources.add_ram(AI, total_available_ram) AI.apply_pref_name("ai", M.client) //If this runtimes oh well jobcode is fucked. AI.set_core_display_icon(null, M.client) diff --git a/code/modules/mapping/map_template.dm b/code/modules/mapping/map_template.dm index 3a6caa8a806d..36e26a43d5f3 100644 --- a/code/modules/mapping/map_template.dm +++ b/code/modules/mapping/map_template.dm @@ -28,6 +28,7 @@ /datum/parsed_map/proc/initTemplateBounds() var/list/obj/machinery/atmospherics/atmos_machines = list() var/list/obj/structure/cable/cables = list() + var/list/obj/structure/ethernet_cable/ethernet_cables = list() var/list/atom/atoms = list() var/list/area/areas = list() @@ -44,6 +45,9 @@ if(istype(A, /obj/structure/cable)) cables += A continue + if(istype(A, /obj/structure/ethernet_cable)) + ethernet_cables += A + continue if(istype(A, /obj/machinery/atmospherics)) atmos_machines += A for(var/L in border) @@ -53,6 +57,7 @@ SSmapping.reg_in_areas_in_z(areas) SSatoms.InitializeAtoms(atoms) SSmachines.setup_template_powernets(cables) + SSmachines.setup_template_ainets(ethernet_cables) SSair.setup_template_machinery(atmos_machines) /datum/map_template/proc/load_new_z(secret = FALSE) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 261f74ecbc83..41eed9e98be6 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -112,7 +112,6 @@ //Reduces/Increases download speed by this modifier var/downloadSpeedModifier = 1 - var/login_warned_temp = FALSE //Do we have access to camera tracking? var/canCameraMemoryTrack = FALSE @@ -123,8 +122,8 @@ //Did we get the death prompt? var/is_dying = FALSE - ///Multiplier for amount of points gained when passively using CPU for science - var/research_point_booster = 1 + + var/datum/ai_network/ai_network @@ -134,7 +133,7 @@ return INITIALIZE_HINT_QDEL //Delete AI. if(!istype(loc, /obj/machinery/ai/data_core) && !shunted) - relocate(TRUE) + relocate(TRUE, TRUE) if(L && istype(L, /datum/ai_laws)) laws = L @@ -234,7 +233,7 @@ qdel(eyeobj) // No AI, no Eye malfhack = null apc_override = null - GLOB.ai_os.remove_ai(src) + ai_network.remove_ai(src) . = ..() @@ -557,7 +556,7 @@ if(href_list["instant_download"]) if(!href_list["console"]) return - var/obj/machinery/computer/ai_control_console/C = locate(href_list["console"]) + var/datum/computer_file/program/ai_network_interface/C = locate(href_list["console"]) if(!C) return if(C.downloading != src) @@ -576,6 +575,10 @@ to_chat(src, "[target] is not on or near any active cameras on the station.") +/mob/living/silicon/ai/proc/switch_ainet(datum/ai_network/old_net, datum/ai_network/new_net) + for(var/datum/ai_project/project in dashboard.completed_projects) + project.switch_network(old_net, new_net) + /mob/living/silicon/ai/proc/switchCamera(obj/machinery/camera/C) if(QDELETED(C)) diff --git a/code/modules/mob/living/silicon/ai/ai_network/ai_network.dm b/code/modules/mob/living/silicon/ai/ai_network/ai_network.dm new file mode 100644 index 000000000000..8e815d23666f --- /dev/null +++ b/code/modules/mob/living/silicon/ai/ai_network/ai_network.dm @@ -0,0 +1,346 @@ +//////////////////////////////////////////// +// AI NETWORK DATUM +// each contiguous network of ethernet cables & AI machinery +///////////////////////////////////// +/datum/ai_network + var/number // unique id + var/list/cables = list() // all cables & junctions + var/list/nodes = list() // all connected machines + + var/list/ai_list = list() //List of all AIs in this network + + var/list/remote_networks = list() + + var/previous_ram = 0 + + var/datum/ai_shared_resources/resources + //Cash from crypto, can be withdrawn at network console + var/bitcoin_payout = 0 + + var/temp_limit = AI_TEMP_LIMIT + + var/local_cpu_usage = list() //How we use CPU locally + + var/label + + + + +/datum/ai_network/New() + SSmachines.ainets += src + label = num2hex(rand(1,65535), -1) + resources = new(starting_network = src) + +/datum/ai_network/Destroy() + //Go away references, you suck! + for(var/obj/structure/ethernet_cable/C in cables) + cables -= C + C.network = null + for(var/obj/machinery/ai/M in nodes) + nodes -= M + M.network = null + + resources.networks -= src + + if(!length(resources.networks)) + qdel(resources) + + resources = null + + SSmachines.ainets -= src + return ..() + +/datum/ai_network/process() + var/total_cpu = resources.total_cpu() + var/resources_assigned = resources.cpu_assigned[src] ? resources.cpu_assigned[src] : 0 + + if(local_cpu_usage[AI_CRYPTO]) + var/points = max(round(AI_RESEARCH_PER_CPU * (local_cpu_usage[AI_CRYPTO] * total_cpu * resources_assigned)), 0) + var/bitcoin_mined = points * (1-0.05*sqrt(points)) + bitcoin_mined = clamp(bitcoin_mined, 0, MAX_AI_BITCOIN_MINED_PER_TICK) + bitcoin_payout += bitcoin_mined * AI_BITCOIN_PRICE + + var/locally_used = 0 + for(var/A in local_cpu_usage) + locally_used += local_cpu_usage[A] + + var/research_points = max(round(AI_RESEARCH_PER_CPU * ((1 - locally_used) * total_cpu * resources_assigned)), 0) + SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_AI = research_points)) + + + +/datum/ai_network/proc/is_empty() + return !cables.len && !nodes.len + +//remove a cable from the current network +//if the network is then empty, delete it +//Warning : this proc DON'T check if the cable exists +/datum/ai_network/proc/remove_cable(obj/structure/ethernet_cable/C) + cables -= C + C.network = null + if(is_empty())//the network is now empty... + qdel(src)///... delete it + +//add a cable to the current network +//Warning : this proc DON'T check if the cable exists +/datum/ai_network/proc/add_cable(obj/structure/ethernet_cable/C) + if(C.network)// if C already has a network... + if(C.network == src) + return + else + C.network.remove_cable(C) //..remove it + C.network = src + cables +=C + +//remove a power machine from the current network +//if the network is then empty, delete it +//Warning : this proc DON'T check if the machine exists +/datum/ai_network/proc/remove_machine(obj/machinery/ai/M) + nodes -=M + M.network = null + if(is_empty())//the network is now empty... + qdel(src)///... delete it + +//add a power machine to the current network +//Warning : this proc DOESN'T check if the machine exists +/datum/ai_network/proc/add_machine(obj/machinery/ai/M) + if(M.network)// if M already has a network... + if(M.network == src) + return + else + M.disconnect_from_network()//..remove it + M.network = src + nodes[M] = M + +/datum/ai_network/proc/find_data_core() + for(var/obj/machinery/ai/data_core/core in get_all_nodes()) + if(core.can_transfer_ai()) + return core + +/datum/ai_network/proc/get_all_nodes(checked_nets = list()) + . = nodes.Copy() + for(var/datum/ai_network/net in resources.networks) + if(net == src) + continue + . += net.nodes + +/datum/ai_network/proc/get_local_nodes_oftype(type_to_check) + . = list() + for(var/A in nodes) + if(istype(A, type_to_check)) + . += A + + +/datum/ai_network/proc/get_all_ais(checked_nets = list()) + . = ai_list.Copy() + for(var/datum/ai_network/net in resources.networks) + if(net == src) + continue + . += net.ai_list + +/datum/ai_network/proc/remove_ai(mob/living/silicon/ai/AI) + resources.cpu_assigned[AI] = 0 + resources.ram_assigned[AI] = 0 + ai_list -= AI + + +/datum/ai_network/proc/update_resources() + resources.update_resources() + + +/datum/ai_network/proc/total_cpu() + . = 0 + for(var/obj/machinery/ai/server_cabinet/C in nodes) + . += C.total_cpu + +/datum/ai_network/proc/total_ram() + . = 0 + for(var/obj/machinery/ai/server_cabinet/C in nodes) + . += C.total_ram + + +/datum/ai_network/proc/get_temp_limit() + return temp_limit + +/datum/ai_network/proc/total_cpu_assigned() + return resources.total_cpu_assigned() + +/datum/ai_network/proc/total_ram_assigned() + return resources.total_ram_assigned() + +/* +/datum/ai_network/proc/rebuild_remote(externally_linked = FALSE, touched_networks = list()) + if(!resources) + return + if(src in touched_networks) + return + touched_networks += src + var/list/networks_to_rebuild = list() + for(var/obj/machinery/ai/networking/N in nodes) + if(N.partner && N.partner.network && N.partner.network.resources) + if(N.partner.network in touched_networks) + message_admins("[REF(src)] found touched_network!") + continue + message_admins("[REF(src)] found no mismatched resources!") + if(N.partner.network.resources != resources) + if(length(N.partner.network.resources.networks) > length(resources.networks)) //We merge into the biggest network + N.partner.network.resources.add_resource(resources) + else + resources.add_resource(N.partner.network.resources) + message_admins("[REF(src)] actually rebuilt!") + externally_linked = TRUE + + networks_to_rebuild += N.partner.network + + + if(!externally_linked) + resources.split_resources(src) + + for(var/datum/ai_network/AN in networks_to_rebuild) + message_admins("Telling network [REF(AN)] to rebuild!") + AN.rebuild_remote(TRUE, touched_networks) + +*/ + +/datum/ai_network/proc/rebuild_remote(externally_linked = FALSE, touched_networks = list(), datum/ai_network/originator) + if(src in touched_networks) + return + + if(!originator) + originator = src + + var/list/found_networks = list() + for(var/obj/machinery/ai/networking/N in nodes) + if(N.partner && N.partner.network && N.partner.network.resources) + if(N.partner.network == src) + continue + externally_linked = TRUE + found_networks += N.partner.network + + if(!externally_linked) + if(resources && length(resources.networks) > 1) //We only split if we are actually connected to an external resource network + resources.split_resources(src) + + found_networks -= touched_networks + + uniqueList_inplace(found_networks) + + for(var/datum/ai_network/AN in found_networks) + + + if(originator.resources != AN.resources) + if(length(originator.resources.networks) > length(AN.resources.networks)) + originator.resources.add_resource(AN.resources) + else + AN.resources.add_resource(originator.resources) + AN.rebuild_remote(TRUE, found_networks + src, originator) + + + +/proc/merge_ainets(datum/ai_network/net1, datum/ai_network/net2) + if(!net1 || !net2) //if one of the network doesn't exist, return + return + + if(net1 == net2) //don't merge same networks + return + + //We assume net1 is larger. If net2 is in fact larger we are just going to make them switch places to reduce on code. + if(net1.cables.len < net2.cables.len) //net2 is larger than net1. Let's switch them around + var/temp = net1 + net1 = net2 + net2 = temp + + + //merge net2 into net1 + for(var/obj/structure/ethernet_cable/Cable in net2.cables) //merge cables + net1.add_cable(Cable) + + for(var/obj/machinery/ai/Node in net2.nodes) //merge power machines + if(!Node.connect_to_network()) + Node.disconnect_from_network() //if somehow we can't connect the machine to the new network, disconnect it from the old nonetheless + + + net1.ai_list += net2.ai_list //AIs can only be in 1 network at a time + /* + net1.rebuild_remote() + net2.rebuild_remote() */ + + net1.update_resources() + + + return net1 + + +//remove the old network and replace it with a new one throughout the network. +/proc/propagate_ai_network(obj/O, datum/ai_network/AN) + var/list/worklist = list() + var/list/found_machines = list() + var/index = 1 + var/obj/P = null + + worklist+=O //start propagating from the passed object + + while(index<=worklist.len) //until we've exhausted all power objects + P = worklist[index] //get the next power object found + index++ + + if( istype(P, /obj/structure/ethernet_cable)) + var/obj/structure/ethernet_cable/C = P + if(C.network != AN) //add it to the network, if it isn't already there + AN.add_cable(C) + worklist |= C.get_connections() //get adjacents power objects, with or without a network + else if(P.anchored && istype(P, /obj/machinery/ai)) + var/obj/machinery/ai/M = P + found_machines |= M //we wait until the network is fully propagates to connect the machines + else + continue + + //now that the network is set, connect found machines to it + for(var/obj/machinery/ai/PM in found_machines) + if(!PM.connect_to_network()) //couldn't find a node on its turf... + PM.disconnect_from_network() //... so disconnect if already on a network + + //AN.rebuild_remote() + + +/proc/ai_list(turf/T, source, d, unmarked = FALSE, cable_only = FALSE) + . = list() + + for(var/AM in T) + if(AM == source) + continue //we don't want to return source + + if(!cable_only && istype(AM, /obj/machinery/ai)) + var/obj/machinery/ai/P = AM + if(P.network == 0) + continue + + if(!unmarked || !P.network) //if unmarked we only return things with no network + if(d == 0) + . += P + + else if(istype(AM, /obj/structure/ethernet_cable)) + var/obj/structure/ethernet_cable/C = AM + + if(!unmarked || !C.network) + if(C.d1 == d || C.d2 == d) + . += C + return . + +/proc/_debug_ai_networks() + var/i = 1 + var/list/resource_list = list() + for(var/datum/ai_network/AN in SSmachines.ainets) + var/list/interconnections = list() + for(var/obj/machinery/ai/networking/N in AN.nodes) + if(N.partner && N.partner.network) + interconnections += "#[i] Networking[ADMIN_JMP(N)] connected to [ADMIN_JMP(N.partner)]/[REF(N.partner.network)] | Same resources: [N.partner.network.resources == AN.resources ? "YES" : "NO"]" + i++ + message_admins("Network: [REF(AN)] | Resources: [REF(AN.resources)]") + for(var/A in interconnections) + message_admins(A) + resource_list |= AN.resources + message_admins("----------------------------") + for(var/datum/ai_shared_resources/ASR in resource_list) + message_admins("Resource count [REF(ASR)], CPU: [ASR.total_cpu()] | RAM: [ASR.total_ram()]") + diff --git a/code/modules/mob/living/silicon/ai/ai_network/ethernet_cable.dm b/code/modules/mob/living/silicon/ai/ai_network/ethernet_cable.dm new file mode 100644 index 000000000000..7816c4801e21 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/ai_network/ethernet_cable.dm @@ -0,0 +1,651 @@ +/////////////////////////////// +//CABLE STRUCTURE +/////////////////////////////// + + +//////////////////////////////// +// Definitions +//////////////////////////////// + +/* Cable directions (d1 and d2) + + + 9 1 5 + \ | / + 8 - 0 - 4 + / | \ + 10 2 6 + +If d1 = 0 and d2 = 0, there's no cable +If d1 = 0 and d2 = dir, it's a O-X cable, getting from the center of the tile to dir (knot cable) +If d1 = dir1 and d2 = dir2, it's a full X-X cable, getting from dir1 to dir2 +By design, d1 is the smallest direction and d2 is the highest +*/ + +/obj/structure/ethernet_cable + name = "ethernet cable" + desc = "A rigid and shielded cat 16a cable used for transferring vast amounts of data over long distances. Primarily used for large scale computing networks or advanced neural networks." + icon = 'icons/obj/power_cond/power_local.dmi' + icon_state = "0-1" + level = 1 //is underfloor + layer = ETHERNET_LAYER //Above hidden pipes, GAS_PIPE_HIDDEN_LAYER + anchored = TRUE + obj_flags = CAN_BE_HIT | ON_BLUEPRINTS + var/d1 = 0 // cable direction 1 (see above) + var/d2 = 1 // cable direction 2 (see above) + var/datum/ai_network/network + //Cables no longer keep a copy of the cable to be dropped in nullspace + + FASTDMM_PROP(\ + pipe_type = PIPE_TYPE_CABLE,\ + pipe_interference_group = list("cable"),\ + pipe_group = "cable-ethernet"\ + ) + + +// the ethernet cable object +/obj/structure/ethernet_cable/Initialize(mapload, param_color) + . = ..() + + // ensure d1 & d2 reflect the icon_state for entering and exiting cable + var/dash = findtext(icon_state, "-") + d1 = text2num( copytext( icon_state, 1, dash ) ) + d2 = text2num( copytext( icon_state, dash+1 ) ) + + var/turf/T = get_turf(src) // hide if turf is not intact + if(level==1) + hide(T.underfloor_accessibility < UNDERFLOOR_VISIBLE) + GLOB.ethernet_cable_list += src //add it to the global cable list + + update_icon() + +/obj/structure/ethernet_cable/Destroy() // called when a cable is deleted + if(network) + cut_cable_from_ainet() // update the ai networks + GLOB.ethernet_cable_list -= src //remove it from global cable list + return ..() // then go ahead and delete the cable + +/obj/structure/ethernet_cable/deconstruct(disassembled = TRUE) + if(!(flags_1 & NODECONSTRUCT_1)) + var/turf/T = loc + var/cableNum = 1 + if (d1*d2 > 0) //this be true if the cable has two directions, aka it contains two cables. If there is only one cable, one out of d1 and d2 will be zero + cableNum = 2 + var/newCables = new /obj/item/stack/ethernet_coil(T, cableNum) + TransferComponents(newCables) //this copies the fingerprints over to the new object + qdel(src) + +/////////////////////////////////// +// General procedures +/////////////////////////////////// + +//If underfloor, hide the cable +/obj/structure/ethernet_cable/hide(i) + + if(level == 1 && isturf(loc)) + invisibility = i ? INVISIBILITY_MAXIMUM : 0 + update_icon() + +/obj/structure/ethernet_cable/update_icon() + icon_state = "[d1]-[d2]" + +/obj/structure/ethernet_cable/proc/handlecable(obj/item/W, mob/user, params) + var/turf/T = get_turf(src) + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) + return + if(W.tool_behaviour == TOOL_WIRECUTTER) + user.visible_message("[user] cuts the ethernet cable.", span_notice("You cut the ethernet cable.")) + investigate_log("was cut by [key_name(usr)] in [AREACOORD(src)]", INVESTIGATE_WIRES) + add_fingerprint(user) + deconstruct() + return + + else if(istype(W, /obj/item/stack/ethernet_coil)) + var/obj/item/stack/ethernet_coil/coil = W + if (coil.get_amount() < 1) + to_chat(user, span_warning("Not enough cable!")) + return + coil.cable_join(src, user) + /* + else if(W.tool_behaviour == TOOL_MULTITOOL) //FIX NETWORK STATS + + if(ai network && (ai network.avail > 0)) // is it powered? + to_chat(user, span_danger("Total power: [DisplayPower(ai network.avail)]\nLoad: [DisplayPower(ai network.load)]\nExcess power: [DisplayPower(surplus())]")) + else + to_chat(user, span_danger("The cable is not powered.")) + shock(user, 5, 0.2) + */ + else if(istype(W, /obj/item/modular_computer)) + var/obj/item/modular_computer/MC = W + + if(MC.all_components[MC_AI_NETWORK]) + var/obj/item/computer_hardware/ai_interface/ai_interface = MC.all_components[MC_AI_NETWORK] + if(ai_interface) + if(ai_interface.connected_cable != src) + ai_interface.connect_cable(src) + to_chat(user, span_notice("You connect to the ethernet cable.")) + else + to_chat(user, span_warning("[MC] has no AI interface!")) + + + add_fingerprint(user) + +// Items usable on a cable : +// - Wirecutters : cut it duh ! +// - Cable coil : merge cables +// - Multitool : get the network stats +// +/obj/structure/ethernet_cable/attackby(obj/item/W, mob/user, params) + handlecable(W, user, params) + + +/obj/structure/ethernet_cable/singularity_pull(S, current_size) + ..() + if(current_size >= STAGE_FIVE) + deconstruct() + +///////////////////////////////////////////////// +// Cable laying helpers +//////////////////////////////////////////////// + +//handles merging diagonally matching cables +//for info : direction^3 is flipping horizontally, direction^12 is flipping vertically +/obj/structure/ethernet_cable/proc/mergeDiagonalsNetworks(direction) + + //search for and merge diagonally matching cables from the first direction component (north/south) + var/turf/T = get_step(src, direction&3)//go north/south + + for(var/obj/structure/ethernet_cable/C in T) + + if(!C) + continue + + if(src == C) + continue + + if(C.d1 == (direction^3) || C.d2 == (direction^3)) //we've got a diagonally matching cable + if(!C.network) //if the matching cable somehow got no ai network, make him one (should not happen for cables) + var/datum/ai_network/newAN = new() + newAN.add_cable(C) + + if(network) //if we already have a ai network, then merge the two ai networks + merge_ainets(network,C.network) + //network.rebuild_remote() + else + C.network.add_cable(src) //else, we simply connect to the matching cable ai network + C.network.rebuild_remote() + + //the same from the second direction component (east/west) + T = get_step(src, direction&12)//go east/west + + for(var/obj/structure/ethernet_cable/C in T) + + if(!C) + continue + + if(src == C) + continue + if(C.d1 == (direction^12) || C.d2 == (direction^12)) //we've got a diagonally matching cable + if(!C.network) //if the matching cable somehow got no ai network, make him one (should not happen for cables) + var/datum/ai_network/newAN = new() + newAN.add_cable(C) + + if(network) //if we already have a ai network, then merge the two ai networks + merge_ainets(network,C.network) + //network.rebuild_remote() + else + C.network.add_cable(src) //else, we simply connect to the matching cable ai network + C.network.rebuild_remote() + + + +// merge with the ai networks of power objects in the given direction +/obj/structure/ethernet_cable/proc/mergeConnectedNetworks(direction) + + var/fdir = (!direction)? 0 : turn(direction, 180) //flip the direction, to match with the source position on its turf + + if(!(d1 == direction || d2 == direction)) //if the cable is not pointed in this direction, do nothing + return + + var/turf/TB = get_step(src, direction) + + for(var/obj/structure/ethernet_cable/C in TB) + + if(!C) + continue + + if(src == C) + continue + + if(C.d1 == fdir || C.d2 == fdir) //we've got a matching cable in the neighbor turf + if(!C.network) //if the matching cable somehow got no ai network, make him one (should not happen for cables) + var/datum/ai_network/newAN = new(C.loc.z) + newAN.add_cable(C) + + if(network) //if we already have a ai network, then merge the two ai networks + merge_ainets(network,C.network) + //network.rebuild_remote() + else + C.network.add_cable(src) //else, we simply connect to the matching cable ai network + C.network.rebuild_remote() + +// merge with the ai networks of power objects in the source turf +/obj/structure/ethernet_cable/proc/mergeConnectedNetworksOnTurf() + var/list/to_connect = list() + + if(!network) //if we somehow have no ai network, make one (should not happen for cables) + var/datum/ai_network/newAN = new(loc.z) + newAN.add_cable(src) + + //first let's add turf cables to our ai network + //then we'll connect machines on turf with a node cable is present + for(var/AM in loc) + if(istype(AM, /obj/structure/ethernet_cable)) + var/obj/structure/ethernet_cable/C = AM + if(C.d1 == d1 || C.d2 == d1 || C.d1 == d2 || C.d2 == d2) //only connected if they have a common direction + if(C.network == network) + continue + if(C.network) + merge_ainets(network, C.network) + //network.rebuild_remote() + else + network.add_cable(C) //the cable was ai networkless, let's just add it to our ai network + network.rebuild_remote() + + else if(istype(AM, /obj/machinery/ai)) //other power machines + var/obj/machinery/ai/M = AM + + if(M.network == network) + continue + + to_connect += M //we'll connect the machines after all cables are merged + + + //now that cables are done, let's connect found machines + for(var/obj/machinery/ai/PM in to_connect) + if(!PM.connect_to_network()) + PM.disconnect_from_network() //if we somehow can't connect the machine to the new ai network, remove it from the old nonetheless + + +////////////////////////////////////////////// +// ai networks handling helpers +////////////////////////////////////////////// + +//if ai_networkless_only = 1, will only get connections without ai network +/obj/structure/ethernet_cable/proc/get_connections(ai_networkless_only = 0) + . = list() // this will be a list of all connected power objects + var/turf/T + + //get matching cables from the first direction + if(d1) //if not a node cable + T = get_step(src, d1) + if(T) + . += ai_list(T, src, turn(d1, 180), ai_networkless_only) //get adjacents matching cables + + if(d1&(d1-1)) //diagonal direction, must check the 4 possibles adjacents tiles + T = get_step(src,d1&3) // go north/south + if(T) + . += ai_list(T, src, d1 ^ 3, ai_networkless_only) //get diagonally matching cables + T = get_step(src,d1&12) // go east/west + if(T) + . += ai_list(T, src, d1 ^ 12, ai_networkless_only) //get diagonally matching cables + + . += ai_list(loc, src, d1, ai_networkless_only) //get on turf matching cables + + //do the same on the second direction (which can't be 0) + T = get_step(src, d2) + if(T) + . += ai_list(T, src, turn(d2, 180), ai_networkless_only) //get adjacents matching cables + + if(d2&(d2-1)) //diagonal direction, must check the 4 possibles adjacents tiles + T = get_step(src,d2&3) // go north/south + if(T) + . += ai_list(T, src, d2 ^ 3, ai_networkless_only) //get diagonally matching cables + T = get_step(src,d2&12) // go east/west + if(T) + . += ai_list(T, src, d2 ^ 12, ai_networkless_only) //get diagonally matching cables + . += ai_list(loc, src, d2, ai_networkless_only) //get on turf matching cables + + return . + +//should be called after placing a cable which extends another cable, creating a "smooth" cable that no longer terminates in the centre of a turf. +//needed as this can, unlike other placements, disconnect cables +/obj/structure/ethernet_cable/proc/denode() + var/turf/T1 = loc + if(!T1) + return + + var/list/powerlist = ai_list(T1,src,0,0) //find the other cables that ended in the centre of the turf, with or without a ai network + if(powerlist.len>0) + var/datum/ai_network/AN = new() + propagate_ai_network(powerlist[1],AN) //propagates the new ai network beginning at the source cable + + if(AN.is_empty()) //can happen with machines made nodeless when smoothing cables + qdel(AN) + +/obj/structure/ethernet_cable/proc/auto_propogate_cut_cable(obj/O, ) + if(O && !QDELETED(O)) + var/datum/ai_network/newAN = new()// creates a new ai network... + + propagate_ai_network(O, newAN)//... and propagates it to the other side of the cable + + + +// cut the cable's ai network at this cable and updates the powergrid +/obj/structure/ethernet_cable/proc/cut_cable_from_ainet(remove=TRUE) + var/turf/T1 = loc + var/list/P_list + if(!T1) + return + if(d1) + T1 = get_step(T1, d1) + P_list = ai_list(T1, src, turn(d1,180),0,cable_only = 1) // what adjacently joins on to cut cable... + + P_list += ai_list(loc, src, d1, 0, cable_only = 1)//... and on turf + + if(P_list.len == 0)//if nothing in both list, then the cable was a lone cable, just delete it and its ai network + network.remove_cable(src) + + for(var/obj/machinery/ai/P in T1)//check if it was powering a machine + if(!P.connect_to_network()) //can't find a node cable on a the turf to connect to + P.disconnect_from_network() //remove from current network (and delete ai network) + return + + var/obj/O = P_list[1] + // remove the cut cable from its turf and ai network, so that it doesn't get count in propagate_network worklist + if(remove) + moveToNullspace() + + network.remove_cable(src) //remove the cut cable from its ai network + + + addtimer(CALLBACK(O, .proc/auto_propogate_cut_cable, O), 0) //so we don't rebuild the network X times when singulo/explosion destroys a line of X cables + + // Disconnect machines connected to nodes + if(d1 == 0) // if we cut a node (O-X) cable + for(var/obj/machinery/ai/P in T1) + if(!P.connect_to_network()) //can't find a node cable on a the turf to connect to + P.disconnect_from_network() //remove from current network + + +/////////////////////////////////////////////// +// The cable coil object, used for laying cable +/////////////////////////////////////////////// + +//////////////////////////////// +// Definitions +//////////////////////////////// + +/obj/item/stack/ethernet_coil + name = "ethernet cable coil" + desc = "A coil of shielded ethernet cable." + custom_price = 25 + gender = NEUTER //That's a cable coil sounds better than that's some cable coils + icon = 'icons/obj/power.dmi' + icon_state = "wire" + item_state = "coil" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + max_amount = MAXCOIL + amount = MAXCOIL + merge_type = /obj/item/stack/ethernet_coil // This is here to let its children merge between themselves + + throwforce = 0 + w_class = WEIGHT_CLASS_SMALL + throw_speed = 3 + throw_range = 5 + materials = list(/datum/material/iron=10, /datum/material/glass=5, /datum/material/gold=1) + slot_flags = ITEM_SLOT_BELT + attack_verb = list("whipped", "lashed", "disciplined", "flogged") + singular_name = "ethernet cable piece" + full_w_class = WEIGHT_CLASS_SMALL + grind_results = list(/datum/reagent/copper = 2) //2 copper per cable in the coil + usesound = 'sound/items/deconstruct.ogg' + +/obj/item/stack/ethernet_coil/cyborg + is_cyborg = TRUE + materials = list() + cost = 1 + +/obj/item/stack/ethernet_coil/suicide_act(mob/user) + if(locate(/obj/structure/chair/stool) in get_turf(user)) + user.visible_message(span_suicide("[user] is making a noose with [src]! It looks like [user.p_theyre()] trying to commit suicide!")) + else + user.visible_message(span_suicide("[user] is trying to upload [user.p_them()]selves to the afterlife with [src]! It looks like [user.p_theyre()] trying to commit suicide!")) + return(OXYLOSS) + +/obj/item/stack/ethernet_coil/Initialize(mapload, new_amount = null, param_color = null) + . = ..() + + pixel_x = rand(-2,2) + pixel_y = rand(-2,2) + update_icon() + +/////////////////////////////////// +// General procedures +/////////////////////////////////// + + +//you can use wires to heal robotics +/obj/item/stack/ethernet_coil/attack(mob/living/carbon/human/H, mob/user) + if(!istype(H)) + return ..() + + var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected)) + if(affecting.burn_dam <= 0) + to_chat(user, span_warning("[affecting] is already in good condition!")) + return FALSE + if(affecting && affecting.status == BODYPART_ROBOTIC) + 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].")) + heal_robo_limb(src, H, user, 0, 15) + user.visible_message(span_notice("[user] fixes the wires in [H]'s [affecting.name]."), span_notice("You fix the wires in [H == user ? "your" : "[H]'s"] [affecting.name].")) + return + else + return ..() + +/obj/item/stack/ethernet_coil/proc/heal_robo_limb(obj/item/I, mob/living/carbon/human/H, mob/user, brute_heal, burn_heal) + if(I.use_tool(H, user, 2 SECONDS, amount=1)) + if(item_heal_robotic(H, user, brute_heal, burn_heal)) + return heal_robo_limb(I, H, user, brute_heal, burn_heal) + return TRUE + +/obj/item/stack/ethernet_coil/update_icon() + icon_state = "[initial(icon_state)][amount < 3 ? amount : ""]" + name = "ethernet cable [amount < 3 ? "piece" : "coil"]" + +/obj/item/stack/ethernet_coil/attack_hand(mob/user) + . = ..() + if(.) + return + var/obj/item/stack/ethernet_coil/new_cable = ..() + if(istype(new_cable)) + new_cable.update_icon() + +//add cables to the stack +/obj/item/stack/ethernet_coil/proc/give(extra) + if(amount + extra > max_amount) + amount = max_amount + else + amount += extra + update_icon() + + + +/////////////////////////////////////////////// +// Cable laying procedures +////////////////////////////////////////////// + +/obj/item/stack/ethernet_coil/proc/get_new_cable(location) + var/path = /obj/structure/ethernet_cable + return new path(location) + +// called when cable_coil is clicked on a turf +/obj/item/stack/ethernet_coil/proc/place_turf(turf/T, mob/user, dirnew) + if(!isturf(user.loc)) + return + + if(!isturf(T) || T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE || !T.can_have_cabling()) + to_chat(user, span_warning("You can only lay cables on top of exterior catwalks and plating!")) + return + + if(get_amount() < 1) // Out of cable + to_chat(user, span_warning("There is no cable left!")) + return + + if(get_dist(T,user) > 1) // Too far + to_chat(user, span_warning("You can't lay cable at a place that far away!")) + return + + var/dirn + if(!dirnew) //If we weren't given a direction, come up with one! (Called as null from catwalk.dm and floor.dm) + if(user.loc == T) + dirn = user.dir //If laying on the tile we're on, lay in the direction we're facing + else + dirn = get_dir(T, user) + else + dirn = dirnew + + + for(var/obj/structure/ethernet_cable/LC in T) + if(LC.d2 == dirn && LC.d1 == 0) + to_chat(user, span_warning("There's already a cable at that position!")) + return + + var/obj/structure/ethernet_cable/C = get_new_cable(T) + + //set up the new cable + C.d1 = 0 //it's a O-X node cable + C.d2 = dirn + C.add_fingerprint(user) + C.update_icon() + + //create a new ai network with the cable, if needed it will be merged later + var/datum/ai_network/AN = new() + AN.add_cable(C) + + C.mergeConnectedNetworks(C.d2) //merge the ai network with adjacents ai networks + C.mergeConnectedNetworksOnTurf() //merge the ai network with on turf ai networks + + if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions + C.mergeDiagonalsNetworks(C.d2) + + use(1) + + return C + +// called when cable_coil is click on an installed obj/cable +// or click on a turf that already contains a "node" cable +/obj/item/stack/ethernet_coil/proc/cable_join(obj/structure/ethernet_cable/C, mob/user, var/showerror = TRUE, forceddir) + var/turf/U = user.loc + if(!isturf(U)) + return + + var/turf/T = C.loc + + if(!isturf(T) || T.underfloor_accessibility ) // sanity checks, also stop use interacting with T-scanner revealed cable + return + + if(get_dist(C, user) > 1) // make sure it's close enough + to_chat(user, span_warning("You can't lay cable at a place that far away!")) + return + + + if(U == T && !forceddir) //if clicked on the turf we're standing on and a direction wasn't supplied, try to put a cable in the direction we're facing + place_turf(T,user) + return + + var/dirn = get_dir(C, user) + if(forceddir) + dirn = forceddir + + // one end of the clicked cable is pointing towards us and no direction was supplied + if((C.d1 == dirn || C.d2 == dirn) && !forceddir) + if(!U.can_have_cabling()) //checking if it's a plating or catwalk + if (showerror) + to_chat(user, span_warning("You can only lay cables on catwalks and plating!")) + return + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) //can't place a cable if it's a plating with a tile on it + to_chat(user, span_warning("You can't lay cable there unless the floor tiles are removed!")) + return + else + // cable is pointing at us, we're standing on an open tile + // so create a stub pointing at the clicked cable on our tile + + var/fdirn = turn(dirn, 180) // the opposite direction + + for(var/obj/structure/ethernet_cable/LC in U) // check to make sure there's not a cable there already + if(LC.d1 == fdirn || LC.d2 == fdirn) + if (showerror) + to_chat(user, span_warning("There's already a cable at that position!")) + return + + var/obj/structure/ethernet_cable/NC = get_new_cable (U) + + NC.d1 = 0 + NC.d2 = fdirn + NC.add_fingerprint(user) + NC.update_icon() + + //create a new ai network with the cable, if needed it will be merged later + var/datum/ai_network/newAN = new() + newAN.add_cable(NC) + + NC.mergeConnectedNetworks(NC.d2) //merge the ai network with adjacents ai networks + NC.mergeConnectedNetworksOnTurf() //merge the ai network with on turf ai networks + + if(NC.d2 & (NC.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions + NC.mergeDiagonalsNetworks(NC.d2) + + + use(1) + + return + + // exisiting cable doesn't point at our position or we have a supplied direction, so see if it's a stub + else if(C.d1 == 0) + // if so, make it a full cable pointing from it's old direction to our dirn + var/nd1 = C.d2 // these will be the new directions + var/nd2 = dirn + + + if(nd1 > nd2) // swap directions to match icons/states + nd1 = dirn + nd2 = C.d2 + + + for(var/obj/structure/ethernet_cable/LC in T) // check to make sure there's no matching cable + if(LC == C) // skip the cable we're interacting with + continue + if((LC.d1 == nd1 && LC.d2 == nd2) || (LC.d1 == nd2 && LC.d2 == nd1) ) // make sure no cable matches either direction + if (showerror) + to_chat(user, span_warning("There's already a cable at that position!")) + + return + + + C.update_icon() + + C.d1 = nd1 + C.d2 = nd2 + + //updates the stored cable coil + + C.add_fingerprint(user) + C.update_icon() + + + C.mergeConnectedNetworks(C.d1) //merge the ai networks... + C.mergeConnectedNetworks(C.d2) //...in the two new cable directions + C.mergeConnectedNetworksOnTurf() + + if(C.d1 & (C.d1 - 1))// if the cable is layed diagonally, check the others 2 possible directions + C.mergeDiagonalsNetworks(C.d1) + + if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions + C.mergeDiagonalsNetworks(C.d2) + + + use(1) + + C.denode()// this call may have disconnected some cables that terminated on the centre of the turf, if so split the ai networks. + return diff --git a/code/modules/mob/living/silicon/ai/ai_network/networking_machines.dm b/code/modules/mob/living/silicon/ai/ai_network/networking_machines.dm new file mode 100644 index 000000000000..cd6b5ed89975 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/ai_network/networking_machines.dm @@ -0,0 +1,189 @@ +GLOBAL_LIST_EMPTY(ai_networking_machines) + +/obj/machinery/ai/networking + name = "networking machine" + desc = "A solar panel. Generates electricity when in contact with sunlight." + icon = 'goon/icons/obj/power.dmi' + icon_state = "sp_base" + density = TRUE + use_power = NO_POWER_USE + idle_power_usage = 0 + active_power_usage = 0 + max_integrity = 150 + integrity_failure = 0.33 + + var/label + //For mapping, will connect to machine with this label if found + var/roundstart_connection + + var/mutable_appearance/panelstructure + var/mutable_appearance/paneloverlay + + var/obj/machinery/ai/networking/partner + var/rotation_to_partner + var/locked = FALSE + var/mob/remote_control + + +/obj/machinery/ai/networking/Initialize(mapload) + . = ..() + if(!label) + label = num2hex(rand(1,65535), -1) + GLOB.ai_networking_machines += src + panelstructure = mutable_appearance(icon, "solar_panel", FLY_LAYER) + paneloverlay = mutable_appearance(icon, "solar_panel-o", FLY_LAYER) + paneloverlay.color = "#599ffa" + update_icon(TRUE) + +/obj/machinery/ai/networking/Destroy(mapload) + GLOB.ai_networking_machines -= src + disconnect() + . = ..() +/obj/machinery/ai/networking/proc/roundstart_connect(mapload) + for(var/obj/machinery/ai/networking/N in GLOB.ai_networking_machines) + if(partner) + break + if(N == src) + continue + if(N.partner) + continue + if(roundstart_connection && N.label == roundstart_connection) + connect_to_partner(N) + break + if(!roundstart_connection) + connect_to_partner(N) + break + + +/obj/machinery/ai/networking/update_icon(forced = FALSE) + ..() + if(!rotation_to_partner && !forced) + return + cut_overlays() + var/matrix/turner = matrix() + turner.Turn(rotation_to_partner) + panelstructure.transform = turner + paneloverlay.transform = turner + add_overlay(list(paneloverlay, panelstructure)) + +/obj/machinery/ai/networking/proc/disconnect() + if(partner) + var/datum/ai_network/AN = partner.network + + partner.partner = null + partner = null + AN.rebuild_remote() + network.rebuild_remote() + + +/obj/machinery/ai/networking/proc/connect_to_partner(obj/machinery/ai/networking/target) + if(target.partner) + return + if(target == src) + return + + + partner = target + rotation_to_partner = Get_Angle(src, partner) + target.partner = src + target.rotation_to_partner = Get_Angle(target, src) + target.update_icon() + + + network.rebuild_remote() + + update_icon() + + +/obj/machinery/ai/networking/ui_status(mob/user) + . = ..() + if (!QDELETED(remote_control) && user == remote_control) + . = UI_INTERACTIVE + +/obj/machinery/ai/networking/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AiNetworking", name) + ui.open() + +/obj/machinery/ai/networking/ui_data(mob/living/carbon/human/user) + var/list/data = list() + + data["is_connected"] = partner ? partner.label : FALSE + data["label"] = label + + data["locked"] = locked + + data["possible_targets"] = list() + for(var/obj/machinery/ai/networking/N in GLOB.ai_networking_machines) + if(N == src) + continue + if(N.z != src.z) + continue + if(N.locked) + continue + data["possible_targets"] += N.label + + return data + +/obj/machinery/ai/networking/ui_act(action, params) + if(..()) + return + + switch(action) + if("switch_label") + if(locked) + return + var/new_label = stripped_input(usr, "Enter new label", "Set label", max_length = 16) + if(new_label) + if(isnotpretty(new_label)) + to_chat(usr, span_notice("The machine rejects the input. See rule 0.1.")) + var/log_message = "[key_name(usr)] just tripped a pretty filter: '[new_label]'." + message_admins(log_message) + log_say(log_message) + return + for(var/obj/machinery/ai/networking/N in GLOB.ai_networking_machines) + if(N.label == new_label) + to_chat(usr, span_warning("A machine with this label already exists!")) + return + label = new_label + . = TRUE + if("connect") + if(locked) + return + var/target_label = params["target_label"] + if(target_label == label) + return + for(var/obj/machinery/ai/networking/N in GLOB.ai_networking_machines) + if(N.z != src.z) + return + if(N.label == target_label) + if(N.locked) + to_chat(usr, span_warning("Unable to connect to '[target_label]'! It seems to be locked.")) + return + if(N.partner) + to_chat(usr, span_warning("Unable to connect to '[target_label]'! It seems to already have a connection established.")) + return + connect_to_partner(N) + to_chat(usr, span_notice("Connection established to '[target_label]'.")) + return + . = TRUE + if("disconnect") + if(locked) + return + disconnect() + . = TRUE + if("toggle_lock") + locked = !locked + . = TRUE + +/obj/machinery/ai/networking/connect_to_network() + . = ..() + if(partner) + network.rebuild_remote() + +/obj/machinery/ai/networking/disconnect_from_network() + var/datum/ai_network/temp = network + . = ..() + if(partner) + temp.rebuild_remote() diff --git a/code/modules/mob/living/silicon/ai/ai_network/shared_resources.dm b/code/modules/mob/living/silicon/ai/ai_network/shared_resources.dm new file mode 100644 index 000000000000..148dbf999d7e --- /dev/null +++ b/code/modules/mob/living/silicon/ai/ai_network/shared_resources.dm @@ -0,0 +1,250 @@ +/datum/ai_shared_resources + var/ram_sources = list() + var/cpu_sources = list() + + + var/list/cpu_assigned = list() + var/list/ram_assigned = list() + + var/networks = list() + + var/previous_ram = 0 + + + +/datum/ai_shared_resources/New(network_assigned_cpu, network_assigned_ram, datum/ai_network/split_network, datum/ai_network/starting_network) + if((network_assigned_ram || network_assigned_cpu) && split_network) + ram_assigned = network_assigned_ram + cpu_assigned = network_assigned_cpu + + if(split_network) + split_network.resources = src + networks |= split_network + update_resources() + + if(starting_network) + starting_network.resources = src + networks |= starting_network + + for(var/datum/ai_network/AN in networks) + AN.rebuild_remote() + + START_PROCESSING(SSobj, src) + +/datum/ai_shared_resources/Destroy(network_assigned_cpu, network_assigned_ram, datum/ai_network/split_network, datum/ai_network/starting_network) + STOP_PROCESSING(SSobj, src) + . = ..() + +/datum/ai_shared_resources/process() + for(var/datum/ai_network/net in networks) + net.process() + + //Networks automatically use their unspent CPU to research, this just catches cluster unassigned CPU. Local clusters can have their points boosted by local AIs + var/unused_cpu = 1 - total_cpu_assigned() + + var/research_points = max(round(AI_RESEARCH_PER_CPU * (unused_cpu * total_cpu())), 0) + SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_AI = research_points)) + + + + +/datum/ai_shared_resources/proc/total_cpu_assigned() + var/total = 0 + for(var/AI in cpu_assigned) + total += cpu_assigned[AI] + return total + +/datum/ai_shared_resources/proc/total_ram_assigned() + var/total = 0 + for(var/AI in ram_assigned) + total += (ram_assigned[AI]) + return total + +/datum/ai_shared_resources/proc/total_cpu() + var/total = 0 + for(var/C in cpu_sources) + total += cpu_sources[C] + return total + +/datum/ai_shared_resources/proc/total_ram() + var/total = 0 + for(var/C in ram_sources) + total += ram_sources[C] + return total + +/datum/ai_shared_resources/proc/update_resources() + previous_ram = total_ram() + ram_sources = list() + cpu_sources = list() + for(var/datum/ai_network/N in networks) + ram_sources[N] += N.total_ram() + cpu_sources[N] += N.total_cpu() + update_allocations() + +/datum/ai_shared_resources/proc/add_resource(datum/ai_shared_resources/new_resources) + + for(var/RU in new_resources.ram_assigned) + ram_assigned[RU] = new_resources.ram_assigned[RU] + + for(var/CU in cpu_assigned) //We split the CPUs 50/50 + cpu_assigned[CU] = round((cpu_assigned[CU] * 0.5) * 100) / 100 + + for(var/CU in new_resources.cpu_assigned) + cpu_assigned[CU] = round((new_resources.cpu_assigned[CU] * 0.5) * 100) / 100 + + for(var/datum/ai_network/N in new_resources.networks) + networks |= N + N.resources = src + + update_resources() + update_allocations() + qdel(new_resources) + +/datum/ai_shared_resources/proc/split_resources(datum/ai_network/split_network) + var/network_ram_assign = list() + var/network_cpu_assign = list() + + + var/split_network_cpu = 0 + var/network_ais = split_network.ai_list + for(var/A in cpu_assigned) + if(A in network_ais || A == split_network) + network_cpu_assign[A] = cpu_assigned[A] + split_network_cpu += cpu_assigned[A] + cpu_assigned[A] = 0 + + //Normalize CPU so 100% is used in the new network if 100% was used in total before + var/total_usage = total_cpu_assigned() //We normalise around this value, so the split network CPU usage will (approximately) end up at this too + for(var/A in network_cpu_assign) + var/split_usage = network_cpu_assign[A] / split_network_cpu + network_cpu_assign[A] = 1 * round(split_usage, 0.01) + + //We do the same for the network we leave behid + for(var/A in cpu_assigned) + var/split_usage = cpu_assigned[A] / total_usage + cpu_assigned[A] = 1 * round(split_usage, 0.01) + + + //Not needed for RAM since it's not a percentage + for(var/A in ram_assigned) + if(A in network_ais || A == split_network) + network_ram_assign[A] = ram_assigned[A] + ram_assigned[A] = 0 + + networks -= split_network + update_resources() + + new /datum/ai_shared_resources(network_cpu_assign, network_ram_assign, split_network) + + if(!length(networks)) + qdel(src) + + +/datum/ai_shared_resources/proc/update_allocations() + //Do we have the same amount or more RAM than before? Do nothing + var/total_ram = total_ram() + if(total_ram >= previous_ram) + return + //Find out how much is actually assigned. We can have more total_cpu than the sum of cpu_assigned. Same with RAM + var/total_assigned_ram = total_ram_assigned() + //If we have less assigned ram than we have cpu and ram, just return, everything is fine. + if(total_assigned_ram < total_ram) + return + + //Copy the lists of assigned resources so we don't manipulate the list prematurely. + var/list/ram_assigned_copy = ram_assigned.Copy() + //List of touched AIs so we can notify them at the end. + var/list/affected_AIs = list() + + + if(total_assigned_ram > total_ram) + var/needed_amount = total_assigned_ram - total_ram + for(var/A in ram_assigned_copy) + if(isAI(A)) + var/mob/living/silicon/ai/AI = A + if((ram_assigned_copy[AI]) >= needed_amount) + ram_assigned_copy[AI] -= needed_amount + total_assigned_ram -= needed_amount + affected_AIs |= AI + break + else if(ram_assigned_copy[AI]) + var/amount = ram_assigned_copy[AI] + ram_assigned_copy[AI] -= amount + affected_AIs |= AI + needed_amount -= amount + total_assigned_ram -= amount + if(total_ram >= total_assigned_ram) + break + else //If we're not an AI we are a network, networks have no programs to stop (for now) + if((ram_assigned_copy[A]) >= needed_amount) + ram_assigned_copy[A] -= needed_amount + total_assigned_ram -= needed_amount + break + else if(ram_assigned_copy[A]) + var/amount = ram_assigned_copy[A] + ram_assigned_copy[A] -= amount + needed_amount -= amount + total_assigned_ram -= amount + if(total_ram >= total_assigned_ram) + break + //Set the actual values of the assigned to our manipulated copies. Bypass helper procs as we assume we're correct. + ram_assigned = ram_assigned_copy + + to_chat(affected_AIs, span_warning("You have been deducted memory capacity. Please contact your network administrator if you believe this to be an error.")) + + + +/datum/ai_shared_resources/proc/set_cpu(target, amount) + if(!istype(target, /datum/ai_network) && !istype(target, /mob/living/silicon/ai)) + stack_trace("Attempted to set_cpu with non-AI/network target! T: [target]") + return + + if(!target) + return + if(amount > 1 || amount < 0) + return + cpu_assigned[target] = amount + + update_allocations() + + +/datum/ai_shared_resources/proc/add_ram(target, amount) + if(!istype(target, /datum/ai_network) && !istype(target, /mob/living/silicon/ai)) + stack_trace("Attempted to add_ram with non-AI/network target! T: [target]") + return + + if(!target || !amount) + return + ram_assigned[target] += amount + + update_allocations() + + +/datum/ai_shared_resources/proc/remove_ram(target, amount) + if(!istype(target, /datum/ai_network) && !istype(target, /mob/living/silicon/ai)) + stack_trace("Attempted to remove_ram with non-AI/network target! T: [target]") + return + + if(!target || !amount) + return + if(ram_assigned[target] - amount < 0) + ram_assigned[target] = 0 + else + ram_assigned[target] -= amount + + update_allocations() + + +/datum/ai_shared_resources/proc/clear_ai_resources(target) + if(!istype(target, /datum/ai_network) && !istype(target, /mob/living/silicon/ai)) + stack_trace("Attempted to clear_ai_resources with non-AI/network target! T: [target]") + return + + if(!target) + return + + remove_ram(target, ram_assigned[target]) + cpu_assigned[target] = 0 + + update_allocations() + diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index a646a92fb17e..435812c1e0fc 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -26,7 +26,7 @@ ShutOffDoomsdayDevice() - GLOB.ai_os.remove_ai(src) + ai_network?.remove_ai(src) if(explosive) spawn(10) diff --git a/code/modules/mob/living/silicon/ai/decentralized/_ai_machinery.dm b/code/modules/mob/living/silicon/ai/decentralized/_ai_machinery.dm index dda04e4f79ce..fe7cca02dad2 100644 --- a/code/modules/mob/living/silicon/ai/decentralized/_ai_machinery.dm +++ b/code/modules/mob/living/silicon/ai/decentralized/_ai_machinery.dm @@ -9,17 +9,22 @@ icon_state = "RD-server-on" density = TRUE + var/datum/ai_network/network + /obj/machinery/ai/Initialize(mapload) . = ..() SSair.atmos_machinery += src + connect_to_network() /obj/machinery/ai/Destroy() . = ..() - + disconnect_from_network() SSair.atmos_machinery -= src /obj/machinery/ai/proc/valid_holder() + if(!network) + return FALSE if(stat & (BROKEN|NOPOWER|EMPED)) return FALSE @@ -31,13 +36,15 @@ if(istype(T, /turf/open/space) || total_moles < 10) return FALSE - if(env.return_temperature() > GLOB.ai_os.get_temp_limit() || !env.heat_capacity()) + if(env.return_temperature() > network.get_temp_limit() || !env.heat_capacity()) return FALSE return TRUE /obj/machinery/ai/proc/get_holder_status() if(stat & (BROKEN|NOPOWER|EMPED)) return FALSE + if(!network) + return FALSE var/turf/T = get_turf(src) var/datum/gas_mixture/env = T.return_air() @@ -47,6 +54,39 @@ if(istype(T, /turf/open/space) || total_moles < 10) return AI_MACHINE_NO_MOLES - if(env.return_temperature() > GLOB.ai_os.get_temp_limit() || !env.heat_capacity()) + if(env.return_temperature() > network.get_temp_limit() || !env.heat_capacity()) return AI_MACHINE_TOO_HOT - \ No newline at end of file + + +/obj/machinery/ai/proc/connect_to_network() + var/turf/T = src.loc + if(!T || !istype(T)) + return FALSE + + var/obj/structure/ethernet_cable/C = T.get_ai_cable_node() //check if we have a node cable on the machine turf, the first found is picked + if(!C || !C.network) + return FALSE + + C.network.add_machine(src) + return TRUE + +// remove and disconnect the machine from its current powernet +/obj/machinery/ai/proc/disconnect_from_network() + if(!network) + return FALSE + network.remove_machine(src) + return TRUE + +// attach a wire to a power machine - leads from the turf you are standing on +//almost never called, overwritten by all power machines but terminal and generator +/obj/machinery/ai/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/stack/ethernet_coil)) + var/obj/item/stack/ethernet_coil/coil = W + var/turf/T = user.loc + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE || !isfloorturf(T)) + return + if(get_dist(src, user) > 1) + return + coil.place_turf(T, user) + else + return ..() diff --git a/code/modules/mob/living/silicon/ai/decentralized/ai_data_core.dm b/code/modules/mob/living/silicon/ai/decentralized/ai_data_core.dm index 69683bb2cf55..61ea4531ef20 100644 --- a/code/modules/mob/living/silicon/ai/decentralized/ai_data_core.dm +++ b/code/modules/mob/living/silicon/ai/decentralized/ai_data_core.dm @@ -2,7 +2,7 @@ GLOBAL_LIST_EMPTY(data_cores) GLOBAL_VAR_INIT(primary_data_core, null) /obj/machinery/ai/data_core - name = "AI Data Core" + name = "AI data core" desc = "A complicated computer system capable of emulating the neural functions of an organic being at near-instantanous speeds." icon = 'icons/obj/machines/ai_core.dmi' icon_state = "core-offline" @@ -113,8 +113,9 @@ GLOBAL_VAR_INIT(primary_data_core, null) /obj/machinery/ai/data_core/proc/valid_data_core() if(!is_reebe(z) && !is_station_level(z)) return FALSE - if(valid_ticks > 0) + if(valid_ticks > 0 && network && network.total_cpu() >= AI_CORE_CPU_REQUIREMENT && network.total_ram() >= AI_CORE_RAM_REQUIREMENT) return TRUE + return FALSE @@ -168,6 +169,14 @@ GLOBAL_VAR_INIT(primary_data_core, null) AI.forceMove(src) if(AI.eyeobj) AI.eyeobj.forceMove(get_turf(src)) + + if(network != AI.ai_network) + if(AI.ai_network) + AI.ai_network.remove_ai(AI) + var/old_net = AI.ai_network + AI.ai_network = network + network.ai_list += AI + AI.switch_ainet(old_net, network) /obj/machinery/ai/data_core/update_icon() cut_overlays() @@ -179,6 +188,25 @@ GLOBAL_VAR_INIT(primary_data_core, null) else icon_state = "core-offline" +/obj/machinery/ai/data_core/connect_to_network() //If we ever get connected to a network (or a new one gets created) we get the AIs to the correct one too + . = ..() + for(var/mob/living/silicon/ai/AI in contents) + if(!AI.ai_network) + network.ai_list |= AI + var/old_net = AI.ai_network + AI.ai_network = network + AI.switch_ainet(old_net, network) + + if(AI.ai_network != network) + if(AI.ai_network) + AI.ai_network.remove_ai(AI) + var/old_net = AI.ai_network + AI.ai_network = network + network.ai_list |= AI + AI.switch_ainet(old_net, network) + + + /obj/machinery/ai/data_core/proc/partytime() var/current_color = random_color() set_light(7, 3, current_color) @@ -189,6 +217,9 @@ GLOBAL_VAR_INIT(primary_data_core, null) if(TimerID) deltimer(TimerID) TimerID = null + + + /obj/machinery/ai/data_core/primary name = "primary AI Data Core" desc = "A complicated computer system capable of emulating the neural functions of a human at near-instantanous speeds. This one has a scrawny and faded note saying: 'Primary AI Data Core'" diff --git a/code/modules/mob/living/silicon/ai/decentralized/computer_science_datum.dm b/code/modules/mob/living/silicon/ai/decentralized/computer_science_datum.dm new file mode 100644 index 000000000000..daabc3307057 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/decentralized/computer_science_datum.dm @@ -0,0 +1,3 @@ +/datum/computer_science + var/projects = list() + diff --git a/code/modules/mob/living/silicon/ai/decentralized/decentralized_os.dm b/code/modules/mob/living/silicon/ai/decentralized/decentralized_os.dm deleted file mode 100644 index 42ba34b5257f..000000000000 --- a/code/modules/mob/living/silicon/ai/decentralized/decentralized_os.dm +++ /dev/null @@ -1,131 +0,0 @@ -GLOBAL_DATUM_INIT(ai_os, /datum/ai_os, new) - -/datum/ai_os - var/name = "Decentralized Resource Management System (DRMS)" - - var/total_cpu = 0 - var/total_ram = 0 - - var/previous_ram = 0 - - var/list/cpu_assigned - var/list/ram_assigned - - var/temp_limit = AI_TEMP_LIMIT - -/datum/ai_os/New() - update_hardware() - cpu_assigned = list() - ram_assigned = list() - -/datum/ai_os/proc/remove_ai(mob/living/silicon/ai/AI) - cpu_assigned.Remove(AI) - ram_assigned.Remove(AI) - update_allocations() - -/datum/ai_os/proc/total_cpu_assigned() - var/total = 0 - for(var/N in cpu_assigned) - total += cpu_assigned[N] - return total - -/datum/ai_os/proc/total_ram_assigned() - var/total = 0 - for(var/mob/living/silicon/ai/AI in ram_assigned) - total += (ram_assigned[AI] - AI.dashboard.free_ram) - return total - -/datum/ai_os/proc/update_hardware() - previous_ram = total_ram - total_ram = 0 - total_cpu = 0 - for(var/obj/machinery/ai/server_cabinet/C in GLOB.server_cabinets) - if(!C.valid_holder() && !C.roundstart) - continue - total_ram += C.total_ram - total_cpu += C.total_cpu - - update_allocations() - -/datum/ai_os/proc/update_allocations() - //Do we have the same amount or more RAM than before? Do nothing - if(total_ram >= previous_ram) - return - //Find out how much is actually assigned. We can have more total_cpu than the sum of cpu_assigned. Same with RAM - var/total_assigned_ram = total_ram_assigned() - //If we have less assigned ram than we have cpu and ram, just return, everything is fine. - if(total_assigned_ram < total_ram) - return - - //Copy the lists of assigned resources so we don't manipulate the list prematurely. - var/list/ram_assigned_copy = ram_assigned.Copy() - //List of touched AIs so we can notify them at the end. - var/list/affected_AIs = list() - - - if(total_assigned_ram > total_ram) - var/needed_amount = total_assigned_ram - total_ram - for(var/A in ram_assigned_copy) - var/mob/living/silicon/ai/AI = A - if((ram_assigned_copy[AI] - AI.dashboard.free_ram) >= needed_amount) - ram_assigned_copy[AI] -= needed_amount - total_assigned_ram -= needed_amount - affected_AIs |= AI - break - else if(ram_assigned_copy[AI]) - var/amount = ram_assigned_copy[AI] - AI.dashboard.free_ram - ram_assigned_copy[AI] -= amount - affected_AIs |= AI - needed_amount -= amount - total_assigned_ram -= amount - if(total_ram >= total_assigned_ram) - break - //Set the actual values of the assigned to our manipulated copies. Bypass helper procs as we assume we're correct. - ram_assigned = ram_assigned_copy - - to_chat(affected_AIs, span_warning("You have been deducted memory capacity. Please contact your network administrator if you believe this to be an error.")) - -/datum/ai_os/proc/set_cpu(mob/living/silicon/ai/AI, amount) - if(!AI) - return - if(amount > 1 || amount < 0) - return - if(!istype(AI)) - return - cpu_assigned[AI] = amount - - update_allocations() - -/datum/ai_os/proc/add_ram(mob/living/silicon/ai/AI, amount) - if(!AI || !amount) - return - if(!istype(AI)) - return - ram_assigned[AI] += amount - - update_allocations() - -/datum/ai_os/proc/remove_ram(mob/living/silicon/ai/AI, amount) - if(!AI || !amount) - return - if(!istype(AI)) - return - if(ram_assigned[AI] - amount < 0) - ram_assigned[AI] = 0 - else - ram_assigned[AI] -= amount - - update_allocations() - - -/datum/ai_os/proc/clear_ai_resources(mob/living/silicon/ai/AI) - if(!AI || !istype(AI)) - return - - remove_ram(AI, ram_assigned[AI]) - cpu_assigned[AI] = 0 - - update_allocations() - -/datum/ai_os/proc/get_temp_limit() - return temp_limit diff --git a/code/modules/mob/living/silicon/ai/decentralized/management/ai_controlpanel.dm b/code/modules/mob/living/silicon/ai/decentralized/management/ai_controlpanel.dm deleted file mode 100644 index d5ada3439079..000000000000 --- a/code/modules/mob/living/silicon/ai/decentralized/management/ai_controlpanel.dm +++ /dev/null @@ -1,446 +0,0 @@ -GLOBAL_VAR_INIT(ai_control_code, random_nukecode(6)) - -/obj/machinery/computer/ai_control_console - name = "\improper AI control console" - desc = "Used for accessing the central AI repository from which AIs can be downloaded or uploaded." - req_access = list(ACCESS_RD) - icon_keyboard = "tech_key" - icon_screen = "ai-fixer" - light_color = LIGHT_COLOR_PINK - - var/cleared_for_use = FALSE //Have we inserted the RDs code to unlock upload/download? - - var/one_time_password_used = FALSE //Did we use the one time password to log in? If so disallow logging out. - - authenticated = FALSE - - var/obj/item/aicard/intellicard - - var/mob/living/silicon/ai/downloading - var/mob/user_downloading - var/download_progress = 0 - var/download_warning = FALSE - - circuit = /obj/item/circuitboard/computer/ai_upload_download - -/obj/machinery/computer/ai_control_console/Initialize(mapload) - . = ..() - if(mapload) - cleared_for_use = TRUE - -/obj/machinery/computer/ai_control_console/Destroy() - stop_download() - . = ..() - -/obj/machinery/computer/ai_control_console/attackby(obj/item/W, mob/living/user, params) - if(istype(W, /obj/item/aicard)) - if(intellicard) - to_chat(user, span_warning("There's already an IntelliCard inserted!")) - return ..() - to_chat(user, span_notice("You insert [W].")) - W.forceMove(src) - intellicard = W - return FALSE - if(istype(W, /obj/item/mmi)) - var/obj/item/mmi/brain = W - if(!brain.brainmob) - to_chat(user, span_warning("[W] is not active!")) - return ..() - SSticker.mode.remove_antag_for_borging(brain.brainmob.mind) - if(!istype(brain.laws, /datum/ai_laws/ratvar)) - remove_servant_of_ratvar(brain.brainmob, TRUE) - var/mob/living/silicon/ai/A = null - - var/datum/ai_laws/laws = new - laws.set_laws_config() - - if (brain.overrides_aicore_laws) - A = new /mob/living/silicon/ai(loc, brain.laws, brain.brainmob) - else - A = new /mob/living/silicon/ai(loc, laws, brain.brainmob) - - A.relocate(TRUE) - - if(brain.force_replace_ai_name) - A.fully_replace_character_name(A.name, brain.replacement_ai_name()) - SSblackbox.record_feedback("amount", "ais_created", 1) - qdel(W) - to_chat(user, span_notice("AI succesfully uploaded.")) - return FALSE - if(istype(W, /obj/item/surveillance_upgrade)) - if(!authenticated) - to_chat(user, span_warning("You need to be logged in to do this!")) - return ..() - var/mob/living/silicon/ai/AI = input("Select an AI", "Select an AI", null, null) as null|anything in GLOB.ai_list - if(!AI) - return ..() - var/obj/item/surveillance_upgrade/upgrade = W - upgrade.afterattack(AI, user) - - if(istype(W, /obj/item/malf_upgrade)) - if(!authenticated) - to_chat(user, span_warning("You need to be logged in to do this!")) - return ..() - var/mob/living/silicon/ai/AI = input("Select an AI", "Select an AI", null, null) as null|anything in GLOB.ai_list - if(!AI) - return ..() - var/obj/item/malf_upgrade/upgrade = W - upgrade.afterattack(AI, user) - - return ..() - -/obj/machinery/computer/ai_control_console/emag_act(mob/user) - if(obj_flags & EMAGGED) - return - to_chat(user, span_warning("You bypass the access restrictions")) - authenticated = TRUE - obj_flags |= EMAGGED - -/obj/machinery/computer/ai_control_console/process() - if(stat & (BROKEN|NOPOWER|EMPED)) - return - - if(downloading && download_progress >= 50 && !download_warning) - var/turf/T = get_turf(src) - to_chat(downloading, span_userdanger("Warning! Download is 50% completed! Download location: [get_area(src)] ([T.x], [T.y], [T.z])!")) - download_warning = TRUE - if(downloading && download_progress >= 100) - finish_download() - - if(downloading) - if(!downloading.can_download) - stop_download() - return - download_progress += AI_DOWNLOAD_PER_PROCESS * downloading.downloadSpeedModifier - - -/obj/machinery/computer/ai_control_console/ui_interact(mob/user, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "AiControlPanel", name) - ui.open() - -/obj/machinery/computer/ai_control_console/ui_data(mob/living/carbon/human/user) - var/list/data = list() - - if(!cleared_for_use) - data["cleared_for_use"] = FALSE - return data - - data["cleared_for_use"] = TRUE - data["authenticated"] = authenticated - - if(issilicon(user)) - var/mob/living/silicon/borg = user - data["username"] = borg.name - data["has_access"] = TRUE - - if(IsAdminGhost(user)) - data["username"] = user.client.holder.admin_signature - data["has_access"] = TRUE - - if(ishuman(user) && !(obj_flags & EMAGGED)) - var/username = user.get_authentification_name("Unknown") - data["username"] = user.get_authentification_name("Unknown") - if(username != "Unknown") - var/datum/data/record/record - for(var/RP in GLOB.data_core.general) - var/datum/data/record/R = RP - - if(!istype(R)) - continue - if(R.fields["name"] == username) - record = R - break - if(record) - if(istype(record.fields["photo_front"], /obj/item/photo)) - var/obj/item/photo/P1 = record.fields["photo_front"] - var/icon/picture = icon(P1.picture.picture_image) - picture.Crop(10, 32, 22, 22) - var/md5 = md5(fcopy_rsc(picture)) - - if(!SSassets.cache["photo_[md5]_cropped.png"]) - SSassets.transport.register_asset("photo_[md5]_cropped.png", picture) - SSassets.transport.send_assets(user, list("photo_[md5]_cropped.png" = picture)) - - data["user_image"] = SSassets.transport.get_asset_url("photo_[md5]_cropped.png") - data["has_access"] = check_access(user.get_idcard()) - - if(obj_flags & EMAGGED) - data["username"] = "ERROR" - data["has_access"] = TRUE - - if(!authenticated) - return data - - data["intellicard"] = intellicard - if(intellicard && intellicard.AI) - data["intellicard_ai"] = intellicard.AI.real_name - data["intellicard_ai_health"] = intellicard.AI.health - else - data["intellicard_ai"] = null - data["intellicard_ai_health"] = 0 - - data["can_upload"] = available_ai_cores() - - if(downloading) - data["downloading"] = downloading.real_name - data["download_progress"] = download_progress - data["downloading_ref"] = REF(downloading) - else - data["downloading"] = null - data["download_progress"] = 0 - - data["ais"] = list() - data["current_ai_ref"] = null - if(isAI(user)) - data["current_ai_ref"] = REF(user) - - data["can_log_out"] = !one_time_password_used - - for(var/mob/living/silicon/ai/A in GLOB.ai_list) - var/being_hijacked = A.hijacking ? TRUE : FALSE - data["ais"] += list(list("name" = A.name, "ref" = REF(A), "can_download" = A.can_download, "health" = A.health, "active" = A.mind ? TRUE : FALSE, "being_hijacked" = being_hijacked, "in_core" = istype(A.loc, /obj/machinery/ai/data_core))) - - data["is_infiltrator"] = is_infiltrator(user) - - return data - -/obj/machinery/computer/ai_control_console/proc/finish_download() - if(!is_station_level(z)) - return - if(intellicard) - if(!isaicore(downloading.loc)) - stop_download(TRUE) - return - downloading.transfer_ai(AI_TRANS_TO_CARD, user_downloading, null, intellicard) - intellicard.forceMove(get_turf(src)) - intellicard.update_icon() - intellicard = null - stop_download(TRUE) - -/obj/machinery/computer/ai_control_console/proc/stop_download(silent = FALSE) - if(downloading) - if(!silent) - to_chat(downloading, span_userdanger("Download stopped.")) - downloading = null - user_downloading = null - download_progress = 0 - download_warning = FALSE - -/obj/machinery/computer/ai_control_console/proc/upload_ai(silent = FALSE) - to_chat(intellicard.AI, span_notice("You are being uploaded. Please stand by...")) - intellicard.AI.radio_enabled = TRUE - intellicard.AI.control_disabled = FALSE - intellicard.AI.relocate(TRUE) - intellicard.AI = null - intellicard.update_icon() - -/obj/machinery/computer/ai_control_console/ui_act(action, params) - if(..()) - return - - if(!cleared_for_use) - if(action == "clear_for_use") - var/code = params["control_code"] - - if(!code) - return - - if(!GLOB.ai_control_code) - return - - var/length_of_number = length(code) - if(length_of_number < 6) - to_chat(usr, span_warning("Incorrect code. Too short")) - return - - if(length_of_number > 6) - to_chat(usr, span_warning("Incorrect code. Too long")) - return - - if(!is_station_level(z)) - to_chat(usr, span_warning("Unable to connect to NT Servers. Please verify you are onboard the station.")) - return - - if(code == GLOB.ai_control_code) - cleared_for_use = TRUE - else - to_chat(usr, span_warning("Incorrect code. Make sure you have the latest one.")) - - return - - if(!authenticated) - if(action == "log_in") - if(issilicon(usr)) - authenticated = TRUE - return - - if(IsAdminGhost(usr)) - authenticated = TRUE - - if(obj_flags & EMAGGED) - authenticated = TRUE - - var/mob/living/carbon/human/H = usr - if(!istype(H)) - return - - if(check_access(H.get_idcard())) - authenticated = TRUE - if(action == "log_in_control_code") - var/code = params["control_code"] - - if(!code) - return - - if(!GLOB.ai_control_code) - return - - var/length_of_number = length(code) - if(length_of_number < 6) - to_chat(usr, span_warning("Incorrect code. Too short")) - return - - if(length_of_number > 6) - to_chat(usr, span_warning("Incorrect code. Too long")) - return - - if(code == GLOB.ai_control_code) - cleared_for_use = TRUE - authenticated = TRUE - one_time_password_used = TRUE - var/msg = "

Warning!


We have detected usage of the AI Control Code for unlocking a console at coordinates ([src.x], [src.y], [src.z]) by [usr.name]. Please verify that this is correct. Be aware we have cancelled the current control code.
\ - If needed a new code can be printed at a communications console." - priority_announce(msg, sender_override = "Central Cyber Security Update", has_important_message = TRUE, sanitize = FALSE) - GLOB.ai_control_code = null - else - to_chat(usr, span_warning("Incorrect code. Make sure you have the latest one.")) - return - - switch(action) - if("log_out") - if(one_time_password_used) - return - authenticated = FALSE - . = TRUE - if("upload_intellicard") - if(!intellicard || downloading) - return - if(!intellicard.AI) - return - upload_ai() - - if("eject_intellicard") - if(issilicon(usr)) - to_chat(usr, span_warning("You're unable to remotely eject the IntelliCard!")) - return - stop_download() - intellicard.forceMove(get_turf(src)) - intellicard = null - - if("stop_download") - if(isAI(usr)) - to_chat(usr, span_warning("You need physical access to stop the download!")) - return - if(!is_station_level(z)) - to_chat(usr, span_warning("No connection. Try again later.")) - return - stop_download() - - if("start_download") - if(!intellicard || downloading) - return - var/mob/living/silicon/ai/target = locate(params["download_target"]) - if(!target || !istype(target)) - return - if(!istype(target.loc, /obj/machinery/ai/data_core)) - return - if(!target.can_download) - return - if(!is_station_level(z)) - to_chat(usr, span_warning("No connection. Try again later.")) - return - downloading = target - to_chat(downloading, span_userdanger("Warning! Someone is attempting to download you from [get_area(src)]! (Click here to finish download instantly)")) - user_downloading = usr - download_progress = 0 - . = TRUE - if("skip_download") - if(!downloading) - return - if(usr == downloading) - finish_download() - - if("start_hijack") - var/mob/user = usr - if(!is_infiltrator(usr)) - return - if(!is_station_level(z)) - to_chat(user, span_warning("No connection. Try again later.")) - return - if(!istype(user.get_active_held_item(), /obj/item/ai_hijack_device)) - to_chat(user, span_warning("You need to be holding the serial exploitation unit to initiate the hijacking process!")) - return - var/obj/item/ai_hijack_device/device = user.get_active_held_item() - var/mob/living/silicon/ai/target = locate(params["target_ai"]) - if(!target || !isAI(target)) - return - var/mob/living/silicon/ai/A = target - if(A.mind && A.mind.has_antag_datum(/datum/antagonist/hijacked_ai)) - to_chat(user, span_warning("[A] has already been hijacked!")) - return - if(A.stat == DEAD) - to_chat(user, span_warning("[A] is dead!")) - return - if(A.hijacking) - to_chat(user, span_warning("[A] is already in the process of being hijacked!")) - return - user.visible_message(span_warning("[user] begins furiously typing something into [src]...")) - if(do_after(user, 5.5 SECONDS, src)) - user.dropItemToGround(device) - device.forceMove(A) - A.hijacking = device - A.hijack_start = world.time - A.update_icons() - to_chat(A, span_danger("Unknown device connected to /dev/ttySL0")) - to_chat(A, span_danger("Connected at 115200 bps")) - to_chat(A, span_binarysay("ntai login: root")) - to_chat(A, span_binarysay("Password: *****r2")) - to_chat(A, span_binarysay("$ dd from=/dev/ttySL0 of=/tmp/ai-hijack bs=4096 && chmod +x /tmp/ai-hijack && tmp/ai-hijack")) - to_chat(A, span_binarysay("111616 bytes (112 KB, 109 KiB) copied, 1 s, 14.4 KB/s")) - message_admins("[ADMIN_LOOKUPFLW(user)] has attached a hijacking device to [ADMIN_LOOKUPFLW(A)]!") - notify_ghosts("[user] has begun to hijack [A]!", source = src, action = NOTIFY_ORBIT, ghost_sound = 'sound/machines/chime.ogg') - - if("stop_hijack") - var/mob/living/silicon/ai/target = locate(params["target_ai"]) - if(!target || !isAI(target)) - return - var/mob/living/silicon/ai/A = target - var/mob/user = usr - - if(!is_station_level(z)) - to_chat(user, span_warning("No connection. Try again later.")) - return - - user.visible_message(span_danger("[user] attempts to cancel a process on [src]."), span_notice("An unknown process seems to be interacting with [A]! You attempt to end the proccess..")) - if (do_after(user, 10 SECONDS, src)) - A.hijacking.forceMove(get_turf(src)) - A.hijacking = null - A.hijack_start = 0 - A.update_icons() - to_chat(A, span_bolddanger("Unknown device disconnected. Systems confirmed secure.")) - else - to_chat(user, span_notice("You fail to remove the device.")) - - - -/obj/item/paper/ai_control_code/Initialize(mapload) - ..() - print() - -/obj/item/paper/ai_control_code/proc/print() - name = "paper - 'AI control code'" - info = "

Daily AI Control Key Reset


The new authentication key is '[GLOB.ai_control_code]'.
Please keep this a secret and away from the clown.
This code may be invalidated if a new one is requested." - add_overlay("paper_words") - diff --git a/code/modules/mob/living/silicon/ai/decentralized/management/ai_dashboard.dm b/code/modules/mob/living/silicon/ai/decentralized/management/ai_dashboard.dm index fd590ef810a7..e4ca7802d91d 100644 --- a/code/modules/mob/living/silicon/ai/decentralized/management/ai_dashboard.dm +++ b/code/modules/mob/living/silicon/ai/decentralized/management/ai_dashboard.dm @@ -11,10 +11,6 @@ var/completed_projects var/running_projects - ///Should we be contributing spare CPU to generate research points? - var/contribute_spare_cpu = TRUE - ///Are we using 50% of our spare CPU to mine bitcoin? - var/crypto_mining = FALSE /datum/ai_dashboard/New(mob/living/silicon/ai/new_owner) if(!istype(new_owner)) @@ -57,8 +53,8 @@ /datum/ai_dashboard/ui_data(mob/user) var/list/data = list() - data["current_cpu"] = GLOB.ai_os.cpu_assigned[owner] ? GLOB.ai_os.cpu_assigned[owner] : 0 - data["current_ram"] = GLOB.ai_os.ram_assigned[owner] ? GLOB.ai_os.ram_assigned[owner] : 0 + data["current_cpu"] = owner.ai_network.resources.cpu_assigned[owner] ? owner.ai_network.resources.cpu_assigned[owner] : 0 + data["current_ram"] = owner.ai_network.resources.ram_assigned[owner] ? owner.ai_network.resources.ram_assigned[owner] : 0 data["current_ram"] += free_ram var/total_cpu_used = 0 @@ -69,13 +65,13 @@ for(var/I in ram_usage) total_ram_used += ram_usage[I] - data["contribute_spare_cpu"] = contribute_spare_cpu data["used_cpu"] = total_cpu_used data["used_ram"] = total_ram_used - data["max_cpu"] = GLOB.ai_os.total_cpu - data["max_ram"] = GLOB.ai_os.total_ram + data["total_cpu_used"] = owner.ai_network.resources.total_cpu_assigned() + data["max_cpu"] = owner.ai_network.resources.total_cpu() + data["max_ram"] = owner.ai_network.resources.total_ram() data["categories"] = GLOB.ai_project_categories data["available_projects"] = list() @@ -164,9 +160,36 @@ if(!set_project_cpu(project, amount_to_add)) to_chat(owner, span_warning("Unable to add CPU to [params["project_name"]]. Either not enough free CPU or project is unavailable.")) . = TRUE - if("toggle_contribute_cpu") - contribute_spare_cpu = !contribute_spare_cpu - to_chat(owner, span_notice("You now[contribute_spare_cpu ? "" : " DO NOT"] contribute spare CPU to generating research points.")) + if("clear_ai_resources") + owner.ai_network.resources.clear_ai_resources(src) + . = TRUE + + if("set_cpu") + var/amount = params["amount_cpu"] + + if(amount > 1 || amount < 0) + return + + owner.ai_network.resources.set_cpu(owner, amount) + . = TRUE + if("max_cpu_assign") + var/amount = (1 - owner.ai_network.resources.total_cpu_assigned()) + owner.ai_network.resources.cpu_assigned[owner] + + owner.ai_network.resources.set_cpu(owner, amount) + . = TRUE + if("add_ram") + if(owner.ai_network.resources.total_ram_assigned() >= owner.ai_network.resources.total_ram()) + return + owner.ai_network.resources.add_ram(owner, 1) + . = TRUE + + if("remove_ram") + var/current_ram = owner.ai_network.resources.ram_assigned[owner] + + if(current_ram <= 0) + return + owner.ai_network.resources.remove_ram(owner, 1) + . = TRUE /datum/ai_dashboard/proc/get_project_by_name(project_name, only_available = FALSE) for(var/datum/ai_project/AP as anything in available_projects) @@ -210,7 +233,7 @@ /datum/ai_dashboard/proc/run_project(datum/ai_project/project) - var/current_ram = GLOB.ai_os.ram_assigned[owner] ? GLOB.ai_os.ram_assigned[owner] : 0 + var/current_ram = owner.ai_network.resources.ram_assigned[owner] ? owner.ai_network.resources.ram_assigned[owner] : 0 current_ram += free_ram var/total_ram_used = 0 @@ -268,8 +291,8 @@ //Stuff is handled in here per tick :) /datum/ai_dashboard/proc/tick(seconds) - var/current_cpu = GLOB.ai_os.cpu_assigned[owner] ? GLOB.ai_os.total_cpu * GLOB.ai_os.cpu_assigned[owner] : 0 - var/current_ram = GLOB.ai_os.ram_assigned[owner] ? GLOB.ai_os.ram_assigned[owner] : 0 + var/current_cpu = owner.ai_network.resources.cpu_assigned[owner] ? owner.ai_network.total_cpu() * owner.ai_network.resources.cpu_assigned[owner] : 0 + var/current_ram = owner.ai_network.resources.ram_assigned[owner] ? owner.ai_network.resources.ram_assigned[owner] : 0 current_ram += free_ram @@ -296,22 +319,7 @@ var/remaining_cpu = 1 for(var/I in cpu_usage) remaining_cpu -= cpu_usage[I] - - if(remaining_cpu > 0 && contribute_spare_cpu) - var/points = max(round(AI_RESEARCH_PER_CPU * (remaining_cpu * current_cpu) * owner.research_point_booster), 0) - - if(crypto_mining) - points *= 0.5 - var/bitcoin_mined = points * (1-0.05*sqrt(points)) - bitcoin_mined = clamp(bitcoin_mined, 0, MAX_AI_BITCOIN_MINED_PER_TICK) - var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR) - if(D) - D.adjust_money(bitcoin_mined * AI_BITCOIN_PRICE) - - SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_AI = points)) - - for(var/project_being_researched in cpu_usage) if(!cpu_usage[project_being_researched]) continue diff --git a/code/modules/mob/living/silicon/ai/decentralized/management/resource_distribution.dm b/code/modules/mob/living/silicon/ai/decentralized/management/resource_distribution.dm index 1bbd36bb6573..d8e15064b0e2 100644 --- a/code/modules/mob/living/silicon/ai/decentralized/management/resource_distribution.dm +++ b/code/modules/mob/living/silicon/ai/decentralized/management/resource_distribution.dm @@ -1,3 +1,4 @@ +/* /obj/machinery/computer/ai_resource_distribution name = "\improper AI system resource distribution" desc = "Used for distributing processing resources across the current artificial intelligences." @@ -189,3 +190,4 @@ human_only = !human_only to_chat(usr, span_notice("This console is now operable by [human_only ? "humans only." : "humans and silicons."]")) +*/ diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/_ai_project.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/_ai_project.dm index 3d6d9486e4b2..6a3cd91d8782 100644 --- a/code/modules/mob/living/silicon/ai/decentralized/projects/_ai_project.dm +++ b/code/modules/mob/living/silicon/ai/decentralized/projects/_ai_project.dm @@ -55,6 +55,8 @@ GLOBAL_LIST_EMPTY(ai_projects) dashboard.running_projects += src return TRUE +/datum/ai_project/proc/switch_network(datum/ai_network/old_net, datum/ai_network/new_net) + return TRUE /datum/ai_project/proc/stop() SHOULD_CALL_PARENT(TRUE) diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/ai_dab.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/ai_dab.dm index b3090fa553b0..4e0e6e8f54f4 100644 --- a/code/modules/mob/living/silicon/ai/decentralized/projects/ai_dab.dm +++ b/code/modules/mob/living/silicon/ai/decentralized/projects/ai_dab.dm @@ -10,7 +10,7 @@ . = ..() if(!.) return . - for(var/obj/machinery/ai/data_core/datacores in GLOB.data_cores) + for(var/obj/machinery/ai/data_core/datacores in ai.ai_network.get_all_nodes()) datacores.DabAnimation() stop() diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/coolant_manager.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/coolant_manager.dm index 32bb902377d8..b946c5f97abb 100644 --- a/code/modules/mob/living/silicon/ai/decentralized/projects/coolant_manager.dm +++ b/code/modules/mob/living/silicon/ai/decentralized/projects/coolant_manager.dm @@ -7,6 +7,8 @@ can_be_run = FALSE /datum/ai_project/coolant_manager/finish() - if(GLOB.ai_os.temp_limit == AI_TEMP_LIMIT) //Limit to only 1 AI doing it. - GLOB.ai_os.temp_limit += 10 - \ No newline at end of file + ai.ai_network.temp_limit += 10 + +/datum/ai_project/coolant_manager/switch_network(datum/ai_network/old_net, datum/ai_network/new_net) + old_net.temp_limit -= 10 + new_net.temp_limit += 10 diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/cryptominer.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/cryptominer.dm deleted file mode 100644 index 737b3dae4d4f..000000000000 --- a/code/modules/mob/living/silicon/ai/decentralized/projects/cryptominer.dm +++ /dev/null @@ -1,17 +0,0 @@ -/datum/ai_project/crypto_miner - name = "Crypto Miner" - description = "Allocating spare CPU capacity to mining crypto currency should be able to help fund the station budget. This would however reduce AI research point generation by 50%" - category = AI_PROJECT_MISC - - research_cost = 2000 - - -/datum/ai_project/crypto_miner/run_project(force_run = FALSE) - . = ..(force_run) - if(!.) - return . - dashboard.crypto_mining = TRUE - -/datum/ai_project/crypto_miner/stop() - dashboard.crypto_mining = FALSE - ..() diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/research_booster.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/research_booster.dm deleted file mode 100644 index 4f38cc003342..000000000000 --- a/code/modules/mob/living/silicon/ai/decentralized/projects/research_booster.dm +++ /dev/null @@ -1,19 +0,0 @@ -/datum/ai_project/research_booster - name = "Research Acceleration" - description = "Using fast RAM instead of slow SSD and HDD storage allows for the production of approximately 25% more research points" - research_cost = 2500 - ram_required = 8 - research_requirements_text = "None" - category = AI_PROJECT_MISC - -/datum/ai_project/research_booster/run_project(force_run = FALSE) - . = ..(force_run) - if(!.) - return . - - ai.research_point_booster += 0.25 - -/datum/ai_project/research_booster/stop() - ai.research_point_booster -= 0.25 - ..() - diff --git a/code/modules/mob/living/silicon/ai/decentralized/projects/self_defense.dm b/code/modules/mob/living/silicon/ai/decentralized/projects/self_defense.dm index 2e1c35d976c3..5656a911f5bf 100644 --- a/code/modules/mob/living/silicon/ai/decentralized/projects/self_defense.dm +++ b/code/modules/mob/living/silicon/ai/decentralized/projects/self_defense.dm @@ -26,6 +26,7 @@ if(!isaicore(owner.loc)) to_chat(owner, span_warning("You must be in your core to do this!")) return - for(var/obj/machinery/ai/data_core/core in GLOB.data_cores) + var/mob/living/silicon/ai/AI = owner + for(var/obj/machinery/ai/data_core/core in AI.ai_network.get_all_nodes()) tesla_zap(core, 2, 15000, (TESLA_MOB_DAMAGE | TESLA_MOB_STUN)) core.use_power(5000) diff --git a/code/modules/mob/living/silicon/ai/decentralized/server_cabinet.dm b/code/modules/mob/living/silicon/ai/decentralized/server_cabinet.dm index cfbee01d3539..9a0199537971 100644 --- a/code/modules/mob/living/silicon/ai/decentralized/server_cabinet.dm +++ b/code/modules/mob/living/silicon/ai/decentralized/server_cabinet.dm @@ -1,7 +1,7 @@ GLOBAL_LIST_EMPTY(server_cabinets) /obj/machinery/ai/server_cabinet - name = "Server Cabinet" + name = "server cabinet" desc = "A simple cabinet of bPCIe slots for installing server racks." icon = 'icons/obj/machines/telecomms.dmi' icon_state = "expansion_bus" @@ -42,11 +42,10 @@ GLOBAL_LIST_EMPTY(server_cabinets) update_icon() RefreshParts() + /obj/machinery/ai/server_cabinet/Destroy() installed_racks = list() GLOB.server_cabinets -= src - //Recalculate all the CPUs and RAM :) - GLOB.ai_os.update_hardware() ..() /obj/machinery/ai/server_cabinet/RefreshParts() @@ -67,6 +66,7 @@ GLOBAL_LIST_EMPTY(server_cabinets) /obj/machinery/ai/server_cabinet/process_atmos() valid_ticks = clamp(valid_ticks, 0, MAX_AI_EXPANSION_TICKS) if(valid_holder()) + roundstart = FALSE var/total_usage = (cached_power_usage * power_modifier) use_power(total_usage) @@ -82,8 +82,8 @@ GLOBAL_LIST_EMPTY(server_cabinets) update_icon() was_valid_holder = TRUE - if(!hardware_synced) - GLOB.ai_os.update_hardware() + if(!hardware_synced && network) + network.update_resources() hardware_synced = TRUE else valid_ticks-- @@ -91,9 +91,9 @@ GLOBAL_LIST_EMPTY(server_cabinets) if(valid_ticks > 0) return was_valid_holder = FALSE - cut_overlays() + update_icon() hardware_synced = FALSE - GLOB.ai_os.update_hardware() + network?.update_resources() /obj/machinery/ai/server_cabinet/update_icon() @@ -108,7 +108,9 @@ GLOBAL_LIST_EMPTY(server_cabinets) if(!(stat & (BROKEN|NOPOWER|EMPED))) var/mutable_appearance/on_overlay = mutable_appearance(icon, "expansion_bus_on") add_overlay(on_overlay) - if(!valid_ticks) + if(!valid_ticks) //If we are running on valid ticks we don't turn off instantly, only when we run out + return + if(!network) //If we lose network connection we cut out INSTANTLY return if(installed_racks.len > 0) var/mutable_appearance/on_top_overlay = mutable_appearance(icon, "expansion_bus_top_on") @@ -129,7 +131,7 @@ GLOBAL_LIST_EMPTY(server_cabinets) total_cpu += rack.get_cpu() total_ram += rack.get_ram() cached_power_usage += rack.get_power_usage() - GLOB.ai_os.update_hardware() + network?.update_resources() use_power = ACTIVE_POWER_USE update_icon() return FALSE @@ -142,7 +144,7 @@ GLOBAL_LIST_EMPTY(server_cabinets) total_cpu = 0 total_ram = 0 cached_power_usage = 0 - GLOB.ai_os.update_hardware() + network?.update_resources() to_chat(user, span_notice("You remove all the racks from [src]")) use_power = IDLE_POWER_USE update_icon() @@ -179,4 +181,14 @@ GLOBAL_LIST_EMPTY(server_cabinets) total_ram += rack.get_ram() cached_power_usage += rack.get_power_usage() installed_racks += rack - GLOB.ai_os.update_hardware() + + +/obj/machinery/ai/server_cabinet/connect_to_network() + . = ..() + if(network) + network.update_resources() + +/obj/machinery/ai/server_cabinet/disconnect_from_network() + var/datum/ai_network/temp = network + . = ..() + temp.update_resources() diff --git a/code/modules/mob/living/silicon/ai/decentralized_ai.dm b/code/modules/mob/living/silicon/ai/decentralized_ai.dm index e7d89b406c5d..319a7cc51761 100644 --- a/code/modules/mob/living/silicon/ai/decentralized_ai.dm +++ b/code/modules/mob/living/silicon/ai/decentralized_ai.dm @@ -1,6 +1,12 @@ -/proc/available_ai_cores() +/mob/living/silicon/ai/proc/available_ai_cores(forced = FALSE) if(!GLOB.data_cores.len) return FALSE + + if(!forced) + if(!ai_network) + return FALSE + return ai_network.find_data_core() + var/obj/machinery/ai/data_core/new_data_core = GLOB.primary_data_core if(!new_data_core || !new_data_core.can_transfer_ai()) for(var/obj/machinery/ai/data_core/DC in GLOB.data_cores) @@ -24,20 +30,20 @@ -/mob/living/silicon/ai/proc/relocate(silent = FALSE) +/mob/living/silicon/ai/proc/relocate(silent = FALSE, forced = FALSE) if(is_dying) return if(!silent) to_chat(src, span_userdanger("Connection to data core lost. Attempting to reaquire connection...")) - - if(!GLOB.data_cores.len) - INVOKE_ASYNC(src, /mob/living/silicon/ai.proc/death_prompt) - is_dying = TRUE - return + var/obj/machinery/ai/data_core/new_data_core + new_data_core = available_ai_cores(forced) - var/obj/machinery/ai/data_core/new_data_core = available_ai_cores() + if(!new_data_core) + INVOKE_ASYNC(src, /mob/living/silicon/ai.proc/death_prompt) + is_dying = TRUE + return if(!new_data_core || (new_data_core && !new_data_core.can_transfer_ai())) INVOKE_ASYNC(src, /mob/living/silicon/ai.proc/death_prompt) diff --git a/code/modules/mob/living/silicon/ai/login.dm b/code/modules/mob/living/silicon/ai/login.dm index 454e7eba34e8..036cd889503e 100644 --- a/code/modules/mob/living/silicon/ai/login.dm +++ b/code/modules/mob/living/silicon/ai/login.dm @@ -12,6 +12,3 @@ if(multicam_on) end_multicam() view_core() - if(!login_warned_temp) - to_chat(src, span_userdanger("WARNING. THE WAY AI IS PLAYED HAS CHANGED. PLEASE REFER TO https://github.com/yogstation13/Yogstation/pull/12388")) - login_warned_temp = TRUE diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 332762bc5bf5..7403b10f8422 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -346,6 +346,7 @@ /obj/item/stack/rods/cyborg, /obj/item/stack/tile/plasteel/cyborg, /obj/item/stack/cable_coil/cyborg, + /obj/item/stack/ethernet_coil/cyborg, /obj/item/barrier_taperoll/engineering) radio_channels = list(RADIO_CHANNEL_ENGINEERING) emag_modules = list(/obj/item/borg/stun) @@ -684,6 +685,7 @@ /obj/item/stack/tile/plasteel/cyborg, /obj/item/destTagger/borg, /obj/item/stack/cable_coil/cyborg, + /obj/item/stack/ethernet_coil/cyborg, /obj/item/pinpointer/syndicate_cyborg, /obj/item/borg_chameleon, ) diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm index 78fd1669310d..97a758cff765 100644 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -105,7 +105,7 @@ GLOBAL_VAR_INIT(mouse_killed, 0) /mob/living/simple_animal/mouse/handle_automated_action() if(prob(chew_probability)) var/turf/open/floor/F = get_turf(src) - if(istype(F) && !F.intact) + if(istype(F) && F.underfloor_accessibility >= UNDERFLOOR_INTERACTABLE) var/obj/structure/cable/C = locate() in F if(C && prob(15)) if(C.avail()) @@ -116,6 +116,11 @@ GLOBAL_VAR_INIT(mouse_killed, 0) else C.deconstruct() visible_message(span_warning("[src] chews through the [C].")) + + var/obj/structure/ethernet_cable/E = locate() in F + if(E && prob(15)) + E.deconstruct() + visible_message(span_warning("[src] chews through the [E].")) for(var/obj/item/reagent_containers/food/snacks/cheesewedge/cheese in range(1, src)) if(prob(10)) be_fruitful() diff --git a/code/modules/mob/living/simple_animal/hostile/rat.dm b/code/modules/mob/living/simple_animal/hostile/rat.dm index b52aed171114..85b9107a9fba 100644 --- a/code/modules/mob/living/simple_animal/hostile/rat.dm +++ b/code/modules/mob/living/simple_animal/hostile/rat.dm @@ -82,7 +82,7 @@ if (!mind) if(prob(40)) var/turf/open/floor/F = get_turf(src) - if(istype(F) && !F.intact) + if(istype(F) && !F.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) var/obj/structure/cable/C = locate() in F if(C && prob(15)) if(C.avail()) diff --git a/code/modules/modular_computers/computers/_modular_computer_shared.dm b/code/modules/modular_computers/computers/_modular_computer_shared.dm index b8017d182091..b89f9405387e 100644 --- a/code/modules/modular_computers/computers/_modular_computer_shared.dm +++ b/code/modules/modular_computers/computers/_modular_computer_shared.dm @@ -64,3 +64,10 @@ . += "It has a printer installed." if(user_is_adjacent) . += "The printer's paper levels are at: [printer_slot.stored_paper]/[printer_slot.max_paper].]" + + var/obj/item/computer_hardware/ai_interface/ai_interface = get_modular_computer_part(MC_AI_NETWORK) + if(ai_interface) + if(ai_interface.connected_cable) + . += "It has an AI network interface. It is currently connected to an ethernet cable." + else + . += "It has an AI network interface." diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index 4e5f275639a6..5eaddba955fd 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -131,7 +131,8 @@ if(user.canUseTopic(src, BE_CLOSE)) var/obj/item/computer_hardware/card_slot/card_slot2 = all_components[MC_CARD2] var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD] - return (card_slot2?.try_eject(user) || card_slot?.try_eject(user)) //Try the secondary one first. + var/obj/item/computer_hardware/ai_slot/ai_slot = all_components[MC_AI] + return (card_slot2?.try_eject(user) || card_slot?.try_eject(user) || ai_slot?.try_eject(user)) //Try the secondary one first. // Gets IDs/access levels from card slot. Would be useful when/if PDAs would become modular PCs. @@ -582,6 +583,17 @@ program.alert_pending = FALSE enabled = TRUE +/obj/item/modular_computer/pickup(mob/user) + . = ..() + RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/parent_moved) + +/obj/item/modular_computer/dropped(mob/user) + . = ..() + UnregisterSignal(user, COMSIG_MOVABLE_MOVED) + +/obj/item/modular_computer/proc/parent_moved() + SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED) + /// Sets visible messages to also send to holder because coders didn't know it didn't do this /obj/item/modular_computer/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags) . = ..() @@ -590,3 +602,4 @@ /obj/item/modular_computer/proc/uplink_check(mob/living/M, code) return SEND_SIGNAL(src, COMSIG_NTOS_CHANGE_RINGTONE, M, code) & COMPONENT_STOP_RINGTONE_CHANGE + diff --git a/code/modules/modular_computers/computers/item/laptop/laptop_presets.dm b/code/modules/modular_computers/computers/item/laptop/laptop_presets.dm index 840ca9232238..2f119e308573 100644 --- a/code/modules/modular_computers/computers/item/laptop/laptop_presets.dm +++ b/code/modules/modular_computers/computers/item/laptop/laptop_presets.dm @@ -11,3 +11,14 @@ /obj/item/modular_computer/laptop/preset/brig_physician desc = "A low-end laptop often used by brig physicians." starting_files = list(new /datum/computer_file/program/secureye) + + +/obj/item/modular_computer/laptop/preset/network_admin + desc = "A multi-purpose laptop often used by network admins." + starting_files = list(new /datum/computer_file/program/ai_network_interface) + starting_components = list( /obj/item/computer_hardware/processor_unit/small, + /obj/item/stock_parts/cell/computer, + /obj/item/computer_hardware/hard_drive, + /obj/item/computer_hardware/network_card, + /obj/item/computer_hardware/ai_interface, + /obj/item/computer_hardware/ai_slot) diff --git a/code/modules/modular_computers/computers/machinery/console/console_presets.dm b/code/modules/modular_computers/computers/machinery/console/console_presets.dm index 686d42d27ee9..c333f8aa287c 100644 --- a/code/modules/modular_computers/computers/machinery/console/console_presets.dm +++ b/code/modules/modular_computers/computers/machinery/console/console_presets.dm @@ -217,3 +217,17 @@ qdel(frame) return FALSE return ..() + + +// ===== NETWORK ADMIN CONSOLE ===== +/obj/machinery/modular_computer/console/preset/netmin + console_department = "Engineering" + name = "ai network console" + desc = "A stationary computer. This one comes preloaded with ai network administration software" + starting_files = list( new /datum/computer_file/program/ai_network_interface, new /datum/computer_file/program/aidiag) + initial_program = /datum/computer_file/program/ai_network_interface + starting_components = list( /obj/item/computer_hardware/network_card/wired, + /obj/item/computer_hardware/recharger/APC, + /obj/item/computer_hardware/hard_drive/super, + /obj/item/computer_hardware/processor_unit, + /obj/item/computer_hardware/ai_slot) diff --git a/code/modules/modular_computers/file_system/programs/ainetworkinterface.dm b/code/modules/modular_computers/file_system/programs/ainetworkinterface.dm new file mode 100644 index 000000000000..777e7332118b --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/ainetworkinterface.dm @@ -0,0 +1,465 @@ +/datum/computer_file/program/ai_network_interface + filename = "aiinterface" + filedesc = "AI Network Interface" + category = PROGRAM_CATEGORY_ENGI + program_icon_state = "power_monitor" + extended_desc = "This program connects to a local AI network to allow for administrative access" + ui_header = "power_norm.gif" + transfer_access = ACCESS_NETWORK + usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP | PROGRAM_TABLET + requires_ntnet = FALSE + size = 8 + tgui_id = "NtosAIMonitor" + program_icon = "network-wired" + + var/obj/structure/ethernet_cable/attached_cable + var/obj/machinery/ai/networking/active_networking + var/mob/networking_operator + var/mob/living/silicon/ai/downloading + var/mob/user_downloading + var/download_progress = 0 + var/download_warning = FALSE + + + + +/datum/computer_file/program/ai_network_interface/run_program(mob/living/user) + . = ..(user) + if(ismachinery(computer.physical)) + search() + + +/datum/computer_file/program/ai_network_interface/process_tick() + if(ismachinery(computer.physical) && !get_ainet()) + search() + + if(networking_operator && (!networking_operator.Adjacent(computer.physical))) + if(active_networking) + active_networking.remote_control = null + networking_operator = null + + if(!get_ainet()) + stop_download() + return + if(!get_ai(TRUE)) + stop_download() + return + + if(downloading && download_progress >= 50 && !download_warning) + var/turf/T = get_turf(computer.physical) + if(!downloading.mind && downloading.deployed_shell.mind) + to_chat(downloading.deployed_shell, span_userdanger("Warning! Download is 50% completed! Download location: [get_area(computer.physical)] ([T.x], [T.y], [T.z])!")) + else + to_chat(downloading, span_userdanger("Warning! Download is 50% completed! Download location: [get_area(computer.physical)] ([T.x], [T.y], [T.z])!")) + download_warning = TRUE + if(downloading && download_progress >= 100) + finish_download() + + if(downloading) + if(!downloading.can_download) + stop_download() + return + download_progress += AI_DOWNLOAD_PER_PROCESS * downloading.downloadSpeedModifier + + +/datum/computer_file/program/ai_network_interface/proc/search() + var/turf/T = get_turf(computer) + attached_cable = locate(/obj/structure/ethernet_cable) in T + if(attached_cable) + return + +/datum/computer_file/program/ai_network_interface/proc/get_ainet() + if(ismachinery(computer.physical)) + if(attached_cable) + return attached_cable.network + if(computer.all_components[MC_AI_NETWORK]) + var/obj/item/computer_hardware/ai_interface/ai_interface = computer.all_components[MC_AI_NETWORK] + if(ai_interface) + return ai_interface.get_network() + return FALSE + +/datum/computer_file/program/ai_network_interface/ui_data(mob/user) + var/list/data = get_header_data() + var/datum/ai_network/net = get_ainet() + data["has_ai_net"] = net + + if(!net) + return data + + + //Networking devices control + data["networking_devices"] = list() + for(var/obj/machinery/ai/networking/N in net.get_local_nodes_oftype(/obj/machinery/ai/networking)) + data["networking_devices"] += list(list("label" = N.label, "ref" = REF(N), "has_partner" = N.partner ? N.partner.label : null)) + + //Downloading/Uploadingainet + data["ai_list"] = list() + for(var/mob/living/silicon/ai/AI in net.get_all_ais()) + var/being_hijacked = AI.hijacking ? TRUE : FALSE + data["ai_list"] += list(list("name" = AI.name, "ref" = REF(AI), "can_download" = AI.can_download, "health" = AI.health, "active" = AI.mind ? TRUE : FALSE, "being_hijacked" = being_hijacked, "in_core" = istype(AI.loc, /obj/machinery/ai/data_core), + "assigned_cpu" = net.resources.cpu_assigned[AI] ? net.resources.cpu_assigned[AI] : 0, "assigned_ram" = net.resources.ram_assigned[AI] ? net.resources.ram_assigned[AI] : 0)) + + data["is_infiltrator"] = is_infiltrator(user) + + data["connection_type"] = ismachinery(computer.physical) ? "wired connection" : "local wire shunt" + data["network_name"] = net.label + + data["current_ai_ref"] = null + if(isAI(user)) + data["current_ai_ref"] = REF(user) + + data["intellicard"] = get_ai(TRUE) + var/mob/living/silicon/ai/card_ai = get_ai() + if(card_ai) + data["intellicard_ai"] = card_ai.real_name + data["intellicard_ai_health"] = card_ai.health + else + data["intellicard_ai"] = null + data["intellicard_ai_health"] = 0 + + + if(downloading) + data["downloading"] = downloading.real_name + data["download_progress"] = download_progress + data["downloading_ref"] = REF(downloading) + else + data["downloading"] = null + data["download_progress"] = 0 + + data["holding_mmi"] = user.is_holding_item_of_type(/obj/item/mmi) ? TRUE : FALSE + + data["can_upload"] = net.find_data_core() ? TRUE : FALSE + + + //Resource allocation + + data["total_cpu"] = net.resources.total_cpu() + data["total_ram"] = net.resources.total_ram() + + + data["total_assigned_cpu"] = net.resources.total_cpu_assigned() + data["total_assigned_ram"] = net.resources.total_ram_assigned() + + //Local processing + + data["network_cpu_assignments"] = list() + var/remaining_net_cpu = 1 + for(var/project in GLOB.possible_ainet_activities) + var/assigned = net.local_cpu_usage[project] ? net.local_cpu_usage[project] : 0 + data["network_cpu_assignments"] += list(list("name" = project, "assigned" = assigned, "tagline" = GLOB.ainet_activity_tagline[project], "description" = GLOB.ainet_activity_description[project])) + remaining_net_cpu -= assigned + + data["network_ref"] = REF(net) + data["network_assigned_ram"] = net.resources.ram_assigned[net] ? net.resources.ram_assigned[net] : 0 + data["network_assigned_cpu"] = net.resources.cpu_assigned[net] ? net.resources.cpu_assigned[net] : 0 + data["bitcoin_amount"] = round(net.bitcoin_payout, 1) + + data["remaining_network_cpu"] = remaining_net_cpu + + return data + +/datum/computer_file/program/ai_network_interface/ui_act(action, params, datum/tgui/ui) + if(..()) + return + var/mob/user = usr + var/datum/ai_network/net = get_ainet() + if(!net) + return + + switch(action) + //General actions + if("change_network_name") + var/new_label = stripped_input(usr, "Enter new label", "Set label", max_length = 32) + if(new_label) + if(isnotpretty(new_label)) + to_chat(usr, span_notice("The machine rejects the input. See rule 0.1.")) + var/log_message = "[key_name(usr)] just tripped a pretty filter: '[new_label]'." + message_admins(log_message) + log_say(log_message) + return + net.label = new_label + . = TRUE + //AI interaction, downloading/uploading + if("apply_object") + if(!net) + return TRUE + var/applied_something = FALSE + var/mob/living/silicon/ai/targeted_ai = locate(params["ai_ref"]) in net.get_all_ais() + if(!targeted_ai) + to_chat(user, span_warning("Unable to locate AI.")) + return TRUE + + var/obj/item/surveillance_upgrade/upgrade = user.is_holding_item_of_type(/obj/item/surveillance_upgrade) + if(upgrade) + applied_something = TRUE + upgrade.afterattack(targeted_ai, user) + + var/obj/item/malf_upgrade/malf_upgrade = user.is_holding_item_of_type(/obj/item/malf_upgrade) + if(malf_upgrade) + applied_something = TRUE + malf_upgrade.afterattack(targeted_ai, user) + if(!applied_something) + to_chat(user, span_warning("You don't have any upgrades to upload!")) + return TRUE + if("upload_person") + if(!net) + return TRUE + var/obj/item/mmi/brain = user.is_holding_item_of_type(/obj/item/mmi) + if(brain) + if(!brain.brainmob) + to_chat(user, span_warning("[brain] is not active!")) + return ..() + SSticker.mode.remove_antag_for_borging(brain.brainmob.mind) + if(!istype(brain.laws, /datum/ai_laws/ratvar)) + remove_servant_of_ratvar(brain.brainmob, TRUE) + var/mob/living/silicon/ai/A + + var/datum/ai_laws/laws = new + laws.set_laws_config() + + if (brain.overrides_aicore_laws) + A = new /mob/living/silicon/ai(computer.physical.loc, brain.laws, brain.brainmob) + else + A = new /mob/living/silicon/ai(computer.physical.loc, laws, brain.brainmob) + + A.relocate(TRUE) + + if(brain.force_replace_ai_name) + A.fully_replace_character_name(A.name, brain.replacement_ai_name()) + SSblackbox.record_feedback("amount", "ais_created", 1) + qdel(brain) + to_chat(user, span_notice("AI succesfully uploaded.")) + return FALSE + if("upload_ai") + if(!net) + return TRUE + var/mob/living/silicon/ai/AI = get_ai() + var/obj/item/aicard/intellicard = get_ai(TRUE) + if(!istype(AI)) + to_chat(user, span_warning("IntelliCard contains no AI!")) + return TRUE + to_chat(AI, span_notice("You are being uploaded. Please stand by...")) + AI.radio_enabled = TRUE + AI.control_disabled = FALSE + AI.relocate(TRUE) + intellicard.AI = null + intellicard.update_icon() + to_chat(user, span_notice("AI successfully uploaded")) + + if("stop_download") + if(isAI(user)) + to_chat(user, span_warning("You need physical access to stop the download!")) + return + stop_download() + + if("start_download") + if(!get_ai(TRUE) || downloading) + return + var/mob/living/silicon/ai/target = locate(params["download_target"]) in net.get_all_ais() + if(!target || !istype(target)) + return + if(!istype(target.loc, /obj/machinery/ai/data_core)) + return + if(!target.can_download) + return + downloading = target + + if(!downloading.mind && downloading.deployed_shell.mind) + to_chat(downloading.deployed_shell, span_userdanger("Warning! Someone is attempting to download you from [get_area(computer.physical)]! (Click here to finish download instantly)")) + else + to_chat(downloading, span_userdanger("Warning! Someone is attempting to download you from [get_area(computer.physical)]! (Click here to finish download instantly)")) + user_downloading = user + download_progress = 0 + . = TRUE + if("skip_download") + if(!downloading) + return + if(user == downloading) + finish_download() + + if("start_hijack") + if(!is_infiltrator(user)) + return + if(!istype(user.get_active_held_item(), /obj/item/ai_hijack_device)) + to_chat(user, span_warning("You need to be holding the serial exploitation unit to initiate the hijacking process!")) + return + var/obj/item/ai_hijack_device/device = user.get_active_held_item() + var/mob/living/silicon/ai/target = locate(params["target_ai"]) in net.get_all_ais() + if(!target || !isAI(target)) + return + var/mob/living/silicon/ai/A = target + if(A.mind && A.mind.has_antag_datum(/datum/antagonist/hijacked_ai)) + to_chat(user, span_warning("[A] has already been hijacked!")) + return + if(A.stat == DEAD) + to_chat(user, span_warning("[A] is dead!")) + return + if(A.hijacking) + to_chat(user, span_warning("[A] is already in the process of being hijacked!")) + return + user.visible_message(span_warning("[user] begins furiously typing something into [computer.physical]...")) + if(do_after(user, 5.5 SECONDS, computer.physical)) + user.dropItemToGround(device) + device.forceMove(A) + A.hijacking = device + A.hijack_start = world.time + A.update_icons() + to_chat(A, span_danger("Unknown device connected to /dev/ttySL0")) + to_chat(A, span_danger("Connected at 115200 bps")) + to_chat(A, span_binarysay("ntai login: root")) + to_chat(A, span_binarysay("Password: *****r2")) + to_chat(A, span_binarysay("$ dd from=/dev/ttySL0 of=/tmp/ai-hijack bs=4096 && chmod +x /tmp/ai-hijack && tmp/ai-hijack")) + to_chat(A, span_binarysay("111616 bytes (112 KB, 109 KiB) copied, 1 s, 14.4 KB/s")) + message_admins("[ADMIN_LOOKUPFLW(user)] has attached a hijacking device to [ADMIN_LOOKUPFLW(A)]!") + notify_ghosts("[user] has begun to hijack [A]!", source = computer.physical, action = NOTIFY_ORBIT, ghost_sound = 'sound/machines/chime.ogg') + + if("stop_hijack") + var/mob/living/silicon/ai/target = locate(params["target_ai"]) in net.get_all_ais() + if(!target || !isAI(target)) + return + var/mob/living/silicon/ai/A = target + + + user.visible_message(span_danger("[user] attempts to cancel a process on [computer.physical]."), span_notice("An unknown process seems to be interacting with [A]! You attempt to end the proccess..")) + if (do_after(user, 10 SECONDS, computer.physical)) + A.hijacking.forceMove(get_turf(computer.physical)) + A.hijacking = null + A.hijack_start = 0 + A.update_icons() + to_chat(A, span_bolddanger("Unknown device disconnected. Systems confirmed secure.")) + else + to_chat(user, span_notice("You fail to remove the device.")) + + //Network control + if("control_networking") + if(!params["ref"]) + return + var/obj/machinery/ai/networking/N = locate(params["ref"]) in net.get_local_nodes_oftype(/obj/machinery/ai/networking) + if(active_networking) + active_networking.remote_control = null + networking_operator = user + active_networking = N + active_networking.remote_control = networking_operator + active_networking.ui_interact(networking_operator) + + //Resource allocation + if("clear_ai_resources") + var/atom/target_ai = locate(params["target_ai"]) in net.get_all_ais() | net.resources.networks + + net.resources.clear_ai_resources(target_ai) + . = TRUE + + if("set_cpu") + var/atom/target_ai = locate(params["target_ai"]) in net.get_all_ais() | net.resources.networks + + var/amount = params["amount_cpu"] + if(amount > 1 || amount < 0) + return + net.resources.set_cpu(target_ai, amount) + . = TRUE + if("max_cpu") + var/atom/target_ai = locate(params["target_ai"]) in net.get_all_ais() | net.resources.networks + + var/amount = (1 - net.resources.total_cpu_assigned()) + net.resources.cpu_assigned[target_ai] + + net.resources.set_cpu(target_ai, amount) + . = TRUE + if("add_ram") + var/atom/target_ai = locate(params["target_ai"]) in net.get_all_ais() | net.resources.networks + + if(net.resources.total_ram_assigned() >= net.resources.total_ram()) + return + net.resources.add_ram(target_ai, 1) + . = TRUE + + if("remove_ram") + var/atom/target_ai = locate(params["target_ai"]) in net.get_all_ais() | net.resources.networks + + var/current_ram = net.resources.ram_assigned[target_ai] + + if(current_ram <= 0) + return + net.resources.remove_ram(target_ai, 1) + . = TRUE + + //Local computing + if("allocate_network_cpu") + var/project_type = params["project_name"] + if(!(project_type in GLOB.possible_ainet_activities)) + return + var/amount = text2num(params["amount"]) + if(amount < 0 || amount > 1) + return + + var/total_cpu_used = 0 + for(var/I in net.local_cpu_usage) + if(I == project_type) + continue + total_cpu_used += net.local_cpu_usage[I] + + if((1 - total_cpu_used) >= amount) + net.local_cpu_usage[project_type] = amount + else + net.local_cpu_usage[project_type] = (1 - total_cpu_used) + + . = TRUE + + if("max_network_cpu") + var/project_type = params["project_name"] + if(!(project_type in GLOB.possible_ainet_activities)) + return + + var/total_cpu_used = 0 + for(var/I in net.local_cpu_usage) + if(I == project_type) + continue + total_cpu_used += net.local_cpu_usage[I] + + var/amount_to_add = 1 - total_cpu_used + + net.local_cpu_usage[project_type] = amount_to_add + . = TRUE + if("bitcoin_payout") + var/payout_amount = round(net.bitcoin_payout, 1) //Sure you can have your extra 0.5 credits :) + var/obj/item/holochip/holochip = new (computer.physical.drop_location(), payout_amount) + user.put_in_hands(holochip) + to_chat(user, span_notice("Payout of [payout_amount]cr confirmed.")) + net.bitcoin_payout = 0 + + + + +/datum/computer_file/program/ai_network_interface/proc/finish_download() + var/obj/item/aicard/intellicard = get_ai(TRUE) + if(intellicard) + if(!isaicore(downloading.loc)) + stop_download(TRUE) + return + downloading.transfer_ai(AI_TRANS_TO_CARD, user_downloading, null, intellicard) + intellicard.update_icon() + stop_download(TRUE) + +/datum/computer_file/program/ai_network_interface/proc/stop_download(silent = FALSE) + if(downloading) + if(!silent) + to_chat(downloading, span_userdanger("Download stopped.")) + downloading = null + user_downloading = null + download_progress = 0 + download_warning = FALSE + + +/datum/computer_file/program/ai_network_interface/proc/get_ai(get_card = FALSE) + var/obj/item/computer_hardware/ai_slot/ai_slot + + if(computer) + ai_slot = computer.all_components[MC_AI] + + if(computer && ai_slot && ai_slot.check_functionality()) + if(ai_slot.enabled && ai_slot.stored_card) + if(get_card) + return ai_slot.stored_card + if(ai_slot.stored_card.AI) + return ai_slot.stored_card.AI + + diff --git a/code/modules/modular_computers/hardware/aiinterface.dm b/code/modules/modular_computers/hardware/aiinterface.dm new file mode 100644 index 000000000000..49bc5baa108e --- /dev/null +++ b/code/modules/modular_computers/hardware/aiinterface.dm @@ -0,0 +1,43 @@ +/obj/item/computer_hardware/ai_interface + name = "portable AI network interface" + desc = "A module allowing this computer to interface with local AI networks. Only works with portable computers" + power_usage = 15 //W + icon_state = "card_mini" + w_class = WEIGHT_CLASS_SMALL // Can't be installed into tablets/PDAs + device_type = MC_AI_NETWORK + expansion_hw = TRUE + + var/obj/structure/ethernet_cable/connected_cable = null + + +// Called when component is installed into PC. +/obj/item/computer_hardware/ai_interface/on_install(obj/item/modular_computer/M, mob/living/user = null) + RegisterSignal(M, COMSIG_MOVABLE_MOVED, .proc/parent_moved) + + +/obj/item/computer_hardware/ai_interface/on_remove(obj/item/modular_computer/M, mob/living/user = null) + UnregisterSignal(M, COMSIG_MOVABLE_MOVED) + connected_cable = null + +/obj/item/computer_hardware/ai_interface/proc/parent_moved() + if(connected_cable) + if(!connected_cable.Adjacent(holder.physical.loc)) + connected_cable = null + if(ismob(holder.physical.loc)) + to_chat(holder.physical.loc, span_warning("You disconnect [holder] from the cable!")) + +/obj/item/computer_hardware/ai_interface/proc/connect_cable(obj/structure/ethernet_cable/EC) + connected_cable = EC + + +/obj/item/computer_hardware/ai_interface/proc/get_network() + if(!connected_cable) + return FALSE + return connected_cable.network + + +/obj/item/computer_hardware/ai_interface/can_install(obj/item/modular_computer/M, mob/living/user = null) + if(!ismachinery(M.physical) && !M.physical.anchored) + return ..() + to_chat(user, span_warning("\The [src] is incompatible with stationary computers!")) + return FALSE diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index b0a2ca6165f0..88d63d955d7c 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -621,7 +621,7 @@ var/turf/host_turf = get_turf(src) if(!host_turf) CRASH("attackby on APC when it's not on a turf") - if (host_turf.intact) + if (host_turf.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) to_chat(user, span_warning("You must remove the floor plating in front of the APC first!")) return else if (terminal) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index adb4804ebe5d..31b131ef8cfe 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -94,7 +94,7 @@ By design, d1 is the smallest direction and d2 is the highest var/turf/T = get_turf(src) // hide if turf is not intact if(level==1) - hide(T.intact) + hide(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) GLOB.cable_list += src //add it to the global cable list var/list/cable_colors = GLOB.cable_colors @@ -137,7 +137,7 @@ By design, d1 is the smallest direction and d2 is the highest /obj/structure/cable/proc/handlecable(obj/item/W, mob/user, params) var/turf/T = get_turf(src) - if(T.intact) + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) return if(W.tool_behaviour == TOOL_WIRECUTTER) if (shock(user, 50)) @@ -591,7 +591,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai if(!isturf(user.loc)) return - if(!isturf(T) || T.intact || !T.can_have_cabling()) + if(!isturf(T) || T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE || !T.can_have_cabling()) to_chat(user, span_warning("You can only lay cables on top of exterior catwalks and plating!")) return @@ -612,6 +612,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai else dirn = dirnew + for(var/obj/structure/cable/LC in T) if(LC.d2 == dirn && LC.d1 == 0) to_chat(user, span_warning("There's already a cable at that position!")) @@ -653,7 +654,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai var/turf/T = C.loc - if(!isturf(T) || T.intact) // sanity checks, also stop use interacting with T-scanner revealed cable + if(!isturf(T) || T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) // sanity checks, also stop use interacting with T-scanner revealed cable return if(get_dist(C, user) > 1) // make sure it's close enough @@ -675,7 +676,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai if (showerror) to_chat(user, span_warning("You can only lay cables on catwalks and plating!")) return - if(U.intact) //can't place a cable if it's a plating with a tile on it + if(U.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) //can't place a cable if it's a plating with a tile on it to_chat(user, span_warning("You can't lay cable there unless the floor tiles are removed!")) return else diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index fa967e02f788..6472bcc62644 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -152,7 +152,7 @@ if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/coil = W var/turf/T = user.loc - if(T.intact || !isfloorturf(T)) + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE || !isfloorturf(T)) return if(get_dist(src, user) > 1) return @@ -406,6 +406,14 @@ return C return null +/turf/proc/get_ai_cable_node() + if(!can_have_cabling()) + return null + for(var/obj/structure/ethernet_cable/C in src) + if(C.d1 == 0) + return C + return null + /area/proc/get_apc() for(var/obj/machinery/power/apc/APC in GLOB.apcs_list) if(APC.area == src) diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index 9a94a93dca46..57cc5fc51bda 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -116,7 +116,7 @@ return var/turf/T = get_turf(user) - if (T.intact) //is the floor plating removed ? + if (T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) //can we get to the underfloor? to_chat(user, span_warning("You must first remove the floor plating!")) return diff --git a/code/modules/power/terminal.dm b/code/modules/power/terminal.dm index 9e14c1e12b32..28f741f62c25 100644 --- a/code/modules/power/terminal.dm +++ b/code/modules/power/terminal.dm @@ -16,7 +16,7 @@ . = ..() var/turf/T = get_turf(src) if(level == 1) - hide(T.intact) + hide(T.underfloor_accessibility < UNDERFLOOR_VISIBLE) /obj/machinery/power/terminal/Destroy() if(master) @@ -50,7 +50,7 @@ /obj/machinery/power/terminal/proc/dismantle(mob/living/user, obj/item/I) if(isturf(loc)) var/turf/T = loc - if(T.intact) + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) to_chat(user, span_warning("You must first expose the power terminal!")) return diff --git a/code/modules/procedural_mapping/mapGenerators/repair.dm b/code/modules/procedural_mapping/mapGenerators/repair.dm index 20ba10b0e18a..a44315ce2207 100644 --- a/code/modules/procedural_mapping/mapGenerators/repair.dm +++ b/code/modules/procedural_mapping/mapGenerators/repair.dm @@ -32,6 +32,7 @@ var/list/obj/machinery/atmospherics/atmos_machines = list() var/list/obj/structure/cable/cables = list() + var/list/obj/structure/ethernet_cable/ethernet_cables = list() var/list/atom/atoms = list() repopulate_sorted_areas() @@ -46,11 +47,15 @@ if(istype(A,/obj/structure/cable)) cables += A continue + if(istype(A,/obj/structure/ethernet_cable)) + ethernet_cables += A + continue if(istype(A,/obj/machinery/atmospherics)) atmos_machines += A SSatoms.InitializeAtoms(atoms) SSmachines.setup_template_powernets(cables) + SSmachines.setup_template_ainets(ethernet_cables) SSair.setup_template_machinery(atmos_machines) GLOB.reloading_map = FALSE diff --git a/code/modules/recycling/disposal/construction.dm b/code/modules/recycling/disposal/construction.dm index 925216f86fc3..18db47b3ef28 100644 --- a/code/modules/recycling/disposal/construction.dm +++ b/code/modules/recycling/disposal/construction.dm @@ -118,7 +118,7 @@ var/ispipe = is_pipe() // Indicates if we should change the level of this pipe var/turf/T = get_turf(src) - if(T.intact && isfloorturf(T)) + if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE && isfloorturf(T)) to_chat(user, span_warning("You can only attach the [pipename] if the floor plating is removed!")) return TRUE diff --git a/code/modules/recycling/disposal/pipe.dm b/code/modules/recycling/disposal/pipe.dm index 26c8e6928839..5cb3e88cb9f9 100644 --- a/code/modules/recycling/disposal/pipe.dm +++ b/code/modules/recycling/disposal/pipe.dm @@ -83,7 +83,7 @@ // update the icon_state to reflect hidden status /obj/structure/disposalpipe/proc/update() var/turf/T = get_turf(src) - hide(T.intact && !isspaceturf(T)) // space never hides pipes + hide(T.overfloor_placed && !isspaceturf(T)) // space never hides pipes // hide called by levelupdate if turf intact status changes // change visibility status and force update of icon diff --git a/code/modules/research/designs/comp_board_designs.dm b/code/modules/research/designs/comp_board_designs.dm index 56ff85dcf5c6..fb23fb3076c7 100644 --- a/code/modules/research/designs/comp_board_designs.dm +++ b/code/modules/research/designs/comp_board_designs.dm @@ -311,10 +311,3 @@ category = list("Computer Boards") departmental_flags = DEPARTMENTAL_FLAG_SCIENCE -/datum/design/board/ai_resource_distribution - name = "Computer Design (AI Resource Distribution Console)" - desc = "Allows for the construction of circuit boards used to build an AI Resource Distribution console." - id = "ai_resource_distribution" - build_path = /obj/item/circuitboard/computer/ai_resource_distribution - category = list("Computer Boards") - departmental_flags = DEPARTMENTAL_FLAG_SCIENCE diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 001f754a8321..a80a9cc308de 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -359,7 +359,7 @@ display_name = "Artificial Intelligence" description = "AI unit research." prereq_ids = list("base") - design_ids = list("server_cabinet", "ai_data_core", "ai_core_display", "ai_server_overview", "ram1", "basic_ai_cpu", "ai_resource_distribution", "aifixer", "safeguard_module", "onehuman_module", "protectstation_module", "quarantine_module", "oxygen_module", "freeform_module", "reset_module", "purge_module", "remove_module", "freeformcore_module", "asimov_module", "crewsimov_module", "paladin_module", "tyrant_module", "overlord_module", "ceo_module", "cowboy_module", "mother_module", "silicop_module", "construction_module", "metaexperiment_module", "researcher_module", "siliconcollective_module", "spotless_module", "clown_module", "chapai_module", "druid_module", "detective_module", "default_module", "borg_ai_control", "mecha_tracking_ai_control", "intellicard") + design_ids = list("server_cabinet", "ai_data_core", "ai_core_display", "ai_server_overview", "ram1", "basic_ai_cpu", "aifixer", "safeguard_module", "onehuman_module", "protectstation_module", "quarantine_module", "oxygen_module", "freeform_module", "reset_module", "purge_module", "remove_module", "freeformcore_module", "asimov_module", "crewsimov_module", "paladin_module", "tyrant_module", "overlord_module", "ceo_module", "cowboy_module", "mother_module", "silicop_module", "construction_module", "metaexperiment_module", "researcher_module", "siliconcollective_module", "spotless_module", "clown_module", "chapai_module", "druid_module", "detective_module", "default_module", "borg_ai_control", "mecha_tracking_ai_control", "intellicard") research_costs = list(TECHWEB_POINT_TYPE_AI = 1000) /////////////////////////EMP tech///////////////////////// diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index 76edff4ee88a..ecb25d22a5a7 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -260,7 +260,7 @@ All ShuttleMove procs go here /obj/machinery/atmospherics/pipe/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation) . = ..() var/turf/T = loc - hide(T.intact) + hide(T.underfloor_accessibility < UNDERFLOOR_VISIBLE) /obj/machinery/navbeacon/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock) . = ..() @@ -270,7 +270,7 @@ All ShuttleMove procs go here /obj/machinery/navbeacon/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation) . = ..() var/turf/T = loc - hide(T.intact) + hide(T.underfloor_accessibility < UNDERFLOOR_VISIBLE) if(codes["patrol"]) if(!GLOB.navbeacons["[z]"]) GLOB.navbeacons["[z]"] = list() @@ -283,7 +283,7 @@ All ShuttleMove procs go here . = ..() var/turf/T = src.loc if(level==1) - hide(T.intact) + hide(T.underfloor_accessibility < UNDERFLOOR_VISIBLE) /************************************Item move procs************************************/ @@ -348,7 +348,7 @@ All ShuttleMove procs go here . = ..() var/turf/T = loc if(level==1) - hide(T.intact) + hide(T.underfloor_accessibility < UNDERFLOOR_VISIBLE) /obj/structure/shuttle/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock) . = ..() diff --git a/config/maps.txt b/config/maps.txt index eb45f3ec3b0d..079a3bfb5339 100644 --- a/config/maps.txt +++ b/config/maps.txt @@ -19,6 +19,7 @@ endmap map asteroidstation minplayers 25 + disabled endmap map omegastation @@ -29,6 +30,7 @@ endmap map yogsmeta minplayers 25 votable + disabled endmap map yogsdelta @@ -44,6 +46,7 @@ endmap map gaxstation maxplayers 40 votable + disabled endmap map icebox diff --git a/icons/obj/tiles.dmi b/icons/obj/tiles.dmi index b69c131a49c9..d6a260869ae9 100644 Binary files a/icons/obj/tiles.dmi and b/icons/obj/tiles.dmi differ diff --git a/icons/turf/floors/catwalk_plating.dmi b/icons/turf/floors/catwalk_plating.dmi new file mode 100644 index 000000000000..b49c46564de5 Binary files /dev/null and b/icons/turf/floors/catwalk_plating.dmi differ diff --git a/tgui/docs/component-reference.md b/tgui/docs/component-reference.md index 34c6347b997c..e6c3523e3c0c 100644 --- a/tgui/docs/component-reference.md +++ b/tgui/docs/component-reference.md @@ -39,6 +39,7 @@ Make sure to add new items to this list if you document new components. - [`NoticeBox`](#noticebox) - [`NumberInput`](#numberinput) - [`ProgressBar`](#progressbar) + - [`RoundGauge`](#roundgauge) - [`Section`](#section) - [`Slider`](#slider) - [`Table`](#table) @@ -754,6 +755,39 @@ based on whether the value lands in the range between `from` and `to`. - `color: string` - Color of the progress bar. - `children: any` - Content to render inside the progress bar. +### `RoundGauge` + +The RoundGauge component provides a visual representation of a single metric, as well as being capable of showing informational or cautionary boundaries related to that metric. + +```jsx + +``` + +The alert on the gauge is optional, and will only be shown if the `alertAfter` prop is defined. When defined, the alert will begin to flash the respective color upon which the needle currently rests, as defined in the `ranges` prop. + +**Props:** + +- See inherited props: [Box](#box) +- `value: number` - The current value of the metric. +- `minValue: number` (default: 0) - The lower bound of the guage. +- `maxValue: number` (default: 1) - The upper bound of the guage. +- `ranges: { color: [from, to] }` (default: `{ "good": [0, 1] }`) - Provide regions of the guage to color between two specified values of the metric. +- `alertAfter: number` (optional) - When provided, will cause an alert symbol on the gauge to begin flashing in the color upon which the needle currently rests, as defined in `ranges`. +- `alertBefore: number` (optional) - As with alertAfter, but alerts below a value. If both are set, and alertAfter comes earlier, the alert will only flash when the needle is between both values. Otherwise, the alert will flash when on the active side of either threshold. +- `format: function(value) => string` (optional) - When provided, will be used to format the value of the metric for display. +- `size: number` (default: 1) - When provided scales the gauge. + ### `Section` Section is a surface that displays content and actions on a single topic. diff --git a/tgui/packages/tgui/components/RoundGauge.js b/tgui/packages/tgui/components/RoundGauge.js new file mode 100644 index 000000000000..89a0caaa0e94 --- /dev/null +++ b/tgui/packages/tgui/components/RoundGauge.js @@ -0,0 +1,142 @@ +/** + * @file + * @copyright 2020 bobbahbrown (https://github.com/bobbahbrown) + * @license MIT + */ + +import { clamp01, keyOfMatchingRange, scale } from 'common/math'; +import { classes } from 'common/react'; +import { AnimatedNumber } from './AnimatedNumber'; +import { Box, computeBoxClassName, computeBoxProps } from './Box'; + +export const RoundGauge = props => { + // Support for IE8 is for losers sorry B) + if (Byond.IS_LTE_IE8) { + return ( + + ); + } + + const { + value, + minValue = 1, + maxValue = 1, + ranges, + alertAfter, + alertBefore, + format, + size = 1, + className, + style, + ...rest + } = props; + + const scaledValue = scale( + value, + minValue, + maxValue); + const clampedValue = clamp01(scaledValue); + const scaledRanges = ranges ? {} : { "primary": [0, 1] }; + if (ranges) { + Object.keys(ranges).forEach(x => { + const range = ranges[x]; + scaledRanges[x] = [ + scale(range[0], minValue, maxValue), + scale(range[1], minValue, maxValue), + ]; + }); + } + + const shouldShowAlert = () => { + // If both after and before alert props are set, attempt to interpret both + // in a helpful way. + if (alertAfter && alertBefore && alertAfter < alertBefore) { + // If alertAfter is before alertBefore, only display an alert if + // we're between them. + if (alertAfter < value && alertBefore > value) { + return true; + } + } else if (alertAfter < value || alertBefore > value) { + // Otherwise, we have distint ranges, or only one or neither are set. + // Either way, being on the active side of either is sufficient. + return true; + } + return false; + }; + + const alertColor = shouldShowAlert() + && keyOfMatchingRange(clampedValue, scaledRanges); + + return ( + +
+ + {(alertAfter || alertBefore) && ( + + + + )} + + + + + {Object.keys(scaledRanges).map((x, i) => { + const col_ranges = scaledRanges[x]; + return ( + + ); + })} + + + + + + +
+ +
+ ); +}; diff --git a/tgui/packages/tgui/components/index.js b/tgui/packages/tgui/components/index.js index 5580cc38fbeb..9a4406b17c3b 100644 --- a/tgui/packages/tgui/components/index.js +++ b/tgui/packages/tgui/components/index.js @@ -27,6 +27,7 @@ export { Modal } from './Modal'; export { NoticeBox } from './NoticeBox'; export { NumberInput } from './NumberInput'; export { ProgressBar } from './ProgressBar'; +export { RoundGauge } from './RoundGauge'; export { Section } from './Section'; export { Slider } from './Slider'; export { Table } from './Table'; diff --git a/tgui/packages/tgui/interfaces/AiDashboard.js b/tgui/packages/tgui/interfaces/AiDashboard.js index c26059f6da07..521628a8a570 100644 --- a/tgui/packages/tgui/interfaces/AiDashboard.js +++ b/tgui/packages/tgui/interfaces/AiDashboard.js @@ -1,6 +1,6 @@ import { Fragment } from 'inferno'; import { useBackend, useLocalState } from '../backend'; -import { Box, Button, Tabs, ProgressBar, Section, Divider, LabeledControls, NumberInput, Input } from '../components'; +import { Box, Button, Tabs, ProgressBar, Section, Divider, LabeledControls, NumberInput, Input, LabeledList, Flex } from '../components'; import { Window } from '../layouts'; export const AiDashboard = (props, context) => { @@ -22,9 +22,7 @@ export const AiDashboard = (props, context) => { resizable title="Dashboard"> -
act('toggle_contribute_cpu')} color={data.contribute_spare_cpu ? "good" : "bad"} icon={data.contribute_spare_cpu ? "toggle-on" : "toggle-off"}>{!data.contribute_spare_cpu ? "NOT " : null}Contributing Spare CPU to Research - )}> +
{ )} {tab === 4 && (
-
- {amount_of_cpu}/{data.max_cpu} THz - -
-
- {data.current_ram ? data.current_ram : 0 }/{data.max_ram} TB - +
act("clear_ai_resources")}>Clear AI Resources + )}> + + CPU Capacity: + + {amount_of_cpu} THz + + act('set_cpu', { + amount_cpu: Math.round((value / 100) * 100) / 100, + })} /> + + + + + + RAM Capacity: + + {data.current_ram} TB + +
)} diff --git a/tgui/packages/tgui/interfaces/AiNetworking.js b/tgui/packages/tgui/interfaces/AiNetworking.js new file mode 100644 index 000000000000..4ff5ed6e8399 --- /dev/null +++ b/tgui/packages/tgui/interfaces/AiNetworking.js @@ -0,0 +1,69 @@ +import { Fragment } from 'inferno'; +import { useBackend } from '../backend'; +import { Box, Button, LabeledList, Section, NoticeBox, RoundGauge } from '../components'; +import { LabeledListDivider, LabeledListItem } from '../components/LabeledList'; +import { Window } from '../layouts'; + +export const AiNetworking = (props, context) => { + const { act, data } = useBackend(context); + + + if (data.locked) { + return ( + + +
+ Machine locked + + + +
+
+
+ ); + } + + return ( + + +
+ + + + )}> + + {data.possible_targets.map(target => ( + data.is_connected === target ? ( + + act('disconnect')} + disabled={!data.is_connected} color="bad">Disconnect + + )} /> + + + + ) : ( + + act('connect', { target_label: target })} + disabled={data.is_connected} tooltip={data.is_connected ? "Already connected. Please disconnect" : ""} tooltipPosition="left">Connect + + )} /> + + + ) + ))} + +
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/NtosAIMonitor.js b/tgui/packages/tgui/interfaces/NtosAIMonitor.js new file mode 100644 index 000000000000..2420b70c2389 --- /dev/null +++ b/tgui/packages/tgui/interfaces/NtosAIMonitor.js @@ -0,0 +1,382 @@ +import { NtosWindow } from '../layouts'; +import { Fragment } from 'inferno'; +import { useBackend, useLocalState } from '../backend'; +import { Button, Box, Section, Tabs, NoticeBox, Flex, ProgressBar, LabeledList, NumberInput, Divider } from '../components'; + +export const NtosAIMonitor = (props, context) => { + const { act, data } = useBackend(context); + const [tab, setTab] = useLocalState(context, 'tab', 1); + const [clusterTab, setClusterTab] = useLocalState(context, 'clustertab', 1); + + if (!data.has_ai_net) { + return ( + + +
+ + No network connection. Please connect to ethernet cable to proceed! + +
+
+
+ ); + } + + return ( + + + + + setTab(1))}> + Cluster Control + + setTab(2))}> + Resource Allocation + + setTab(3))}> + Networking + + setTab(4))}> + AI Upload + + setTab(5))}> + AI Download + + + {tab === 1 && ( + + + + setClusterTab(1))}> + Dashboard + + setClusterTab(2))}> + Local Computing + + + + )} + {(clusterTab === 1 && tab === 1) && ( + + )} + {(clusterTab === 2 && tab === 1) && ( + + )} + {tab === 2 && ( + + )} + {tab === 3 && ( + + )} + {tab === 4 && ( + + )} + {tab === 5 && ( + + )} + + + + ); +}; + + +const LocalDashboard = (props, context) => { + const { act, data } = useBackend(context); + let network_remaining_cpu = data.remaining_network_cpu * 100; + + return ( +
+ + act("bitcoin_payout")}>Withdraw)}> + {data.bitcoin_amount} cr + + +
+ ); +}; + +const LocalCompute = (props, context) => { + const { act, data } = useBackend(context); + let network_remaining_cpu = data.remaining_network_cpu * 100; + + return ( +
+ Local CPU Resources: + {(100 - network_remaining_cpu)}% ({data.total_cpu * data.network_assigned_cpu} THz) + +
+ + {data.network_cpu_assignments.map((project, index) => { + return ( +
{project.name})} buttons={( + + Assigned CPU:  + act('allocate_network_cpu', { + project_name: project.name, + amount: Math.round((value / 100) * 100) / 100, + })} /> + + + + )}> + {project.tagline} + {project.description} +
+ ); + })} +
+
+
+ ); +}; + + +const ResourceAllocation = (props, context) => { + const { act, data } = useBackend(context); + let remaining_cpu = (1 - data.total_assigned_cpu) * 100; + + return ( + +
+ {data.total_cpu * data.total_assigned_cpu}/{data.total_cpu} THz + ({data.total_assigned_cpu * 100}%) + +
+
+ {data.total_assigned_ram}/{data.total_ram} TB + +
+
+ + + CPU Capacity: + + {data.total_cpu * data.network_assigned_cpu} THz + + act('set_cpu', { + target_ai: data.network_ref, + amount_cpu: Math.round((value / 100) * 100) / 100, + })} /> + + + + + RAM Capacity: + + {data.network_assigned_ram} TB + +
+
+ + {data.ai_list.map((ai, index) => { + return ( +
act("clear_ai_resources", { target_ai: ai.ref })}>Clear AI Resources + )}> + + CPU Capacity: + + {data.total_cpu * ai.assigned_cpu} THz + + act('set_cpu', { + target_ai: ai.ref, + amount_cpu: Math.round((value / 100) * 100) / 100, + })} /> + + + + + RAM Capacity: + + {ai.assigned_ram} TB + +
+ ); + })} +
+
+
+ ); +}; + + +const AIDownload = (props, context) => { + const { act, data } = useBackend(context); + + return ( +
+ {data.downloading && ( + + Currently downloading {data.downloading} + + + {!!data.current_ai_ref && data.current_ai_ref === data.downloading_ref && ( + + )} + + + )|| ( + + {data.ai_list.filter(ai => { + return !!ai.in_core; + }).map((ai, index) => { + return ( +
{ai.name} | {ai.active ? "Active" : "Inactive"})} + buttons={( + + + + {!!data.is_infiltrator && !ai.being_hijacked && ( + + ) } + {!!ai.being_hijacked && ( + + )} + + )}> + Integrity: + +
+ ); + })} +
+ )} +
+ ); +}; + +const AIUpload = (props, context) => { + const { act, data } = useBackend(context); + + return ( +
+ + + + {!data.intellicard && ( + + + No IntelliCard inserted! + + + ) || ( + + {data.intellicard_ai && ( + + +
+ + +
+
+
+ ) || ( + + + Intellicard contains no AI! + + + )} +
+ )} +
+ ); +}; + +const Networking = (props, context) => { + const { act, data } = useBackend(context); + + return ( +
+ + {data.networking_devices.map((networker, index) => { + return ( + act("control_networking", { ref: networker.ref })}>Control)}> + {networker.has_partner ? "ONLINE - CONNECTED TO " + networker.has_partner : "DISCONNECTED"} + + ); + })} + +
+ ); +}; diff --git a/tgui/packages/tgui/styles/components/RoundGauge.scss b/tgui/packages/tgui/styles/components/RoundGauge.scss new file mode 100644 index 000000000000..0ca0e2f89acd --- /dev/null +++ b/tgui/packages/tgui/styles/components/RoundGauge.scss @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2020 bobbahbrown (https://github.com/bobbahbrown) + * SPDX-License-Identifier: MIT + */ + +@use '../base.scss'; +@use '../colors.scss'; +@use '../functions.scss' as *; + +$fg-map: colors.$fg-map !default; +$ring-color: #6a96c9 !default; + +.RoundGauge { + font-size: 1rem; + width: 2.6em; + height: 1.3em; + margin: 0 auto; + margin-bottom: 0.2em; +} + +$pi: 3.1416; + +.RoundGauge__ringTrack { + fill: transparent; + stroke: rgba(255, 255, 255, 0.1); + stroke-width: 10; + stroke-dasharray: 50 * $pi; + stroke-dashoffset: 50 * $pi; +} + +.RoundGauge__ringFill { + fill: transparent; + stroke: $ring-color; + stroke-width: 10; + stroke-dasharray: 100 * $pi; + transition: stroke 50ms; +} + +.RoundGauge__needle, .RoundGauge__ringFill { + transition: transform 50ms ease-in-out; +} + +.RoundGauge__needleLine, .RoundGauge__needleMiddle { + fill: colors.$bad; +} + +.RoundGauge__alert { + fill-rule: evenodd; + clip-rule: evenodd; + stroke-linejoin: round; + stroke-miterlimit: 2; + fill: rgba(255, 255, 255, 0.1); +} + +.RoundGauge__alert.max { + fill: colors.$bad; +} + +@each $color-name, $color-value in $fg-map { + .RoundGauge--color--#{$color-name}.RoundGauge__ringFill { + stroke: $color-value; + } +} + +@each $color-name, $color-value in $fg-map { + .RoundGauge__alert--#{$color-name} { + fill: $color-value; + transition: opacity 0.6s cubic-bezier(0.25, 1, 0.5, 1); + animation: RoundGauge__alertAnim 1s cubic-bezier(0.34, 1.56, 0.64, 1) infinite; + } +} + +@keyframes RoundGauge__alertAnim { + 0% { + opacity: 0.1; + } + 50% { + opacity: 1; + } + 100% { + opacity: 0.1; + } +} diff --git a/tgui/packages/tgui/styles/main.scss b/tgui/packages/tgui/styles/main.scss index 2e2e6c76eb5e..368c8c2f87f8 100644 --- a/tgui/packages/tgui/styles/main.scss +++ b/tgui/packages/tgui/styles/main.scss @@ -31,6 +31,7 @@ @include meta.load-css('./components/NoticeBox.scss'); @include meta.load-css('./components/NumberInput.scss'); @include meta.load-css('./components/ProgressBar.scss'); +@include meta.load-css('./components/RoundGauge.scss'); @include meta.load-css('./components/Section.scss'); @include meta.load-css('./components/Slider.scss'); @include meta.load-css('./components/Table.scss'); diff --git a/tools/build/build.js b/tools/build/build.js index 62642539eb8d..a588a2eee734 100644 --- a/tools/build/build.js +++ b/tools/build/build.js @@ -178,8 +178,8 @@ let tasksToRun = []; switch (BUILD_MODE) { case STANDARD_BUILD: tasksToRun = [ - taskYarn, - taskTgui, + //taskYarn, + //taskTgui, taskDm('CBT'), ] break; diff --git a/yogstation.dme b/yogstation.dme index 6e2620d0068e..43dd62a1b0be 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -1297,6 +1297,7 @@ #include "code\game\turfs\simulated\floor\plating.dm" #include "code\game\turfs\simulated\floor\reinf_floor.dm" #include "code\game\turfs\simulated\floor\plating\asteroid.dm" +#include "code\game\turfs\simulated\floor\plating\catwalk_plating.dm" #include "code\game\turfs\simulated\floor\plating\dirt.dm" #include "code\game\turfs\simulated\floor\plating\misc_plating.dm" #include "code\game\turfs\simulated\wall\mineral_walls.dm" @@ -2447,12 +2448,15 @@ #include "code\modules\mob\living\silicon\ai\robot_control.dm" #include "code\modules\mob\living\silicon\ai\say.dm" #include "code\modules\mob\living\silicon\ai\vox_sounds.dm" +#include "code\modules\mob\living\silicon\ai\ai_network\ai_network.dm" +#include "code\modules\mob\living\silicon\ai\ai_network\ethernet_cable.dm" +#include "code\modules\mob\living\silicon\ai\ai_network\networking_machines.dm" +#include "code\modules\mob\living\silicon\ai\ai_network\shared_resources.dm" #include "code\modules\mob\living\silicon\ai\decentralized\_ai_machinery.dm" #include "code\modules\mob\living\silicon\ai\decentralized\ai_core_display.dm" #include "code\modules\mob\living\silicon\ai\decentralized\ai_data_core.dm" -#include "code\modules\mob\living\silicon\ai\decentralized\decentralized_os.dm" +#include "code\modules\mob\living\silicon\ai\decentralized\computer_science_datum.dm" #include "code\modules\mob\living\silicon\ai\decentralized\server_cabinet.dm" -#include "code\modules\mob\living\silicon\ai\decentralized\management\ai_controlpanel.dm" #include "code\modules\mob\living\silicon\ai\decentralized\management\ai_dashboard.dm" #include "code\modules\mob\living\silicon\ai\decentralized\management\ai_server_overview.dm" #include "code\modules\mob\living\silicon\ai\decentralized\management\resource_distribution.dm" @@ -2461,12 +2465,10 @@ #include "code\modules\mob\living\silicon\ai\decentralized\projects\ai_huds.dm" #include "code\modules\mob\living\silicon\ai\decentralized\projects\camera_mobility.dm" #include "code\modules\mob\living\silicon\ai\decentralized\projects\coolant_manager.dm" -#include "code\modules\mob\living\silicon\ai\decentralized\projects\cryptominer.dm" #include "code\modules\mob\living\silicon\ai\decentralized\projects\examine.dm" #include "code\modules\mob\living\silicon\ai\decentralized\projects\firewall.dm" #include "code\modules\mob\living\silicon\ai\decentralized\projects\induction.dm" #include "code\modules\mob\living\silicon\ai\decentralized\projects\memory_compressor.dm" -#include "code\modules\mob\living\silicon\ai\decentralized\projects\research_booster.dm" #include "code\modules\mob\living\silicon\ai\decentralized\projects\rgb.dm" #include "code\modules\mob\living\silicon\ai\decentralized\projects\self_defense.dm" #include "code\modules\mob\living\silicon\ai\decentralized\projects\surveillance.dm" @@ -2662,6 +2664,7 @@ #include "code\modules\modular_computers\file_system\data.dm" #include "code\modules\modular_computers\file_system\program.dm" #include "code\modules\modular_computers\file_system\program_events.dm" +#include "code\modules\modular_computers\file_system\programs\ainetworkinterface.dm" #include "code\modules\modular_computers\file_system\programs\arcade.dm" #include "code\modules\modular_computers\file_system\programs\configurator.dm" #include "code\modules\modular_computers\file_system\programs\file_browser.dm" @@ -2697,6 +2700,7 @@ #include "code\modules\modular_computers\file_system\programs\supply\cargobounty.dm" #include "code\modules\modular_computers\hardware\_hardware.dm" #include "code\modules\modular_computers\hardware\ai_slot.dm" +#include "code\modules\modular_computers\hardware\aiinterface.dm" #include "code\modules\modular_computers\hardware\battery_module.dm" #include "code\modules\modular_computers\hardware\card_slot.dm" #include "code\modules\modular_computers\hardware\CPU.dm" diff --git a/yogstation/code/modules/atmospherics/machinery/pipes/bluespace.dm b/yogstation/code/modules/atmospherics/machinery/pipes/bluespace.dm index 7e9daa9c63f1..8fd7af0000fb 100644 --- a/yogstation/code/modules/atmospherics/machinery/pipes/bluespace.dm +++ b/yogstation/code/modules/atmospherics/machinery/pipes/bluespace.dm @@ -53,7 +53,7 @@ GLOBAL_LIST_EMPTY(bluespace_pipe_networks) underlays.Cut() var/turf/T = loc - if(level == 2 || !T.intact) + if(level == 2 || !T.underfloor_accessibility < UNDERFLOOR_VISIBLE) showpipe = TRUE plane = GAME_PLANE else @@ -83,4 +83,4 @@ GLOBAL_LIST_EMPTY(bluespace_pipe_networks) if(color) . = getpipeimage('icons/obj/atmospherics/components/binary_devices.dmi', state, dir, color) else - . = getpipeimage('icons/obj/atmospherics/components/binary_devices.dmi', state, dir) \ No newline at end of file + . = getpipeimage('icons/obj/atmospherics/components/binary_devices.dmi', state, dir) diff --git a/yogstation/code/modules/jobs/job_types/network_admin.dm b/yogstation/code/modules/jobs/job_types/network_admin.dm index 7307918be523..fb10da074bfb 100644 --- a/yogstation/code/modules/jobs/job_types/network_admin.dm +++ b/yogstation/code/modules/jobs/job_types/network_admin.dm @@ -15,7 +15,7 @@ outfit = /datum/outfit/job/network_admin added_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_MAINT_TUNNELS) - base_access = list(ACCESS_TCOMSAT, ACCESS_TCOM_ADMIN, ACCESS_TECH_STORAGE, ACCESS_RC_ANNOUNCE, ACCESS_CONSTRUCTION, ACCESS_MECH_ENGINE, ACCESS_NETWORK, ACCESS_RESEARCH, ACCESS_MINISAT) + base_access = list(ACCESS_TCOM_ADMIN, ACCESS_TECH_STORAGE, ACCESS_RC_ANNOUNCE, ACCESS_CONSTRUCTION, ACCESS_MECH_ENGINE, ACCESS_NETWORK, ACCESS_RESEARCH, ACCESS_MINISAT, ACCESS_TOX) paycheck = PAYCHECK_MEDIUM paycheck_department = ACCOUNT_ENG display_order = JOB_DISPLAY_ORDER_NETWORK_ADMIN @@ -41,7 +41,7 @@ gloves = /obj/item/clothing/gloves/color/black shoes = /obj/item/clothing/shoes/workboots digitigrade_shoes = /obj/item/clothing/shoes/xeno_wraps/engineering - backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1) + backpack_contents = list(/obj/item/modular_computer/laptop/preset/network_admin=1) backpack = /obj/item/storage/backpack/industrial satchel = /obj/item/storage/backpack/satchel/eng