diff --git a/_maps/map_files/CogStation/CogStation.dmm b/_maps/map_files/CogStation/CogStation.dmm index 40a57135fd..3c64b9f6ad 100644 --- a/_maps/map_files/CogStation/CogStation.dmm +++ b/_maps/map_files/CogStation/CogStation.dmm @@ -2878,7 +2878,6 @@ /turf/closed/wall/r_wall, /area/security/processing) "agX" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/structure/cable{ icon_state = "1-2" }, @@ -4171,22 +4170,11 @@ /turf/open/floor/plasteel, /area/construction/secondary) "akg" = ( -/obj/machinery/power/solar_control{ - dir = 4; - id = "foreport"; - name = "Port Bow Solar Control" - }, -/obj/structure/sign/warning/electricshock{ - pixel_x = -32 - }, /obj/structure/cable{ - icon_state = "2-4" - }, -/obj/structure/cable{ - icon_state = "0-4" + icon_state = "1-2" }, /turf/open/floor/plating, -/area/maintenance/solars/port) +/area/maintenance/solars/starboard/fore) "akh" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/plasteel, @@ -4196,14 +4184,16 @@ /turf/open/floor/plating, /area/construction/secondary) "akj" = ( -/obj/structure/chair{ - dir = 8 - }, /obj/structure/cable{ icon_state = "4-8" }, +/obj/machinery/door/airlock/external{ + name = "Starboard Bow Solar Exterior Airlock"; + req_access_txt = "10;13" + }, +/obj/machinery/door/firedoor, /turf/open/floor/plating, -/area/maintenance/solars/port) +/area/maintenance/solars/starboard/fore) "akk" = ( /obj/item/stack/tile/plasteel{ pixel_x = 10; @@ -4361,18 +4351,12 @@ /turf/open/floor/plasteel, /area/security/warden) "akz" = ( -/obj/machinery/light/small{ - dir = 1; - light_color = "#ffc1c1" +/obj/machinery/door/airlock/external, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 }, -/obj/machinery/power/terminal{ - dir = 4 - }, -/obj/structure/cable{ - icon_state = "0-8" - }, -/turf/open/floor/plating, -/area/maintenance/solars/port) +/turf/open/floor/plasteel, +/area/router/service) "akA" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable{ @@ -6331,16 +6315,16 @@ /turf/open/floor/plasteel, /area/security/brig) "aoW" = ( -/obj/machinery/door/firedoor, -/obj/machinery/door/airlock/external/glass{ - name = "Port Bow Solars External Access"; - req_access_txt = "10;13" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 +/obj/machinery/power/solar_control{ + dir = 4; + id = "foreport"; + name = "Port Bow Solar Control" }, /obj/structure/cable{ - icon_state = "4-8" + icon_state = "0-4" + }, +/obj/structure/cable{ + icon_state = "2-4" }, /turf/open/floor/plating, /area/maintenance/solars/port) @@ -7335,12 +7319,19 @@ /turf/open/floor/plasteel, /area/security/brig) "arr" = ( -/obj/structure/table, -/obj/machinery/cell_charger, -/obj/structure/sign/warning/vacuum/external{ - pixel_x = -32 +/obj/machinery/light/small{ + dir = 1; + light_color = "#ffc1c1" + }, +/obj/machinery/power/terminal{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/structure/chair{ + dir = 8 }, -/obj/item/stock_parts/cell/high/plus, /turf/open/floor/plating, /area/maintenance/solars/port) "ars" = ( @@ -7774,10 +7765,16 @@ /turf/open/floor/plasteel, /area/security/prison) "asl" = ( -/obj/machinery/portable_atmospherics/canister/oxygen, -/obj/machinery/camera{ - c_tag = "Port Bow Solar Maintenance"; - dir = 1 +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/airlock/external/glass{ + name = "Port Bow Solars External Access"; + req_access_txt = "10;13" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 }, /turf/open/floor/plating, /area/maintenance/solars/port) @@ -7991,12 +7988,18 @@ name = "Canister Storage" }) "asH" = ( -/obj/machinery/firealarm{ - dir = 1; - pixel_y = -26 +/obj/machinery/camera{ + c_tag = "Port Bow Solar Maintenance"; + dir = 1 }, -/obj/machinery/atmospherics/pipe/manifold/general/visible{ - dir = 8 +/obj/structure/table, +/obj/machinery/cell_charger, +/obj/item/stock_parts/cell/high/plus, +/obj/structure/sign/warning/vacuum/external{ + pixel_x = -32 + }, +/obj/structure/sign/warning/electricshock{ + pixel_y = -32 }, /turf/open/floor/plating, /area/maintenance/solars/port) @@ -8236,12 +8239,16 @@ /turf/open/floor/plasteel/cafeteria, /area/crew_quarters/kitchen) "atn" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ +/obj/machinery/firealarm{ + dir = 1; + pixel_y = -26 + }, +/obj/machinery/atmospherics/pipe/manifold/general/visible{ dir = 8 }, -/obj/machinery/door/airlock/external, -/turf/open/floor/plasteel, -/area/router/service) +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/open/floor/plating, +/area/maintenance/solars/port) "ato" = ( /obj/structure/disposalpipe/segment{ dir = 6 @@ -10451,13 +10458,11 @@ /turf/open/floor/circuit, /area/ai_monitored/turret_protected/ai) "aya" = ( -/obj/structure/disposalpipe/segment, -/obj/structure/cable{ - icon_state = "1-2" +/obj/machinery/atmospherics/pipe/simple/cyan/hidden{ + dir = 4 }, -/obj/machinery/camera{ - c_tag = "AI Core Exterior"; - dir = 1 +/obj/structure/cable{ + icon_state = "2-4" }, /turf/open/floor/plating/airless, /area/space/nearstation) @@ -15104,19 +15109,19 @@ }, /area/chapel/main) "aHj" = ( -/obj/machinery/door/firedoor, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 1 +/obj/effect/turf_decal/tile/yellow, +/obj/effect/turf_decal/tile/yellow{ + dir = 4 }, /obj/structure/cable{ - icon_state = "1-2" + icon_state = "4-8" }, -/obj/machinery/door/airlock/external{ - name = "Starboard Bow Solar Exterior Airlock"; - req_access_txt = "10;13" +/obj/machinery/airalarm{ + dir = 1; + pixel_y = -22 }, -/turf/open/floor/plating, -/area/maintenance/solars/starboard/fore) +/turf/open/floor/plasteel, +/area/tcommsat/computer) "aHk" = ( /obj/structure/chair{ dir = 4 @@ -15272,13 +15277,14 @@ /area/bridge) "aHE" = ( /obj/structure/cable{ - icon_state = "2-4" + icon_state = "4-8" }, -/obj/machinery/atmospherics/pipe/simple/cyan/hidden{ - dir = 4 +/obj/machinery/airalarm{ + dir = 1; + pixel_y = -22 }, -/turf/open/floor/plating/airless, -/area/space/nearstation) +/turf/open/floor/plating, +/area/tcommsat/computer) "aHF" = ( /turf/open/floor/plasteel/dark, /area/bridge) @@ -20986,19 +20992,18 @@ /turf/open/floor/plasteel, /area/security/brig) "aTh" = ( -/obj/effect/turf_decal/stripes/line, -/obj/machinery/light{ +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/door/airlock/external/glass{ + name = "Telecommunications External Access"; + req_access_txt = "61" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 }, -/obj/machinery/power/apc{ - name = "AI Upload Foyer APC"; - pixel_y = -24 - }, -/obj/structure/cable{ - icon_state = "0-4" - }, -/turf/open/floor/plasteel, -/area/ai_monitored/turret_protected/ai_upload_foyer) +/turf/open/floor/plating, +/area/tcommsat/computer) "aTi" = ( /obj/effect/turf_decal/tile/blue{ dir = 4 @@ -22804,14 +22809,14 @@ /turf/open/floor/wood, /area/library) "aXf" = ( -/obj/structure/window/reinforced/spawner/east, -/obj/structure/table/wood, +/obj/machinery/photocopier, /obj/machinery/light{ dir = 1; - light_color = "#c1caff" + light_color = "#e8eaff" }, -/turf/open/floor/carpet, -/area/library) +/obj/item/paper/fluff/cogstation/eva, +/turf/open/floor/plasteel/dark, +/area/security/checkpoint/customs) "aXg" = ( /obj/machinery/vending/coffee, /turf/open/floor/plasteel, @@ -23913,35 +23918,20 @@ /turf/closed/wall, /area/lawoffice) "aZz" = ( -/obj/structure/table/reinforced, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ +/obj/structure/lattice, +/obj/machinery/camera{ + c_tag = "Routing Depot - Fore Exterior"; dir = 4 }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/obj/item/paper_bin, -/obj/item/pen, -/turf/open/floor/plasteel/dark, -/area/lawoffice) +/turf/open/space/basic, +/area/maintenance/department/eva) "aZA" = ( -/obj/structure/table/reinforced, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral{ +/obj/machinery/computer/card{ dir = 8 }, +/obj/item/paper/guides/cogstation/job_changes, /turf/open/floor/plasteel/dark, -/area/lawoffice) +/area/security/checkpoint/customs) "aZB" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -23961,7 +23951,9 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, -/obj/item/book/manual/wiki/security_space_law, +/obj/item/paper_bin, +/obj/item/pen, +/obj/structure/window/reinforced/spawner/north, /turf/open/floor/plasteel/dark, /area/lawoffice) "aZD" = ( @@ -24018,13 +24010,21 @@ /turf/open/floor/plasteel, /area/hallway/secondary/civilian) "aZI" = ( +/obj/structure/table/reinforced, +/obj/effect/turf_decal/tile/neutral, /obj/effect/turf_decal/tile/neutral{ dir = 4 }, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, -/obj/effect/landmark/start/lawyer, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/machinery/door/window/northleft{ + name = "Law Office Counter"; + req_access_txt = "38" + }, /turf/open/floor/plasteel/dark, /area/lawoffice) "aZJ" = ( @@ -24426,13 +24426,21 @@ /turf/open/floor/wood, /area/library) "baz" = ( -/obj/machinery/photocopier, -/obj/machinery/light{ - dir = 1; - light_color = "#e8eaff" +/obj/structure/table/reinforced, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/item/book/manual/wiki/security_space_law, +/obj/structure/window/reinforced/spawner/north, /turf/open/floor/plasteel/dark, -/area/security/checkpoint/customs) +/area/lawoffice) "baA" = ( /obj/structure/filingcabinet/chestdrawer, /obj/item/folder/blue, @@ -25282,11 +25290,17 @@ /turf/closed/wall/r_wall, /area/science/mixing) "bcz" = ( -/obj/machinery/computer/card{ - dir = 8 +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/machinery/newscaster{ + pixel_x = -30 }, /turf/open/floor/plasteel/dark, -/area/security/checkpoint/customs) +/area/lawoffice) "bcA" = ( /obj/effect/turf_decal/tile/brown{ dir = 1 @@ -26131,9 +26145,21 @@ /turf/open/floor/plasteel, /area/quartermaster/office) "beC" = ( -/obj/machinery/recharge_station, -/turf/open/floor/plating, -/area/ai_monitored/turret_protected/ai_upload_foyer) +/obj/structure/rack, +/obj/item/storage/toolbox/mechanical, +/obj/item/radio/off, +/obj/effect/turf_decal/tile/yellow, +/obj/effect/turf_decal/tile/yellow{ + dir = 4 + }, +/obj/effect/turf_decal/tile/yellow{ + dir = 1 + }, +/obj/machinery/airalarm{ + pixel_y = 24 + }, +/turf/open/floor/plasteel, +/area/tcommsat/computer) "beD" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 10 @@ -26156,13 +26182,16 @@ /turf/open/floor/plasteel, /area/hallway/primary/central) "beG" = ( -/obj/structure/lattice, -/obj/machinery/camera{ - c_tag = "Routing Depot - Fore Exterior"; +/obj/effect/turf_decal/tile/neutral{ dir = 4 }, -/turf/open/space/basic, -/area/space/nearstation) +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/landmark/start/lawyer, +/obj/structure/chair/stool, +/turf/open/floor/plasteel/dark, +/area/lawoffice) "beH" = ( /obj/structure/window/reinforced/spawner/east, /obj/machinery/light{ @@ -30649,9 +30678,11 @@ /turf/open/floor/plasteel, /area/hallway/primary/central) "bnS" = ( -/obj/machinery/atmospherics/components/unary/outlet_injector/on, -/turf/open/floor/plating/airless, -/area/space/nearstation) +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plating, +/area/crew_quarters/fitness/cogpool) "bnT" = ( /obj/structure/disposalpipe/segment, /turf/closed/wall/r_wall, @@ -30768,17 +30799,17 @@ /turf/open/floor/plasteel, /area/ai_monitored/nuke_storage) "bof" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, /obj/machinery/door/airlock/external/glass{ name = "Pool Exterior Access"; req_access_txt = "13" }, -/obj/structure/cable{ - icon_state = "1-2" - }, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 1 }, -/turf/open/floor/plating, +/turf/open/space/basic, /area/crew_quarters/fitness/cogpool) "bog" = ( /obj/machinery/light{ @@ -32879,19 +32910,9 @@ /turf/open/floor/plasteel/stairs/left, /area/hydroponics) "bsx" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 1 - }, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/machinery/door/airlock/external{ - name = "Recycler Exterior Access"; - req_one_access_txt = "13;50" - }, -/obj/machinery/atmospherics/pipe/simple/supplymain/hidden, -/turf/open/floor/plasteel, -/area/maintenance/disposal) +/obj/structure/lattice, +/turf/closed/wall/r_wall, +/area/crew_quarters/fitness/cogpool) "bsy" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/disposalpipe/segment, @@ -33297,21 +33318,9 @@ /turf/open/floor/plating, /area/maintenance/aft) "btw" = ( -/obj/structure/disposalpipe/segment, -/obj/structure/cable{ - icon_state = "2-4" - }, -/obj/structure/cable{ - icon_state = "2-8" - }, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/machinery/light/small, -/turf/open/floor/plating{ - icon_state = "platingdmg2" - }, -/area/maintenance/department/eva) +/obj/machinery/atmospherics/components/unary/outlet_injector/on, +/turf/open/floor/plating/airless, +/area/router) "btx" = ( /obj/machinery/space_heater, /turf/open/floor/plating, @@ -34237,17 +34246,13 @@ /turf/open/floor/plasteel, /area/crew_quarters/bar) "bvM" = ( -/obj/machinery/door/airlock/external/glass{ - name = "External Construction Access"; - req_one_access_txt = "10;31" +/obj/structure/lattice, +/obj/machinery/camera{ + c_tag = "Routing Depot - Aft Exterior"; + pixel_x = 22 }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/supplymain/hidden, -/turf/open/floor/plasteel, -/area/quartermaster/warehouse) +/turf/open/space/basic, +/area/router) "bvN" = ( /obj/machinery/atmospherics/components/binary/valve/digital/on{ dir = 4 @@ -34971,21 +34976,30 @@ /turf/open/floor/plating, /area/ai_monitored/turret_protected/ai) "bxm" = ( -/obj/effect/turf_decal/tile/yellow{ - dir = 8 - }, -/turf/closed/wall/r_wall, -/area/tcommsat/computer) -"bxn" = ( -/obj/effect/turf_decal/tile/yellow, -/obj/effect/turf_decal/tile/yellow{ - dir = 4 +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "2-4" }, /obj/structure/cable{ - icon_state = "4-8" + icon_state = "2-8" }, -/turf/open/floor/plasteel, -/area/tcommsat/computer) +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/light/small, +/turf/open/floor/plating, +/area/maintenance/department/eva) +"bxn" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/camera{ + c_tag = "AI Core Exterior"; + dir = 1 + }, +/turf/open/floor/plating/airless, +/area/maintenance/department/eva) "bxo" = ( /obj/machinery/door/airlock/external{ name = "Telecommunications External Access"; @@ -35048,18 +35062,13 @@ /turf/open/floor/plating, /area/maintenance/disposal) "bxt" = ( -/obj/machinery/door/airlock/external/glass{ - name = "Telecommunications External Access"; - req_access_txt = "61" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/obj/structure/cable{ - icon_state = "4-8" +/obj/effect/spawner/structure/window/reinforced, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{ + dir = 4 }, /turf/open/floor/plating, -/area/tcommsat/computer) +/area/maintenance/disposal) "bxu" = ( /obj/structure/rack, /obj/item/circuitboard/machine/telecomms/broadcaster, @@ -35217,18 +35226,15 @@ /turf/open/floor/plasteel, /area/tcommsat/computer) "bxK" = ( -/obj/structure/rack, -/obj/item/storage/toolbox/mechanical, -/obj/item/radio/off, -/obj/effect/turf_decal/tile/yellow, -/obj/effect/turf_decal/tile/yellow{ +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/effect/turf_decal/delivery, +/obj/machinery/atmospherics/pipe/manifold/supplymain/hidden{ dir = 4 }, -/obj/effect/turf_decal/tile/yellow{ - dir = 1 - }, /turf/open/floor/plasteel, -/area/tcommsat/computer) +/area/maintenance/disposal) "bxL" = ( /obj/structure/disposalpipe/segment{ dir = 5 @@ -35905,11 +35911,11 @@ /turf/open/floor/plating, /area/maintenance/starboard/central) "bzp" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, +/obj/structure/lattice/catwalk, +/obj/structure/disposalpipe/segment, +/obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, -/area/maintenance/solars/starboard/fore) +/area/maintenance/disposal) "bzq" = ( /obj/machinery/light{ dir = 8 @@ -37644,12 +37650,20 @@ /turf/open/floor/plasteel/showroomfloor, /area/medical/morgue) "bDb" = ( -/mob/living/simple_animal/mouse/white{ - desc = "Wubba lubba dub dub."; - name = "Rick" +/obj/structure/lattice/catwalk, +/obj/structure/cable{ + icon_state = "1-2" }, -/turf/open/floor/plasteel/showroomfloor, -/area/medical/morgue) +/obj/machinery/door/airlock/external{ + name = "Recycler Exterior Access"; + req_one_access_txt = "13;50" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/supplymain/hidden, +/turf/open/floor/plasteel, +/area/maintenance/disposal) "bDc" = ( /obj/machinery/vending/security, /obj/structure/disposalpipe/segment, @@ -39183,23 +39197,9 @@ /turf/open/floor/plasteel/white, /area/medical/medbay/central) "bFY" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 1 - }, -/obj/structure/noticeboard{ - pixel_y = 28 - }, -/obj/machinery/light{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/cyan/hidden{ - dir = 4 - }, -/turf/open/floor/plasteel/white, -/area/medical/medbay/central) +/obj/structure/lattice/catwalk, +/turf/closed/wall/r_wall, +/area/engine/atmos) "bFZ" = ( /obj/machinery/chem_heater, /turf/open/floor/plasteel/white, @@ -45857,11 +45857,11 @@ /area/engine/atmos) "bTJ" = ( /obj/structure/lattice, -/obj/machinery/atmospherics/pipe/simple/violet/hidden{ - dir = 8 - }, -/turf/open/space/basic, -/area/space/nearstation) +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/orange/visible, +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/plating, +/area/maintenance/disposal) "bTK" = ( /turf/open/floor/engine/co2, /area/engine/atmos) @@ -46099,17 +46099,12 @@ /turf/open/floor/plasteel, /area/ai_monitored/turret_protected/ai_upload_foyer) "bUj" = ( -/obj/structure/cable{ - icon_state = "1-8" +/obj/machinery/atmospherics/pipe/simple/violet/hidden{ + dir = 8 }, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{ - dir = 9 - }, -/turf/open/floor/plasteel, -/area/ai_monitored/turret_protected/ai_upload_foyer) +/obj/structure/lattice/catwalk, +/turf/open/space/basic, +/area/space/nearstation) "bUk" = ( /obj/structure/closet/crate, /obj/effect/decal/cleanable/cobweb, @@ -46481,11 +46476,11 @@ /turf/open/floor/plasteel, /area/ai_monitored/turret_protected/ai_upload_foyer) "bUV" = ( -/obj/structure/lattice, /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/simple/violet/hidden{ dir = 10 }, +/obj/structure/lattice/catwalk, /turf/open/space/basic, /area/space/nearstation) "bUW" = ( @@ -46837,14 +46832,9 @@ /turf/open/floor/plating, /area/ai_monitored/turret_protected/ai_upload_foyer) "bVD" = ( -/obj/structure/cable{ - icon_state = "1-8" - }, -/obj/machinery/atmospherics/pipe/simple/orange/hidden{ - dir = 8 - }, -/turf/open/floor/plating, -/area/ai_monitored/turret_protected/ai_upload_foyer) +/obj/structure/lattice, +/turf/open/space/basic, +/area/space) "bVE" = ( /obj/effect/landmark/start/atmospheric_technician, /obj/machinery/atmospherics/pipe/simple/orange/visible{ @@ -47270,13 +47260,16 @@ /turf/open/floor/engine/n2o, /area/engine/atmos) "bWq" = ( -/obj/structure/lattice, -/obj/machinery/camera{ - c_tag = "Routing Depot - Aft Exterior"; - pixel_x = 22 +/obj/effect/turf_decal/stripes/line{ + dir = 4 }, -/turf/open/space/basic, -/area/space/nearstation) +/obj/machinery/atmospherics/pipe/simple/cyan/hidden, +/obj/machinery/airalarm{ + dir = 8; + pixel_x = 23 + }, +/turf/open/floor/plasteel, +/area/hallway/primary/central) "bWr" = ( /obj/structure/closet/l3closet/scientist, /obj/effect/turf_decal/stripes/line, @@ -47442,17 +47435,18 @@ /turf/closed/wall/r_wall, /area/ai_monitored/turret_protected/ai_upload_foyer) "bWJ" = ( -/obj/effect/turf_decal/stripes/line, -/obj/structure/disposalpipe/segment, -/obj/structure/cable{ - icon_state = "2-4" - }, +/obj/structure/lattice/catwalk, /obj/structure/cable{ icon_state = "4-8" }, -/obj/machinery/atmospherics/pipe/simple/orange/hidden, -/turf/open/floor/plasteel, -/area/ai_monitored/turret_protected/ai_upload_foyer) +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/supplymain/visible{ + dir = 1 + }, +/turf/open/space/basic, +/area/space/nearstation) "bWK" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/atmospherics/pipe/simple/orange/visible, @@ -49080,14 +49074,15 @@ }, /area/library) "bZV" = ( +/obj/structure/window/reinforced/spawner/east, /obj/structure/table/wood, -/obj/structure/window/reinforced/spawner/north, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/open/floor/carpet{ - icon_state = "carpetsymbol" +/obj/machinery/light{ + dir = 1; + light_color = "#c1caff" }, +/obj/item/paper_bin, +/obj/item/pen, +/turf/open/floor/carpet, /area/library) "bZW" = ( /obj/structure/sign/warning/fire, @@ -49805,18 +49800,24 @@ /turf/open/floor/plating, /area/ai_monitored/storage/eva) "cbI" = ( -/obj/structure/lattice/catwalk, /obj/structure/cable{ icon_state = "4-8" }, -/obj/machinery/atmospherics/pipe/manifold/supplymain/visible{ - dir = 1 - }, /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/open/space/basic, -/area/space/nearstation) +/obj/machinery/atmospherics/pipe/simple/supplymain/visible{ + dir = 4 + }, +/obj/machinery/door/airlock/external{ + name = "Atmospherics External Airlock"; + req_access_txt = "24" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/engine/atmos) "cbJ" = ( /obj/structure/table/reinforced, /obj/item/analyzer, @@ -49858,19 +49859,13 @@ /obj/structure/cable{ icon_state = "4-8" }, -/obj/machinery/door/airlock/external{ - name = "Atmospherics External Airlock"; - req_access_txt = "24" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, /obj/machinery/atmospherics/pipe/simple/supplymain/hidden{ dir = 4 }, /obj/structure/disposalpipe/segment{ dir = 4 }, +/obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, /area/engine/atmos) "cbM" = ( @@ -51026,24 +51021,17 @@ /turf/closed/wall/r_wall, /area/medical/medbay/lobby) "cea" = ( -/obj/effect/turf_decal/delivery, -/obj/machinery/photocopier, -/obj/structure/disposalpipe/segment{ - dir = 4 +/obj/structure/table/wood, +/obj/structure/window/reinforced/spawner/north, +/obj/structure/cable{ + icon_state = "1-2" }, -/obj/machinery/requests_console{ - department = "Cargo Bay"; - departmentType = 2; - name = "Cargo RC"; - pixel_y = 30 +/obj/item/paper_bin, +/obj/item/pen, +/turf/open/floor/carpet{ + icon_state = "carpetsymbol" }, -/obj/machinery/camera{ - c_tag = "Supply - Delivery Office Aft"; - network = list("ss13","rd") - }, -/obj/item/paper/guides/cogstation/disposals, -/turf/open/floor/plasteel, -/area/quartermaster/sorting) +/area/library) "ceb" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/door/poddoor/shutters/preopen{ @@ -55857,6 +55845,28 @@ }, /turf/open/floor/wood, /area/library) +"cnQ" = ( +/obj/structure/lattice, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/orange/hidden, +/obj/machinery/camera{ + c_tag = "Supply - Warehouse Exterior"; + dir = 1 + }, +/turf/open/space/basic, +/area/quartermaster/warehouse) +"cnR" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/supplymain/hidden{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/ai_monitored/turret_protected/ai_upload_foyer) "cnS" = ( /obj/structure/cable{ icon_state = "0-2" @@ -56625,18 +56635,25 @@ /turf/open/floor/plasteel, /area/hallway/primary/central) "cpm" = ( -/obj/structure/chair/stool, -/obj/effect/turf_decal/tile/neutral{ +/obj/effect/turf_decal/delivery, +/obj/machinery/photocopier, +/obj/structure/disposalpipe/segment{ dir = 4 }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 +/obj/machinery/requests_console{ + department = "Cargo Bay"; + departmentType = 2; + name = "Cargo RC"; + pixel_y = 30 }, -/obj/machinery/newscaster{ - pixel_x = -30 +/obj/machinery/camera{ + c_tag = "Supply - Delivery Office Aft"; + network = list("ss13","rd") }, -/turf/open/floor/plasteel/dark, -/area/lawoffice) +/obj/item/paper/guides/cogstation/disposals, +/obj/item/paper/fluff/cogstation/mulebot, +/turf/open/floor/plasteel, +/area/quartermaster/sorting) "cpn" = ( /obj/effect/turf_decal/tile/neutral, /obj/effect/turf_decal/tile/neutral{ @@ -58509,8 +58526,9 @@ req_access_txt = "5" }, /obj/item/clipboard, -/obj/item/clothing/glasses/hud/health, /obj/machinery/atmospherics/pipe/simple/orange/hidden, +/obj/item/paper/guides/cogstation/letter_med, +/obj/item/clothing/glasses/hud/health, /obj/item/pen, /obj/item/clothing/glasses/hud/health, /turf/open/floor/plasteel/white, @@ -61375,6 +61393,16 @@ /obj/machinery/atmospherics/pipe/simple/cyan/hidden, /turf/open/floor/plasteel, /area/quartermaster/miningoffice) +"cyd" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/simple/orange/hidden{ + dir = 8 + }, +/obj/machinery/atmospherics/components/unary/vent_pump/on, +/turf/open/floor/plating, +/area/ai_monitored/turret_protected/ai_upload_foyer) "cye" = ( /obj/structure/disposalpipe/segment{ dir = 5 @@ -65719,19 +65747,24 @@ /turf/open/floor/plasteel/white, /area/medical/medbay/central) "cFs" = ( -/obj/structure/table, -/obj/effect/turf_decal/tile/red{ +/obj/effect/turf_decal/tile/blue{ + dir = 4 + }, +/obj/effect/turf_decal/tile/blue{ dir = 1 }, -/obj/effect/turf_decal/tile/red{ - dir = 8 +/obj/structure/noticeboard{ + pixel_y = 28 }, -/obj/machinery/atmospherics/pipe/simple/orange/hidden, -/obj/item/storage/backpack/duffelbag/med/surgery, +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/cyan/hidden{ + dir = 4 + }, +/obj/item/paper/guides/cogstation/letter_med, /turf/open/floor/plasteel/white, -/area/medical/medbay/zone2{ - name = "Medbay Treatment Center" - }) +/area/medical/medbay/central) "cFt" = ( /obj/effect/turf_decal/tile/blue{ dir = 1 @@ -67921,6 +67954,11 @@ /obj/machinery/atmospherics/pipe/simple/supplymain/hidden, /turf/open/floor/plasteel/freezer, /area/crew_quarters/toilet/restrooms) +"cJg" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/plating, +/area/quartermaster/warehouse) "cJh" = ( /obj/structure/table, /obj/structure/bedsheetbin/towel, @@ -68022,6 +68060,18 @@ /area/engine/engineering{ name = "Engine Room" }) +"cJq" = ( +/obj/machinery/atmospherics/pipe/simple/supplymain/visible, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/external/glass{ + name = "External Construction Access"; + req_one_access_txt = "10;31" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper, +/turf/open/floor/plasteel, +/area/quartermaster/warehouse) "cJr" = ( /obj/structure/lattice/catwalk, /obj/machinery/atmospherics/pipe/simple/supplymain/visible{ @@ -68030,23 +68080,28 @@ /turf/open/space/basic, /area/space/nearstation) "cJs" = ( -/obj/structure/lattice/catwalk, /obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/simple/supplymain/visible{ - dir = 4 - }, -/turf/open/space/basic, -/area/space/nearstation) +/obj/machinery/atmospherics/pipe/simple/orange/hidden, +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/plating, +/area/quartermaster/warehouse) "cJt" = ( -/obj/structure/lattice/catwalk, +/obj/effect/turf_decal/stripes/line, +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/power/apc{ + name = "AI Upload Foyer APC"; + pixel_y = -24 + }, /obj/structure/cable{ - icon_state = "1-2" + icon_state = "0-4" }, -/obj/machinery/atmospherics/pipe/manifold/supplymain/visible{ - dir = 4 +/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{ + dir = 5 }, -/turf/open/space/basic, -/area/space/nearstation) +/turf/open/floor/plasteel, +/area/ai_monitored/turret_protected/ai_upload_foyer) "cJu" = ( /obj/machinery/atmospherics/components/unary/portables_connector/visible{ dir = 1 @@ -69993,6 +70048,21 @@ "cNB" = ( /turf/open/floor/plating, /area/quartermaster/miningdock/airless) +"cNC" = ( +/obj/effect/turf_decal/stripes/line, +/obj/structure/disposalpipe/segment, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/orange/hidden, +/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/ai_monitored/turret_protected/ai_upload_foyer) "cND" = ( /obj/effect/landmark/event_spawn, /turf/open/floor/plasteel, @@ -70935,15 +71005,25 @@ /turf/open/space/basic, /area/space/nearstation) "cPG" = ( -/obj/structure/lattice, -/obj/structure/disposalpipe/segment, -/obj/machinery/camera{ - c_tag = "Supply - Warehouse Exterior"; - dir = 1 +/obj/effect/turf_decal/stripes/line, +/obj/structure/cable{ + icon_state = "1-8" }, -/obj/machinery/atmospherics/pipe/simple/orange/hidden, -/turf/open/space/basic, -/area/space/nearstation) +/obj/machinery/turretid{ + control_area = "/area/science/server"; + icon_state = "control_stun"; + name = "Computer Core turret control"; + pixel_x = -3; + pixel_y = -23; + req_access_txt = "65" + }, +/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/science/server{ + name = "Computer Core" + }) "cPH" = ( /obj/machinery/conveyor_switch{ id = "EngiCargoConveyer" @@ -71796,9 +71876,6 @@ /obj/item/paper/guides/jobs/medical/cloning{ pixel_x = -4 }, -/obj/item/paper/fluff/cogstation/cloner{ - pixel_x = 6 - }, /turf/open/floor/plasteel, /area/medical/medbay/central) "cRc" = ( @@ -71864,22 +71941,11 @@ /turf/open/floor/plasteel/white/corner, /area/engine/atmos) "cRh" = ( -/obj/effect/turf_decal/stripes/line, -/obj/structure/cable{ - icon_state = "1-8" +/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{ + dir = 4 }, -/obj/machinery/turretid{ - control_area = "/area/science/server"; - icon_state = "control_stun"; - name = "Computer Core turret control"; - pixel_x = -3; - pixel_y = -23; - req_access_txt = "65" - }, -/turf/open/floor/plasteel, -/area/science/server{ - name = "Computer Core" - }) +/turf/closed/wall/r_wall, +/area/ai_monitored/turret_protected/ai_upload_foyer) "cRi" = ( /obj/effect/turf_decal/tile/purple{ dir = 1 @@ -72023,6 +72089,53 @@ }, /turf/open/floor/plasteel, /area/science/robotics/lab) +"cRs" = ( +/obj/machinery/recharge_station, +/obj/machinery/atmospherics/pipe/simple/supplymain/hidden{ + dir = 9 + }, +/obj/machinery/airalarm{ + dir = 4; + pixel_x = -22 + }, +/turf/open/floor/plating, +/area/ai_monitored/turret_protected/ai_upload_foyer) +"cRt" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/supplymain/hidden, +/obj/effect/turf_decal/delivery, +/turf/open/floor/plasteel, +/area/quartermaster/warehouse) +"cRu" = ( +/obj/effect/turf_decal/delivery, +/turf/open/floor/plasteel, +/area/science/mixing) +"cRv" = ( +/mob/living/simple_animal/opossum{ + desc = "Wubba lubba dub dub."; + name = "Rick" + }, +/turf/open/floor/plasteel/showroomfloor, +/area/medical/morgue) +"cRw" = ( +/obj/structure/table, +/obj/effect/turf_decal/tile/red{ + dir = 1 + }, +/obj/effect/turf_decal/tile/red{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/orange/hidden, +/obj/item/paper/guides/cogstation/letter_med{ + pixel_y = 4 + }, +/obj/item/storage/backpack/duffelbag/med/surgery, +/turf/open/floor/plasteel/white, +/area/medical/medbay/zone2{ + name = "Medbay Treatment Center" + }) "cVq" = ( /obj/machinery/atmospherics/pipe/simple/orange/visible{ dir = 4 @@ -72130,14 +72243,6 @@ }, /turf/open/floor/plasteel, /area/engine/atmos) -"frb" = ( -/obj/structure/lattice/catwalk, -/obj/machinery/atmospherics/pipe/simple/supplymain/visible, -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/open/space/basic, -/area/space/nearstation) "fti" = ( /obj/machinery/atmospherics/components/binary/pump, /obj/machinery/atmospherics/pipe/simple/orange/hidden{ @@ -84950,7 +85055,7 @@ akI aAJ cMp aYa -bxm +akI akI aNC bxv @@ -85206,7 +85311,7 @@ aLH akI aAK aRC -bxn +aHj akI bxA hiV @@ -85723,7 +85828,7 @@ aXm aXs bxC akI -bxK +beC bxY byh byb @@ -85977,7 +86082,7 @@ aaU aaU aEa cMK -bxt +aHE akI akI akI @@ -86233,9 +86338,9 @@ aaU aaa aaU aEa -aHE -bab -aaa +cMK +aTh +akI aaa aaU aaa @@ -86490,7 +86595,8 @@ aaU aaU aaU aEb -aPT +aya +bab aaU aaU aye @@ -86508,7 +86614,6 @@ aye aye aye aye -aye aaa aaa aaa @@ -90657,7 +90762,7 @@ aaa aaa aaa aaa -aaa +aWj aaU aaa aaU @@ -90913,9 +91018,9 @@ aaa aaa aaa aaa -aaa -aWj -aaU +bcw +aUZ +bcw aaa bcy cnU @@ -91171,7 +91276,7 @@ aaa aaa aaa bcw -aUZ +cRu bcw aaa bcy @@ -91193,7 +91298,7 @@ aaa aaa aaU aaa -bAb +brs bxT bFq bHY @@ -91363,10 +91468,10 @@ aaa aaa aaU abx -aqw -aoW -aqw -aqw +aiN +alu +aiN +abx aaU aaa aaa @@ -91620,9 +91725,9 @@ aaa aaa aaU abx -akg -apS -arr +aiN +asl +aiN abx aaU aaa @@ -91877,9 +91982,9 @@ aaa aaa aaU aiN -akj -anV -asl +aoW +apS +asH abx aaU aaU @@ -92134,9 +92239,9 @@ aaa aaa aaU aiN -akz +arr aDO -asH +atn awm axc awm @@ -95499,7 +95604,7 @@ aNL aNL aVl aYT -baz +aXf bFH aYT aaU @@ -97043,7 +97148,7 @@ aVL aYT baG bbM -bcz +aZA aYT bdy beM @@ -98094,7 +98199,7 @@ bgA bWf bXm bZQ -ccN +bWq ccN cei ccN @@ -99380,12 +99485,12 @@ bWh csG bQA aZy -aXf +bZV bZJ bZF cpu bax -bZV +cea bZX ccY cab @@ -99628,8 +99733,8 @@ bnz bpw bQx bll -aZz -cpm +aZC +bcz bad bah baR @@ -99885,8 +99990,8 @@ bnA bpy bQI bll -aZA aZI +beG bae chP baS @@ -100142,7 +100247,7 @@ bnD bpC bQx bll -aZC +baz aZN bCS bak @@ -102760,7 +102865,7 @@ caR czi cKj buS -bFY +cFs cEX bIU aJE @@ -103536,7 +103641,7 @@ cFe cFk cFm cFq -cFs +cRw cFz bqt blx @@ -104781,8 +104886,8 @@ bLz bNe ajO bQb -bUj -aTh +cnR +cJt bfh brb bzN @@ -105022,9 +105127,9 @@ bOV aRq cjD bnU -btw +bxm bns -aya +bxn avy alo awn @@ -105039,7 +105144,7 @@ bPp bPU bQi bUU -bWJ +cNC bWP cbV bzR @@ -105279,7 +105384,7 @@ aSt aSt aSt aSt -cpG +aWd aSt brs avv @@ -105296,7 +105401,7 @@ cRf bPV bQT bVq -cRh +cPG bfh cbY cdn @@ -105523,7 +105628,7 @@ axV aog aog aSH -beG +aZz aaU aaU aaU @@ -105535,9 +105640,9 @@ aRv aaU aaU aaU -aWj -aSq -aWj +aSt +cpG +aSt aaU avv ajO @@ -105553,7 +105658,7 @@ ajO ajO aRy bVC -aRy +cRh bfh bfh bBR @@ -105809,8 +105914,8 @@ bmH aYZ bht bcY -bVD -beC +cyd +cRs cgF bfh bBS @@ -106033,7 +106138,7 @@ aOJ aOJ bmF bnT -aRJ +bnT aRJ aRJ chm @@ -106289,13 +106394,13 @@ bfv bfv bkW bmJ +bnS bof aQJ aQJ aQJ aQJ aQJ -aQJ aRZ aaU aaa @@ -106357,7 +106462,7 @@ cyP byQ bzS czw -bDb +cRv bBu crX czI @@ -106547,7 +106652,7 @@ bjL blD bmK boi -aaU +bsx aaU aaU aaU @@ -106805,7 +106910,7 @@ aOJ aPN bes aaU -aye +bQe aye bQe aye @@ -107839,7 +107944,7 @@ aye aye aaU aWj -bnS +btw buq bwC bAr @@ -108619,7 +108724,7 @@ bMS bBv bXM bvB -bWq +bvM acY adz bsz @@ -109124,7 +109229,7 @@ aaa aaa aaU aWj -bnS +btw buq bwZ bBC @@ -113190,7 +113295,7 @@ abe aeP agX ajS -aHj +akg bvm ahP aif @@ -113448,7 +113553,7 @@ aaV ahP ahP ahP -bzp +akj ahP aif aiB @@ -115821,10 +115926,10 @@ bra bwW bwW aaU -bdR -cJr -bTJ -aaa +anr +aWj +bUj +bVD aaa cPz aaa @@ -116078,8 +116183,8 @@ brr bCr cwv bAQ -bAQ -cJs +bxt +bzp bUV caf bam @@ -116089,7 +116194,7 @@ bYl bam bam bam -bam +cJg bbX bbX bcn @@ -116335,8 +116440,8 @@ brP brX bsh bsu -bsx -cJt +bxK +bDb sVC cdp sVC @@ -116346,8 +116451,8 @@ bZp sVC sVC sVC -frb -bvM +cJq +cRt bvW bvX bwd @@ -116593,7 +116698,7 @@ bsi bsv bsy bsy -bsD +bTJ bsI bRv bsD @@ -116602,8 +116707,8 @@ bsD cPE cPF cPF -cPF -cPG +cnQ +cJs bBL bBL bCm @@ -118141,9 +118246,9 @@ bJv aaU cwJ aaU -cbG -aaU -aaU +bWJ +mIT +cJr aaU bbT bbT @@ -118397,10 +118502,10 @@ bPA wPS aaa cwI -aaa +cwA cbI -mIT -cJr +cwA +anr aaa aaU aaU @@ -118654,9 +118759,9 @@ bgM cwA cwA cwL -cww +cwA cbL -cww +cwA bdR mIT mIT @@ -118670,7 +118775,7 @@ bgk bbT bkd bbT -cea +cpm bVG cgn cje @@ -119876,7 +119981,7 @@ aaa aaa aaa arM -atn +atl arM aaU aaU @@ -120132,9 +120237,9 @@ aaa aaa aaa aaa -aaa -aWj -aaU +arM +akz +arM aaU aaU aaU @@ -120390,9 +120495,9 @@ aaa aaa aaa aaa -aaa -aaa -aaa +aWj +aaU +aaU aaa aaa aaU @@ -125338,11 +125443,11 @@ aWj cww cJm cww -aaU -aaa -aaa -aaa -aaa +aWj +aWj +aWj +aWj +aWj aaU aaU aaa @@ -125593,9 +125698,9 @@ bal aaU aWj cww -cJn +cJm cww -aaU +aWj bal bal bal @@ -125849,10 +125954,10 @@ aaa aaa aaU aWj +bFY +cJn +cww aWj -aWj -aaa -aaa aaa aaa aaa @@ -126105,11 +126210,11 @@ aaa aaa aaa aaU -aaa -aaa -aaa -aaa -aaa +aWj +aWj +aWj +aWj +aWj bal bal bal diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index fdc313c30a..6f0636d3cb 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -982,11 +982,11 @@ /area/security/prison) "aci" = ( /obj/structure/lattice/catwalk, -/obj/machinery/door/airlock/external{ - req_one_access_txt = "13,8" +/obj/structure/cable{ + icon_state = "0-2" }, /turf/open/space, -/area/maintenance/starboard/fore) +/area/solar/starboard/fore) "acj" = ( /obj/machinery/light/small{ dir = 1 @@ -3123,6 +3123,17 @@ }, /turf/open/floor/plasteel, /area/security/prison) +"afQ" = ( +/obj/machinery/door/airlock/external{ + name = "Solar Maintenance"; + req_access_txt = "10; 13" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plating, +/area/maintenance/solars/starboard/fore) "afR" = ( /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ dir = 1 @@ -5480,15 +5491,17 @@ /turf/open/floor/plasteel/dark, /area/engine/gravity_generator) "akd" = ( -/turf/open/space, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plating, /area/maintenance/solars/starboard/fore) "ake" = ( -/obj/structure/cable{ - icon_state = "0-2" - }, -/obj/structure/lattice/catwalk, /turf/open/space, -/area/maintenance/solars/starboard/fore) +/area/space) "akf" = ( /obj/machinery/conveyor{ dir = 1; @@ -6294,11 +6307,6 @@ /obj/structure/cable{ icon_state = "1-2" }, -/obj/machinery/door/airlock/external{ - name = "Solar Maintenance"; - req_access_txt = "10; 13" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper, /turf/open/floor/plating, /area/maintenance/solars/starboard/fore) "alx" = ( @@ -6997,6 +7005,10 @@ /obj/structure/window/reinforced, /turf/open/floor/plasteel/dark, /area/crew_quarters/fitness/recreation) +"amB" = ( +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/plating, +/area/maintenance/port) "amC" = ( /obj/structure/chair{ dir = 4 @@ -7014,6 +7026,17 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/closed/wall, /area/crew_quarters/fitness/recreation) +"amF" = ( +/obj/machinery/door/airlock/maintenance/abandoned{ + name = "Storage Room"; + req_access_txt = "12" + }, +/obj/structure/barricade/wooden, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) +"amG" = ( +/turf/closed/wall, +/area/crew_quarters/fitness/pool) "amH" = ( /obj/machinery/door/airlock/external{ req_one_access_txt = "13,8" @@ -7086,14 +7109,9 @@ /turf/open/floor/plasteel/dark, /area/engine/gravity_generator) "amN" = ( -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, +/obj/effect/turf_decal/stripes/corner, /turf/open/floor/plating, -/area/maintenance/solars/starboard/fore) +/area/crew_quarters/fitness/pool) "amO" = ( /obj/machinery/light/small{ dir = 8 @@ -7158,6 +7176,13 @@ icon_state = "platingdmg2" }, /area/maintenance/port) +"amV" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) "amW" = ( /obj/structure/table/reinforced, /obj/item/folder, @@ -7438,6 +7463,9 @@ /obj/item/paper, /turf/open/floor/plasteel, /area/security/main) +"anz" = ( +/turf/open/floor/plasteel, +/area/crew_quarters/fitness/pool) "anA" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/structure/disposalpipe/segment, @@ -7898,6 +7926,10 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, /area/security/warden) +"aov" = ( +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) "aow" = ( /obj/machinery/door/firedoor, /obj/structure/cable/yellow{ @@ -8616,6 +8648,12 @@ }, /turf/open/floor/plasteel/showroomfloor, /area/security/warden) +"apP" = ( +/obj/effect/turf_decal/stripes/corner{ + dir = 1 + }, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) "apQ" = ( /obj/structure/reagent_dispensers/peppertank{ pixel_x = 32 @@ -8682,6 +8720,9 @@ /obj/item/assembly/flash/handheld, /turf/open/floor/plasteel, /area/security/main) +"apX" = ( +/turf/open/pool, +/area/crew_quarters/fitness/pool) "apY" = ( /obj/structure/table, /obj/item/folder/red, @@ -8747,6 +8788,12 @@ }, /turf/open/floor/plasteel/dark, /area/crew_quarters/fitness/recreation) +"aqe" = ( +/obj/machinery/pool/filter{ + pixel_y = 16 + }, +/turf/open/pool, +/area/crew_quarters/fitness/pool) "aqf" = ( /obj/structure/closet/lasertag/blue, /obj/effect/turf_decal/tile/neutral{ @@ -9248,6 +9295,12 @@ }, /turf/open/floor/plasteel/showroomfloor, /area/security/warden) +"arh" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) "ari" = ( /obj/machinery/holopad, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, @@ -9478,6 +9531,14 @@ }, /turf/open/floor/plasteel, /area/crew_quarters/dorms) +"arF" = ( +/obj/structure/pool/ladder{ + dir = 8; + icon_state = "ladder"; + pixel_x = 4 + }, +/turf/open/pool, +/area/crew_quarters/fitness/pool) "arG" = ( /obj/structure/closet, /obj/item/storage/box/lights/mixed, @@ -10167,6 +10228,13 @@ /obj/structure/chair, /turf/open/floor/plasteel/grimy, /area/security/main) +"asN" = ( +/obj/machinery/light/built{ + icon_state = "tube-empty"; + dir = 8 + }, +/turf/open/floor/plasteel, +/area/crew_quarters/fitness/pool) "asO" = ( /obj/item/paper_bin{ pixel_x = -3; @@ -10466,6 +10534,10 @@ }, /turf/open/floor/plating, /area/maintenance/port/fore) +"atw" = ( +/obj/machinery/pool/drain, +/turf/open/pool, +/area/crew_quarters/fitness/pool) "atx" = ( /obj/structure/cable/yellow{ icon_state = "2-4" @@ -10536,6 +10608,12 @@ }, /turf/open/floor/plating, /area/maintenance/port/fore) +"atC" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) "atD" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 @@ -10558,6 +10636,10 @@ }, /turf/open/floor/plating, /area/maintenance/port/fore) +"atF" = ( +/obj/machinery/pool/controller, +/turf/open/floor/plasteel, +/area/crew_quarters/fitness/pool) "atG" = ( /obj/structure/cable/yellow{ icon_state = "4-8" @@ -10601,6 +10683,23 @@ }, /turf/open/floor/plating, /area/maintenance/port/fore) +"atJ" = ( +/obj/structure/sign/poster/ripped{ + pixel_y = 32 + }, +/obj/structure/table, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/obj/item/light/tube, +/obj/machinery/power/apc{ + areastring = "/area/crew_quarters/fitness/pool"; + dir = 4; + name = "Pool APC"; + pixel_x = 26 + }, +/turf/open/floor/plasteel, +/area/crew_quarters/fitness/pool) "atK" = ( /obj/machinery/computer/prisoner/gulag_teleporter_computer{ dir = 1 @@ -11069,6 +11168,24 @@ }, /turf/open/floor/plating, /area/maintenance/port/fore) +"auQ" = ( +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) +"auR" = ( +/obj/structure/pool/Lboard, +/turf/open/pool, +/area/crew_quarters/fitness/pool) +"auS" = ( +/obj/structure/pool/Rboard, +/turf/open/floor/plasteel, +/area/crew_quarters/fitness/pool) +"auT" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/crew_quarters/fitness/pool) "auU" = ( /obj/structure/disposalpipe/segment{ dir = 6 @@ -11659,6 +11776,50 @@ }, /turf/open/floor/plating, /area/maintenance/port/fore) +"avU" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) +"avV" = ( +/obj/structure/cable/yellow{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/machinery/door/airlock/maintenance/abandoned, +/obj/structure/barricade/wooden, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) +"avW" = ( +/obj/structure/cable/yellow{ + icon_state = "1-2" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/structure/cable/yellow{ + icon_state = "1-8" + }, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 4 + }, +/turf/open/floor/plating, +/area/maintenance/port/aft) +"avX" = ( +/obj/structure/chair{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/crew_quarters/fitness/pool) "avY" = ( /obj/machinery/door/airlock/external{ name = "Labor Camp Shuttle Airlock"; @@ -11932,6 +12093,11 @@ }, /turf/open/floor/plasteel/dark, /area/security/brig) +"awA" = ( +/obj/structure/closet/athletic_mixed, +/obj/item/toy/poolnoodle/blue, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) "awB" = ( /obj/structure/reagent_dispensers/watertank, /obj/item/storage/box/lights/mixed, @@ -12053,6 +12219,18 @@ /obj/effect/spawner/lootdrop/maintenance, /turf/open/floor/plating, /area/maintenance/port/fore) +"awN" = ( +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) +"awO" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) "awP" = ( /obj/item/clothing/gloves/color/rainbow, /obj/item/clothing/shoes/sneakers/rainbow, @@ -12105,6 +12283,25 @@ "awW" = ( /turf/closed/wall/r_wall, /area/security/nuke_storage) +"awX" = ( +/obj/effect/turf_decal/stripes/corner{ + dir = 4 + }, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) +"awY" = ( +/obj/machinery/door/airlock/external{ + name = "Solar Maintenance"; + req_access_txt = "10; 13" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 8 + }, +/turf/open/floor/plating, +/area/maintenance/solars/starboard/aft) "awZ" = ( /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ dir = 8 @@ -54179,21 +54376,6 @@ /obj/structure/lattice/catwalk, /turf/open/space, /area/solar/port/aft) -"cek" = ( -/obj/machinery/door/airlock/external{ - req_access_txt = "13" - }, -/turf/open/floor/plating, -/area/maintenance/port/aft) -"cel" = ( -/obj/structure/sign/warning/vacuum/external{ - pixel_y = 32 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/turf/open/floor/plating, -/area/maintenance/port/aft) "cem" = ( /obj/structure/cable/yellow{ icon_state = "1-2" @@ -54885,16 +55067,6 @@ }, /turf/open/floor/plating, /area/maintenance/port/fore) -"cfB" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/structure/cable/yellow{ - icon_state = "1-2" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/turf/open/floor/plating, -/area/maintenance/port/aft) "cfC" = ( /obj/item/trash/pistachios, /obj/structure/closet, @@ -55509,13 +55681,6 @@ /obj/structure/reagent_dispensers/cooking_oil, /turf/open/floor/plasteel/showroomfloor, /area/crew_quarters/kitchen) -"cgG" = ( -/obj/structure/closet/emcloset/anchored, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/turf/open/floor/plating, -/area/maintenance/port/aft) "cgH" = ( /obj/structure/cable/yellow{ icon_state = "4-8" @@ -81287,19 +81452,6 @@ }, /turf/open/floor/plating, /area/maintenance/starboard/aft) -"gsT" = ( -/obj/machinery/door/airlock/external{ - name = "Solar Maintenance"; - req_access_txt = "10; 13" - }, -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/turf/open/floor/plating, -/area/solar/starboard/aft) "gEk" = ( /obj/structure/cable/yellow{ icon_state = "2-8" @@ -97098,15 +97250,15 @@ bTp bUP bVS bXv -bYC -bYC -bYC -bYC -aaa -aaf -aaa -aaa -aaf +bTn +bTn +bTn +bTn +amG +auQ +auQ +amG +amG aaf aaf aaa @@ -97356,16 +97508,16 @@ bTn bTn bTn bTn +amN +anz +arh +asN +anz +arh +awN +amG aaa -aaf -aaa -aaa -aaf -aaf -aaf -aaf -aaa -aaa +lMJ aaa aaa aaa @@ -97609,20 +97761,20 @@ bzx alC mEe alK -aob -aob dix -alK -aaf -aaf -aaf -aaf -aaf -aaa -aaa -aaf -aaa +aob +amB +amF +amV +apX +apX +apX +apX +apX +awO +auQ aaa +lMJ aaa aaa aaa @@ -97869,17 +98021,17 @@ bTr bUQ bVT aob -alK -aaa -aaf -aaa -aaa -aaa -aaa -aaa -aaf -aaa +amG +anz +aqe +apX +atw +apX +apX +anz +auQ aaa +lMJ aaa aaa aaa @@ -98126,15 +98278,15 @@ alK bJs bVU bXx -alK -aaa -aaf -aaf -ack -aaf -aaf -aaf -aaf +amG +aov +apX +arF +apX +auR +apX +anz +auQ aaf aaf aaf @@ -98383,15 +98535,15 @@ alK bUR alK alK -alK -aaa -aaf -aaa -ack -aaf -aaa -aaa -aaa +amG +apP +anz +anz +atC +auS +atC +awX +amG aaa aaa aaa @@ -98640,15 +98792,15 @@ alK alK alK bXy -dux -dux -dux -dux -cek -dux -dux -dux -dux +amG +amG +amG +amG +atF +auT +avX +amG +amG ckN ckN ckN @@ -98900,11 +99052,11 @@ bXz bYE bYE cbp -dux -cel -bUU -cgG -dux +amG +atJ +avU +awA +amG cjp ckO cmg @@ -99157,11 +99309,11 @@ dux dux dux cbq -dux -dux -cek -dux -dux +amG +amG +avV +amG +amG cjq ckP ckS @@ -99416,7 +99568,7 @@ dux cbr bYE cem -cfB +avW cbp dux diE @@ -119752,7 +119904,7 @@ cJf dvY aaa dbN -gsT +awY dbN aaa aaa @@ -124021,7 +124173,7 @@ aaf aaa aaf dnh -aci +amH dnh ape dnS @@ -126848,7 +127000,7 @@ aaa aaf aaa aaa -akd +ake alv apm apm @@ -127103,7 +127255,7 @@ aaf aaa aaa aaf -akd +alv alv alv alv @@ -127359,10 +127511,10 @@ abR abR abR abR -abR -ake +aci +afQ +akd alw -amN sGh apo aqz @@ -127617,7 +127769,7 @@ aaf aaa aaa aaf -akd +alv alv alv alv @@ -127876,7 +128028,7 @@ aaa aaf aaa aaa -akd +ake alv apm apm diff --git a/_maps/map_files/Snaxi/IcemoonUnderground_Above.dmm b/_maps/map_files/Snaxi/IcemoonUnderground_Above.dmm index 403f155854..153ad4265d 100644 --- a/_maps/map_files/Snaxi/IcemoonUnderground_Above.dmm +++ b/_maps/map_files/Snaxi/IcemoonUnderground_Above.dmm @@ -112,7 +112,7 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/closed/mineral/random/snow, +/turf/open/floor/plating/asteroid/snow/icemoon, /area/icemoon/underground/unexplored/rivers) "eH" = ( /obj/machinery/airalarm{ @@ -581,7 +581,7 @@ desc = "A horn off of a bicycle. This one has been charred to hell and back, yet somehow it still honks."; name = "charred bike horn" }, -/turf/closed/mineral/random/snow, +/turf/open/floor/plating/asteroid/snow/icemoon, /area/icemoon/underground/unexplored/rivers) "nN" = ( /turf/closed/wall/r_wall, @@ -722,6 +722,9 @@ }, /turf/open/floor/plasteel, /area/mine/living_quarters) +"rs" = ( +/turf/open/floor/plating/asteroid/snow/icemoon, +/area/icemoon/underground/unexplored/rivers) "ry" = ( /obj/effect/turf_decal/tile/purple{ dir = 8 @@ -809,6 +812,9 @@ }, /turf/open/floor/plasteel/white, /area/mine/living_quarters) +"sL" = ( +/turf/open/transparent/openspace/icemoon, +/area/icemoon/underground/unexplored/rivers) "sM" = ( /obj/structure/table, /obj/item/storage/firstaid/toxin{ @@ -2367,7 +2373,7 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/closed/mineral/random/snow, +/turf/open/floor/plating/asteroid/snow/icemoon, /area/icemoon/underground/unexplored/rivers) "WE" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper{ @@ -29940,9 +29946,9 @@ ah ah ah ah +rs ah -ah -ah +rs ah ah ah @@ -30199,8 +30205,8 @@ ah ah ah ah -ah -ah +rs +rs ah ah ah @@ -30456,8 +30462,8 @@ ah ah ah ah -ah -ah +rs +rs ah ah ah @@ -30712,10 +30718,10 @@ ah ah ah nE -ah -ah -ah -ah +rs +sL +sL +rs ah ah ah @@ -30968,11 +30974,11 @@ ah ah ah ah -ah -ah -ah -ah -ah +rs +rs +rs +sL +rs ah ah ah @@ -31498,8 +31504,8 @@ ah ah ah ah -ah -ah +rs +rs ah ah ah @@ -31749,14 +31755,14 @@ ah ah ah ah +rs +rs +rs +rs ah -ah -ah -ah -ah -ah -ah -ah +rs +rs +rs ah ah ah @@ -32005,14 +32011,14 @@ Gw op nd ah -ah -ah -ah -ah -ah -ah -ah -ah +sL +rs +rs +rs +rs +rs +rs +rs ah ah ah @@ -32262,15 +32268,15 @@ GI Lg nd ah -ah -ah -ah +sL +sL +rs op WE op -ah -ah -ah +rs +rs +rs ah ah ah @@ -32519,17 +32525,17 @@ GN Lu nd ah -ah -ah -ah +rs +rs +rs op sa op -ah -ah -ah -ah -ah +rs +rs +rs +rs +rs ah ah ah @@ -32782,11 +32788,11 @@ nd op WM op -ah -ah -ah -ah -ah +rs +rs +rs +rs +rs ah ah ah @@ -33039,10 +33045,10 @@ Rx ry WO op -ah -ah -ah -ah +rs +rs +rs +rs ah ah ah @@ -33296,9 +33302,9 @@ sa sa sa op -ah -ah -ah +rs +rs +rs ah ah ah @@ -33553,8 +33559,8 @@ TA sa Xf op -ah -ah +rs +rs ah ah ah @@ -33810,8 +33816,8 @@ TA sa sa op -ah -ah +rs +rs ah ah ah @@ -37651,8 +37657,8 @@ ah ah ah ah -ah -ah +rs +rs op sa Ho @@ -37908,8 +37914,8 @@ ah ah ah ah -ah -ah +rs +rs op ET HY @@ -38165,18 +38171,18 @@ ah ah ah ah -ah -ah +rs +rs op op Iq op op -ah -ah -ah -ah -ah +rs +rs +rs +rs +rs ah ah ah @@ -38422,19 +38428,19 @@ ah ah ah ah -ah -ah -ah +rs +rs +rs op Iv op -ah -ah -ah -ah -ah -ah -ah +rs +rs +rs +rs +rs +rs +rs ah ah ah @@ -38680,18 +38686,18 @@ ah ah ah ah -ah -ah +rs +rs op Ho op -ah -ah -ah -ah -ah -ah -ah +rs +rs +sL +rs +rs +rs +rs ah ah ah @@ -38937,18 +38943,18 @@ ah ah ah ah -ah -ah +sL +rs op Ho op -ah -ah -ah -ah -ah -ah -ah +rs +sL +sL +sL +rs +rs +rs ah ah ah @@ -39193,21 +39199,21 @@ ah ah ah ah -ah -ah -ah +sL +sL +rs op Ho op -ah -ah -ah -ah -ah -ah -ah -ah -ah +rs +sL +sL +sL +rs +rs +rs +rs +rs ah ah ah @@ -39444,26 +39450,26 @@ ah ah ah ah +rs +rs +rs ah ah ah ah -ah -ah -ah -ah -ah +rs +rs er IB er -ah -ah -ah -ah -ah -ah -ah -ah +rs +sL +sL +rs +rs +rs +rs +rs ah ah ah @@ -39700,24 +39706,24 @@ ah ah ah ah +rs +rs +rs +rs +rs ah ah ah -ah -ah -ah -ah -ah -ah -ah +rs +rs er IB er -ah -ah -ah -ah -ah +rs +sL +sL +rs +rs ah ah ah @@ -39957,24 +39963,24 @@ ah ah ah ah -ah +rs eZ fB er +rs ah ah ah -ah -ah -ah +rs +rs er IB er -ah -ah -ah -ah -ah +rs +rs +sL +sL +rs ah ah ah @@ -40213,25 +40219,25 @@ ah ah ah ah -ah -ah +rs +rs er fC er +rs +rs ah ah -ah -ah -ah -ah +rs +rs er IF er -ah -ah -ah -ah -ah +rs +rs +sL +sL +rs ah ah ah @@ -40470,25 +40476,25 @@ ah ah ah ah -ah +rs er er fD er er +rs ah -ah -ah -ah +rs +rs Be er IK er er -ah -ah -ah -ah +rs +rs +rs +rs ah ah ah @@ -40743,8 +40749,8 @@ IM gS er eq -ah -ah +rs +rs ah ah ah @@ -40983,7 +40989,7 @@ ah ah ah ah -ah +rs eq eH fb @@ -41000,8 +41006,8 @@ IB fC Nt eq -ah -ah +rs +rs ah ah ah @@ -41240,7 +41246,7 @@ ah ah ah ah -ah +rs er eI fc @@ -41497,7 +41503,7 @@ ah ah ah ah -ah +rs er eJ fd @@ -41774,8 +41780,8 @@ er Tk NK er -ah -ah +rs +rs ah ah ah @@ -42009,7 +42015,7 @@ ah ah ah ah -ah +rs dW ei es @@ -42031,9 +42037,9 @@ Rf Tn NP VC -ah -ah -ah +rs +rs +rs ah ah ah @@ -42265,8 +42271,8 @@ ah ah ah ah -ah -ah +rs +rs dX ej et @@ -42288,8 +42294,8 @@ er To UJ er -ah -ah +rs +rs ah ah ah @@ -42522,8 +42528,8 @@ ah ah ah ah -ah -ah +rs +rs dX ej eu @@ -42780,7 +42786,7 @@ ah ah ah ah -ah +rs dW ek ew @@ -44069,9 +44075,9 @@ ah ah ah ex -ah -ah -ah +rs +rs +rs ex ah ah @@ -44324,13 +44330,13 @@ ah ah ah ah -ah -ah -ah -ah -ah -ah -ah +rs +rs +rs +rs +rs +rs +rs ah ah ah @@ -44581,13 +44587,13 @@ ah ah ah ah -ah -ah -ah -ah -ah -ah -ah +rs +rs +rs +rs +rs +rs +rs ah ah ah @@ -44839,11 +44845,11 @@ ah ah ah ah -ah -ah -ah -ah -ah +rs +rs +rs +rs +rs ah ah ah @@ -45097,9 +45103,9 @@ ah ah ah ah -ah -ah -ah +rs +rs +rs ah ah ah diff --git a/_maps/map_files/Snaxi/IcemoonUnderground_Below.dmm b/_maps/map_files/Snaxi/IcemoonUnderground_Below.dmm index 42971e4315..79e5080644 100644 --- a/_maps/map_files/Snaxi/IcemoonUnderground_Below.dmm +++ b/_maps/map_files/Snaxi/IcemoonUnderground_Below.dmm @@ -5,6 +5,9 @@ "b" = ( /turf/closed/mineral/random/high_chance/snow, /area/icemoon/underground/unexplored/rivers) +"c" = ( +/turf/open/floor/plating/asteroid/snow/icemoon, +/area/icemoon/underground/unexplored/rivers) "d" = ( /turf/closed/wall, /area/icemoon/underground/explored) @@ -19,6 +22,9 @@ /obj/item/gps/mining, /turf/open/floor/plating/asteroid/snow/icemoon, /area/icemoon/underground/explored) +"G" = ( +/turf/open/floor/plating/asteroid/snow/icemoon, +/area/mine/maintenance) "N" = ( /obj/item/flashlight/lantern{ on = 1 @@ -33,6 +39,22 @@ /obj/structure/ladder, /turf/open/floor/plating/asteroid/snow/icemoon, /area/icemoon/underground/explored) +"X" = ( +/obj/machinery/telecomms/relay/preset/mining, +/obj/machinery/bluespace_beacon, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced, +/obj/machinery/door/window/eastright{ + dir = 8; + req_access_txt = "48" + }, +/turf/open/floor/circuit, +/area/icemoon/underground/explored) (1,1,1) = {" a @@ -39499,9 +39521,9 @@ a a a a -a -a -a +c +c +c a a a @@ -40011,13 +40033,13 @@ a a a a -a +c e i h h e -a +c a a a @@ -40268,13 +40290,13 @@ a a a a -a +c h h T h h -a +c a a a @@ -40525,13 +40547,13 @@ a a a a -a +c e N h -h +G e -a +c a a a @@ -40786,7 +40808,7 @@ a d O h -e +X d a a @@ -41041,9 +41063,9 @@ a a a a -a -a -a +c +c +c a a a diff --git a/_maps/map_files/Snaxi/Snaxi.dmm b/_maps/map_files/Snaxi/Snaxi.dmm index 45e6e4dee0..ed574fa1a4 100644 --- a/_maps/map_files/Snaxi/Snaxi.dmm +++ b/_maps/map_files/Snaxi/Snaxi.dmm @@ -254,10 +254,11 @@ /turf/open/floor/plasteel, /area/hallway/primary/aft) "aar" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/structure/sign/departments/botany, -/turf/open/floor/plating, -/area/hydroponics) +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/starboard/fore) "aas" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/disposalpipe/segment{ @@ -310,6 +311,9 @@ dir = 1 }, /obj/machinery/disposal/bin, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 5 + }, /turf/open/floor/plasteel, /area/crew_quarters/fitness) "aaw" = ( @@ -516,13 +520,6 @@ }, /turf/open/floor/plasteel/grimy, /area/crew_quarters/fitness/recreation) -"aaM" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/visible, -/obj/machinery/atmospherics/components/binary/valve{ - dir = 4 - }, -/turf/open/floor/plating/asteroid/snow/icemoon, -/area/icemoon/surface/outdoors) "aaN" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on, /obj/machinery/quantumpad{ @@ -602,7 +599,8 @@ /obj/structure/sign/departments/restroom{ pixel_x = 32 }, -/turf/open/floor/carpet, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/turf/open/floor/wood, /area/crew_quarters/dorms) "aaV" = ( /obj/structure/sign/directions/evac{ @@ -673,8 +671,8 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/obj/structure/sign/mining{ - pixel_x = 32 +/obj/machinery/light{ + dir = 4 }, /turf/open/floor/plasteel, /area/hallway/primary/central) @@ -942,7 +940,7 @@ /obj/structure/sign/poster/official/fashion{ pixel_y = -32 }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "abB" = ( /obj/structure/cable{ @@ -1080,13 +1078,14 @@ /turf/open/floor/plasteel, /area/hallway/primary/port) "abL" = ( -/obj/structure/table, -/obj/item/mmi, -/obj/item/mmi, -/obj/item/mmi, /obj/structure/sign/poster/official/state_laws{ pixel_y = -32 }, +/obj/machinery/camera{ + c_tag = "Robotics Lab South"; + dir = 1; + network = list("ss13","rd") + }, /turf/open/floor/plasteel/white, /area/science/robotics/lab) "abM" = ( @@ -1184,14 +1183,8 @@ /turf/open/floor/plasteel, /area/hallway/primary/central) "abU" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ - dir = 5 - }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/starboard/fore) "abV" = ( /obj/effect/turf_decal/tile/red{ dir = 1 @@ -1358,7 +1351,9 @@ /obj/structure/cable{ icon_state = "4-8" }, -/obj/machinery/atmospherics/pipe/simple/supply/visible, +/obj/machinery/atmospherics/components/binary/valve{ + dir = 4 + }, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "acV" = ( @@ -1568,8 +1563,9 @@ icon_state = "4-8" }, /obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ - dir = 9 + dir = 4 }, +/obj/machinery/light/floor, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "aeG" = ( @@ -1711,6 +1707,7 @@ /obj/machinery/atmospherics/pipe/simple/supply/visible{ dir = 9 }, +/obj/machinery/light/floor, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "akB" = ( @@ -1858,7 +1855,6 @@ /obj/structure/table/reinforced, /obj/machinery/door/window/eastright{ base_state = "left"; - dir = 8; icon_state = "left"; name = "Chemistry Desk"; req_access_txt = "33" @@ -1866,6 +1862,10 @@ /obj/machinery/door/firedoor/border_only{ dir = 8 }, +/obj/machinery/door/window/eastright{ + dir = 8; + name = "Chemistry Desk" + }, /turf/open/floor/plasteel/white, /area/medical/chemistry) "anw" = ( @@ -2075,8 +2075,8 @@ /obj/machinery/door/firedoor/border_only{ dir = 1 }, -/obj/machinery/door/airlock/external, /obj/structure/fans/tiny, +/obj/machinery/door/airlock/external/glass, /turf/open/floor/plasteel, /area/hallway/primary/port) "arE" = ( @@ -2164,6 +2164,7 @@ /obj/structure/disposalpipe/segment{ dir = 9 }, +/obj/machinery/light/floor, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "asE" = ( @@ -2505,17 +2506,10 @@ /obj/structure/cable{ icon_state = "4-8" }, -/obj/machinery/door/airlock/highsecurity{ - name = "AI Upload Access"; - req_access_txt = "16" - }, -/obj/machinery/door/firedoor/border_only{ - dir = 4 - }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/turf/open/floor/plasteel/dark, +/turf/closed/wall/r_wall, /area/ai_monitored/turret_protected/ai_upload) "axc" = ( /obj/structure/table, @@ -2604,17 +2598,9 @@ /obj/structure/plasticflaps/opaque, /turf/open/floor/plasteel/dark, /area/science/lab) -"axL" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ - dir = 10 - }, -/turf/open/floor/plating/asteroid/snow/icemoon, -/area/icemoon/surface/outdoors) "axN" = ( -/obj/machinery/atmospherics/pipe/simple/supply/visible{ - dir = 10 - }, -/turf/open/floor/plating/asteroid/snow/icemoon, +/obj/structure/fluff/railing, +/turf/open/transparent/openspace/icemoon, /area/icemoon/surface/outdoors) "ayk" = ( /obj/machinery/atmospherics/pipe/manifold/supply/hidden{ @@ -2626,7 +2612,14 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/turf/closed/wall/r_wall, +/obj/machinery/door/airlock/highsecurity{ + name = "AI Upload Access"; + req_access_txt = "16" + }, +/obj/machinery/door/firedoor/border_only{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, /area/ai_monitored/turret_protected/ai_upload) "aym" = ( /obj/structure/cable{ @@ -2741,20 +2734,34 @@ /obj/structure/cable{ icon_state = "1-2" }, -/obj/machinery/conveyor_switch/oneway{ - dir = 8; - id = "robo2" - }, /obj/machinery/firealarm{ dir = 8; pixel_x = 24 }, +/obj/structure/table, +/obj/item/storage/firstaid/regular{ + empty = 1; + name = "First-Aid (empty)" + }, +/obj/item/storage/firstaid/regular{ + empty = 1; + name = "First-Aid (empty)" + }, +/obj/item/storage/firstaid/regular{ + empty = 1; + name = "First-Aid (empty)" + }, +/obj/item/healthanalyzer, +/obj/item/healthanalyzer, +/obj/item/healthanalyzer, /turf/open/floor/plasteel/white, /area/science/robotics/lab) "ayC" = ( -/obj/machinery/mecha_part_fabricator, -/turf/open/floor/plasteel/dark, -/area/science/robotics/lab) +/obj/structure/fluff/railing/corner{ + dir = 8 + }, +/turf/open/transparent/openspace/icemoon, +/area/icemoon/surface/outdoors) "ayD" = ( /obj/structure/cable{ icon_state = "0-4" @@ -2805,6 +2812,7 @@ /obj/structure/disposalpipe/segment{ dir = 9 }, +/obj/machinery/light/floor, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/maintenance/department/electrical) "azq" = ( @@ -2890,20 +2898,11 @@ /turf/open/floor/plasteel, /area/hallway/primary/port) "azH" = ( -/obj/machinery/conveyor{ - dir = 8; - id = "robo2" +/obj/structure/fluff/railing{ + dir = 4 }, -/obj/item/stack/sheet/metal/fifty, -/obj/item/stack/sheet/metal/fifty, -/obj/item/stack/sheet/metal/fifty, -/obj/item/stack/sheet/glass{ - amount = 20; - pixel_x = -3; - pixel_y = 6 - }, -/turf/open/floor/plasteel/dark, -/area/science/robotics/lab) +/turf/open/transparent/openspace/icemoon, +/area/icemoon/surface/outdoors) "aAe" = ( /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden, /obj/structure/disposalpipe/segment{ @@ -3136,24 +3135,11 @@ /turf/open/floor/plasteel/white, /area/science/robotics/lab) "aCr" = ( -/obj/structure/table, -/obj/item/storage/firstaid/regular{ - empty = 1; - name = "First-Aid (empty)" +/obj/structure/fluff/railing{ + dir = 8 }, -/obj/item/storage/firstaid/regular{ - empty = 1; - name = "First-Aid (empty)" - }, -/obj/item/storage/firstaid/regular{ - empty = 1; - name = "First-Aid (empty)" - }, -/obj/item/healthanalyzer, -/obj/item/healthanalyzer, -/obj/item/healthanalyzer, -/turf/open/floor/plasteel/white, -/area/science/robotics/lab) +/turf/open/transparent/openspace/icemoon, +/area/icemoon/surface/outdoors) "aCV" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 @@ -3199,8 +3185,7 @@ /area/hallway/primary/port) "aDc" = ( /obj/effect/landmark/start/scientist, -/obj/effect/turf_decal/stripes/line, -/turf/open/floor/plasteel/white, +/turf/open/floor/circuit, /area/science/lab) "aDd" = ( /obj/structure/cable{ @@ -3226,10 +3211,6 @@ /obj/machinery/vending/clothing, /turf/open/floor/plasteel, /area/hallway/secondary/entry) -"aDf" = ( -/obj/effect/turf_decal/stripes/line, -/turf/open/floor/plasteel/white, -/area/science/lab) "aDg" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 1 @@ -3380,8 +3361,10 @@ /turf/open/floor/plasteel, /area/security/checkpoint/medical) "aEE" = ( -/obj/machinery/rnd/destructive_analyzer, -/turf/open/floor/circuit, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/plasteel/white, /area/science/lab) "aEF" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ @@ -3390,25 +3373,24 @@ /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "aEG" = ( -/turf/open/floor/circuit, -/area/science/lab) -"aEH" = ( -/obj/machinery/computer/rdconsole/core{ - dir = 1 +/obj/structure/fluff/railing{ + dir = 10 }, +/turf/open/transparent/openspace/icemoon, +/area/icemoon/surface/outdoors) +"aEH" = ( /obj/machinery/light, /turf/open/floor/circuit, /area/science/lab) "aEI" = ( -/obj/machinery/rnd/production/protolathe/department/science, +/obj/machinery/rnd/destructive_analyzer, /turf/open/floor/circuit, /area/science/lab) "aEJ" = ( /turf/closed/wall/r_wall, /area/hallway/secondary/entry) "aEK" = ( -/obj/machinery/rnd/production/circuit_imprinter/department/science, -/obj/item/reagent_containers/glass/beaker/sulphuric, +/obj/machinery/rnd/production/protolathe/department/science, /turf/open/floor/circuit, /area/science/lab) "aEL" = ( @@ -3606,35 +3588,11 @@ /turf/open/floor/circuit, /area/science/robotics/mechbay) "aHK" = ( -/obj/structure/rack, -/obj/item/storage/toolbox/mechanical{ - pixel_x = -2; - pixel_y = -1 +/obj/structure/fluff/railing{ + dir = 6 }, -/obj/item/storage/toolbox/electrical{ - pixel_x = 1; - pixel_y = 6 - }, -/obj/item/clothing/head/welding{ - pixel_x = -3; - pixel_y = 5 - }, -/obj/item/clothing/head/welding{ - pixel_x = -3; - pixel_y = 5 - }, -/obj/item/clothing/glasses/welding, -/obj/item/clothing/glasses/welding, -/obj/item/multitool{ - pixel_x = 3 - }, -/obj/item/multitool{ - pixel_x = 3 - }, -/obj/item/storage/belt/utility, -/obj/item/storage/belt/utility, -/turf/open/floor/plasteel/white, -/area/science/robotics/lab) +/turf/open/transparent/openspace/icemoon, +/area/icemoon/surface/outdoors) "aHU" = ( /obj/machinery/rnd/production/techfab/department/service, /turf/open/floor/plating, @@ -3749,11 +3707,12 @@ /turf/open/floor/plasteel/dark, /area/hallway/secondary/entry) "aKa" = ( -/obj/machinery/atmospherics/components/binary/valve/digital{ - dir = 4 +/obj/structure/cable{ + icon_state = "0-2" }, -/turf/closed/wall/r_wall, -/area/storage/atmos) +/obj/machinery/power/tracker, +/turf/open/floor/plating/asteroid/snow/ice/icemoon/solarpanel, +/area/solar/port/fore) "aKf" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/disposalpipe/segment{ @@ -4062,14 +4021,14 @@ /turf/open/floor/wood, /area/security/courtroom) "aNL" = ( -/obj/machinery/door/airlock/external, /obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/machinery/door/firedoor/border_only{ dir = 1; name = "north facing firelock" }, /obj/structure/fans/tiny, -/turf/open/floor/carpet, +/obj/machinery/door/airlock/external/glass, +/turf/open/floor/plasteel, /area/crew_quarters/dorms) "aNS" = ( /obj/machinery/turnstile{ @@ -4136,18 +4095,12 @@ /obj/structure/cable{ icon_state = "0-4" }, -/obj/machinery/power/apc{ - areastring = "/area/storage/atmos"; - dir = 8; - name = "Atmospherics APC"; - pixel_x = -24 - }, /obj/structure/extinguisher_cabinet{ pixel_y = -30 }, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/storage/atmos) +/area/maintenance/department/electrical) "aOq" = ( /obj/structure/cable{ icon_state = "2-4" @@ -4159,7 +4112,7 @@ dir = 8 }, /turf/open/floor/plating, -/area/storage/atmos) +/area/maintenance/department/electrical) "aOr" = ( /obj/structure/lattice/catwalk, /obj/machinery/atmospherics/pipe/simple/scrubbers/visible, @@ -4203,9 +4156,11 @@ /turf/open/floor/plating, /area/security/checkpoint/medical) "aPC" = ( -/obj/effect/spawner/structure/window/reinforced, -/turf/open/floor/plating, -/area/storage/atmos) +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/port/fore) "aPD" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable{ @@ -4213,10 +4168,17 @@ }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plating, -/area/storage/atmos) +/area/maintenance/department/electrical) "aPE" = ( -/turf/closed/wall/r_wall, -/area/storage/atmos) +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/power/solar{ + id = "auxsolareast"; + name = "Port Auxiliary Solar Array" + }, +/turf/open/floor/plating/asteroid/snow/ice/icemoon/solarpanel, +/area/solar/port/fore) "aPY" = ( /obj/effect/turf_decal/tile/blue, /obj/effect/turf_decal/tile/blue{ @@ -4286,7 +4248,7 @@ icon_state = "2-4" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/starboard/fore) "aQT" = ( /obj/structure/cable{ icon_state = "1-2" @@ -4352,6 +4314,7 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ dir = 9 }, +/obj/machinery/light/floor, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "aSI" = ( @@ -4700,6 +4663,13 @@ }, /turf/open/floor/plating, /area/quartermaster/storage) +"bfo" = ( +/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "bfB" = ( /obj/structure/cable{ icon_state = "1-2" @@ -4755,6 +4725,12 @@ /obj/machinery/vending/coffee, /turf/open/floor/plasteel/dark, /area/maintenance/department/bridge) +"bjR" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 4 + }, +/turf/open/floor/carpet, +/area/crew_quarters/dorms) "bjU" = ( /obj/machinery/airalarm{ dir = 8; @@ -4804,13 +4780,6 @@ /obj/machinery/holopad, /turf/open/floor/plasteel/dark, /area/maintenance/department/bridge) -"blD" = ( -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel, -/area/crew_quarters/fitness) "blI" = ( /obj/machinery/hydroponics/soil, /obj/item/seeds/ambrosia, @@ -4977,6 +4946,12 @@ }, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) +"bqb" = ( +/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ + dir = 8 + }, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "bqx" = ( /obj/structure/table/reinforced, /obj/machinery/door/poddoor/shutters/preopen{ @@ -5185,9 +5160,6 @@ /area/icemoon/surface/outdoors) "buF" = ( /obj/machinery/light, -/obj/structure/window/plasma/reinforced{ - dir = 4 - }, /obj/structure/table, /obj/item/clothing/gloves/color/yellow, /obj/item/clothing/gloves/color/yellow, @@ -5200,6 +5172,9 @@ dir = 8 }, /obj/item/pipe_dispenser, +/obj/structure/window/reinforced{ + dir = 4 + }, /turf/open/floor/plasteel/dark, /area/engine/engineering) "buI" = ( @@ -6106,9 +6081,6 @@ /obj/structure/cable{ icon_state = "4-8" }, -/obj/machinery/airalarm{ - pixel_y = 28 - }, /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, @@ -6218,9 +6190,6 @@ /obj/effect/turf_decal/tile/brown{ dir = 4 }, -/obj/machinery/light{ - dir = 4 - }, /turf/open/floor/plasteel, /area/hallway/primary/central) "bCM" = ( @@ -6414,6 +6383,17 @@ /obj/machinery/vending/wardrobe/science_wardrobe, /turf/open/floor/plasteel/white, /area/science/misc_lab) +"bEp" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/grille, +/obj/structure/cable, +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/open/floor/plating/asteroid/snow/icemoon, +/area/icemoon/surface/outdoors) "bEJ" = ( /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden, /obj/effect/turf_decal/tile/purple{ @@ -6921,7 +6901,7 @@ /obj/structure/window/reinforced, /obj/structure/table/reinforced, /obj/machinery/button/door{ - id = "xenobio2"; + id = "xenobiospec"; name = "Containment Blast Doors"; pixel_y = 4; req_access_txt = "55" @@ -6982,7 +6962,7 @@ req_access_txt = "55" }, /obj/machinery/door/poddoor/preopen{ - id = "xenobio2"; + id = "xenobiospec"; name = "containment blast door" }, /turf/open/floor/engine, @@ -7138,35 +7118,9 @@ /obj/machinery/disposal/bin, /turf/open/floor/plasteel/cult, /area/lawoffice) -"bJQ" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/obj/machinery/door/airlock/external{ - name = "Arrivals Airlock" - }, -/obj/structure/fans/tiny, -/turf/open/floor/plating, -/area/hallway/secondary/exit/departure_lounge) "bKl" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/obj/effect/turf_decal/tile/red{ - dir = 4 - }, -/obj/effect/turf_decal/tile/red{ - dir = 8 - }, -/obj/effect/turf_decal/tile/red, -/obj/effect/turf_decal/tile/red{ - dir = 1 - }, /obj/effect/landmark/event_spawn, -/turf/open/floor/plasteel, +/turf/open/transparent/glass/reinforced, /area/crew_quarters/fitness) "bKo" = ( /obj/machinery/door/airlock/public/glass{ @@ -7245,7 +7199,7 @@ icon_state = "0-4" }, /turf/open/floor/plating/asteroid/snow/ice/icemoon/solarpanel, -/area/icemoon/surface/outdoors) +/area/solar/port/aft) "bLI" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 1 @@ -7477,6 +7431,7 @@ /obj/structure/cable{ icon_state = "1-2" }, +/obj/machinery/recharge_station, /turf/open/floor/plasteel, /area/maintenance/department/electrical) "bOp" = ( @@ -7621,16 +7576,16 @@ dir = 8; name = "west facing firelock" }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, /obj/machinery/door/poddoor/preopen{ - id = "xenobio2"; + id = "xenobiospec"; name = "containment blast door" }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, /turf/open/floor/engine, /area/science/xenobiology) "bPW" = ( @@ -8578,23 +8533,14 @@ "chp" = ( /turf/open/floor/plating, /area/maintenance/aft) -"chN" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/tile/blue, -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 1 - }, -/turf/open/floor/plasteel, -/area/crew_quarters/fitness) "chZ" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/maintenance/solars/port/fore) +"cih" = ( +/obj/structure/cable, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/port/aft) "cio" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable{ @@ -8822,7 +8768,7 @@ icon_state = "0-4" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/starboard/fore) "cly" = ( /obj/machinery/atmospherics/pipe/heat_exchanging/simple, /turf/open/floor/plating/snowed/smoothed/icemoon, @@ -9154,6 +9100,12 @@ }, /turf/open/floor/plasteel/grimy, /area/crew_quarters/fitness/recreation) +"cvN" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 6 + }, +/turf/open/floor/plasteel, +/area/crew_quarters/fitness) "cwm" = ( /obj/machinery/vending/boozeomat, /obj/machinery/firealarm{ @@ -9506,15 +9458,6 @@ }, /turf/open/floor/plating, /area/bridge) -"cDO" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 1 - }, -/turf/open/floor/plasteel, -/area/crew_quarters/fitness) "cDS" = ( /obj/structure/bodycontainer/morgue{ dir = 8 @@ -9542,6 +9485,12 @@ /obj/structure/reflector/single, /turf/open/floor/plating, /area/engine/storage) +"cEs" = ( +/obj/machinery/atmospherics/pipe/simple/supply/visible, +/obj/structure/disposalpipe/segment, +/obj/machinery/light/floor, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors) "cFm" = ( /obj/structure/reagent_dispensers/peppertank{ pixel_x = -30 @@ -9698,7 +9647,7 @@ }, /obj/effect/turf_decal/stripes/line, /turf/open/floor/plasteel, -/area/storage/atmos) +/area/maintenance/department/electrical) "cKQ" = ( /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ dir = 4 @@ -9723,7 +9672,7 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/open/floor/plasteel, +/turf/open/floor/wood, /area/crew_quarters/fitness) "cLC" = ( /obj/effect/turf_decal/tile/brown{ @@ -9770,7 +9719,7 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "cNE" = ( /obj/structure/cable{ @@ -10043,6 +9992,13 @@ "cTO" = ( /turf/closed/wall/r_wall, /area/quartermaster/miningoffice) +"cTV" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/turf/open/floor/plasteel, +/area/crew_quarters/dorms) "cUd" = ( /obj/structure/cable{ icon_state = "1-2" @@ -10062,6 +10018,40 @@ }, /turf/open/floor/plating, /area/maintenance/solars/starboard/aft) +"cUs" = ( +/obj/effect/landmark/start/ai, +/obj/item/radio/intercom{ + freerange = 1; + name = "Common Channel"; + pixel_x = 25; + pixel_y = -4 + }, +/obj/item/radio/intercom{ + freerange = 1; + frequency = 1447; + name = "Private Channel"; + pixel_x = 25; + pixel_y = -13 + }, +/obj/item/radio/intercom{ + freerange = 1; + listening = 0; + name = "Custom Channel"; + pixel_x = 25; + pixel_y = 7 + }, +/obj/machinery/button/door{ + id = "AI Chamber entrance shutters"; + name = "AI Chamber entrance shutters control"; + pixel_x = -7; + pixel_y = -24; + req_access_txt = "16" + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/open/floor/circuit, +/area/ai_monitored/turret_protected/ai) "cUC" = ( /obj/structure/chair, /obj/effect/landmark/start/geneticist, @@ -10090,6 +10080,12 @@ }, /turf/open/floor/pod/dark, /area/maintenance/starboard) +"cVa" = ( +/obj/structure/fluff/railing{ + dir = 9 + }, +/turf/open/transparent/openspace/icemoon, +/area/engine/atmospherics_engine) "cVu" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/effect/turf_decal/tile/blue{ @@ -10143,6 +10139,10 @@ }, /turf/open/floor/plasteel, /area/quartermaster/storage) +"cWI" = ( +/obj/structure/cable, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/starboard/aft) "cWO" = ( /obj/machinery/atmospherics/pipe/heat_exchanging/simple{ dir = 4 @@ -10167,11 +10167,9 @@ /turf/open/floor/plasteel/dark, /area/security/prison) "cXI" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, -/turf/closed/wall/r_wall, -/area/ai_monitored/turret_protected/ai) +/obj/structure/cable, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/port/fore) "cXO" = ( /obj/structure/cable, /obj/effect/landmark/start/ai/secondary, @@ -10495,21 +10493,23 @@ name = "Port Solar Array" }, /turf/open/floor/plating/asteroid/snow/ice/icemoon/solarpanel, -/area/icemoon/surface/outdoors) +/area/solar/port/aft) "dfy" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, /obj/structure/cable{ icon_state = "1-4" }, /obj/structure/cable{ icon_state = "2-4" }, +/obj/effect/landmark/event_spawn, +/obj/machinery/flasher{ + id = "AI"; + pixel_x = -26; + pixel_y = 3 + }, /obj/machinery/ai_slipper{ uses = 10 }, -/obj/effect/landmark/event_spawn, /turf/open/floor/circuit/off, /area/ai_monitored/turret_protected/ai) "dfV" = ( @@ -10817,8 +10817,8 @@ dir = 4 }, /obj/machinery/door/airlock/atmos{ - name = "Atmospherics"; - req_access_txt = "24" + name = "Antimatter Engine"; + req_access_txt = "10" }, /obj/machinery/door/firedoor/border_only{ dir = 8; @@ -10886,10 +10886,11 @@ /obj/structure/cable{ icon_state = "2-4" }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 6 +/obj/structure/cable{ + icon_state = "2-8" }, -/turf/open/floor/carpet, +/obj/machinery/atmospherics/pipe/manifold4w/scrubbers/hidden, +/turf/open/floor/wood, /area/crew_quarters/dorms) "duI" = ( /obj/structure/cable{ @@ -10934,6 +10935,7 @@ /obj/structure/disposalpipe/segment{ dir = 6 }, +/obj/machinery/light/floor, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "dvs" = ( @@ -10946,7 +10948,7 @@ /obj/machinery/door/firedoor/border_only{ name = "south facing firelock" }, -/turf/open/floor/carpet, +/turf/open/floor/plasteel, /area/crew_quarters/dorms) "dvw" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ @@ -11053,12 +11055,6 @@ }, /turf/open/floor/pod/dark, /area/maintenance/starboard) -"dAi" = ( -/obj/structure/sign/warning/pods{ - pixel_x = -32 - }, -/turf/open/floor/carpet, -/area/crew_quarters/dorms) "dAs" = ( /obj/structure/cable{ icon_state = "1-2" @@ -11158,36 +11154,11 @@ /turf/open/floor/plasteel, /area/quartermaster/storage) "dDC" = ( -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ +/obj/structure/fluff/railing{ dir = 1 }, -/obj/structure/closet/crate/engineering{ - name = "Antimatter Engine Crate" - }, -/obj/machinery/power/am_control_unit, -/obj/item/am_shielding_container, -/obj/item/am_shielding_container, -/obj/item/am_shielding_container, -/obj/item/am_shielding_container, -/obj/item/am_shielding_container, -/obj/item/am_shielding_container, -/obj/item/am_shielding_container, -/obj/item/am_shielding_container, -/obj/item/am_shielding_container, -/obj/item/am_shielding_container, -/obj/item/am_shielding_container, -/obj/item/am_shielding_container, -/obj/item/am_containment, -/obj/item/am_containment, -/turf/open/floor/plasteel/dark, -/area/engine/secure_construction) +/turf/open/transparent/openspace/icemoon, +/area/icemoon/surface/outdoors) "dDK" = ( /obj/machinery/atmospherics/pipe/simple/supply/visible{ dir = 6 @@ -11265,9 +11236,11 @@ /turf/closed/wall, /area/quartermaster/qm) "dFJ" = ( -/obj/effect/turf_decal/stripes/corner, -/turf/open/floor/plasteel/white, -/area/science/lab) +/obj/structure/fluff/railing{ + dir = 5 + }, +/turf/open/transparent/openspace/icemoon, +/area/icemoon/surface/outdoors) "dGb" = ( /obj/structure/cable{ icon_state = "1-8" @@ -11354,7 +11327,7 @@ /obj/machinery/door/firedoor/border_only{ name = "south facing firelock" }, -/turf/open/floor/carpet, +/turf/open/floor/carpet/blue, /area/crew_quarters/dorms) "dJc" = ( /obj/structure/cable{ @@ -11386,7 +11359,7 @@ /obj/structure/disposalpipe/segment{ dir = 6 }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "dKw" = ( /obj/structure/cable{ @@ -11437,6 +11410,11 @@ "dMj" = ( /turf/closed/wall/r_wall, /area/ai_monitored/nuke_storage) +"dMo" = ( +/obj/structure/disposalpipe/segment, +/obj/machinery/light/floor, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors) "dMI" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -12102,6 +12080,7 @@ dir = 1; sortType = 26 }, +/obj/machinery/atmospherics/components/unary/vent_pump/on, /turf/open/floor/plasteel, /area/crew_quarters/fitness) "egM" = ( @@ -12218,15 +12197,6 @@ }, /turf/open/floor/plasteel/dark, /area/security/brig) -"ejw" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/turf/open/floor/plasteel, -/area/crew_quarters/fitness) "ekw" = ( /obj/structure/chair{ dir = 1 @@ -12287,6 +12257,18 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/plasteel/dark, /area/hallway/secondary/exit/departure_lounge) +"eoH" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/open/floor/carpet, +/area/crew_quarters/dorms) "eoL" = ( /obj/structure/chair{ dir = 4 @@ -12354,9 +12336,6 @@ /turf/open/floor/plasteel/dark, /area/engine/engineering) "ery" = ( -/obj/machinery/light{ - dir = 8 - }, /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, @@ -12371,10 +12350,6 @@ /obj/effect/turf_decal/tile/blue{ dir = 1 }, -/obj/item/radio/intercom{ - name = "Station Intercom (General)"; - pixel_x = -28 - }, /turf/open/floor/plasteel/dark, /area/ai_monitored/turret_protected/ai_upload_foyer) "erG" = ( @@ -12587,6 +12562,12 @@ }, /turf/open/floor/plasteel/white, /area/science/mixing) +"eyc" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/turf/closed/wall, +/area/crew_quarters/dorms) "eyP" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable{ @@ -12690,6 +12671,13 @@ }, /turf/open/floor/plating, /area/maintenance/solars/port/aft) +"eCS" = ( +/obj/machinery/door/airlock{ + id_tag = "Dorm5"; + name = "Room Four" + }, +/turf/open/floor/carpet/purple, +/area/crew_quarters/dorms) "eDr" = ( /obj/structure/cable{ icon_state = "4-8" @@ -12870,7 +12858,7 @@ /area/hallway/primary/central) "eHK" = ( /obj/effect/spawner/structure/window/reinforced, -/obj/machinery/atmospherics/pipe/simple/yellow/visible{ +/obj/machinery/atmospherics/pipe/layer_manifold{ dir = 4 }, /turf/open/floor/plating, @@ -12982,25 +12970,6 @@ }, /turf/open/floor/plasteel, /area/maintenance/aft) -"eLl" = ( -/obj/structure/window{ - dir = 1 - }, -/obj/effect/turf_decal/tile/yellow{ - dir = 4 - }, -/obj/effect/turf_decal/tile/yellow{ - dir = 8 - }, -/obj/effect/turf_decal/tile/red{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue, -/obj/structure/window{ - dir = 4 - }, -/turf/open/floor/plasteel, -/area/crew_quarters/fitness) "eLm" = ( /obj/structure/cable{ icon_state = "4-8" @@ -13174,10 +13143,6 @@ }, /turf/open/floor/wood, /area/crew_quarters/bar) -"eOO" = ( -/obj/structure/weightmachine/weightlifter, -/turf/open/floor/plasteel, -/area/crew_quarters/fitness) "eOZ" = ( /obj/machinery/atmospherics/components/binary/pump/on, /turf/open/floor/plasteel/dark, @@ -13417,6 +13382,20 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/closed/wall/mineral/wood, /area/maintenance/bar) +"eXy" = ( +/obj/effect/turf_decal/stripes/corner, +/turf/open/floor/plasteel/white, +/area/science/lab) +"eXO" = ( +/obj/structure/table, +/obj/item/mmi, +/obj/item/mmi, +/obj/item/mmi, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/open/floor/plasteel/dark, +/area/science/robotics/lab) "eYe" = ( /obj/machinery/conveyor{ dir = 4; @@ -13489,7 +13468,7 @@ icon_state = "1-4" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/starboard/aft) "faR" = ( /obj/structure/window/reinforced{ dir = 8 @@ -13497,7 +13476,7 @@ /obj/machinery/atmospherics/pipe/manifold4w/scrubbers/hidden, /obj/effect/landmark/blobstart, /turf/open/floor/plating, -/area/storage/atmos) +/area/maintenance/department/electrical) "faV" = ( /obj/machinery/light{ dir = 4 @@ -13819,6 +13798,13 @@ /obj/machinery/space_heater, /turf/open/floor/plating, /area/icemoon/surface/outdoors) +"fkA" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "fkC" = ( /obj/machinery/atmospherics/pipe/simple/green/visible, /turf/closed/wall/r_wall, @@ -13914,9 +13900,14 @@ /turf/open/floor/plasteel/dark, /area/ai_monitored/security/armory) "fne" = ( -/obj/effect/landmark/start/roboticist, -/turf/open/floor/plasteel/dark, -/area/science/robotics/lab) +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/port/fore) "fni" = ( /obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/carbon_output{ dir = 8 @@ -13957,6 +13948,11 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plasteel, /area/engine/engineering) +"fol" = ( +/obj/machinery/rnd/production/circuit_imprinter/department/science, +/obj/item/reagent_containers/glass/beaker/sulphuric, +/turf/open/floor/circuit, +/area/science/lab) "foy" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 @@ -13986,17 +13982,6 @@ /turf/open/floor/plating, /area/maintenance/disposal) "fpS" = ( -/obj/structure/table, -/obj/item/hemostat, -/obj/item/retractor, -/obj/item/scalpel{ - pixel_y = 12 - }, -/obj/item/circular_saw, -/obj/item/cautery{ - pixel_x = 4 - }, -/obj/item/surgical_drapes, /obj/machinery/airalarm{ pixel_y = 23 }, @@ -14004,7 +13989,14 @@ c_tag = "Robotics Lab"; network = list("ss13","rd") }, -/turf/open/floor/plasteel/white, +/obj/machinery/mecha_part_fabricator, +/obj/item/stack/sheet/glass{ + amount = 20; + pixel_x = -3; + pixel_y = 6 + }, +/obj/item/stack/sheet/metal/fifty, +/turf/open/floor/plasteel/dark, /area/science/robotics/lab) "fqj" = ( /obj/machinery/field/generator, @@ -14088,7 +14080,7 @@ icon_state = "1-8" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/port/aft) "fsA" = ( /obj/structure/bodycontainer/morgue, /obj/effect/turf_decal/tile/blue{ @@ -14115,11 +14107,8 @@ /turf/open/floor/plasteel/dark/telecomms, /area/tcommsat/server) "ftH" = ( -/obj/machinery/mineral/ore_redemption{ - input_dir = 2; - output_dir = 1 - }, -/turf/open/floor/plating, +/obj/effect/spawner/structure/window/reinforced, +/turf/open/space/basic, /area/quartermaster/miningdock) "ftM" = ( /obj/structure/cable{ @@ -14189,11 +14178,6 @@ /turf/open/floor/plasteel, /area/engine/engineering) "fvz" = ( -/obj/structure/table/optable{ - name = "Robotics Operating Table" - }, -/obj/item/tank/internals/anesthetic, -/obj/item/clothing/mask/breath, /obj/structure/extinguisher_cabinet{ pixel_y = 30 }, @@ -14355,6 +14339,9 @@ c_tag = "Bathrooms"; dir = 1 }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ + dir = 8 + }, /turf/open/floor/plasteel/freezer, /area/crew_quarters/dorms) "fBG" = ( @@ -14376,9 +14363,6 @@ /turf/open/floor/engine, /area/engine/atmospherics_engine) "fCQ" = ( -/obj/structure/toilet/secret/low_loot{ - pixel_y = 14 - }, /obj/machinery/button/door{ id = "Bath2"; name = "Door Bolt Control"; @@ -14391,6 +14375,7 @@ dir = 8 }, /obj/effect/landmark/blobstart, +/obj/machinery/recharge_station, /turf/open/floor/plasteel/freezer, /area/crew_quarters/dorms) "fDi" = ( @@ -14416,6 +14401,13 @@ "fDJ" = ( /turf/open/floor/plasteel/white, /area/medical/medbay/zone3) +"fEz" = ( +/obj/machinery/computer/operating, +/obj/machinery/light{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/science/robotics/lab) "fET" = ( /obj/effect/turf_decal/tile/neutral, /obj/machinery/camera{ @@ -14514,7 +14506,18 @@ dir = 4 }, /turf/open/floor/plating, -/area/storage/atmos) +/area/maintenance/department/electrical) +"fIk" = ( +/obj/machinery/button/door{ + id = "holoprivacy"; + name = "Holodeck Privacy"; + pixel_x = 24; + pixel_y = 7 + }, +/turf/open/floor/engine{ + name = "Holodeck Projector Floor" + }, +/area/holodeck/rec_center) "fIu" = ( /obj/structure/cable{ icon_state = "1-8" @@ -14733,11 +14736,11 @@ pixel_y = -28 }, /turf/open/floor/plating, -/area/storage/atmos) +/area/maintenance/department/electrical) "fNh" = ( /obj/structure/cable, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/starboard/fore) "fNC" = ( /obj/structure/cable{ icon_state = "1-2" @@ -14869,6 +14872,9 @@ dir = 8; name = "west facing firelock" }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, /turf/open/floor/plating, /area/crew_quarters/dorms) "fPN" = ( @@ -14955,6 +14961,13 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/plasteel/white, /area/medical/medbay/central) +"fSb" = ( +/obj/machinery/airalarm{ + dir = 4; + pixel_x = -22 + }, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "fSw" = ( /obj/structure/cable{ icon_state = "2-4" @@ -14998,8 +15011,14 @@ /obj/machinery/light{ dir = 4 }, -/turf/open/floor/carpet, +/turf/open/floor/plasteel, /area/crew_quarters/dorms) +"fUc" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/port/aft) "fUm" = ( /obj/structure/cable{ icon_state = "1-2" @@ -15044,7 +15063,7 @@ icon_state = "2-4" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/starboard/fore) "fVT" = ( /obj/machinery/atmospherics/pipe/manifold/supply/hidden, /turf/open/floor/engine, @@ -15273,6 +15292,12 @@ /obj/item/storage/fancy/donut_box, /turf/open/floor/plasteel, /area/security/checkpoint/supply) +"gdH" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 8 + }, +/turf/open/floor/plasteel/freezer, +/area/crew_quarters/dorms) "gdL" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 1 @@ -15441,6 +15466,12 @@ }, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/engine/engineering) +"gjZ" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 9 + }, +/turf/open/floor/plasteel, +/area/crew_quarters/fitness) "gkl" = ( /obj/machinery/jukebox, /turf/open/floor/wood, @@ -15504,28 +15535,6 @@ }, /turf/open/floor/plasteel, /area/engine/engineering) -"gls" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/obj/effect/turf_decal/tile/red{ - dir = 4 - }, -/obj/effect/turf_decal/tile/red{ - dir = 8 - }, -/obj/effect/turf_decal/tile/red, -/obj/effect/turf_decal/tile/red{ - dir = 1 - }, -/obj/machinery/door/window/westright{ - name = "Red Corner" - }, -/turf/open/floor/plasteel, -/area/crew_quarters/fitness) "gmf" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/structure/disposalpipe/segment, @@ -15699,9 +15708,6 @@ /turf/closed/wall, /area/security/courtroom) "grZ" = ( -/obj/structure/cable{ - icon_state = "1-2" - }, /obj/structure/table, /obj/item/aiModule/core/full/custom, /obj/item/aiModule/core/freeformcore, @@ -15713,6 +15719,9 @@ dir = 1; network = list("aiupload") }, +/obj/structure/cable{ + icon_state = "1-4" + }, /turf/open/floor/circuit, /area/ai_monitored/turret_protected/ai_upload) "gsr" = ( @@ -15814,12 +15823,11 @@ /turf/open/floor/plasteel/dark, /area/bridge) "guI" = ( -/obj/machinery/light/floor, -/obj/structure/disposalpipe/segment{ - dir = 5 +/obj/structure/cable{ + icon_state = "0-8" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/port/fore) "guR" = ( /obj/structure/table/glass, /obj/effect/turf_decal/tile/yellow{ @@ -16063,7 +16071,7 @@ dir = 1 }, /turf/open/floor/plasteel, -/area/storage/atmos) +/area/maintenance/department/electrical) "gCG" = ( /obj/structure/closet/firecloset, /turf/open/floor/plating, @@ -16078,15 +16086,10 @@ /turf/open/floor/plasteel, /area/engine/atmos) "gCO" = ( -/obj/machinery/light, -/obj/machinery/door/airlock/public/glass{ - name = "Holodeck Door" - }, -/obj/structure/fans/tiny, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/turf/open/floor/plasteel/white, +/turf/open/floor/wood, /area/crew_quarters/dorms) "gCS" = ( /obj/structure/bodycontainer/morgue, @@ -16240,6 +16243,12 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/port) +"gIW" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/starboard/aft) "gJi" = ( /obj/machinery/atmospherics/pipe/simple/orange/visible, /obj/machinery/atmospherics/pipe/simple/green/visible{ @@ -16486,7 +16495,7 @@ }, /obj/effect/landmark/event_spawn, /turf/open/floor/plasteel, -/area/storage/atmos) +/area/maintenance/department/electrical) "gPE" = ( /obj/machinery/portable_atmospherics/pump, /obj/machinery/firealarm{ @@ -16662,7 +16671,7 @@ icon_state = "2-8" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/starboard/fore) "gTH" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 @@ -16692,11 +16701,18 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, +/obj/machinery/light/floor, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "gUc" = ( -/obj/machinery/light, -/turf/open/floor/plasteel/white, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/machinery/camera{ + c_tag = "Dorms Central"; + dir = 1 + }, +/turf/open/floor/carpet, /area/crew_quarters/dorms) "gUw" = ( /obj/structure/plasticflaps, @@ -16773,7 +16789,8 @@ /obj/structure/cable{ icon_state = "2-8" }, -/turf/open/floor/plasteel/white, +/obj/effect/landmark/start/roboticist, +/turf/open/floor/plasteel/dark, /area/science/robotics/lab) "gXE" = ( /obj/structure/table, @@ -17108,13 +17125,16 @@ /turf/open/floor/plasteel/white, /area/medical/chemistry) "hiO" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, /obj/effect/turf_decal/tile/neutral{ dir = 4 }, /obj/effect/turf_decal/tile/neutral, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "1-2" + }, /turf/open/floor/plasteel, /area/crew_quarters/fitness) "hjv" = ( @@ -17158,6 +17178,14 @@ }, /turf/open/floor/plating/asteroid/snow/icemoon, /area/icemoon/surface/outdoors) +"hlQ" = ( +/obj/item/radio/intercom{ + name = "Station Intercom (General)"; + pixel_x = 30 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "hlT" = ( /obj/structure/disposalpipe/segment{ dir = 6 @@ -17168,9 +17196,6 @@ /obj/structure/cable{ icon_state = "2-8" }, -/obj/structure/cable{ - icon_state = "1-2" - }, /turf/open/floor/circuit/off, /area/ai_monitored/turret_protected/ai) "hmM" = ( @@ -17195,6 +17220,15 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/port) +"hnN" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/visible, +/obj/structure/disposalpipe/segment, +/obj/machinery/light/floor, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors) "hnO" = ( /obj/machinery/atmospherics/components/unary/cryo_cell, /turf/open/floor/plasteel/white, @@ -17219,20 +17253,10 @@ /turf/open/floor/plasteel/white, /area/medical/medbay/central) "hop" = ( -/obj/structure/window{ - dir = 4 +/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden, +/obj/structure/cable{ + icon_state = "4-8" }, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/tile/blue, -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 1 - }, -/obj/effect/landmark/start/assistant, /turf/open/floor/plasteel, /area/crew_quarters/fitness) "hoq" = ( @@ -17342,6 +17366,7 @@ /obj/machinery/light{ dir = 1 }, +/obj/machinery/vending/cigarette, /turf/open/floor/plasteel, /area/crew_quarters/fitness) "hrN" = ( @@ -17361,15 +17386,14 @@ /turf/open/floor/plasteel, /area/quartermaster/miningdock) "hrS" = ( -/obj/effect/turf_decal/tile/neutral, -/turf/open/floor/plasteel, -/area/crew_quarters/fitness) +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/port/fore) "hse" = ( /obj/structure/cable{ - icon_state = "1-4" + icon_state = "0-4" }, -/turf/open/floor/circuit/off, -/area/ai_monitored/turret_protected/ai) +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/port/fore) "hsl" = ( /turf/open/floor/plating, /area/maintenance/starboard) @@ -17419,12 +17443,6 @@ }, /turf/open/floor/wood, /area/bridge/meeting_room) -"hsQ" = ( -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel, -/area/crew_quarters/fitness) "hta" = ( /obj/structure/cable{ icon_state = "1-2" @@ -17471,11 +17489,14 @@ /turf/open/floor/engine/co2, /area/engine/atmos) "huF" = ( -/obj/machinery/mineral/stacking_unit_console{ - machinedir = 4 +/obj/structure/cable{ + icon_state = "1-8" }, -/turf/closed/wall, -/area/maintenance/disposal) +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/port/fore) "huQ" = ( /obj/machinery/power/terminal{ dir = 1 @@ -17507,6 +17528,14 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/central) +"hvG" = ( +/obj/machinery/light, +/obj/machinery/airalarm{ + dir = 1; + pixel_y = -22 + }, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "hwg" = ( /obj/machinery/computer/teleporter{ dir = 8 @@ -17567,7 +17596,7 @@ }, /obj/effect/turf_decal/stripes/line, /turf/open/floor/plasteel, -/area/storage/atmos) +/area/maintenance/department/electrical) "hxP" = ( /obj/machinery/door/airlock/medical/glass{ id_tag = "MedbayFoyer"; @@ -17589,6 +17618,18 @@ /obj/structure/closet/secure_closet/personal/cabinet, /turf/open/floor/carpet, /area/quartermaster/miningoffice) +"hyx" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/machinery/airalarm{ + pixel_y = 28 + }, +/turf/open/floor/plasteel, +/area/quartermaster/miningdock) "hyz" = ( /obj/machinery/vending/autodrobe, /turf/open/floor/plasteel, @@ -17680,7 +17721,7 @@ dir = 1; name = "north facing firelock" }, -/turf/open/floor/carpet, +/turf/open/floor/plasteel, /area/crew_quarters/dorms) "hBb" = ( /obj/machinery/camera{ @@ -17710,6 +17751,10 @@ /obj/machinery/vending/medical, /turf/open/floor/plasteel/white, /area/medical/virology) +"hBM" = ( +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/plasteel/white, +/area/science/lab) "hBQ" = ( /obj/structure/cable{ icon_state = "2-4" @@ -17720,6 +17765,16 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/plasteel, /area/hallway/primary/port) +"hCx" = ( +/obj/machinery/door/airlock/public/glass{ + name = "Dormitory" + }, +/obj/machinery/door/firedoor/border_only{ + dir = 8; + name = "west facing firelock" + }, +/turf/open/floor/carpet, +/area/crew_quarters/dorms) "hCD" = ( /obj/structure/cable{ icon_state = "4-8" @@ -17829,7 +17884,7 @@ dir = 4 }, /turf/open/floor/plasteel, -/area/storage/atmos) +/area/maintenance/department/electrical) "hFG" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ @@ -17855,7 +17910,7 @@ icon_state = "0-8" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/starboard/fore) "hGU" = ( /obj/structure/closet/secure_closet/personal/cabinet{ pixel_x = -8 @@ -17896,6 +17951,12 @@ }, /turf/open/floor/plasteel, /area/engine/atmospherics_engine) +"hHV" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/turf/open/floor/plasteel/freezer, +/area/crew_quarters/dorms) "hHW" = ( /obj/effect/turf_decal/tile/yellow{ dir = 1 @@ -18001,7 +18062,7 @@ /obj/machinery/atmospherics/pipe/manifold/supply/hidden{ dir = 1 }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "hKt" = ( /obj/machinery/atmospherics/pipe/manifold/supply/hidden{ @@ -18127,7 +18188,7 @@ /area/engine/secure_construction) "hNT" = ( /obj/effect/landmark/event_spawn, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "hNZ" = ( /obj/effect/turf_decal/tile/yellow{ @@ -18154,7 +18215,7 @@ }, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/storage/atmos) +/area/maintenance/department/electrical) "hOw" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /obj/effect/turf_decal/tile/neutral{ @@ -18403,6 +18464,10 @@ }, /turf/open/floor/plasteel, /area/quartermaster/storage) +"hUg" = ( +/obj/machinery/atmospherics/pipe/manifold/supply/hidden, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "hUo" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable{ @@ -18554,6 +18619,10 @@ }, /turf/open/floor/plasteel/white, /area/medical/medbay/central) +"hWp" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "hWW" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 1 @@ -18866,28 +18935,6 @@ /obj/machinery/space_heater, /turf/open/floor/plasteel, /area/engine/atmos) -"igK" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/tile/blue, -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 1 - }, -/obj/machinery/door/window/eastleft{ - name = "Blue Corner" - }, -/turf/open/floor/plasteel, -/area/crew_quarters/fitness) "igO" = ( /obj/machinery/vending/boozeomat, /turf/open/floor/wood{ @@ -18916,17 +18963,6 @@ /obj/structure/cable{ icon_state = "1-2" }, -/obj/machinery/flasher{ - id = "AI"; - pixel_x = -26; - pixel_y = 3 - }, -/obj/machinery/turretid{ - icon_state = "control_stun"; - name = "AI Chamber turret control"; - pixel_x = -25; - pixel_y = -3 - }, /turf/open/floor/circuit/off, /area/ai_monitored/turret_protected/ai) "ihE" = ( @@ -18937,6 +18973,7 @@ dir = 10 }, /obj/machinery/atmospherics/components/unary/portables_connector/visible, +/obj/machinery/portable_atmospherics/canister, /turf/open/floor/plasteel, /area/science/mixing) "ihJ" = ( @@ -18970,6 +19007,9 @@ /obj/machinery/power/smes, /turf/open/floor/plating, /area/maintenance/department/electrical) +"ihY" = ( +/turf/open/floor/plasteel/dark, +/area/science/robotics/lab) "iiM" = ( /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -19305,6 +19345,12 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) +"iru" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/turf/open/floor/circuit/off, +/area/ai_monitored/turret_protected/ai) "irN" = ( /obj/machinery/requests_console{ department = "AI"; @@ -19363,7 +19409,7 @@ }, /obj/machinery/light, /turf/open/floor/plating, -/area/storage/atmos) +/area/maintenance/department/electrical) "itw" = ( /obj/structure/cable{ icon_state = "4-8" @@ -19437,7 +19483,7 @@ dir = 1; name = "north facing firelock" }, -/turf/open/floor/carpet, +/turf/open/floor/plasteel, /area/crew_quarters/dorms) "iuP" = ( /obj/machinery/door/airlock/external{ @@ -19446,15 +19492,6 @@ }, /turf/open/floor/engine, /area/engine/atmospherics_engine) -"ivM" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/obj/machinery/door/airlock/external{ - name = "Escape Airlock" - }, -/turf/open/floor/plating, -/area/hallway/secondary/exit/departure_lounge) "ivQ" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -19488,6 +19525,13 @@ }, /turf/open/floor/plasteel, /area/quartermaster/storage) +"iwH" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = 27 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "ixf" = ( /obj/structure/cable{ icon_state = "1-2" @@ -19501,6 +19545,12 @@ /obj/item/hand_tele, /turf/open/floor/plasteel/dark, /area/teleporter) +"ixO" = ( +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/port/aft) "ixZ" = ( /obj/structure/chair/office/dark, /mob/living/simple_animal/pet/cat/Runtime{ @@ -19791,6 +19841,13 @@ /obj/effect/turf_decal/tile/blue{ dir = 8 }, +/obj/item/radio/intercom{ + name = "Station Intercom (General)"; + pixel_x = -28 + }, +/obj/machinery/light{ + dir = 8 + }, /turf/open/floor/plasteel/dark, /area/ai_monitored/turret_protected/ai_upload_foyer) "iFl" = ( @@ -19976,7 +20033,7 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "iJK" = ( /obj/structure/table/reinforced, @@ -20018,6 +20075,13 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/aft) +"iMk" = ( +/obj/effect/spawner/structure/window/reinforced, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plating, +/area/ai_monitored/turret_protected/aisat/service) "iML" = ( /obj/machinery/light, /obj/machinery/requests_console{ @@ -20030,14 +20094,15 @@ /turf/open/floor/carpet, /area/crew_quarters/heads/hop) "iMX" = ( -/obj/structure/cable, -/obj/machinery/power/terminal, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/machinery/porta_turret/ai{ + dir = 4 + }, /turf/open/floor/circuit, /area/ai_monitored/turret_protected/ai_upload) "iNi" = ( -/obj/structure/window/plasma/reinforced{ - dir = 8 - }, /obj/machinery/computer/rdconsole/production{ dir = 4 }, @@ -20047,6 +20112,9 @@ /obj/effect/turf_decal/tile/yellow{ dir = 8 }, +/obj/structure/window/reinforced{ + dir = 8 + }, /turf/open/floor/plasteel/dark, /area/engine/engineering) "iNE" = ( @@ -20062,22 +20130,6 @@ }, /turf/open/floor/engine, /area/engine/engineering) -"iNK" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, -/obj/effect/turf_decal/tile/yellow{ - dir = 8 - }, -/obj/effect/turf_decal/tile/yellow{ - dir = 4 - }, -/obj/effect/turf_decal/tile/red{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue, -/turf/open/floor/plasteel, -/area/crew_quarters/fitness) "iNV" = ( /obj/structure/cable{ icon_state = "1-2" @@ -20102,12 +20154,6 @@ /obj/structure/extinguisher_cabinet{ pixel_x = -27 }, -/obj/structure/window/plasma/reinforced{ - dir = 8 - }, -/obj/structure/window/plasma/reinforced{ - dir = 1 - }, /obj/machinery/rnd/production/protolathe/department/engineering, /obj/effect/turf_decal/tile/yellow{ dir = 4 @@ -20119,6 +20165,12 @@ c_tag = "Engineering Storage"; dir = 4 }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, /turf/open/floor/plasteel/dark, /area/engine/engineering) "iOG" = ( @@ -20163,6 +20215,13 @@ /obj/machinery/light, /turf/open/floor/plasteel, /area/hallway/primary/port) +"iQu" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "iQv" = ( /obj/machinery/door/airlock/public/glass{ name = "Courtroom"; @@ -20204,12 +20263,12 @@ /turf/open/floor/plasteel/white, /area/medical/medbay/central) "iRF" = ( -/obj/machinery/door/airlock/external, /obj/machinery/door/firedoor/border_only{ dir = 1; name = "north facing firelock" }, /obj/structure/fans/tiny, +/obj/machinery/door/airlock/external/glass, /turf/open/floor/plating, /area/hallway/primary/aft) "iRO" = ( @@ -20246,9 +20305,13 @@ /turf/open/floor/plasteel/cult, /area/lawoffice) "iSB" = ( -/obj/machinery/light/floor, -/turf/open/floor/plating/asteroid/snow/icemoon, -/area/icemoon/surface/outdoors) +/obj/structure/cable, +/obj/machinery/power/solar{ + id = "auxsolareast"; + name = "Port Auxiliary Solar Array" + }, +/turf/open/floor/plating/asteroid/snow/ice/icemoon/solarpanel, +/area/solar/port/fore) "iTP" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/carpet, @@ -20404,7 +20467,7 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 4 }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "iZu" = ( /obj/machinery/firealarm{ @@ -20709,7 +20772,7 @@ /area/quartermaster/storage) "jjB" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "jjC" = ( /obj/structure/closet/crate, @@ -20776,7 +20839,7 @@ }, /obj/effect/turf_decal/stripes/line, /turf/open/floor/plasteel, -/area/storage/atmos) +/area/maintenance/department/electrical) "jmU" = ( /obj/effect/turf_decal/tile/brown{ dir = 1 @@ -20898,10 +20961,11 @@ /turf/open/floor/plasteel/dark, /area/hallway/primary/fore) "jso" = ( -/obj/machinery/light/small{ - dir = 8 +/obj/machinery/power/smes{ + charge = 5e+006 }, -/turf/open/floor/circuit/off, +/obj/structure/cable, +/turf/open/floor/circuit, /area/ai_monitored/turret_protected/ai) "jsu" = ( /obj/structure/cable{ @@ -20952,11 +21016,11 @@ /turf/open/floor/plasteel/dark, /area/hallway/primary/fore) "jvV" = ( -/obj/machinery/mineral/stacking_unit_console{ - machinedir = 8 +/obj/structure/cable{ + icon_state = "0-2" }, -/turf/closed/wall, -/area/maintenance/disposal) +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/port/fore) "jwc" = ( /obj/structure/cable{ icon_state = "1-2" @@ -21027,7 +21091,7 @@ name = "Starboard Solar Array" }, /turf/open/floor/plating/asteroid/snow/ice/icemoon/solarpanel, -/area/icemoon/surface/outdoors) +/area/solar/starboard/aft) "jxS" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/visible, /obj/structure/cable{ @@ -21122,22 +21186,6 @@ }, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) -"jAT" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/obj/effect/landmark/start/assistant, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 1 - }, -/turf/open/floor/plasteel, -/area/crew_quarters/fitness) "jBk" = ( /obj/structure/cable{ icon_state = "1-2" @@ -21256,6 +21304,12 @@ /obj/effect/landmark/start/paramedic, /turf/open/floor/plasteel/white, /area/medical/paramedic) +"jEm" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/starboard/aft) "jER" = ( /obj/machinery/vending/kink, /turf/open/floor/plating, @@ -21569,7 +21623,7 @@ }, /obj/effect/turf_decal/stripes/corner, /turf/open/floor/plasteel, -/area/storage/atmos) +/area/maintenance/department/electrical) "jOB" = ( /obj/structure/cable{ icon_state = "4-8" @@ -21604,6 +21658,12 @@ }, /turf/open/floor/plating, /area/engine/atmospherics_engine) +"jPf" = ( +/obj/machinery/computer/rdconsole/core{ + dir = 8 + }, +/turf/open/floor/circuit, +/area/science/lab) "jPh" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 4 @@ -21824,6 +21884,9 @@ "jWr" = ( /turf/closed/wall/r_wall, /area/storage/tech) +"jWw" = ( +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/starboard/aft) "jWx" = ( /obj/structure/table/glass, /obj/item/stack/sheet/mineral/plasma, @@ -21882,7 +21945,7 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "jYS" = ( /obj/structure/chair{ @@ -21941,6 +22004,13 @@ /obj/machinery/smartfridge, /turf/open/floor/plasteel, /area/hydroponics) +"kbE" = ( +/obj/structure/chair/comfy/brown{ + color = "#596479"; + dir = 8 + }, +/turf/open/transparent/glass/reinforced, +/area/crew_quarters/fitness) "kbR" = ( /obj/structure/table, /obj/item/storage/firstaid/regular{ @@ -22027,15 +22097,18 @@ }, /turf/open/floor/plasteel, /area/storage/auxiliary) +"kdy" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/turf/open/floor/plasteel/freezer, +/area/crew_quarters/dorms) "kdA" = ( /obj/structure/table/glass, /obj/machinery/firealarm{ dir = 4; pixel_x = -24 }, -/obj/effect/turf_decal/stripes/line{ - dir = 6 - }, /turf/open/floor/plasteel/white, /area/science/lab) "kdM" = ( @@ -22124,24 +22197,11 @@ /turf/open/floor/carpet, /area/chapel/office) "kge" = ( -/obj/structure/window{ - dir = 8 - }, -/obj/structure/window{ - dir = 1 - }, -/obj/effect/turf_decal/tile/red{ +/obj/structure/chair/comfy/brown{ + color = "#596479"; dir = 4 }, -/obj/effect/turf_decal/tile/red{ - dir = 8 - }, -/obj/effect/turf_decal/tile/red, -/obj/effect/turf_decal/tile/red{ - dir = 1 - }, -/obj/effect/landmark/start/assistant, -/turf/open/floor/plasteel, +/turf/open/transparent/glass/reinforced, /area/crew_quarters/fitness) "kgx" = ( /obj/structure/table, @@ -22245,6 +22305,14 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/fore) +"kjx" = ( +/obj/machinery/door/window/eastright{ + dir = 8; + name = "Robotics Surgery"; + req_access_txt = "29" + }, +/turf/open/floor/plasteel/dark, +/area/science/robotics/lab) "kkn" = ( /obj/structure/cable{ icon_state = "4-8" @@ -22412,7 +22480,7 @@ icon_state = "2-8" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/starboard/fore) "kol" = ( /obj/machinery/light{ dir = 1 @@ -22934,6 +23002,13 @@ }, /turf/open/floor/wood, /area/crew_quarters/bar) +"kHJ" = ( +/obj/structure/grille, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/open/floor/plating/asteroid/snow/icemoon, +/area/icemoon/surface/outdoors) "kHP" = ( /obj/machinery/atmospherics/pipe/manifold/yellow/visible{ dir = 4 @@ -22963,6 +23038,12 @@ }, /turf/open/floor/plating, /area/maintenance/solars/port/fore) +"kIV" = ( +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 8 + }, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "kJk" = ( /obj/machinery/atmospherics/pipe/simple/green/visible{ dir = 9 @@ -23063,7 +23144,6 @@ /obj/structure/cable{ icon_state = "4-8" }, -/obj/machinery/door/airlock/external, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 }, @@ -23071,6 +23151,7 @@ dir = 4 }, /obj/structure/fans/tiny, +/obj/machinery/door/airlock/external/glass, /turf/open/floor/plasteel, /area/hallway/primary/port) "kMy" = ( @@ -23153,9 +23234,6 @@ /turf/open/floor/plasteel, /area/quartermaster/storage) "kPu" = ( -/obj/structure/window/plasma/reinforced{ - dir = 4 - }, /obj/structure/table, /obj/item/stack/sheet/metal/fifty, /obj/item/stack/sheet/metal/fifty, @@ -23166,6 +23244,9 @@ /obj/effect/turf_decal/tile/yellow{ dir = 8 }, +/obj/structure/window/reinforced{ + dir = 4 + }, /turf/open/floor/plasteel/dark, /area/engine/engineering) "kPA" = ( @@ -23227,9 +23308,6 @@ }, /turf/open/floor/plating/asteroid/snow/icemoon, /area/maintenance/aft/secondary) -"kRk" = ( -/turf/open/floor/plasteel/white, -/area/crew_quarters/dorms) "kRz" = ( /obj/structure/cable{ icon_state = "1-8" @@ -23363,6 +23441,13 @@ "kVO" = ( /turf/closed/wall, /area/hallway/primary/aft) +"kWz" = ( +/obj/machinery/door/airlock{ + id_tag = "Dorm6"; + name = "Room Five" + }, +/turf/open/floor/carpet/purple, +/area/crew_quarters/dorms) "kWC" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -23373,6 +23458,17 @@ /obj/machinery/door/airlock/maintenance, /turf/open/floor/plating, /area/maintenance/aft/secondary) +"kXL" = ( +/obj/machinery/door/airlock/public/glass{ + name = "Snow Airlock" + }, +/obj/effect/mapping_helpers/airlock/cyclelink_helper, +/obj/machinery/door/firedoor/border_only{ + dir = 1; + name = "north facing firelock" + }, +/turf/open/floor/plasteel, +/area/crew_quarters/dorms) "kXY" = ( /obj/structure/cable{ icon_state = "4-8" @@ -23486,7 +23582,7 @@ name = "Port Auxiliary Solar Array" }, /turf/open/floor/plating/asteroid/snow/ice/icemoon/solarpanel, -/area/icemoon/surface/outdoors) +/area/solar/starboard/fore) "lbv" = ( /obj/machinery/atmospherics/components/binary/pump, /obj/machinery/door/firedoor/border_only{ @@ -23495,6 +23591,19 @@ }, /turf/open/floor/plasteel/white, /area/science/xenobiology) +"lcv" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/light/floor, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors) "ldt" = ( /obj/structure/cable{ icon_state = "1-2" @@ -23593,15 +23702,15 @@ icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/machinery/door/airlock/public/glass{ - name = "Hydroponics"; - req_access_txt = "35" - }, /obj/machinery/door/firedoor/border_only{ dir = 1; name = "north facing firelock" }, /obj/structure/disposalpipe/segment, +/obj/machinery/door/airlock{ + name = "Hydroponics"; + req_access_txt = "35" + }, /turf/open/floor/plasteel, /area/hydroponics) "lfD" = ( @@ -23621,6 +23730,12 @@ /obj/structure/closet/cardboard, /turf/open/floor/plating, /area/maintenance/starboard) +"lgg" = ( +/obj/structure/fluff/railing{ + dir = 5 + }, +/turf/open/transparent/openspace/icemoon, +/area/engine/atmospherics_engine) "lgn" = ( /obj/structure/cable{ icon_state = "1-2" @@ -23673,14 +23788,12 @@ /turf/open/floor/plasteel, /area/maintenance/aft) "lhr" = ( -/obj/structure/cable{ - icon_state = "0-8" +/obj/machinery/mineral/stacking_unit_console{ + machinedir = 1; + pixel_x = -30 }, -/obj/machinery/power/smes{ - charge = 5e+006 - }, -/turf/open/floor/circuit, -/area/ai_monitored/turret_protected/ai_upload) +/turf/open/floor/plasteel, +/area/maintenance/disposal) "lhB" = ( /obj/machinery/camera{ c_tag = "Northwestern Hall 7"; @@ -23710,29 +23823,27 @@ /obj/structure/cable{ icon_state = "2-8" }, -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/manifold/supply/hidden, -/obj/effect/landmark/start/assistant, -/obj/effect/turf_decal/tile/red, -/obj/effect/turf_decal/tile/red{ - dir = 4 +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 10 }, /turf/open/floor/plasteel, /area/crew_quarters/fitness) "liL" = ( -/obj/structure/cable{ - icon_state = "0-2" - }, /obj/machinery/ai_slipper{ uses = 10 }, -/obj/machinery/power/apc/highcap/five_k{ - areastring = "/area/ai_monitored/turret_protected/ai"; +/obj/machinery/door/window{ + base_state = "rightsecure"; dir = 4; - name = "AI Chamber APC"; - pixel_x = 24 + icon_state = "rightsecure"; + layer = 4.1; + name = "Secondary AI Core Access"; + obj_integrity = 300; + pixel_x = 4; + req_access_txt = "16" + }, +/obj/structure/cable{ + icon_state = "2-4" }, /turf/open/floor/circuit/off, /area/ai_monitored/turret_protected/ai) @@ -23757,11 +23868,11 @@ /turf/open/floor/pod/dark, /area/medical/paramedic) "lki" = ( -/obj/machinery/door/airlock/external, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 }, /obj/structure/fans/tiny, +/obj/machinery/door/airlock/external/glass, /turf/open/floor/plasteel, /area/hallway/primary/port) "lkP" = ( @@ -23992,7 +24103,7 @@ dir = 4 }, /turf/open/floor/plasteel, -/area/storage/atmos) +/area/maintenance/department/electrical) "lqW" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 4 @@ -24544,7 +24655,12 @@ dir = 4 }, /obj/effect/turf_decal/tile/neutral, -/obj/structure/weightmachine/stacklifter, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 9 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, /turf/open/floor/plasteel, /area/crew_quarters/fitness) "lJi" = ( @@ -24571,12 +24687,6 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/icemoon/surface/outdoors) -"lJN" = ( -/obj/machinery/light{ - dir = 1 - }, -/turf/open/floor/plasteel/white, -/area/crew_quarters/dorms) "lKT" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ @@ -24591,12 +24701,6 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/wood, /area/crew_quarters/theatre) -"lLv" = ( -/obj/structure/chair/comfy/beige{ - dir = 8 - }, -/turf/open/floor/carpet, -/area/crew_quarters/dorms) "lLD" = ( /obj/structure/cable{ icon_state = "1-2" @@ -24672,6 +24776,19 @@ }, /turf/open/floor/carpet/orange, /area/engine/secure_construction) +"lOa" = ( +/obj/machinery/door/airlock/public/glass{ + name = "Dormitory" + }, +/obj/machinery/door/firedoor/border_only{ + dir = 8; + name = "west facing firelock" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/turf/open/floor/carpet, +/area/crew_quarters/dorms) "lOs" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plasteel, @@ -24716,27 +24833,35 @@ /obj/machinery/atmospherics/pipe/simple/orange/visible, /turf/open/floor/plasteel, /area/engine/atmospherics_engine) -"lQp" = ( +"lQd" = ( /obj/structure/cable{ - icon_state = "1-2" + icon_state = "4-8" }, -/obj/machinery/porta_turret/ai{ - dir = 4 +/obj/structure/cable{ + icon_state = "1-8" }, -/turf/open/floor/plasteel/dark, -/area/ai_monitored/turret_protected/ai) +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/starboard/aft) +"lQp" = ( +/obj/machinery/atmospherics/components/binary/pump{ + dir = 1; + name = "waste relief valve" + }, +/turf/open/floor/plasteel, +/area/engine/atmos) "lQs" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/wood, /area/hallway/secondary/exit/departure_lounge) "lQJ" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on, -/obj/effect/turf_decal/tile/red, -/obj/effect/turf_decal/tile/red{ - dir = 4 +/obj/structure/fluff/railing{ + dir = 9 }, -/turf/open/floor/plasteel, -/area/crew_quarters/fitness) +/turf/open/transparent/openspace/icemoon, +/area/icemoon/surface/outdoors) "lRx" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 4 @@ -25107,7 +25232,9 @@ dir = 4 }, /obj/effect/turf_decal/tile/green, -/turf/open/floor/plasteel, +/turf/open/floor/plasteel/dark/side{ + dir = 5 + }, /area/hydroponics) "mbM" = ( /obj/effect/turf_decal/tile/blue{ @@ -25216,6 +25343,13 @@ }, /turf/open/floor/plasteel/white, /area/crew_quarters/heads/cmo) +"mfU" = ( +/obj/machinery/door/airlock/public/glass{ + name = "Holodeck Door" + }, +/obj/machinery/door/firedoor, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "mgo" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/machinery/door/firedoor/border_only{ @@ -25391,7 +25525,7 @@ icon_state = "4-8" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/port/fore) "mmO" = ( /obj/structure/cable{ icon_state = "1-2" @@ -25475,11 +25609,11 @@ /turf/open/floor/plating, /area/medical/virology) "mps" = ( -/obj/machinery/atmospherics/components/binary/valve{ - dir = 4 +/obj/structure/chair/comfy/beige{ + dir = 8 }, -/turf/open/floor/plating/asteroid/snow/icemoon, -/area/icemoon/surface/outdoors) +/turf/open/floor/carpet, +/area/crew_quarters/dorms) "mqb" = ( /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ dir = 8 @@ -25499,6 +25633,15 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/aft) +"mqd" = ( +/obj/item/paper/fluff{ + info = "Crystal has been moved to a lockbox in secure storage until further notice."; + name = "Note from an engineer"; + pixel_x = -5; + pixel_y = 3 + }, +/turf/open/floor/engine, +/area/engine/supermatter) "mqm" = ( /obj/structure/cable{ icon_state = "1-2" @@ -25591,7 +25734,7 @@ /turf/open/floor/plating, /area/maintenance/aft/secondary) "mtP" = ( -/turf/open/floor/carpet, +/turf/open/floor/plasteel, /area/crew_quarters/dorms) "mtY" = ( /obj/structure/cable{ @@ -25846,17 +25989,28 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel, /area/quartermaster/miningdock) +"mEH" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "mEI" = ( /obj/structure/table/reinforced, /obj/machinery/door/window/eastright{ base_state = "left"; - dir = 2; + dir = 1; icon_state = "left"; name = "Chemistry Desk"; req_access_txt = "33" }, /obj/machinery/door/firedoor/border_only, /obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/machinery/door/window/eastright{ + dir = 2; + name = "Chemistry Desk" + }, /turf/open/floor/plasteel/white, /area/medical/chemistry) "mFg" = ( @@ -25917,6 +26071,16 @@ /obj/machinery/space_heater, /turf/open/floor/plating, /area/icemoon/surface/outdoors) +"mHm" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "mHT" = ( /obj/structure/closet/l3closet/scientist, /obj/item/extinguisher, @@ -26527,7 +26691,7 @@ }, /obj/structure/bed, /obj/effect/spawner/lootdrop/bedsheet, -/turf/open/floor/carpet, +/turf/open/floor/carpet/blue, /area/crew_quarters/dorms) "mWD" = ( /obj/structure/cable{ @@ -26618,6 +26782,10 @@ /obj/machinery/door/firedoor/border_only{ dir = 1 }, +/obj/machinery/door/window/eastright{ + dir = 1; + name = "Chemistry Desk" + }, /turf/open/floor/plasteel/white, /area/medical/chemistry) "mZk" = ( @@ -26635,7 +26803,11 @@ name = "Station Intercom (General)"; pixel_x = 30 }, -/turf/open/floor/carpet, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/turf/open/floor/wood, /area/crew_quarters/dorms) "nbr" = ( /obj/structure/cable{ @@ -26975,13 +27147,13 @@ /turf/open/floor/plating, /area/security/checkpoint/medical) "nlF" = ( -/obj/machinery/door/airlock/public/glass{ - name = "Holodeck Door" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/turf/open/floor/plasteel/white, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/open/floor/carpet, /area/crew_quarters/dorms) "nlM" = ( /obj/machinery/light{ @@ -26994,19 +27166,6 @@ /obj/machinery/rnd/production/techfab/department/cargo, /turf/open/floor/plasteel, /area/quartermaster/miningdock) -"nmL" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, -/obj/effect/landmark/start/assistant, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 1 - }, -/turf/open/floor/plasteel, -/area/crew_quarters/fitness) "nmM" = ( /obj/effect/turf_decal/tile/yellow{ dir = 1 @@ -27147,7 +27306,6 @@ /area/storage/auxiliary) "nrY" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/machinery/door/airlock/external, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 1 }, @@ -27155,7 +27313,8 @@ name = "south facing firelock" }, /obj/structure/fans/tiny, -/turf/open/floor/carpet, +/obj/machinery/door/airlock/external/glass, +/turf/open/floor/plasteel, /area/crew_quarters/dorms) "nsf" = ( /obj/machinery/door/firedoor, @@ -27244,6 +27403,12 @@ dir = 4; network = list("aicore") }, +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "2-4" + }, /turf/open/floor/circuit/off, /area/ai_monitored/turret_protected/ai) "ntX" = ( @@ -27258,7 +27423,7 @@ }, /obj/machinery/power/tracker, /turf/open/floor/plating/asteroid/snow/ice/icemoon/solarpanel, -/area/icemoon/surface/outdoors) +/area/solar/starboard/fore) "nuJ" = ( /obj/structure/cable{ icon_state = "1-8" @@ -27362,7 +27527,7 @@ icon_state = "0-2" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/starboard/fore) "nyT" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/closed/wall/r_wall, @@ -27450,7 +27615,7 @@ pixel_x = -24; specialfunctions = 4 }, -/turf/open/floor/carpet, +/turf/open/floor/carpet/blue, /area/crew_quarters/dorms) "nBk" = ( /obj/structure/cable{ @@ -27572,16 +27737,26 @@ /turf/open/floor/plasteel, /area/engine/engineering) "nDd" = ( -/obj/structure/cable{ - icon_state = "4-8" +/obj/structure/closet/crate/engineering{ + name = "Antimatter Engine Crate" }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/supply/visible, -/obj/machinery/light/floor, -/turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/obj/machinery/power/am_control_unit, +/obj/item/am_shielding_container, +/obj/item/am_shielding_container, +/obj/item/am_shielding_container, +/obj/item/am_shielding_container, +/obj/item/am_shielding_container, +/obj/item/am_shielding_container, +/obj/item/am_shielding_container, +/obj/item/am_shielding_container, +/obj/item/am_shielding_container, +/obj/item/am_shielding_container, +/obj/item/am_shielding_container, +/obj/item/am_shielding_container, +/obj/item/am_containment, +/obj/item/am_containment, +/turf/open/floor/carpet/orange, +/area/engine/secure_construction) "nDl" = ( /obj/structure/cable{ icon_state = "4-8" @@ -27597,8 +27772,21 @@ icon_state = "0-8" }, /obj/structure/grille, +/obj/structure/cable{ + icon_state = "4-8" + }, /turf/open/floor/plating/asteroid/snow/icemoon, /area/icemoon/surface/outdoors) +"nDN" = ( +/obj/machinery/atmospherics/pipe/simple/supply/visible{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/light/floor, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors) "nEa" = ( /obj/effect/turf_decal/tile/yellow{ dir = 4 @@ -27640,6 +27828,16 @@ }, /turf/open/floor/carpet, /area/hallway/primary/port) +"nEH" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "nEI" = ( /obj/structure/dresser, /obj/machinery/camera{ @@ -27792,6 +27990,13 @@ /obj/machinery/atmospherics/pipe/simple/orange/visible, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) +"nJB" = ( +/obj/machinery/light, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/turf/open/floor/carpet, +/area/crew_quarters/dorms) "nJI" = ( /obj/structure/table/reinforced, /obj/machinery/door/window/southleft{ @@ -27921,10 +28126,15 @@ /area/hallway/primary/port) "nOY" = ( /obj/machinery/camera{ - c_tag = "Dorms West"; + c_tag = "Dorms Northeast"; dir = 8 }, -/turf/open/floor/carpet, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/turf/open/floor/wood, /area/crew_quarters/dorms) "nPd" = ( /obj/structure/cable{ @@ -28021,6 +28231,13 @@ /obj/machinery/atmospherics/pipe/simple/general/visible, /turf/closed/wall/r_wall, /area/science/mixing) +"nRA" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/structure/chair/comfy/beige, +/turf/open/floor/carpet, +/area/crew_quarters/dorms) "nRS" = ( /obj/structure/disposalpipe/segment{ dir = 10 @@ -28184,6 +28401,12 @@ }, /turf/open/floor/plasteel/dark, /area/security/main) +"nYd" = ( +/obj/machinery/atmospherics/components/binary/valve{ + dir = 4 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors) "nYv" = ( /obj/structure/chair{ dir = 8 @@ -28639,7 +28862,7 @@ dir = 4; name = "east facing firelock" }, -/turf/open/floor/plasteel, +/turf/open/floor/wood, /area/crew_quarters/fitness) "ojs" = ( /obj/structure/cable{ @@ -28824,6 +29047,18 @@ }, /turf/open/floor/engine/n2, /area/engine/atmos) +"onO" = ( +/obj/machinery/power/apc/highcap/five_k{ + areastring = "/area/ai_monitored/turret_protected/ai"; + dir = 4; + name = "AI Chamber APC"; + pixel_x = 24 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/open/floor/circuit/off, +/area/ai_monitored/turret_protected/ai) "onY" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/atmospherics/pipe/simple/green/visible{ @@ -28860,45 +29095,8 @@ /turf/open/floor/plasteel, /area/engine/break_room) "ooR" = ( -/obj/structure/cable{ - icon_state = "0-4" - }, -/obj/effect/landmark/start/ai, -/obj/item/radio/intercom{ - freerange = 1; - frequency = 1447; - name = "Private Channel"; - pixel_x = -25; - pixel_y = -10 - }, -/obj/item/radio/intercom{ - freerange = 1; - listening = 0; - name = "Custom Channel"; - pixel_y = 27 - }, -/obj/item/radio/intercom{ - freerange = 1; - name = "Common Channel"; - pixel_x = -25 - }, -/obj/machinery/button/door{ - id = "AI Chamber entrance shutters"; - name = "AI Chamber entrance shutters control"; - pixel_x = 8; - pixel_y = 23; - req_access_txt = "16" - }, -/obj/machinery/door/window{ - base_state = "rightsecure"; - dir = 4; - icon_state = "rightsecure"; - name = "Primary AI Core Access"; - obj_integrity = 300; - req_access_txt = "16" - }, -/turf/open/floor/circuit, -/area/ai_monitored/turret_protected/ai) +/turf/open/floor/plating/asteroid/snow/icemoon, +/area/icemoon/surface/outdoors/unexplored/rivers/no_monsters) "opq" = ( /obj/machinery/computer/rdservercontrol{ dir = 1 @@ -28917,11 +29115,8 @@ /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 1 }, -/obj/machinery/door/airlock/external{ - name = "External Access"; - req_access_txt = "13" - }, /obj/structure/fans/tiny, +/obj/machinery/door/airlock/external/glass, /turf/open/floor/plasteel, /area/maintenance/aft) "opY" = ( @@ -28995,6 +29190,10 @@ }, /turf/open/floor/plasteel, /area/security/checkpoint/medical) +"ord" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/turf/open/floor/plasteel, +/area/crew_quarters/dorms) "orN" = ( /obj/structure/cable{ icon_state = "2-4" @@ -29253,10 +29452,7 @@ /area/engine/engineering) "oBj" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper, -/obj/machinery/door/airlock/external{ - name = "External Access"; - req_access_txt = "13" - }, +/obj/machinery/door/airlock/external/glass, /turf/open/floor/plasteel, /area/maintenance/aft) "oBl" = ( @@ -29281,7 +29477,7 @@ c_tag = "Dorms South"; dir = 4 }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "oBF" = ( /obj/structure/cable{ @@ -29401,6 +29597,12 @@ }, /turf/open/floor/wood, /area/hallway/primary/central) +"oGZ" = ( +/obj/structure/fluff/railing{ + dir = 6 + }, +/turf/open/transparent/openspace/icemoon, +/area/engine/atmospherics_engine) "oHl" = ( /obj/structure/closet/crate/secure/engineering{ name = "TEG crate" @@ -29601,15 +29803,13 @@ /turf/open/floor/plasteel/dark, /area/ai_monitored/turret_protected/ai_upload_foyer) "oME" = ( -/obj/structure/cable{ - icon_state = "4-8" +/obj/machinery/firealarm{ + dir = 4; + pixel_x = -24 }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ - dir = 4 - }, -/obj/machinery/light/floor, -/turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/obj/machinery/vending/snack/random, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "oNv" = ( /obj/structure/table/wood, /turf/open/floor/wood, @@ -29679,17 +29879,27 @@ /obj/effect/landmark/start/head_of_personnel, /turf/open/floor/carpet, /area/crew_quarters/heads/hop) +"oPk" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/starboard/aft) "oPP" = ( /obj/structure/table/reinforced, /obj/machinery/door/window/eastright{ base_state = "left"; - dir = 2; + dir = 1; icon_state = "left"; name = "Chemistry Desk"; req_access_txt = "33" }, /obj/machinery/door/firedoor/border_only, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/machinery/door/window/eastright{ + dir = 2; + name = "Chemistry Desk" + }, /turf/open/floor/plasteel/white, /area/medical/chemistry) "oPS" = ( @@ -29798,6 +30008,12 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plating, /area/engine/storage) +"oUT" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/turf/open/floor/carpet, +/area/crew_quarters/dorms) "oUV" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 @@ -29994,17 +30210,7 @@ /turf/open/floor/plasteel, /area/storage/primary) "pbf" = ( -/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/tile/blue, -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/effect/turf_decal/tile/blue{ +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ dir = 1 }, /turf/open/floor/plasteel, @@ -30085,13 +30291,11 @@ /turf/open/floor/carpet, /area/hallway/secondary/exit/departure_lounge) "pce" = ( -/obj/machinery/door/airlock/external{ - name = "Auxiliary Airlock" - }, /obj/machinery/door/firedoor/border_only{ name = "south facing firelock" }, /obj/structure/fans/tiny, +/obj/machinery/door/airlock/external/glass, /turf/open/floor/plating, /area/hallway/secondary/exit/departure_lounge) "pcl" = ( @@ -30233,23 +30437,11 @@ dir = 4 }, /obj/machinery/disposal/bin, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "pgk" = ( -/obj/structure/window{ - dir = 1 - }, -/obj/effect/turf_decal/tile/red{ - dir = 4 - }, -/obj/effect/turf_decal/tile/red{ - dir = 8 - }, -/obj/effect/turf_decal/tile/red, -/obj/effect/turf_decal/tile/red{ - dir = 1 - }, -/turf/open/floor/plasteel, +/obj/structure/table, +/turf/open/transparent/glass/reinforced, /area/crew_quarters/fitness) "pgp" = ( /turf/closed/wall, @@ -30419,7 +30611,7 @@ icon_state = "2-8" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/port/aft) "pkJ" = ( /turf/open/floor/wood{ icon_state = "wood-broken6" @@ -30553,6 +30745,13 @@ "pqj" = ( /turf/open/floor/plasteel, /area/hallway/primary/fore) +"pqm" = ( +/obj/machinery/camera{ + c_tag = "Dorms Northwest"; + dir = 4 + }, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "pqs" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/visible{ dir = 4 @@ -30692,7 +30891,7 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "ptv" = ( /obj/machinery/atmospherics/components/unary/outlet_injector/on/layer1, @@ -30705,6 +30904,16 @@ }, /turf/open/floor/engine, /area/engine/atmospherics_engine) +"ptH" = ( +/obj/machinery/computer/holodeck{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "ptU" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable{ @@ -30718,7 +30927,7 @@ dir = 4 }, /obj/machinery/door/poddoor/preopen{ - id = "xenobio2"; + id = "xenobiospec"; name = "containment blast door" }, /turf/open/floor/engine, @@ -30887,6 +31096,15 @@ }, /turf/open/floor/circuit/telecomms/mainframe, /area/tcommsat/server) +"pvP" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/starboard/aft) "pvV" = ( /obj/machinery/airalarm{ pixel_y = 26 @@ -30923,6 +31141,9 @@ /area/engine/storage) "pwE" = ( /obj/effect/landmark/start/cyborg, +/obj/structure/cable{ + icon_state = "1-2" + }, /turf/open/floor/plasteel/dark, /area/ai_monitored/turret_protected/aisat/service) "pwL" = ( @@ -31078,14 +31299,12 @@ /turf/open/floor/plasteel/freezer, /area/security/prison) "pze" = ( -/obj/machinery/door/airlock/external{ - name = "Auxiliary Airlock" - }, /obj/machinery/door/firedoor/border_only{ dir = 1; name = "north facing firelock" }, /obj/structure/fans/tiny, +/obj/machinery/door/airlock/external/glass, /turf/open/floor/plating, /area/quartermaster/miningdock) "pzk" = ( @@ -31176,6 +31395,11 @@ }, /turf/open/floor/wood, /area/crew_quarters/heads/captain) +"pDg" = ( +/obj/structure/table, +/obj/item/paicard, +/turf/open/floor/carpet, +/area/crew_quarters/dorms) "pDh" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 4 @@ -31346,8 +31570,12 @@ /turf/open/floor/plasteel, /area/storage/primary) "pIf" = ( -/turf/open/floor/plasteel/dark, -/area/science/robotics/lab) +/obj/machinery/vending/cigarette, +/turf/open/floor/wood, +/area/crew_quarters/dorms) +"pIs" = ( +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/port/aft) "pIz" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 1 @@ -31376,6 +31604,18 @@ }, /turf/open/floor/plasteel/dark, /area/maintenance/department/bridge) +"pJm" = ( +/obj/structure/table/optable{ + name = "Robotics Operating Table" + }, +/obj/item/tank/internals/anesthetic, +/obj/item/clothing/mask/breath, +/obj/item/radio/intercom{ + name = "Station Intercom (General)"; + pixel_y = 29 + }, +/turf/open/floor/plasteel/dark, +/area/science/robotics/lab) "pJS" = ( /turf/closed/wall, /area/quartermaster/storage) @@ -31651,6 +31891,7 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 10 }, +/obj/machinery/light/floor, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "pQg" = ( @@ -31806,7 +32047,6 @@ icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/obj/machinery/door/airlock/external, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 1 }, @@ -31814,7 +32054,8 @@ name = "south facing firelock" }, /obj/structure/fans/tiny, -/turf/open/floor/carpet, +/obj/machinery/door/airlock/external/glass, +/turf/open/floor/plasteel, /area/crew_quarters/dorms) "pXl" = ( /obj/machinery/computer/cloning{ @@ -32022,7 +32263,7 @@ icon_state = "4-8" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/port/fore) "qfT" = ( /obj/machinery/holopad, /turf/open/floor/carpet, @@ -32103,6 +32344,10 @@ }, /turf/open/floor/engine, /area/engine/engineering) +"qim" = ( +/obj/machinery/light, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "qip" = ( /obj/structure/disposalpipe/trunk{ dir = 8 @@ -32147,6 +32392,18 @@ }, /turf/open/floor/plasteel, /area/storage/primary) +"qjF" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/starboard/aft) "qkg" = ( /obj/effect/turf_decal/tile/green{ dir = 4 @@ -32238,23 +32495,7 @@ /turf/closed/wall, /area/quartermaster/miningdock) "qnx" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/obj/effect/turf_decal/tile/yellow{ - dir = 8 - }, -/obj/effect/turf_decal/tile/yellow{ - dir = 4 - }, -/obj/effect/turf_decal/tile/red{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue, -/turf/open/floor/plasteel, +/turf/open/transparent/glass/reinforced, /area/crew_quarters/fitness) "qnC" = ( /obj/structure/cable, @@ -32338,7 +32579,7 @@ }, /obj/machinery/atmospherics/components/trinary/filter/atmos/flipped/plasma, /turf/open/floor/plating, -/area/storage/atmos) +/area/maintenance/department/electrical) "qqo" = ( /obj/machinery/light{ dir = 4 @@ -32704,7 +32945,7 @@ }, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, -/area/storage/atmos) +/area/maintenance/department/electrical) "qAI" = ( /obj/structure/cable{ icon_state = "4-8" @@ -32731,6 +32972,13 @@ }, /turf/open/floor/carpet, /area/hallway/primary/central) +"qBl" = ( +/obj/machinery/mineral/ore_redemption{ + input_dir = 4; + output_dir = 8 + }, +/turf/open/floor/plating, +/area/quartermaster/miningdock) "qBu" = ( /obj/machinery/atmospherics/components/binary/pump, /turf/open/floor/plasteel, @@ -32867,7 +33115,7 @@ name = "Station Intercom (General)"; pixel_y = 29 }, -/turf/open/floor/carpet, +/turf/open/floor/carpet/blue, /area/crew_quarters/dorms) "qFZ" = ( /obj/structure/closet/emcloset, @@ -32948,12 +33196,19 @@ /area/hallway/primary/fore) "qHC" = ( /obj/effect/spawner/structure/window/reinforced, -/obj/machinery/atmospherics/pipe/simple/yellow/visible, +/obj/machinery/atmospherics/pipe/layer_manifold, /turf/open/floor/plating, /area/engine/atmos) "qHL" = ( -/obj/structure/chair/comfy/beige{ - dir = 1 +/obj/machinery/door/airlock/public/glass{ + name = "Dormitory" + }, +/obj/machinery/door/firedoor/border_only{ + dir = 4; + name = "east facing firelock" + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 }, /turf/open/floor/carpet, /area/crew_quarters/dorms) @@ -32988,13 +33243,10 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/obj/structure/chair/stool{ - pixel_y = 8 - }, /obj/machinery/camera{ - c_tag = "Dorms Central" + c_tag = "Dorms East" }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "qIR" = ( /obj/machinery/button/massdriver{ @@ -33023,6 +33275,18 @@ /obj/effect/turf_decal/tile/green, /turf/open/floor/plasteel/white, /area/medical/virology) +"qIW" = ( +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/starboard/aft) "qJs" = ( /obj/structure/chair, /obj/effect/turf_decal/stripes/line{ @@ -33076,9 +33340,6 @@ /turf/open/floor/plasteel/white, /area/science/xenobiology) "qKA" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -33086,6 +33347,9 @@ dir = 8 }, /obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 10 + }, /turf/open/floor/plasteel, /area/crew_quarters/fitness) "qKP" = ( @@ -33184,6 +33448,14 @@ }, /turf/open/floor/plasteel/freezer, /area/medical/surgery) +"qOJ" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/supply/visible, +/obj/machinery/light/floor, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors) "qOL" = ( /obj/effect/landmark/event_spawn, /turf/open/floor/carpet, @@ -33337,6 +33609,12 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/port) +"qSF" = ( +/obj/structure/chair/comfy/beige{ + dir = 1 + }, +/turf/open/floor/carpet, +/area/crew_quarters/dorms) "qSJ" = ( /obj/machinery/airalarm{ pixel_y = 28 @@ -33527,6 +33805,12 @@ }, /turf/open/floor/engine, /area/engine/engineering) +"qZb" = ( +/obj/structure/fluff/railing{ + dir = 10 + }, +/turf/open/transparent/openspace/icemoon, +/area/engine/atmospherics_engine) "qZO" = ( /obj/machinery/atmospherics/pipe/simple/supply/visible{ dir = 4 @@ -33566,14 +33850,20 @@ /turf/closed/wall/r_wall, /area/maintenance/starboard) "raM" = ( -/obj/machinery/door/airlock/external, -/obj/machinery/door/firedoor/border_only{ - dir = 8; - name = "west facing firelock" +/obj/effect/spawner/structure/window/reinforced, +/obj/machinery/door/poddoor/shutters/preopen{ + id = "holoprivacy"; + name = "Holodeck Shutters" }, -/obj/structure/fans/tiny, /turf/open/floor/plating, /area/crew_quarters/dorms) +"rbb" = ( +/obj/machinery/space_heater, +/obj/machinery/light{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/crew_quarters/dorms) "rbg" = ( /obj/structure/disposalpipe/sorting/mail/flip{ dir = 8; @@ -34095,7 +34385,7 @@ name = "Starboard Solar Array" }, /turf/open/floor/plating/asteroid/snow/ice/icemoon/solarpanel, -/area/icemoon/surface/outdoors) +/area/solar/starboard/aft) "roS" = ( /obj/machinery/computer/card/minor/cmo{ dir = 4 @@ -34327,9 +34617,9 @@ /turf/open/floor/engine, /area/engine/engineering) "ruo" = ( -/obj/machinery/atmospherics/pipe/simple/supply/visible, -/turf/open/floor/plating/asteroid/snow/icemoon, -/area/icemoon/surface/outdoors) +/obj/machinery/vending/cola/random, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "ruD" = ( /obj/machinery/airalarm{ dir = 1; @@ -34412,7 +34702,7 @@ name = "Port Solar Array" }, /turf/open/floor/plating/asteroid/snow/ice/icemoon/solarpanel, -/area/icemoon/surface/outdoors) +/area/solar/port/aft) "rxJ" = ( /obj/item/stack/cable_coil/random, /turf/open/floor/plating/asteroid/snow/icemoon, @@ -34547,7 +34837,6 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, -/obj/machinery/portable_atmospherics/canister, /turf/open/floor/plasteel, /area/science/mixing) "rDE" = ( @@ -34570,6 +34859,18 @@ }, /turf/open/floor/plating, /area/maintenance/department/electrical) +"rEF" = ( +/obj/structure/bed, +/obj/effect/spawner/lootdrop/bedsheet, +/obj/machinery/button/door{ + id = "Dorm6"; + name = "Dorm Bolt Control"; + normaldoorcontrol = 1; + pixel_x = 25; + specialfunctions = 4 + }, +/turf/open/floor/carpet/purple, +/area/crew_quarters/dorms) "rFk" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plasteel/freezer, @@ -34705,6 +35006,12 @@ }, /turf/open/floor/circuit/off, /area/ai_monitored/turret_protected/ai) +"rKC" = ( +/obj/machinery/camera{ + c_tag = "Dorms West" + }, +/turf/open/floor/carpet, +/area/crew_quarters/dorms) "rLb" = ( /obj/effect/turf_decal/tile/yellow{ dir = 4 @@ -34804,28 +35111,16 @@ /turf/open/floor/plasteel, /area/hallway/primary/port) "rPU" = ( -/obj/machinery/conveyor{ - dir = 4; - id = "robo1" +/obj/machinery/light{ + dir = 8 }, -/obj/item/stack/sheet/metal/fifty, -/obj/item/stack/sheet/metal/fifty, -/obj/item/stack/sheet/metal/fifty, -/obj/item/stack/sheet/glass{ - amount = 20; - pixel_x = -3; - pixel_y = 6 - }, -/turf/open/floor/plasteel/dark, -/area/science/robotics/lab) +/turf/open/floor/wood, +/area/crew_quarters/dorms) "rQs" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/hallway/primary/fore) "rQu" = ( -/obj/structure/cable{ - icon_state = "1-8" - }, /obj/machinery/firealarm{ dir = 8; pixel_x = 24 @@ -34865,9 +35160,27 @@ /turf/open/floor/plasteel/white, /area/medical/chemistry) "rRk" = ( -/obj/structure/chair/comfy/beige, +/obj/machinery/door/airlock/public/glass{ + name = "Dormitory" + }, +/obj/machinery/door/firedoor/border_only{ + dir = 4; + name = "east facing firelock" + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, /turf/open/floor/carpet, /area/crew_quarters/dorms) +"rRQ" = ( +/obj/effect/turf_decal/stripes/corner{ + dir = 1 + }, +/turf/open/floor/plasteel/white, +/area/science/lab) "rRV" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 1 @@ -34936,6 +35249,7 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 6 }, +/obj/machinery/light/floor, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "rTW" = ( @@ -35052,9 +35366,7 @@ /turf/open/floor/wood, /area/crew_quarters/bar) "rYc" = ( -/obj/machinery/computer/arcade/battle{ - dir = 8 - }, +/obj/machinery/vending/cigarette, /turf/open/floor/wood, /area/crew_quarters/bar) "rYi" = ( @@ -35100,6 +35412,13 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/port) +"sae" = ( +/obj/machinery/firealarm{ + dir = 8; + pixel_x = 24 + }, +/turf/open/floor/plasteel/dark, +/area/science/robotics/lab) "sat" = ( /obj/machinery/light, /turf/open/floor/plasteel/white, @@ -35184,6 +35503,12 @@ /turf/open/floor/plasteel, /area/maintenance/aft) "scF" = ( +/obj/machinery/turretid{ + icon_state = "control_stun"; + name = "AI Chamber turret control"; + pixel_x = 24; + pixel_y = -3 + }, /obj/structure/cable{ icon_state = "1-2" }, @@ -35674,6 +35999,16 @@ }, /turf/open/floor/engine/n2o, /area/engine/atmos) +"stP" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/structure/grille, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/open/floor/plating/asteroid/snow/icemoon, +/area/icemoon/surface/outdoors) "stW" = ( /obj/structure/table/reinforced, /obj/machinery/door/poddoor/shutters/preopen{ @@ -35688,7 +36023,7 @@ "sub" = ( /obj/machinery/atmospherics/components/trinary/filter/atmos/flipped/co2, /turf/open/floor/plating, -/area/storage/atmos) +/area/maintenance/department/electrical) "sup" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -35751,14 +36086,8 @@ /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "swQ" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/structure/cable{ - icon_state = "1-4" - }, -/turf/open/floor/plating/asteroid/snow/icemoon, -/area/icemoon/surface/outdoors) +/turf/open/floor/wood, +/area/crew_quarters/dorms) "sxa" = ( /obj/machinery/requests_console{ department = "Medbay"; @@ -35963,20 +36292,16 @@ /turf/closed/wall/r_wall, /area/crew_quarters/heads/captain) "sFw" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ - dir = 1 - }, /obj/machinery/light, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/tile/blue, -/obj/effect/turf_decal/tile/blue{ +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/obj/effect/turf_decal/tile/blue{ +/obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 1 }, +/obj/structure/cable{ + icon_state = "4-8" + }, /turf/open/floor/plasteel, /area/crew_quarters/fitness) "sGC" = ( @@ -36059,7 +36384,7 @@ /turf/open/floor/engine, /area/engine/engineering) "sIT" = ( -/obj/structure/reagent_dispensers/fueltank, +/obj/machinery/recharge_station, /turf/open/floor/pod/dark, /area/medical/paramedic) "sJs" = ( @@ -36091,9 +36416,6 @@ /turf/open/floor/plasteel/dark, /area/hallway/secondary/entry) "sKN" = ( -/obj/structure/window/plasma/reinforced{ - dir = 8 - }, /obj/machinery/rnd/production/circuit_imprinter, /obj/effect/turf_decal/tile/yellow{ dir = 4 @@ -36101,6 +36423,9 @@ /obj/effect/turf_decal/tile/yellow{ dir = 8 }, +/obj/structure/window/reinforced{ + dir = 8 + }, /turf/open/floor/plasteel/dark, /area/engine/engineering) "sLg" = ( @@ -36152,6 +36477,12 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) +"sLF" = ( +/obj/structure/sign/mining{ + pixel_x = 32 + }, +/turf/open/floor/plasteel, +/area/quartermaster/miningdock) "sLN" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/visible, /turf/open/floor/plasteel, @@ -36216,6 +36547,32 @@ name = "Robotics Lab APC"; pixel_x = 25 }, +/obj/structure/table, +/obj/item/storage/toolbox/mechanical{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/item/storage/toolbox/electrical{ + pixel_x = 1; + pixel_y = 6 + }, +/obj/item/clothing/head/welding{ + pixel_x = -3; + pixel_y = 5 + }, +/obj/item/clothing/head/welding{ + pixel_x = -3; + pixel_y = 5 + }, +/obj/item/clothing/glasses/welding, +/obj/item/clothing/glasses/welding, +/obj/item/multitool{ + pixel_x = 3 + }, +/obj/item/multitool{ + pixel_x = 3 + }, +/obj/item/storage/belt/utility, /turf/open/floor/plasteel/white, /area/science/robotics/lab) "sOi" = ( @@ -36310,6 +36667,15 @@ }, /turf/open/floor/plating/asteroid/snow/icemoon, /area/icemoon/surface/outdoors) +"sQk" = ( +/obj/structure/cable{ + icon_state = "1-4" + }, +/obj/structure/cable{ + icon_state = "2-4" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/starboard/aft) "sRh" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on{ dir = 4 @@ -36396,8 +36762,24 @@ /turf/open/floor/plasteel/white, /area/medical/medbay/central) "sTq" = ( +/obj/structure/fluff/railing{ + dir = 1 + }, /turf/open/transparent/openspace/icemoon, /area/engine/atmospherics_engine) +"sTt" = ( +/obj/structure/table, +/obj/item/paper_bin{ + pixel_x = -6; + pixel_y = 4 + }, +/obj/item/pen/fourcolor, +/obj/item/paper_bin/bundlenatural{ + pixel_x = 6; + pixel_y = 4 + }, +/turf/open/floor/carpet, +/area/crew_quarters/dorms) "sTz" = ( /obj/effect/turf_decal/bot_white, /obj/structure/window/reinforced{ @@ -36884,22 +37266,9 @@ /turf/open/floor/plasteel/dark, /area/hallway/primary/fore) "tgd" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/obj/structure/window{ - dir = 8 - }, -/obj/effect/turf_decal/tile/red{ - dir = 4 - }, -/obj/effect/turf_decal/tile/red{ - dir = 8 - }, -/obj/effect/turf_decal/tile/red, -/obj/effect/turf_decal/tile/red{ - dir = 1 - }, /turf/open/floor/plasteel, /area/crew_quarters/fitness) "tht" = ( @@ -37181,7 +37550,7 @@ icon_state = "1-8" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/port/aft) "tod" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ @@ -37288,6 +37657,7 @@ /obj/structure/disposalpipe/segment{ dir = 6 }, +/obj/machinery/light/floor, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "tqp" = ( @@ -37357,7 +37727,7 @@ icon_state = "1-2" }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "ttl" = ( /obj/structure/cable{ @@ -37555,6 +37925,18 @@ }, /turf/open/floor/plasteel, /area/quartermaster/miningoffice) +"tzb" = ( +/obj/machinery/light/small{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "0-2" + }, +/obj/machinery/power/terminal{ + dir = 1 + }, +/turf/open/floor/circuit/off, +/area/ai_monitored/turret_protected/ai) "tzB" = ( /obj/machinery/atmospherics/pipe/simple{ dir = 6 @@ -37749,6 +38131,12 @@ /obj/machinery/atmospherics/components/binary/pump/on, /turf/open/floor/plasteel, /area/engine/atmos) +"tEC" = ( +/obj/structure/cable{ + icon_state = "0-8" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/port/aft) "tEQ" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -37776,11 +38164,12 @@ /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "tFu" = ( -/obj/structure/cable{ - icon_state = "2-4" +/obj/item/radio/intercom{ + name = "Station Intercom (General)"; + pixel_x = 30 }, -/turf/open/floor/plasteel/dark, -/area/ai_monitored/turret_protected/ai) +/turf/open/floor/wood, +/area/crew_quarters/dorms) "tFN" = ( /obj/machinery/atmospherics/pipe/heat_exchanging/simple{ dir = 4 @@ -37816,11 +38205,9 @@ /obj/structure/cable{ icon_state = "1-2" }, -/obj/machinery/door/airlock/external{ - name = "Escape Airlock" - }, /obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/structure/fans/tiny, +/obj/machinery/door/airlock/external/glass, /turf/open/floor/carpet, /area/hallway/primary/port) "tHr" = ( @@ -37894,9 +38281,12 @@ /turf/open/floor/plasteel/dark, /area/ai_monitored/turret_protected/ai_upload_foyer) "tJi" = ( -/obj/machinery/vending/wardrobe/robo_wardrobe, -/turf/open/floor/plasteel/white, -/area/science/robotics/lab) +/obj/structure/closet/secure_closet/personal/cabinet, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/open/floor/carpet/purple, +/area/crew_quarters/dorms) "tJA" = ( /obj/structure/cable{ icon_state = "1-2" @@ -37966,6 +38356,16 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plasteel, /area/quartermaster/miningoffice) +"tLb" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/supply/visible{ + dir = 4 + }, +/obj/machinery/light/floor, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors) "tLA" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 @@ -38109,17 +38509,14 @@ /turf/open/floor/plasteel/freezer, /area/medical/surgery) "tOz" = ( -/obj/machinery/light{ - dir = 1 +/obj/machinery/firealarm{ + dir = 4; + pixel_x = -24 }, -/obj/machinery/door/airlock/public/glass{ - name = "Holodeck Door" +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 6 }, -/obj/structure/fans/tiny, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/turf/open/floor/plasteel/white, +/turf/open/floor/wood, /area/crew_quarters/dorms) "tOE" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ @@ -38140,10 +38537,12 @@ name = "Fitness Room APC"; pixel_y = -24 }, -/obj/effect/turf_decal/tile/red, -/obj/effect/turf_decal/tile/red{ +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, +/obj/structure/cable{ + icon_state = "1-4" + }, /turf/open/floor/plasteel, /area/crew_quarters/fitness) "tPB" = ( @@ -38231,18 +38630,11 @@ /turf/open/floor/plasteel/dark, /area/maintenance/department/bridge) "tRC" = ( -/obj/effect/turf_decal/tile/yellow{ - dir = 8 - }, -/obj/effect/turf_decal/tile/yellow{ +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/obj/effect/turf_decal/tile/red{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue, -/obj/structure/window{ - dir = 8 +/obj/structure/cable{ + icon_state = "4-8" }, /turf/open/floor/plasteel, /area/crew_quarters/fitness) @@ -38270,11 +38662,13 @@ /turf/open/floor/plasteel/white, /area/science/xenobiology) "tSd" = ( -/obj/structure/cable{ - icon_state = "2-8" +/obj/item/radio/intercom{ + dir = 4; + name = "Station Intercom (General)"; + pixel_y = 29 }, -/turf/closed/wall/r_wall, -/area/ai_monitored/turret_protected/ai) +/turf/open/floor/carpet/purple, +/area/crew_quarters/dorms) "tSB" = ( /obj/machinery/atmospherics/pipe/simple{ dir = 4 @@ -38350,6 +38744,12 @@ }, /turf/open/floor/plasteel/white, /area/medical/medbay/central) +"tUq" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ + dir = 1 + }, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "tUF" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 @@ -38409,6 +38809,17 @@ }, /turf/open/floor/plasteel, /area/science/robotics/mechbay) +"tWs" = ( +/obj/machinery/door/airlock/external/glass, +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 1 + }, +/obj/machinery/door/firedoor/border_only{ + name = "south facing firelock" + }, +/obj/structure/fans/tiny, +/turf/open/floor/plasteel, +/area/crew_quarters/dorms) "tXn" = ( /obj/structure/cable{ icon_state = "4-8" @@ -38431,7 +38842,7 @@ pixel_x = -24; specialfunctions = 4 }, -/turf/open/floor/carpet, +/turf/open/floor/carpet/blue, /area/crew_quarters/dorms) "tYT" = ( /obj/structure/cable{ @@ -38720,7 +39131,7 @@ /area/engine/atmos) "ugk" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "uha" = ( /obj/structure/cable{ @@ -38803,7 +39214,7 @@ /obj/machinery/door/firedoor/border_only{ name = "south facing firelock" }, -/turf/open/floor/carpet, +/turf/open/floor/carpet/blue, /area/crew_quarters/dorms) "ukJ" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, @@ -38814,6 +39225,10 @@ }, /turf/open/floor/plasteel/freezer, /area/crew_quarters/kitchen) +"ule" = ( +/obj/structure/sign/departments/botany, +/turf/closed/wall, +/area/hydroponics) "ulh" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 1 @@ -38862,14 +39277,14 @@ /turf/open/floor/plating, /area/crew_quarters/heads/hop) "umC" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, /obj/machinery/atmospherics/pipe/manifold/supply/hidden, /obj/effect/turf_decal/tile/neutral{ dir = 4 }, /obj/effect/turf_decal/tile/neutral, +/obj/structure/cable{ + icon_state = "2-4" + }, /turf/open/floor/plasteel, /area/crew_quarters/fitness) "umD" = ( @@ -38892,7 +39307,7 @@ dir = 4 }, /obj/structure/closet/wardrobe/white, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "unA" = ( /obj/effect/spawner/structure/window/reinforced, @@ -39031,7 +39446,7 @@ /obj/structure/cable, /obj/machinery/power/smes, /turf/open/floor/plating, -/area/storage/atmos) +/area/maintenance/department/electrical) "utS" = ( /obj/structure/table, /obj/item/clothing/suit/apron/surgical, @@ -39046,11 +39461,18 @@ }, /turf/open/floor/plasteel/freezer, /area/medical/surgery) +"utY" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "uup" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plating, -/area/storage/atmos) +/area/maintenance/department/electrical) "uut" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 5 @@ -39105,13 +39527,9 @@ /obj/structure/cable{ icon_state = "1-2" }, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 4 - }, /obj/effect/landmark/start/assistant, -/obj/effect/turf_decal/tile/red, -/obj/effect/turf_decal/tile/red{ - dir = 4 +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 5 }, /turf/open/floor/plasteel, /area/crew_quarters/fitness) @@ -39194,6 +39612,12 @@ }, /turf/open/floor/plating, /area/maintenance/solars/starboard/aft) +"uyV" = ( +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/port/aft) "uyW" = ( /obj/structure/cable{ icon_state = "0-4" @@ -39384,13 +39808,13 @@ name = "Dormitory APC"; pixel_y = 24 }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "uFq" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 }, -/obj/machinery/door/airlock/external{ +/obj/machinery/door/airlock/external/glass{ name = "Arrivals Airlock" }, /turf/open/floor/plating, @@ -39566,12 +39990,6 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 }, -/obj/structure/window/plasma/reinforced{ - dir = 4 - }, -/obj/structure/window/plasma/reinforced{ - dir = 1 - }, /obj/structure/table, /obj/item/stack/sheet/glass/fifty, /obj/item/stack/sheet/glass/fifty, @@ -39582,6 +40000,12 @@ /obj/effect/turf_decal/tile/yellow{ dir = 8 }, +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, /turf/open/floor/plasteel/dark, /area/engine/engineering) "uKy" = ( @@ -39769,12 +40193,14 @@ /obj/structure/cable, /obj/machinery/power/tracker, /turf/open/floor/plating/asteroid/snow/ice/icemoon/solarpanel, -/area/icemoon/surface/outdoors) +/area/solar/starboard/aft) "uRg" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/obj/structure/closet/bombcloset, -/turf/open/floor/plasteel/white, -/area/science/mixing) +/obj/machinery/door/airlock{ + id_tag = "Dorm7"; + name = "Room Six" + }, +/turf/open/floor/carpet/purple, +/area/crew_quarters/dorms) "uRi" = ( /obj/structure/cable{ icon_state = "4-8" @@ -39843,8 +40269,14 @@ /turf/open/floor/plasteel, /area/engine/atmos) "uUi" = ( -/obj/machinery/computer/operating, -/turf/open/floor/plasteel/white, +/obj/machinery/mecha_part_fabricator, +/obj/item/stack/sheet/glass{ + amount = 20; + pixel_x = -3; + pixel_y = 6 + }, +/obj/item/stack/sheet/metal/fifty, +/turf/open/floor/plasteel/dark, /area/science/robotics/lab) "uUk" = ( /obj/structure/disposalpipe/segment{ @@ -39937,6 +40369,7 @@ "uWn" = ( /obj/structure/table, /obj/item/toy/cards/deck, +/obj/item/storage/crayons, /turf/open/floor/plasteel/grimy, /area/crew_quarters/fitness/recreation) "uWo" = ( @@ -39968,6 +40401,7 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, +/obj/machinery/light/floor, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "uWW" = ( @@ -40246,11 +40680,9 @@ /turf/open/floor/circuit, /area/science/robotics/mechbay) "vdW" = ( -/obj/structure/cable{ - icon_state = "1-4" - }, -/turf/closed/wall/r_wall, -/area/ai_monitored/turret_protected/ai_upload) +/obj/structure/table/wood, +/turf/open/floor/carpet/purple, +/area/crew_quarters/dorms) "vem" = ( /obj/structure/table/wood, /obj/machinery/keycard_auth{ @@ -40268,7 +40700,7 @@ codes_txt = "patrol;next_patrol=CHW"; location = "Dorm" }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "veF" = ( /obj/structure/table/wood, @@ -40407,7 +40839,7 @@ /obj/machinery/light{ dir = 1 }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "vhf" = ( /obj/effect/spawner/structure/window/reinforced, @@ -40485,6 +40917,11 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/plasteel, /area/hallway/primary/fore) +"vko" = ( +/obj/machinery/atmospherics/pipe/simple/supply/visible, +/obj/machinery/light/floor, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/surface/outdoors) "vkw" = ( /obj/structure/cable{ icon_state = "1-2" @@ -40608,13 +41045,10 @@ /turf/open/floor/plasteel, /area/quartermaster/storage) "vow" = ( -/obj/machinery/door/airlock/public/glass{ - name = "Holodeck Door" +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/turf/open/floor/plasteel/white, +/turf/open/floor/wood, /area/crew_quarters/dorms) "voD" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden{ @@ -40703,7 +41137,7 @@ pixel_x = -24; specialfunctions = 4 }, -/turf/open/floor/carpet, +/turf/open/floor/carpet/blue, /area/crew_quarters/dorms) "vqZ" = ( /obj/structure/window/plasma/reinforced{ @@ -40736,7 +41170,7 @@ "vrg" = ( /obj/machinery/atmospherics/components/trinary/filter/atmos/flipped/n2o, /turf/open/floor/plating, -/area/storage/atmos) +/area/maintenance/department/electrical) "vrx" = ( /turf/closed/wall/r_wall, /area/crew_quarters/dorms) @@ -40812,7 +41246,7 @@ /obj/structure/cable{ icon_state = "4-8" }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "vuk" = ( /obj/effect/spawner/structure/window/plasma/reinforced, @@ -41015,11 +41449,17 @@ /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "vzS" = ( -/obj/machinery/atmospherics/pipe/simple/supply/visible{ - dir = 5 +/obj/structure/bed, +/obj/effect/spawner/lootdrop/bedsheet, +/obj/machinery/button/door{ + id = "Dorm7"; + name = "Dorm Bolt Control"; + normaldoorcontrol = 1; + pixel_x = 25; + specialfunctions = 4 }, -/turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/turf/open/floor/carpet/purple, +/area/crew_quarters/dorms) "vAh" = ( /obj/structure/cable{ icon_state = "1-2" @@ -41193,12 +41633,12 @@ icon_state = "4-8" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/starboard/aft) "vDI" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 6 +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 1 }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "vEd" = ( /obj/effect/landmark/event_spawn, @@ -41208,7 +41648,7 @@ /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ dir = 4 }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "vEi" = ( /obj/structure/cable{ @@ -41295,6 +41735,7 @@ c_tag = "Northwest Paramedic Post"; network = list("ss13","medbay") }, +/obj/item/wrench/medical, /turf/open/floor/plasteel/white, /area/medical/paramedic) "vFe" = ( @@ -41306,6 +41747,18 @@ "vFM" = ( /turf/open/floor/plasteel, /area/quartermaster/sorting) +"vFT" = ( +/obj/structure/bed, +/obj/effect/spawner/lootdrop/bedsheet, +/obj/machinery/button/door{ + id = "Dorm5"; + name = "Dorm Bolt Control"; + normaldoorcontrol = 1; + pixel_x = 25; + specialfunctions = 4 + }, +/turf/open/floor/carpet/purple, +/area/crew_quarters/dorms) "vGi" = ( /obj/structure/cable{ icon_state = "1-2" @@ -41319,6 +41772,8 @@ /area/medical/virology) "vGn" = ( /obj/machinery/light, +/obj/vehicle/ridden/atv/snowmobile, +/obj/item/key, /turf/open/floor/pod/dark, /area/medical/paramedic) "vHU" = ( @@ -41430,17 +41885,7 @@ /obj/machinery/light{ dir = 1 }, -/obj/structure/table, -/obj/item/paper_bin{ - pixel_x = -6; - pixel_y = 4 - }, -/obj/item/pen/fourcolor, -/obj/item/paper_bin/bundlenatural{ - pixel_x = 6; - pixel_y = 4 - }, -/turf/open/floor/carpet, +/turf/open/floor/wood, /area/crew_quarters/dorms) "vKO" = ( /obj/effect/spawner/structure/window/reinforced, @@ -41457,16 +41902,15 @@ /turf/open/floor/plating, /area/bridge) "vKP" = ( -/obj/structure/weightmachine/stacklifter, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 1 - }, /obj/machinery/computer/security/telescreen/entertainment{ pixel_y = -32 }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, /turf/open/floor/plasteel, /area/crew_quarters/fitness) "vKT" = ( @@ -41477,7 +41921,7 @@ dir = 1 }, /turf/open/floor/plating, -/area/storage/atmos) +/area/maintenance/department/electrical) "vLa" = ( /obj/structure/cable{ icon_state = "4-8" @@ -41601,6 +42045,10 @@ pixel_x = 3; pixel_y = 3 }, +/obj/item/reagent_containers/glass/beaker/cryoxadone{ + pixel_x = 5; + pixel_y = 9 + }, /turf/open/floor/plasteel/white, /area/medical/paramedic) "vNY" = ( @@ -41669,15 +42117,15 @@ dir = 8 }, /area/chapel/main) -"vQk" = ( -/obj/machinery/computer/holodeck{ - dir = 4 - }, -/turf/open/floor/plasteel/white, -/area/crew_quarters/dorms) "vQo" = ( /turf/closed/wall/r_wall, /area/engine/supermatter) +"vQz" = ( +/obj/structure/extinguisher_cabinet{ + pixel_x = -27 + }, +/turf/open/floor/wood, +/area/crew_quarters/dorms) "vQW" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable{ @@ -41718,13 +42166,11 @@ /obj/structure/cable{ icon_state = "4-8" }, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, /obj/structure/disposalpipe/sorting/mail/flip{ dir = 4; sortType = 26 }, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden, /turf/open/floor/plasteel, /area/crew_quarters/fitness) "vSg" = ( @@ -41875,6 +42321,22 @@ }, /turf/open/floor/plating, /area/maintenance/department/electrical) +"vVJ" = ( +/obj/machinery/door/airlock/public/glass{ + name = "Dormitory" + }, +/obj/machinery/door/firedoor/border_only{ + dir = 8; + name = "west facing firelock" + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/open/floor/carpet, +/area/crew_quarters/dorms) "vVN" = ( /obj/effect/turf_decal/bot, /obj/structure/window/reinforced{ @@ -41887,7 +42349,7 @@ /area/crew_quarters/fitness) "vVZ" = ( /obj/structure/closet/secure_closet/personal/cabinet, -/turf/open/floor/carpet, +/turf/open/floor/carpet/blue, /area/crew_quarters/dorms) "vWg" = ( /obj/effect/turf_decal/delivery, @@ -42232,11 +42694,11 @@ /turf/open/floor/plasteel/white, /area/medical/medbay/central) "weS" = ( -/obj/machinery/door/airlock/external, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 }, /obj/structure/fans/tiny, +/obj/machinery/door/airlock/external/glass, /turf/open/floor/plating, /area/hallway/primary/aft) "wfN" = ( @@ -42262,7 +42724,7 @@ /obj/machinery/door/firedoor/border_only{ name = "south facing firelock" }, -/turf/open/floor/carpet, +/turf/open/floor/carpet/blue, /area/crew_quarters/dorms) "wgu" = ( /obj/machinery/atmospherics/pipe/simple/supply/visible{ @@ -42281,6 +42743,20 @@ /obj/structure/chair/stool/bar, /turf/open/floor/wood, /area/crew_quarters/bar) +"wgM" = ( +/obj/structure/sink{ + dir = 8; + pixel_x = -12; + pixel_y = 2 + }, +/obj/structure/mirror{ + pixel_x = -28 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/turf/open/floor/plasteel/freezer, +/area/crew_quarters/dorms) "wha" = ( /obj/machinery/atmospherics/components/trinary/filter/atmos/flipped/n2o{ dir = 1 @@ -42733,7 +43209,7 @@ name = "Port Auxiliary Solar Array" }, /turf/open/floor/plating/asteroid/snow/ice/icemoon/solarpanel, -/area/icemoon/surface/outdoors) +/area/solar/starboard/fore) "wuQ" = ( /obj/structure/table, /obj/machinery/plantgenes{ @@ -42925,7 +43401,7 @@ req_access_txt = "12;24" }, /turf/open/floor/plasteel, -/area/storage/atmos) +/area/maintenance/department/electrical) "wEm" = ( /obj/structure/barricade/wooden{ max_integrity = 10; @@ -43174,6 +43650,12 @@ /obj/machinery/chem_master/condimaster, /turf/open/floor/plasteel, /area/hydroponics) +"wMH" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/solar/starboard/aft) "wMJ" = ( /obj/structure/closet/secure_closet/bar{ req_access_txt = "25" @@ -43229,7 +43711,8 @@ icon_state = "4-8" }, /obj/effect/landmark/event_spawn, -/turf/open/floor/plasteel/white, +/obj/effect/landmark/start/roboticist, +/turf/open/floor/plasteel/dark, /area/science/robotics/lab) "wPT" = ( /obj/machinery/atmospherics/pipe/manifold4w/scrubbers/hidden, @@ -43331,11 +43814,9 @@ /turf/open/floor/plasteel/dark, /area/security/prison) "wSc" = ( -/obj/machinery/door/airlock/external{ - name = "Escape Airlock" - }, /obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/structure/fans/tiny, +/obj/machinery/door/airlock/external/glass, /turf/open/floor/carpet, /area/hallway/primary/port) "wSy" = ( @@ -43562,6 +44043,7 @@ /obj/machinery/light{ dir = 1 }, +/obj/machinery/vending/cigarette, /turf/open/floor/plasteel, /area/hallway/primary/fore) "xaS" = ( @@ -43613,22 +44095,10 @@ /turf/open/floor/plasteel, /area/hallway/primary/fore) "xcL" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ +/obj/machinery/atmospherics/components/unary/vent_scrubber/on, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 4 }, -/obj/structure/window{ - dir = 4 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/tile/blue, -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 1 - }, /turf/open/floor/plasteel, /area/crew_quarters/fitness) "xcY" = ( @@ -43658,6 +44128,14 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/plasteel, /area/hallway/primary/central) +"xdr" = ( +/obj/item/storage/backpack/duffelbag/med/surgery, +/obj/structure/table, +/obj/structure/extinguisher_cabinet{ + pixel_y = 30 + }, +/turf/open/floor/plasteel/dark, +/area/science/robotics/lab) "xdD" = ( /obj/machinery/atmospherics/pipe/manifold/scrubbers/visible{ dir = 4 @@ -43666,9 +44144,6 @@ /turf/open/floor/plasteel, /area/engine/atmos) "xeI" = ( -/obj/machinery/conveyor_switch/oneway{ - id = "robo1" - }, /obj/structure/disposalpipe/segment{ dir = 9 }, @@ -43680,8 +44155,13 @@ /turf/open/floor/plasteel, /area/engine/atmos) "xfs" = ( -/obj/structure/table, -/obj/item/paicard, +/obj/machinery/door/airlock/public/glass{ + name = "Dormitory" + }, +/obj/machinery/door/firedoor/border_only{ + dir = 4; + name = "east facing firelock" + }, /turf/open/floor/carpet, /area/crew_quarters/dorms) "xfD" = ( @@ -43819,10 +44299,10 @@ /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 }, -/obj/machinery/door/airlock/external{ - name = "Escape Airlock" - }, /obj/structure/fans/tiny, +/obj/machinery/door/airlock/external/glass{ + name = "Arrivals Airlock" + }, /turf/open/floor/plating, /area/hallway/secondary/exit/departure_lounge) "xka" = ( @@ -43885,6 +44365,7 @@ /obj/machinery/light{ dir = 4 }, +/obj/machinery/vending/wardrobe/robo_wardrobe, /turf/open/floor/plasteel/white, /area/science/robotics/lab) "xmr" = ( @@ -44092,7 +44573,7 @@ /obj/structure/cable{ icon_state = "1-2" }, -/turf/open/floor/plasteel/white, +/turf/open/floor/plasteel/dark, /area/science/robotics/lab) "xtV" = ( /obj/structure/cable{ @@ -44104,6 +44585,7 @@ /obj/structure/disposalpipe/segment{ dir = 9 }, +/obj/machinery/light/floor, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "xui" = ( @@ -44242,11 +44724,8 @@ /turf/open/floor/engine/plasma, /area/engine/atmos) "xAv" = ( -/obj/machinery/atmospherics/pipe/simple/supply/visible{ - dir = 6 - }, -/turf/open/floor/plating/asteroid/snow/icemoon, -/area/icemoon/surface/outdoors) +/turf/open/floor/carpet, +/area/crew_quarters/dorms) "xBi" = ( /obj/structure/cable{ icon_state = "4-8" @@ -44857,6 +45336,7 @@ /obj/structure/disposalpipe/trunk{ dir = 4 }, +/obj/machinery/disposal/bin, /turf/open/floor/wood, /area/crew_quarters/bar) "xUD" = ( @@ -44919,6 +45399,10 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/port) +"xWI" = ( +/obj/machinery/vending/cigarette, +/turf/open/floor/plasteel, +/area/hallway/primary/port) "xXS" = ( /obj/machinery/rnd/server, /obj/machinery/atmospherics/components/unary/vent_pump/siphon/on{ @@ -45156,7 +45640,7 @@ icon_state = "2-8" }, /turf/open/floor/plating/snowed/smoothed/icemoon, -/area/icemoon/surface/outdoors) +/area/solar/port/aft) "ygB" = ( /obj/structure/cable{ icon_state = "2-8" @@ -45218,6 +45702,9 @@ icon_state = "1-8" }, /obj/effect/landmark/start/cyborg, +/obj/structure/cable{ + icon_state = "1-2" + }, /turf/open/floor/plasteel/dark, /area/ai_monitored/turret_protected/aisat/service) "yiZ" = ( @@ -51538,17 +52025,17 @@ qrR qrR bTC avT -lbu -aQK -wuC +aPE +fne +iSB avT -lbu -aQK -wuC +aPE +fne +iSB avT -lbu -aQK -wuC +aPE +fne +iSB avT wuf yhx @@ -51795,17 +52282,17 @@ qrR qrR bTC avT -lbu +aPE qfJ -wuC +iSB avT -lbu +aPE qfJ -wuC +iSB avT -lbu +aPE qfJ -wuC +iSB avT avT avT @@ -51853,7 +52340,7 @@ ydp ydp buI hnP -swQ +phs ghq ghq ghq @@ -52052,17 +52539,17 @@ qrR qrR bTC avT -lbu +aPE qfJ -wuC +iSB avT -lbu +aPE qfJ -wuC +iSB avT -lbu +aPE qfJ -wuC +iSB avT avT avT @@ -52110,14 +52597,14 @@ ydp ydp buI buJ -cXI +ghq ghq hfZ shR ntV jso -shR -shR +tzb +iru hfZ ghq ghq @@ -52309,17 +52796,17 @@ avT avT avT avT -lbu +aPE qfJ -wuC +iSB avT -lbu +aPE qfJ -wuC +iSB avT -lbu +aPE qfJ -wuC +iSB avT avT yhx @@ -52367,14 +52854,14 @@ ydp bTC buI buJ -cXI +ghq ghq shR shR -shR +onO liL scF -hse +lfD shR ghq ghq @@ -52566,17 +53053,17 @@ wuf wuf avT avT -lbu +aPE qfJ -wuC +iSB avT -lbu +aPE qfJ -wuC +iSB avT -lbu +aPE qfJ -wuC +iSB avT wBg avT @@ -52585,12 +53072,12 @@ vrd vrd vrd vrd +nbC +nbC +nbC +nbC yhx -yhx -yhx -yhx -yhx -yhx +nbC yhx yhx yhx @@ -52624,12 +53111,12 @@ ydp buI fJZ phs -cXI +ghq ghq shR shR cpe -cpe +cUs cpe xIJ shR @@ -52824,15 +53311,15 @@ avT avT avT avT -hGK +guI avT avT avT -hGK +guI avT avT avT -hGK +guI avT aNg chZ @@ -52847,12 +53334,12 @@ avT avT avT avT +nbC +nbC +nbC +nbC yhx -yhx -yhx -yhx -yhx -yhx +nbC ydp ydp ydp @@ -52881,7 +53368,7 @@ ydp buI lGy ghq -cXI +ghq aJC shR qVf @@ -53077,21 +53564,21 @@ yhx yhx wuf avT -nuu -sXy -sXy -fNh -xUL -nyq -sXy -fNh -xUL -nyq -sXy -fNh -xUL -nyq -sXy +aKa +aPC +aPC +cXI +hrS +jvV +aPC +cXI +hrS +jvV +aPC +cXI +hrS +jvV +aPC eWw tnL iaq @@ -53138,12 +53625,12 @@ avT buI gJx ghq -cXI +ghq irN irr xIJ cpe -ooR +ghq cpe xIJ irr @@ -53338,15 +53825,15 @@ avT avT avT avT -clq +hse avT avT avT -clq +hse avT avT avT -clq +hse avT aNg chZ @@ -53395,9 +53882,9 @@ avT buI phs ghq -cXI +ghq +irr irr -tFu hmC rBA dfy @@ -53594,17 +54081,17 @@ fBG wuf avT avT -lbu +aPE mmM -wuC +iSB avT -lbu +aPE mmM -wuC +iSB avT -lbu +aPE mmM -wuC +iSB avT ajl avT @@ -53613,10 +54100,10 @@ vrd vrd vrd vrd -yhx -yhx -yhx -yhx +nbC +nbC +nbC +nbC bBh avT avT @@ -53643,7 +54130,7 @@ avT avT avT avT -bmX +avT avT avT avT @@ -53652,8 +54139,8 @@ ayq ghq ghq ghq -tSd -lQp +ghq +vmr rQu rKd gHG @@ -53851,17 +54338,17 @@ qrR qrR avT avT -lbu +aPE mmM -wuC +iSB avT -lbu +aPE mmM -wuC +iSB avT -lbu +aPE mmM -wuC +iSB avT avT avT @@ -53873,7 +54360,7 @@ yhx yhx yhx yhx -yhx +nbC rUq sXy sXy @@ -54108,17 +54595,17 @@ qrR qrR wuf avT -lbu +aPE mmM -wuC +iSB avT -lbu +aPE mmM -wuC +iSB avT -lbu +aPE mmM -wuC +iSB avT avT avT @@ -54130,13 +54617,13 @@ yhx yhx yhx yhx +nbC +nbC +nbC +nbC yhx -yhx -yhx -yhx -yhx -yhx -yhx +nbC +nbC avT avT avT @@ -54152,7 +54639,7 @@ ydp avT avT avT -avT +bmX apJ apJ apJ @@ -54176,7 +54663,7 @@ cwT aAC mGl grZ -vdW +cIh ghq bUB bJf @@ -54365,17 +54852,17 @@ qrR qrR wuf avT -lbu +aPE mmM -wuC +iSB avT -lbu +aPE mmM -wuC +iSB avT -lbu +aPE mmM -wuC +iSB avT avT avT @@ -54393,7 +54880,7 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT @@ -54433,7 +54920,7 @@ hva vZH lac iMX -lhr +cIh ghq bUB bJf @@ -54483,7 +54970,7 @@ wuf avT avT avT -bBh +fUc avT avT avT @@ -54622,17 +55109,17 @@ qrR qrR wuf avT -lbu -gTh -wuC +aPE +huF +iSB avT -lbu -gTh -wuC +aPE +huF +iSB avT -lbu -gTh -wuC +aPE +huF +iSB avT wuf avT @@ -54650,8 +55137,8 @@ yhx yhx yhx yhx -yhx -yhx +nbC +nbC ydp ydp ydp @@ -54740,7 +55227,7 @@ avT avT avT avT -bBh +fUc avT avT avT @@ -54997,7 +55484,7 @@ rxI rxI rxI avT -hGK +tEC avT rxI rxI @@ -55206,7 +55693,7 @@ nOG vEm fet avT -avT +stP avT ydp ydp @@ -55253,9 +55740,9 @@ pjD pjD pjD pjD -fNh -xUL -nyq +cih +pIs +ixO fsh fsh fsh @@ -55461,9 +55948,9 @@ azz aAF yiT pwE -fet -avT -avT +iMk +wMr +bEp bmX avT avT @@ -55511,7 +55998,7 @@ dfx dfx dfx avT -clq +uyV avT dfx dfx @@ -55720,7 +56207,7 @@ uKG vEm fet avT -avT +kHJ avT avT avT @@ -55768,7 +56255,7 @@ avT avT avT avT -bBh +fUc avT avT avT @@ -56025,7 +56512,7 @@ rxI rxI rxI avT -hGK +tEC avT rxI rxI @@ -56281,9 +56768,9 @@ pjD pjD pjD pjD -fNh -xUL -nyq +cih +pIs +ixO fsh fsh fsh @@ -56539,7 +57026,7 @@ dfx dfx dfx avT -clq +uyV avT dfx dfx @@ -56796,7 +57283,7 @@ avT avT avT avT -bBh +fUc avT avT avT @@ -57053,7 +57540,7 @@ rxI rxI rxI avT -hGK +tEC avT rxI rxI @@ -57309,9 +57796,9 @@ pjD pjD pjD pjD -fNh -xUL -nyq +cih +pIs +ixO fsh fsh fsh @@ -57567,7 +58054,7 @@ dfx dfx dfx avT -clq +uyV avT dfx dfx @@ -57824,7 +58311,7 @@ avT avT avT avT -bBh +fUc avT avT avT @@ -58007,7 +58494,7 @@ ydp ydp avT bBh -bmX +avT avT gLH ohf @@ -58081,7 +58568,7 @@ avT avT avT qlH -bBh +fUc qlH avT avT @@ -58286,8 +58773,8 @@ aFI iek wRz erO -aBK -dFJ +tmx +tmx kdA aFI avT @@ -58544,8 +59031,8 @@ cwH lam erO aBK -aDf -aEG +aBK +aBK aFI avT avT @@ -58800,8 +59287,8 @@ lWb dfa obB aAe -aBK -aDf +eXy +aEE aEE bxM avT @@ -59057,8 +59544,8 @@ aFI ays mQK auT -aBK -aDf +hBM +fol aEI bxM avT @@ -59314,7 +59801,7 @@ aFI uJF lam jcS -aBK +hBM aDc aEH bxM @@ -59571,8 +60058,8 @@ nEi jRU uzT gWn -aBK -aDf +hBM +jPf aEK bxM avT @@ -59828,7 +60315,7 @@ eGO ayt nuJ aAw -aBK +rRQ aEJ aEJ aIP @@ -60135,11 +60622,11 @@ yhx yhx yhx yhx -yhx +nbC xUL bBh xUL -yhx +nbC yhx yhx yhx @@ -60392,11 +60879,11 @@ yhx yhx yhx yhx -yhx +nbC xUL bBh xUL -yhx +nbC yhx yhx yhx @@ -60648,12 +61135,12 @@ yhx yhx yhx yhx -yhx -yhx +nbC +nbC xUL bBh xUL -yhx +nbC yhx yhx yhx @@ -60905,12 +61392,12 @@ yhx yhx yhx yhx -yhx +nbC avT xUL bBh xUL -yhx +nbC yhx yhx yhx @@ -61159,15 +61646,15 @@ yhx yhx yhx yhx -yhx -yhx -yhx -yhx +nbC +nbC +nbC +nbC euS sXy jAq -yhx -yhx +nbC +nbC yhx yhx yhx @@ -61417,13 +61904,13 @@ yhx yhx yhx yhx -yhx +nbC avT avT bBh xUL avT -yhx +nbC yhx yhx yhx @@ -61666,21 +62153,21 @@ yhx yhx yhx yhx +nbC +nbC +nbC +nbC +nbC +nbC +nbC yhx -yhx -yhx -yhx -yhx -yhx -yhx -yhx -yhx +nbC avT avT bBh xUL avT -yhx +nbC yhx yhx yhx @@ -61920,10 +62407,10 @@ yhx yhx yhx yhx -yhx -yhx -yhx -yhx +nbC +nbC +nbC +nbC avT xUL xUL @@ -61931,13 +62418,13 @@ xUL xUL avT avT -yhx +nbC xUL xUL bBh xUL -yhx -yhx +nbC +nbC yhx yhx yhx @@ -62171,11 +62658,11 @@ yhx yhx yhx yhx -yhx -yhx -yhx -yhx -yhx +nbC +nbC +nbC +nbC +nbC yhx avT avT @@ -62193,7 +62680,7 @@ sXy sXy jAq xUL -yhx +nbC yhx yhx yhx @@ -62409,9 +62896,9 @@ odR dPx sPA sKh +dMo irt -irt -guI +srB avT avT avT @@ -62425,10 +62912,10 @@ ydp ydp ydp yhx -yhx -yhx -yhx -yhx +nbC +nbC +nbC +nbC avT avT avT @@ -62441,16 +62928,16 @@ xUL xUL xUL avT -yhx +nbC xUL xUL xUL xUL xUL avT -yhx -yhx -yhx +nbC +nbC +nbC yhx yhx yhx @@ -62666,7 +63153,7 @@ aLk aNo aOo sKh -irt +dMo srB bzc avT @@ -62682,7 +63169,7 @@ ydp ydp ydp yhx -yhx +nbC avT avT avT @@ -62696,16 +63183,16 @@ xUL xUL avT avT -yhx -yhx -yhx -yhx -yhx -yhx -yhx -yhx -yhx -yhx +nbC +nbC +nbC +nbC +nbC +nbC +nbC +nbC +nbC +nbC yhx yhx yhx @@ -62917,12 +63404,12 @@ aDb qWM hIH nuS -aPE +qsD wDR fHF -aPC -aPE -aPE +aVv +qsD +qsD hmM bzc bzc @@ -62949,11 +63436,11 @@ xUL xUL xUL avT -yhx -yhx -yhx -yhx -yhx +nbC +nbC +nbC +nbC +nbC yhx yhx yhx @@ -63174,12 +63661,12 @@ bxk bxk hIH iFl -aPC +aVv gCC qAF hOc aOp -aPE +qsD hmM bzc bzc @@ -63202,11 +63689,11 @@ avT euS jAq xUL -yhx -yhx -yhx -yhx -yhx +nbC +nbC +nbC +nbC +nbC yhx yhx yhx @@ -63431,12 +63918,12 @@ hTk vHU qTO aHD -aPC +aVv jOy lqt gPb hFv -aPC +aVv hmM bzc bzc @@ -63458,8 +63945,8 @@ avT euS jAq xUL -yhx -yhx +nbC +nbC yhx yhx yhx @@ -63688,7 +64175,7 @@ srU aFO aFY aHD -aPC +aVv hxx vKT faR @@ -63714,8 +64201,8 @@ avT euS jAq xUL -yhx -yhx +nbC +nbC yhx yhx yhx @@ -63945,7 +64432,7 @@ aDm hLZ aFY aHD -aPC +aVv cKK sub vrg @@ -63970,8 +64457,8 @@ avT euS jAq xUL -yhx -yhx +nbC +nbC yhx yhx yhx @@ -64152,9 +64639,9 @@ ydp ydp ydp ydp -ydp -ydp -avT +bum +bum +bum avT mpj gNb @@ -64202,15 +64689,15 @@ aDp eZi aFU aHD -aPE +qsD jmf fLW utp itp -aPE +qsD aQV vcG -wgu +lzB avT avT ydp @@ -64226,8 +64713,8 @@ avT euS jAq xUL -yhx -yhx +nbC +nbC yhx yhx yhx @@ -64410,8 +64897,8 @@ ydp ydp ydp ydp -ydp -avT +bum +bum avT mpj eSJ @@ -64459,12 +64946,12 @@ aDe rJk aFT jOj -aPE -aKa -aPE -aPE -aPE -aPE +qsD +mSN +qsD +qsD +qsD +qsD aQV vcG lzB @@ -64483,7 +64970,7 @@ euS jAq xUL avT -yhx +nbC yhx yhx yhx @@ -64667,7 +65154,7 @@ ydp ydp ydp ydp -ydp +bum ydp avT mpj @@ -64733,14 +65220,14 @@ ydp ydp ydp ydp -avT +bmX avT avT bBh xUL -yhx -yhx -yhx +nbC +nbC +nbC yhx yhx yhx @@ -64982,7 +65469,7 @@ xUL xUL vcG lzB -bmX +avT avT ydp ydp @@ -64995,8 +65482,8 @@ avT avT bBh xUL -yhx -yhx +nbC +nbC yhx yhx yhx @@ -65190,7 +65677,7 @@ avT avT avT xUL -vBe +xUL mbm iJl iJl @@ -65226,7 +65713,7 @@ xeI rqW rqW aGD -tJi +rqW myh qLm qTG @@ -65252,7 +65739,7 @@ avT avT bBh xUL -yhx +nbC yhx yhx yhx @@ -65479,9 +65966,9 @@ rQJ fwn awb rqW -ayC -rPU -fne +rqW +rqW +rqW rqW rqW fOA @@ -65509,7 +65996,7 @@ avT avT bBh xUL -yhx +nbC yhx yhx yhx @@ -65701,7 +66188,7 @@ ydp ydp avT avT -bmX +avT avT xUL ace @@ -65735,12 +66222,12 @@ iPX rQJ fpS wPD +ihY +rqW +rqW +rqW rqW -pIf -pIf -pIf rqW -aHK myh uJx ikk @@ -65766,7 +66253,7 @@ avT avT bBh xUL -yhx +nbC yhx yhx yhx @@ -65993,11 +66480,11 @@ rQJ fvz awb rqW -ayC -azH -fne rqW -aCr +rqW +rqW +rqW +rqW myh lHH oYn @@ -66008,7 +66495,7 @@ wUr avT avT avT -vcG +lcv wgu avT avT @@ -66023,7 +66510,7 @@ avT avT bBh xUL -yhx +nbC yhx yhx yhx @@ -66218,7 +66705,7 @@ avT avT avT avT -bGt +ace avT avT avT @@ -66475,7 +66962,7 @@ ydp avT avT avT -ace +bGt avT avT avT @@ -66510,8 +66997,8 @@ myh rQJ rQJ rQJ -myh -myh +eXO +kjx rQJ wUr wUr @@ -66767,9 +67254,9 @@ xxi ayD cGz sqg -avT -ydp -ydp +xdr +ihY +rQJ ydp ydp ydp @@ -67023,10 +67510,10 @@ oaS eqP tcj viF -ayG -avT -avT -ydp +sqg +pJm +ihY +rQJ ydp ydp ydp @@ -67281,9 +67768,9 @@ iat pEF nez sqg -avT -avT -avT +fEz +sae +rQJ ydp ydp ydp @@ -67538,9 +68025,9 @@ axr ayE nez sqg -ydp -ydp -avT +rQJ +rQJ +rQJ ydp ydp ydp @@ -67807,7 +68294,7 @@ ydp avT avT avT -vcG +lcv wgu avT avT @@ -68042,7 +68529,7 @@ ujE grz arP xWq -wje +xWI nrd wje sqg @@ -68792,7 +69279,7 @@ ace avT avT avT -bmX +avT avT avT avT @@ -69058,7 +69545,7 @@ avT avT avT vBe -xnm +tLb xUL rhX lXR @@ -69316,12 +69803,12 @@ avT avT xUL xnm -xUL +vBe eTu kHd ljT kHd -gVo +kHd rhX xUL xUL @@ -69573,7 +70060,7 @@ avT avT xUL xnm -xUL +vBe eTu kHd apK @@ -69606,7 +70093,7 @@ ydp ydp avT avT -vcG +lcv wgu avT avT @@ -69829,7 +70316,7 @@ avT avT avT vBe -xnm +tLb xUL rhX rhX @@ -70588,18 +71075,18 @@ avT avT avT ace -xUL vBe xUL -xUL -xUL -xUL vBe xUL xUL xUL vBe xUL +xUL +xUL +xUL +vBe xnm avT avT @@ -70626,9 +71113,9 @@ ydp ydp ydp ydp -avT -avT -avT +ydp +ydp +ydp avT avT avT @@ -70847,11 +71334,11 @@ avT pQd kLh kQr +qOJ lZn lZn lZn -lZn -lZn +qOJ lZn lZn lZn @@ -70881,12 +71368,12 @@ ydp ydp ydp avT -avT -avT -avT -avT -avT -avT +ydp +ydp +ydp +ydp +ydp +ydp avT avT avT @@ -71138,23 +71625,23 @@ ydp ydp avT avT +ydp +ydp +ydp +ydp +ydp +ydp avT avT avT -avT -avT -avT -avT -avT -avT -avT +xUL vcG lzB avT avT avT avT -bmX +avT ydp ydp ydp @@ -71360,7 +71847,7 @@ avT avT avT xZL -qZO +xBk avT avT avT @@ -71391,21 +71878,21 @@ ydp ydp ydp ydp +ydp avT avT +bmX +ydp +ydp +ydp +ydp +ydp +ydp +avT avT avT xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -avT -avT -vcG +lcv wgu xUL xUL @@ -71450,7 +71937,7 @@ nxv kYF bVM avT -bmX +avT ydp ydp ydp @@ -71629,7 +72116,7 @@ avT avT avT avT -bmX +avT avT avT ydp @@ -71651,17 +72138,17 @@ ydp avT avT avT -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL +ydp +ydp +ydp +ydp +ydp +ydp avT +avT +avT +avT +xUL vcG lzB xUL @@ -71873,8 +72360,8 @@ ydp avT avT avT -xZL -xBk +aez +qZO avT avT avT @@ -71907,18 +72394,18 @@ ydp avT avT avT +avT +ydp +ydp +ydp +ydp +ydp +ydp +ydp +avT +avT +avT xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -avT vcG lzB avT @@ -72164,17 +72651,17 @@ ydp avT avT avT -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL +avT +avT +ydp +ydp +ydp +ydp +ydp +avT +avT +avT +avT xUL vcG lzB @@ -72419,20 +72906,20 @@ ydp ydp ydp avT -bmX +avT +avT +avT +avT +avT +ydp +ydp +ydp +avT +avT +avT +avT avT xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -avT vcG lzB avT @@ -72678,18 +73165,18 @@ ydp avT avT avT -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL avT +avT +avT +avT +ydp +avT +avT +avT +avT +avT +avT +xUL vcG lzB avT @@ -72707,7 +73194,7 @@ avT avT avT avT -avT +bmX wql wql vEG @@ -72935,18 +73422,18 @@ ydp avT avT avT -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL avT +avT +avT +avT +avT +avT +avT +avT +avT +avT +avT +xUL vcG lzB avT @@ -73192,19 +73679,19 @@ ydp ydp avT avT -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL avT -vcG +avT +avT +avT +avT +avT +avT +ydp +ydp +avT +avT +xUL +lcv wgu avT avT @@ -73217,7 +73704,7 @@ ydp ydp ydp ydp -bmX +avT avT wql wql @@ -73429,7 +73916,8 @@ avT avT avT avT -avT +bmX +ydp ydp ydp ydp @@ -73449,18 +73937,17 @@ ydp ydp avT avT -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL avT +avT +avT +avT +avT +avT +ydp +ydp +ydp +avT +xUL vcG lzB avT @@ -73507,7 +73994,7 @@ bUD bVM avT avT -bmX +avT avT avT avT @@ -73704,20 +74191,20 @@ ydp ydp ydp ydp +ydp +ydp +avT +avT +avT +avT +avT +avT +avT +ydp +ydp avT avT xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -avT vcG lzB avT @@ -73929,7 +74416,7 @@ avT avT avT avT -xZL +aez qZO avT avT @@ -73961,20 +74448,20 @@ ydp ydp ydp ydp +ydp +ydp +avT +avT +avT +ydp +ydp +avT +avT +avT +avT avT avT xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -avT vcG lzB xUL @@ -74218,20 +74705,20 @@ ydp ydp ydp ydp +ydp +avT +avT +avT +avT +ydp +ydp +ydp +avT +avT +avT avT avT xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -avT vcG lzB xUL @@ -74477,20 +74964,20 @@ ydp ydp avT avT +ydp +ydp +avT +avT +avT +avT +avT +avT +avT +avT +avT xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -vcG -lzB +lcv +nDN xUL xUL xUL @@ -74733,19 +75220,19 @@ ydp ydp avT avT +ydp +ydp +ydp +avT +avT +avT +avT +avT +avT +avT +avT avT xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -avT vcG lzB xUL @@ -74800,7 +75287,7 @@ cer avT avT avT -bmX +avT avT avT avT @@ -74992,19 +75479,19 @@ avT avT avT avT -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL -xUL avT +avT +avT +avT +avT +avT +avT +avT +avT +avT +xUL vcG -wgu +lzB xUL xUL xUL @@ -75249,17 +75736,17 @@ avT avT avT avT -avT xUL xUL xUL -avT -avT xUL xUL xUL -avT -avT +xUL +xUL +xUL +xUL +xUL vcG lzB avT @@ -75512,7 +75999,7 @@ nGx nGx nGx nGx -nGx +hnN nGx nGx nGx @@ -75526,8 +76013,8 @@ avT avT bok unA -bJQ -bJQ +xjZ +xjZ unA avT avT @@ -75762,7 +76249,7 @@ avT avT avT avT -tFr +vcG dvc sLv sLv @@ -75985,7 +76472,7 @@ avT avT avT avT -xZL +aez qZO avT avT @@ -76033,7 +76520,7 @@ avT avT avT avT -bmX +avT avT avT bok @@ -76094,7 +76581,7 @@ ruD clR avT avT -bmX +avT avT avT avT @@ -76534,7 +77021,7 @@ gky vmM jOo azc -lzB +nDN avT avT avT @@ -76559,7 +77046,7 @@ wcB unA avT avT -bmX +avT avT bwt cTD @@ -76808,7 +77295,7 @@ ncg aXh jHC bok -ivM +uFq bok unA uFq @@ -77263,12 +77750,12 @@ ydp ydp ydp ydp -avT -avT -avT -avT -avT -avT +pgp +iHM +iHM +iHM +iHM +iHM avT xZL xBk @@ -77520,15 +78007,15 @@ ydp ydp ydp ydp +pgp +sTt +nRA +pDg +qSF +iHM avT -avT -avT -bHt -nZE -nZE -nZE aez -xBk +qZO avT avT ydp @@ -77561,7 +78048,7 @@ kxI dPM xNs wwx -nDd +aAh aDQ avT avT @@ -77777,15 +78264,15 @@ ydp ydp ydp avT -avT -avT -avT +pgp +xAv +xAv mps xAv -ruo -ruo +iHM +avT acQ -aUb +xBk avT avT avT @@ -78021,28 +78508,28 @@ yhx yhx yhx yhx -ydp -ydp -ydp -ydp -ydp -ydp +nbC +nbC +nbC +pgp +pgp +pgp +pgp +pgp +pgp +pgp +pgp +pgp +pgp +pgp +rKC +bjR +xAv +xAv +pgp avT -avT -avT -avT -avT -avT -avT -avT -avT -avT -axL -aaM -nZE -nZE -abU -vBe +xZL +nYd avT avT avT @@ -78278,28 +78765,28 @@ yhx yhx yhx yhx -ydp -ydp -ydp -ydp -ydp -ydp +nbC +nbC avT -avT -avT -avT -avT -avT -iHM +pgp +tJi +vdW +pgp +tJi +vdW +pgp +tJi +vdW +pgp tOz -iHM +tUq gCO -iHM -axN -ruo -ruo -aAh -vzS +hvG +pgp +pgp +pgp +xZL +xBk avT ydp ydp @@ -78535,27 +79022,27 @@ yhx yhx yhx yhx -ydp -ydp -ydp -ydp -ydp -ydp avT avT avT -avT -avT -avT -iHM -kRk -iHM -kRk -iHM -avT -avT -avT -xZL +pgp +tSd +vzS +pgp +tSd +rEF +pgp +tSd +vFT +pgp +vow +swQ +gCO +swQ +kXL +mtP +tWs +aez xBk avT ydp @@ -78591,13 +79078,13 @@ spa dIj pIH bpT +dMo irt irt +dMo irt irt -irt -irt -irt +dMo gZS uyK aRt @@ -78792,27 +79279,27 @@ yhx yhx yhx yhx -ydp -ydp -ydp -ydp -ydp -ydp avT -avT -iHM -iHM -iHM -iHM -iHM +pgp +pgp +pgp +uRg +pgp +pgp +kWz +pgp +pgp +eCS +pgp +pgp vow -iHM -vow -iHM -iHM -iHM -iHM -xZL +swQ +gCO +swQ +kXL +mtP +tWs +aez xBk avT ydp @@ -79048,26 +79535,26 @@ yhx yhx yhx yhx -yhx -ydp -ydp -ydp -ydp -ydp -ydp -avT +ooR avT iHM -kHD -kHD -kHD -kHD -kHD -kHD -kHD -kHD -kHD -kHD +oME +rPU +swQ +fSb +pqm +swQ +swQ +rPU +swQ +swQ +vQz +vow +swQ +gCO +swQ +iHM +rbb iHM xZL xBk @@ -79103,8 +79590,8 @@ cPI hPe vAs ktw -xZL -lzB +aez +nDN avT avT avT @@ -79305,26 +79792,26 @@ ydp ydp ydp ydp -ydp -ydp -ydp -ydp -ydp -ydp -ydp avT avT iHM -kHD -kHD -kHD -kHD -kHD -kHD -kHD -kHD -kHD -kHD +pIf +swQ +swQ +swQ +swQ +jjB +ugk +ugk +ugk +ugk +ugk +fkA +ugk +hUg +qim +iHM +iHM iHM xZL xBk @@ -79346,7 +79833,7 @@ ydp ydp ydp avT -bmX +avT avT avT avT @@ -79360,7 +79847,7 @@ spa vir fkr ktw -oME +xZL lzB avT avT @@ -79562,27 +80049,27 @@ ydp ydp ydp ydp -ydp -ydp -ydp -ydp -ydp -ydp -avT avT avT iHM -kHD -kHD -kHD -kHD -kHD -kHD -kHD -kHD -kHD -kHD +ruo +tFu +swQ +swQ +hWp +ptH +iQu +iQu +iQu +iQu +mHm +bfo +swQ +gCO iHM +lJC +avT +avT xZL xBk avT @@ -79820,29 +80307,29 @@ ydp ydp ydp ydp -ydp -ydp -ydp -ydp -avT -avT -avT avT +pgp +pgp +pgp +raM +raM +raM +raM +mfU +raM +raM +raM +pgp +vVJ +hCx +lOa iHM -kHD -kHD -kHD -kHD -kHD -kHD -kHD -kHD -kHD -kHD -iHM -xZL -xBk -vBe +avT +avT +avT +aez +qZO +xUL ydp ydp ydp @@ -79957,7 +80444,7 @@ jQj avT avT avT -bmX +avT avT avT avT @@ -80078,25 +80565,25 @@ ydp ydp ydp ydp -ydp -ydp -ydp +pgp +kHD +kHD +kHD +kHD +kHD +kHD +kHD +kHD +kHD +kHD +raM +eoH +xAv +nJB +iHM +avT +avT avT -xUL -cav -xUL -iHM -kHD -kHD -kHD -kHD -kHD -kHD -kHD -kHD -kHD -kHD -iHM xZL xBk xUL @@ -80125,7 +80612,7 @@ sLv sLv sLv sLv -sLv +cEs sLv sLv sLv @@ -80335,25 +80822,25 @@ ydp ydp ydp ydp -ydp -ydp +raM +kHD +kHD +kHD +kHD +kHD +kHD +kHD +kHD +kHD +kHD +raM +nlF +xAv +oUT +iHM +avT avT avT -xUL -xUL -xUL -iHM -iHM -iHM -iHM -iHM -nlF -iHM -nlF -iHM -iHM -iHM -iHM xZL xBk avT @@ -80592,20 +81079,20 @@ ydp ydp ydp ydp -ydp -ydp -avT -avT -xUL -xUL -xUL -avT -avT -avT -avT -iHM -lJN -vQk +raM +kHD +kHD +kHD +kHD +kHD +kHD +kHD +kHD +kHD +kHD +raM +nlF +xAv gUc iHM avT @@ -80849,21 +81336,21 @@ ydp ydp ydp ydp -ydp -ydp -avT -pgp -xUL -xUL -xUL -pgp -avT -avT -avT -iHM -kRk -kRk -kRk +raM +kHD +kHD +kHD +kHD +kHD +kHD +kHD +kHD +kHD +kHD +raM +nlF +xAv +oUT iHM avT avT @@ -81106,28 +81593,28 @@ ydp ydp ydp ydp -ydp -avT -avT pgp -xUL -bSC -xUL -pgp -avT -avT -avT -iHM -vow -iHM -vow +kHD +kHD +kHD +fIk +kHD +kHD +kHD +kHD +kHD +kHD +raM +eoH +xAv +nJB iHM avT avT avT -xZL -xBk -iSB +aez +qZO +avT wdv xUL xUL @@ -81363,18 +81850,18 @@ ydp ydp ydp ydp -avT -avT -iHM -iHM +pgp +pgp pgp raM -iHM pgp -iHM -iHM -iHM -iHM +raM +raM +mfU +raM +raM +raM +pgp rRk xfs qHL @@ -81503,7 +81990,7 @@ avT avT avT avT -avT +bmX ydp ydp ydp @@ -81625,20 +82112,20 @@ xUL aNL mtP dvs -mtP -mtP -dAi -mtP -mtP -mtP -mtP -mtP -lLv -mtP +jjB +kIV +ugk +ugk +ugk +ugk +utY +mEH +ugk +hUg oBD iHM -lJC -lJC +iHM +iHM xZL xBk avT @@ -81661,7 +82148,7 @@ avT avT avT tFr -lzB +nDN avT avT avT @@ -81882,30 +82369,30 @@ xUL aNL fTM dvs -mtP +swQ naE -mtP +bqb aaU nOY -mtP -naE +iwH +hlQ duB tsK -tsK +nEH tsK iuC -tsK +cTV pXb aSE xBk xUL xUL xUL +xUL +xUL vBe xUL xUL -xUL -xUL vBe xUL xUL @@ -81915,7 +82402,7 @@ xUL vBe xUL xUL -xUL +vBe xUL vcG lzB @@ -81975,7 +82462,7 @@ anA wbT rTs hTL -uRg +hTL jab jFy qJV @@ -82140,39 +82627,39 @@ iHM pgp pgp pgp -pgp +eyc fPM pgp pgp pgp pgp vhb -mtP +swQ vDI ugk hAx -ugk +ord nrY -vsM +vko aUb xUL xUL xUL xUL xUL +vBe +xUL +xUL +vBe xUL xUL xUL xUL xUL +vBe xUL xUL -xUL -xUL -xUL -xUL -xUL -xUL +vBe xUL vcG lzB @@ -82392,19 +82879,19 @@ xUL ydp ydp ydp -bmX +avT avT pgp aab dZV -dZV -gLk +wgM +kdy pgp qFH nBd wfS iJs -mtP +swQ sgL qxk pgp @@ -82418,7 +82905,7 @@ xUL xUL xUL avT -bmX +avT avT avT avT @@ -82478,7 +82965,7 @@ vAs vAs krT pze -bEi +sLF bEi lbp bAs @@ -82654,25 +83141,25 @@ avT pgp aac gLk -gLk -gLk +hHV +kdy pgp vVZ mWy pgp iJs -mtP +swQ inA qMn pgp -wdv -wdv +pgp +pgp +xUL +xUL +xUL +xUL +vBe vBe -xUL -xUL -xUL -xUL -xUL xUL avT avT @@ -82740,7 +83227,7 @@ bFT bCO gRE thV -bCO +qBl bEa kxj aaw @@ -82911,7 +83398,7 @@ avT pgp aab aad -gLk +gdH fBs pgp pgp @@ -83457,10 +83944,10 @@ ydp ydp avT avT -bmX +avT avT tFr -lzB +nDN avT avT ydp @@ -84178,7 +84665,7 @@ ydp ydp ydp ydp -avT +bmX avT ydp ydp @@ -84693,7 +85180,7 @@ ydp ydp avT avT -bmX +avT avT avT avT @@ -84795,7 +85282,7 @@ hJE cmC aIt bCO -bBN +hyx vTF tRe eVp @@ -85080,7 +85567,7 @@ bPn avT avT avT -bmX +avT avT avT avT @@ -85259,7 +85746,7 @@ ydp avT avT tFr -lzB +nDN avT avT avT @@ -85432,23 +85919,23 @@ yhx wuf avT nuu -sXy -sXy +aar +aar fNh -xUL +abU nyq -sXy +aar fNh -xUL +abU nyq -sXy +aar fNh -xUL +abU nyq -sXy -sXy -sXy -sXy +aar +aar +aar +aar sDD eNK jwc @@ -86290,7 +86777,7 @@ vcG lzB avT avT -bmX +avT avT ydp ydp @@ -86512,7 +86999,7 @@ mGp rgm wAx wAx -wAx +ule uEz uEz wzf @@ -87026,11 +87513,11 @@ mKv sAh sAh acb -aar +urI +uEz +uEz uEz uEz -hrS -lQJ lia uvB tOY @@ -87058,7 +87545,7 @@ xUL xUL avT tFr -lzB +nDN avT avT ydp @@ -87103,7 +87590,7 @@ avT avT avT avT -bmX +avT avT avT avT @@ -87285,10 +87772,10 @@ sAh acb urI qkO -uEz -blD +qnx kge -gls +kge +qnx tgd tRC pJS @@ -87382,7 +87869,7 @@ avT avT avT avT -bmX +avT avT avT ydp @@ -87542,12 +88029,12 @@ qss qss ylW uoV -uEz -blD +qnx +pgk pgk bKl -iNK -chN +tgd +tRC pJS sWD bNF @@ -87799,9 +88286,9 @@ sAh acb urI uoV -uEz -blD -pgk +qnx +kbE +kbE qnx pbf sFw @@ -87884,7 +88371,7 @@ sXy ikA avT avT -bmX +avT avT avT avT @@ -88056,10 +88543,10 @@ sAh acb urI uoV -uEz -blD -eLl -igK +qnx +kge +kge +qnx xcL hop pJS @@ -88287,14 +88774,14 @@ ydp ydp ydp ydp -bmX +avT avT avT bBh avT aKf irQ -huF +cfp cfp gxY cfp @@ -88313,11 +88800,11 @@ qss oXl pPz uoV -uEz -hsQ -cDO -jAT -nmL +qnx +pgk +pgk +qnx +tgd vKP pJS hNg @@ -88405,7 +88892,7 @@ ydp ydp ydp ydp -avT +bmX avT ydp ydp @@ -88552,7 +89039,7 @@ avT aKf irQ jLG -piu +lhr piu xac gNI @@ -88570,12 +89057,12 @@ wAx wAx wAx hru -uEz -uEz -uEz -ejw -rTv -eOO +qnx +kbE +kbE +qnx +tgd +tRC pJS hNg bNF @@ -88802,7 +89289,7 @@ ydp ydp ydp avT -avT +bmX ydp bBh avT @@ -88830,9 +89317,9 @@ pbg uEz uEz uEz -ejw -rTv -eOO +cvN +gjZ +tRC pJS jiY bNF @@ -88857,7 +89344,7 @@ xUL xiw avT tFr -lzB +nDN avT avT avT @@ -88945,7 +89432,7 @@ ydp ydp ydp avT -bmX +avT avT ydp ydp @@ -90607,7 +91094,7 @@ bBh avT aKf gLO -jvV +cfp evO cfp kBe @@ -90656,7 +91143,7 @@ avT avT avT tFr -lzB +nDN avT avT avT @@ -91422,7 +91909,7 @@ uMF jsl gFM cuY -nGx +hnN nGx nGx nGx @@ -91679,11 +92166,11 @@ dks nEl ust sHJ +cEs sLv sLv sLv sLv -ybT asr avT avT @@ -91989,12 +92476,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT bBh avT -yhx +nbC yhx yhx yhx @@ -92195,7 +92682,7 @@ lGB jJu avT avT -bmX +avT avT avT avT @@ -92246,12 +92733,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT bBh avT -yhx +nbC yhx yhx yhx @@ -92399,8 +92886,8 @@ bqN avT xUL xUL -bmX avT +bmX bxL bxL bxL @@ -92408,7 +92895,7 @@ xUL bxL dri dri -dDC +uot nQp kVx eLQ @@ -92503,12 +92990,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT bBh avT -yhx +nbC yhx yhx yhx @@ -92641,7 +93128,7 @@ avT avT bzc xUL -avT +bmX avT ydp ydp @@ -92660,7 +93147,7 @@ avT avT bxL bxL -bum +axN xUL xUL dri @@ -92758,14 +93245,14 @@ yhx yhx yhx yhx -yhx -yhx -yhx +nbC +nbC +nbC avT avT bBh avT -yhx +nbC yhx yhx yhx @@ -92895,7 +93382,7 @@ ydp ydp ydp avT -avT +bum bzh xUL avT @@ -92917,7 +93404,7 @@ avT bxL bxL bum -bum +axN xUL xUL rww @@ -92925,7 +93412,7 @@ rww rww ttQ lNU -bZI +nDd bZI nNV dBP @@ -93015,14 +93502,14 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT avT bBh avT -yhx +nbC yhx yhx yhx @@ -93152,9 +93639,9 @@ ydp ydp ydp avT -avT -avT -bmX +bum +bum +bum avT avT ydp @@ -93174,7 +93661,7 @@ bxL bxL bum bum -bum +axN xUL xUL jrq @@ -93272,14 +93759,14 @@ yhx yhx yhx yhx -yhx +nbC avT euS sXy sXy jAq avT -yhx +nbC yhx yhx yhx @@ -93409,10 +93896,10 @@ ydp ydp ydp ydp -avT -avT -avT -avT +bum +bum +bum +bum ydp ydp ydp @@ -93431,7 +93918,7 @@ bKI bum bum bum -bum +axN xUL xUL rww @@ -93529,14 +94016,14 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT avT avT avT -yhx +nbC yhx yhx yhx @@ -93667,7 +94154,7 @@ ydp ydp avT avT -avT +bum avT avT ydp @@ -93688,7 +94175,7 @@ bKI bum bum bum -bum +axN xUL xUL dri @@ -93786,14 +94273,14 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT avT -yhx -yhx -yhx +nbC +nbC +nbC yhx yhx yhx @@ -93945,7 +94432,7 @@ bKI bum bum bum -bum +axN xUL xUL wmB @@ -94043,12 +94530,12 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -94199,10 +94686,10 @@ bKI bCC bCC bKI -bum -bum -bum -bum +azH +azH +azH +aHK xUL xUL fen @@ -94245,7 +94732,7 @@ qzz uqa iIQ avT -bmX +avT avT avT ydp @@ -94300,12 +94787,12 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -94557,7 +95044,7 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT @@ -94709,7 +95196,7 @@ bqN bqN bqN bxL -bum +axN xUL xUL xUL @@ -94814,12 +95301,12 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -94966,8 +95453,8 @@ bqN bqN bxL bxL -bum -bum +ayC +aEG xUL xUL bKI @@ -95071,12 +95558,12 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -95224,7 +95711,7 @@ bqN bqN bxL bum -bum +axN xUL xUL bKI @@ -95328,12 +95815,12 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -95481,7 +95968,7 @@ bqN bxL bxL bum -bum +axN xUL xUL bKI @@ -95585,12 +96072,12 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -95737,8 +96224,8 @@ bqN bqN bxL bxL -bum -bum +azH +aHK xUL xUL bKI @@ -95840,14 +96327,14 @@ yhx yhx yhx yhx -yhx -yhx -yhx +nbC +nbC +nbC avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -96005,7 +96492,7 @@ bKI bKI bMT fgj -nOk +lQp lfG sdr gyE @@ -96097,14 +96584,14 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -96359,9 +96846,9 @@ avT avT avT bBh -yhx -yhx -yhx +nbC +nbC +nbC yhx yhx yhx @@ -96508,9 +96995,9 @@ bqN bqN bxL bxL -bum -bum -bum +aCr +aCr +aEG xUL bOb bKI @@ -96611,7 +97098,7 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT @@ -96767,7 +97254,7 @@ bqN bxL bum bum -bum +axN xUL bOb bKI @@ -96868,12 +97355,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx +nbC yhx yhx yhx @@ -97024,7 +97511,7 @@ bqN bxL bum bum -bum +axN xUL bOb bKI @@ -97073,7 +97560,7 @@ wFO mZp avT avT -bmX +avT avT avT avT @@ -97125,12 +97612,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx +nbC yhx yhx yhx @@ -97281,7 +97768,7 @@ bqN bxL bum bum -bum +axN xUL bOb bKI @@ -97382,12 +97869,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx +nbC yhx yhx yhx @@ -97538,13 +98025,13 @@ bqN bxL bum bum -bum +axN xUL bOb -xUL -xUL -xUL -xUL +dDC +bum +bum +axN xbp onY gNy @@ -97639,12 +98126,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx +nbC yhx yhx yhx @@ -97795,13 +98282,13 @@ bxL bxL bxL bum -bum +axN xUL bOb -bum -bum -bum -bum +dFJ +azH +azH +aHK xbp fen eHK @@ -97896,12 +98383,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx +nbC yhx yhx yhx @@ -98052,7 +98539,7 @@ bxL bxL bxL bum -bum +axN bDA bGW bYY @@ -98153,12 +98640,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx +nbC yhx yhx yhx @@ -98309,7 +98796,7 @@ bxL bxL bxL bum -bum +axN bFx bOb bKI @@ -98410,7 +98897,7 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT @@ -98566,7 +99053,7 @@ bqN bqN bxL bum -bum +axN bFx bRD caS @@ -98667,14 +99154,14 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx -yhx -yhx +nbC +nbC +nbC yhx yhx yhx @@ -98823,7 +99310,7 @@ bqN bxL bxL bum -bum +axN aEF bYY ccD @@ -98924,14 +99411,14 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -99079,8 +99566,8 @@ bqN bqN bxL bxL -bum -bum +azH +aHK xUL xUL bKI @@ -99181,14 +99668,14 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -99340,12 +99827,13 @@ xUL xUL xUL xUL +dDC bum bum -bum -bum +axN xbp xUL +dDC bum bum bum @@ -99359,8 +99847,7 @@ bum bum bum bum -bum -bum +axN rGc jPj ucC @@ -99438,14 +99925,14 @@ yhx yhx yhx yhx -yhx -yhx -yhx +nbC +nbC +nbC avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -99597,27 +100084,27 @@ xUL xUL xUL xUL -bum -bum -bum -bum +dFJ +azH +azH +aHK xbp xUL -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum +dFJ +azH +azH +azH +azH +azH +azH +azH +azH +azH +azH +azH +azH +azH +aHK dQW jls ucC @@ -99697,12 +100184,12 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -99850,8 +100337,8 @@ bqN bqN bxL bxL -bum -bum +aCr +aEG xUL xUL xUL @@ -99954,7 +100441,7 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT @@ -100108,7 +100595,7 @@ bqN bxL bxL bum -bum +axN xUL xUL xUL @@ -100211,12 +100698,12 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -100366,24 +100853,24 @@ bxL bxL bxL bum -bum -bum -bum -bum -bum -bum +aCr +aCr +aCr +aCr +aCr +aEG xbp xUL -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum +lQJ +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aEG rGc tdX tdX @@ -100397,7 +100884,7 @@ aNU kVD noQ leT -leT +mqd leT iCq leT @@ -100408,7 +100895,7 @@ wku xGy lBH bnU -bmX +avT avT ydp ydp @@ -100468,12 +100955,12 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -100628,9 +101115,10 @@ bum bum bum bum -bum +axN xbp xUL +dDC bum bum bum @@ -100639,8 +101127,7 @@ bum bum bum bum -bum -bum +axN dQW tdX tdX @@ -100725,12 +101212,12 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -100885,9 +101372,10 @@ bum bum bum bum -bum +axN xbp xUL +dDC bum bum bum @@ -100896,8 +101384,7 @@ bum bum bum bum -bum -bum +axN rGc tdX tdX @@ -100982,12 +101469,12 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -101142,9 +101629,10 @@ bum bum bum bum -bum +axN xbp xUL +dDC bum bum bum @@ -101153,8 +101641,7 @@ bum bum bum bum -bum -bum +axN dQW tdX tdX @@ -101244,7 +101731,7 @@ avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -101399,9 +101886,10 @@ bum bum bum bum -bum +axN xbp xUL +dDC bum bum bum @@ -101410,8 +101898,7 @@ bum bum bum bum -bum -bum +axN rGc jPj dQW @@ -101494,14 +101981,14 @@ yhx yhx yhx yhx -yhx -yhx -yhx +nbC +nbC +nbC avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -101656,9 +102143,10 @@ bum bum bum bum -bum +axN xbp xUL +dDC bum bum bum @@ -101667,8 +102155,7 @@ bum bum bum bum -bum -bum +axN dQW cly cly @@ -101751,14 +102238,14 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -101913,9 +102400,10 @@ bum bum bum bum -bum +axN xbp xUL +dDC bum bum bum @@ -101924,8 +102412,7 @@ bum bum bum bum -bum -bum +axN xUL xUL xUL @@ -102008,14 +102495,14 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh avT avT -yhx +nbC yhx yhx yhx @@ -102170,9 +102657,10 @@ bum bum bum bum -bum +axN xbp xUL +dDC bum bum bum @@ -102181,8 +102669,7 @@ bum bum bum bum -bum -bum +axN xUL xUL xUL @@ -102265,14 +102752,14 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx -yhx -yhx +nbC +nbC +nbC yhx yhx yhx @@ -102427,9 +102914,10 @@ bum bum bum bum -bum +axN xbp xUL +dDC bum bum bum @@ -102438,16 +102926,15 @@ bum bum bum bum -bum -bum +axN xUL xUL xUL xUL xUL -bum -bum -bum +lQJ +aCr +aCr hBq pCv iuP @@ -102522,12 +103009,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx +nbC yhx yhx yhx @@ -102679,24 +103166,24 @@ bqN bxL bxL bxL -bum -bum -bum -bum -bum -bum +azH +azH +azH +azH +azH +aHK xbp xUL -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum +dFJ +azH +azH +azH +azH +azH +azH +azH +azH +aHK xUL xUL xUL @@ -102779,12 +103266,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx +nbC yhx yhx yhx @@ -103036,12 +103523,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx +nbC yhx yhx yhx @@ -103293,12 +103780,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx +nbC yhx yhx yhx @@ -103450,27 +103937,27 @@ bqN bqN bxL bxL -bum -bum -bum -bum -bum -bum +aCr +aCr +aCr +aCr +aCr +aEG xUL xUL -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum +lQJ +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aEG xUL xbp sTq @@ -103550,12 +104037,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx +nbC yhx yhx yhx @@ -103712,9 +104199,10 @@ bum bum bum bum -bum +axN xUL xUL +dDC bum bum bum @@ -103726,11 +104214,10 @@ bum bum bum bum -bum -bum +axN xUL xbp -sTq +lgg hBq xBV hBq @@ -103750,7 +104237,7 @@ avT avT avT avT -bmX +avT ydp ydp ydp @@ -103807,12 +104294,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx +nbC yhx yhx yhx @@ -103969,9 +104456,10 @@ bum bum bum bum -bum +axN xUL xUL +dDC bum bum bum @@ -103983,8 +104471,7 @@ bum bum bum bum -bum -bum +axN rGc rvf umD @@ -104064,12 +104551,12 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx +nbC yhx yhx yhx @@ -104226,9 +104713,10 @@ bum bum bum bum -bum +axN xUL xUL +dDC bum bum bum @@ -104240,8 +104728,7 @@ bum bum bum bum -bum -bum +axN odg xbp bZa @@ -104321,13 +104808,13 @@ yhx yhx yhx yhx -yhx +nbC avT avT avT bBh -yhx -yhx +nbC +nbC yhx yhx yhx @@ -104351,7 +104838,7 @@ faJ rot avT jxB -aQK +sQk rot avT wuf @@ -104483,9 +104970,10 @@ bum bum bum bum -bum +axN xUL xUL +dDC bum bum bum @@ -104497,12 +104985,11 @@ bum bum bum bum -bum -bum +axN odg xbp -sTq -sTq +cVa +qZb lHa nQd umD @@ -104584,8 +105071,8 @@ avT avT bBh avT -yhx -yhx +nbC +nbC yhx yhx yhx @@ -104608,7 +105095,7 @@ vDy rot avT jxB -qfJ +qjF rot avT wuf @@ -104740,9 +105227,10 @@ bum bum bum bum -bum +axN xUL xUL +dDC bum bum bum @@ -104754,12 +105242,11 @@ bum bum bum bum -bum -bum +axN odg xbp -sTq -sTq +lgg +oGZ pQg tFN tFN @@ -104835,13 +105322,13 @@ yhx yhx yhx yhx -yhx -yhx -yhx +nbC +nbC +nbC avT bBh avT -yhx +nbC yhx yhx yhx @@ -104865,7 +105352,7 @@ vDy rot avT jxB -qfJ +qjF rot avT wuf @@ -104997,9 +105484,10 @@ bxL bum bum bum -bum +axN xUL xUL +dDC bum bum bum @@ -105011,8 +105499,7 @@ bum bum bum bum -bum -bum +axN dQW rvf cly @@ -105094,12 +105581,12 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT -yhx -yhx +nbC +nbC yhx yhx yhx @@ -105122,7 +105609,7 @@ vDy rot avT jxB -qfJ +qjF rot avT avT @@ -105254,9 +105741,10 @@ bxL bxL bxL bum -bum +axN xUL xUL +dDC bum bum bum @@ -105268,8 +105756,7 @@ bum bum bum bum -bum -bum +axN xUL wDd alE @@ -105351,7 +105838,7 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT @@ -105379,7 +105866,7 @@ vDy rot avT jxB -qfJ +qjF rot avT avT @@ -105514,22 +106001,22 @@ bKI bKI xUL xUL -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum +dFJ +azH +azH +azH +azH +azH +azH +azH +azH +azH +azH +azH +aHK +xUL +xUL +xUL xUL bOb xUL @@ -105608,7 +106095,7 @@ yhx yhx yhx yhx -yhx +nbC avT bBh avT @@ -105628,15 +106115,15 @@ avT avT avT avT -hGK +jEm avT avT avT -hGK +jEm avT avT avT -hGK +jEm avT avT avT @@ -105865,7 +106352,7 @@ yhx yhx yhx yhx -yhx +nbC avT rUq sXy @@ -105877,26 +106364,26 @@ oBl uyM dUH fUm -sXy -sXy -sXy -sXy -sXy -sXy -sXy -fNh -xUL -xUL -xUL -xUL -xUL -nyq -sXy -fNh -xUL -nyq -sXy -sXy +wMH +wMH +wMH +wMH +wMH +wMH +wMH +cWI +jWw +jWw +jWw +jWw +jWw +gIW +wMH +cWI +jWw +gIW +wMH +wMH uRc avT wuf @@ -106122,8 +106609,8 @@ yhx yhx yhx yhx -yhx -yhx +nbC +nbC avT avT avT @@ -106142,15 +106629,15 @@ avT avT avT avT -clq +oPk avT avT avT -clq +oPk avT avT avT -clq +oPk avT avT avT @@ -106285,24 +106772,24 @@ bKI bKI bxL bxL -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum -bum +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr +aCr bxL bqN bqN @@ -106311,7 +106798,7 @@ bqN avT avT avT -bmX +avT avT avT avT @@ -106399,15 +106886,15 @@ avT avT avT jxB -mmM +qIW rot avT jxB -mmM +qIW rot avT jxB -knR +lQd rot avT avT @@ -106637,11 +107124,11 @@ yhx yhx yhx yhx -yhx -yhx -yhx -yhx -yhx +nbC +nbC +nbC +nbC +nbC yhx yhx yhx @@ -106656,15 +107143,15 @@ avT avT avT jxB -mmM +qIW rot avT jxB -mmM +qIW rot avT jxB -knR +lQd rot avT avT @@ -106913,15 +107400,15 @@ avT avT avT jxB -mmM +qIW rot avT jxB -mmM +qIW rot avT jxB -knR +lQd rot avT wuf @@ -107170,15 +107657,15 @@ avT avT avT jxB -mmM +qIW rot avT jxB -mmM +qIW rot avT jxB -knR +lQd rot avT wuf @@ -107427,15 +107914,15 @@ avT avT avT jxB -gTh +pvP rot avT jxB -gTh +pvP rot avT jxB -gTh +pvP rot avT wuf diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index 585e8da7d7..6aca5cd998 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -99,7 +99,8 @@ #define NO_ASS_SLAP (1<<10) #define BIMBOFICATION (1<<11) #define NO_AUTO_WAG (1<<12) - +#define GENITAL_EXAMINE (1<<13) +#define VORE_EXAMINE (1<<14) #define TOGGLES_CITADEL 0 //belly sound pref things diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm index 3d15412efe..2273d34c82 100644 --- a/code/__DEFINES/colors.dm +++ b/code/__DEFINES/colors.dm @@ -2,19 +2,6 @@ #define COLOR_INPUT_DISABLED "#F0F0F0" #define COLOR_INPUT_ENABLED "#D3B5B5" - -#define COLOR_DARKMODE_INFO_BUTTONS_BG "#40628A" -#define COLOR_DARKMODE_ISSUE_BUTTON_BG "#A92C2C" -#define COLOR_DARKMODE_BACKGROUND "#272727" -#define COLOR_DARKMODE_DARKBACKGROUND "#242424" -#define COLOR_DARKMODE_TEXT "#E0E0E0" - -#define COLOR_WHITEMODE_INFO_BUTTONS_BG "#90B3DD" -#define COLOR_WHITEMODE_ISSUE_BUTTON_BG "#EF7F7F" -#define COLOR_WHITEMODE_BACKGROUND "#F0F0F0" -#define COLOR_WHITEMODE_DARKBACKGROUND "#E6E6E6" -#define COLOR_WHITEMODE_TEXT "#000000" - #define COLOR_FLOORTILE_GRAY "#8D8B8B" #define COLOR_ALMOST_BLACK "#333333" #define COLOR_BLACK "#000000" @@ -64,4 +51,4 @@ #define COLOR_ASSEMBLY_LBLUE "#5D99BE" #define COLOR_ASSEMBLY_BLUE "#38559E" #define COLOR_ASSEMBLY_PURPLE "#6F6192" -#define COLOR_ASSEMBLY_PINK "#ff4adc" \ No newline at end of file +#define COLOR_ASSEMBLY_PINK "#ff4adc" diff --git a/code/__DEFINES/configuration.dm b/code/__DEFINES/configuration.dm index a4bf69b2ad..e9881677ba 100644 --- a/code/__DEFINES/configuration.dm +++ b/code/__DEFINES/configuration.dm @@ -1,6 +1,7 @@ //config files #define CONFIG_GET(X) global.config.Get(/datum/config_entry/##X) #define CONFIG_SET(X, Y) global.config.Set(/datum/config_entry/##X, ##Y) +/// Gets the datum of the object, for when editing a const define. #define CONFIG_GET_ENTRY(X) global.config.GetEntryDatum(/datum/config_entry/##X) #define CONFIG_MAPS_FILE "maps.txt" diff --git a/code/__DEFINES/dye_keys.dm b/code/__DEFINES/dye_keys.dm index 133f9c47d3..a01dcacc18 100644 --- a/code/__DEFINES/dye_keys.dm +++ b/code/__DEFINES/dye_keys.dm @@ -4,6 +4,7 @@ #define DYE_REGISTRY_SNEAKERS "sneakers" #define DYE_REGISTRY_FANNYPACK "fannypack" #define DYE_REGISTRY_BEDSHEET "bedsheet" +#define DYE_LAWYER_SPECIAL "lawyer_special" #define DYE_RED "red" #define DYE_ORANGE "orange" @@ -16,6 +17,7 @@ #define DYE_RAINBOW "rainbow" #define DYE_MIME "mime" #define DYE_COSMIC "cosmic" +#define DYE_SYNDICATE "syndicate" #define DYE_QM "qm" #define DYE_LAW "law" #define DYE_CAPTAIN "captain" @@ -26,3 +28,5 @@ #define DYE_CMO "cmo" #define DYE_REDCOAT "redcoat" #define DYE_CLOWN "clown" +#define DYE_CHAP "chap" +#define DYE_CENTCOM "centcom" diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm index 0e8e34d20e..df5b7d9f11 100644 --- a/code/__DEFINES/machines.dm +++ b/code/__DEFINES/machines.dm @@ -41,11 +41,13 @@ #define MC_HDD "HDD" #define MC_SDD "SDD" #define MC_CARD "CARD" +#define MC_CARD2 "CARD2" #define MC_NET "NET" #define MC_PRINT "PRINT" #define MC_CELL "CELL" #define MC_CHARGE "CHARGE" #define MC_AI "AI" +#define MC_SENSORS "SENSORS" //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/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 927b661898..0704947dda 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -116,6 +116,7 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s #define CRAYON_FONT "Comic Sans MS" #define PRINTER_FONT "Times New Roman" #define SIGNFONT "Times New Roman" +#define CHARCOAL_FONT "Candara" #define RESIZE_DEFAULT_SIZE 1 @@ -318,9 +319,9 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S #define SHELTER_DEPLOY_ANCHORED_OBJECTS "anchored objects" //debug printing macros -#define debug_world(msg) if (GLOB.Debug2) to_chat(world, "DEBUG: [msg]") -#define debug_usr(msg) if (GLOB.Debug2&&usr) to_chat(usr, "DEBUG: [msg]") -#define debug_admins(msg) if (GLOB.Debug2) to_chat(GLOB.admins, "DEBUG: [msg]") +#define debug_world(msg) if (GLOB.Debug2) to_chat(world, "DEBUG: [msg]") +#define debug_usr(msg) if (GLOB.Debug2&&usr) to_chat(usr, "DEBUG: [msg]") +#define debug_admins(msg) if (GLOB.Debug2) to_chat(GLOB.admins, "DEBUG: [msg]") #define debug_world_log(msg) if (GLOB.Debug2) log_world("DEBUG: [msg]") #define INCREMENT_TALLY(L, stat) if(L[stat]){L[stat]++}else{L[stat] = 1} diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 6ddd269b4b..9c39446a67 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -64,7 +64,6 @@ #define DEFAULT_BODYPART_ICON 'icons/mob/human_parts.dmi' #define DEFAULT_BODYPART_ICON_ORGANIC 'icons/mob/human_parts_greyscale.dmi' #define DEFAULT_BODYPART_ICON_ROBOTIC 'icons/mob/augmentation/augments.dmi' -#define DEFAULT_BODYPART_ICON_CITADEL 'modular_citadel/icons/mob/mutant_bodyparts.dmi' #define MONKEY_BODYPART "monkey" #define ALIEN_BODYPART "alien" @@ -333,4 +332,4 @@ /// If you examine the same atom twice in this timeframe, we call examine_more() instead of examine() #define EXAMINE_MORE_TIME 1 SECONDS -#define SILENCE_RANGED_MESSAGE (1<<0) +#define SILENCE_RANGED_MESSAGE (1<<0) diff --git a/code/__DEFINES/rockpaperscissors.dm b/code/__DEFINES/rockpaperscissors.dm new file mode 100644 index 0000000000..77ba81938d --- /dev/null +++ b/code/__DEFINES/rockpaperscissors.dm @@ -0,0 +1,7 @@ +#define ROCKPAPERSCISSORS_RANGE 3 +#define ROCKPAPERSCISSORS_TIME_LIMIT 20 SECONDS + +#define ROCKPAPERSCISSORS_LOSE "lose" +#define ROCKPAPERSCISSORS_WIN "win" +#define ROCKPAPERSCISSORS_TIE "tie" +#define ROCKPAPERSCISSORS_NOT_DECIDED "not_decided" \ No newline at end of file diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index bfff1dc629..d6db35e68d 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -30,6 +30,8 @@ #define STATUS_EFFECT_FLESHMEND /datum/status_effect/fleshmend //Very fast healing; suppressed by fire, and heals less fire damage +#define STATUS_EFFECT_PANACEA /datum/status_effect/panacea //Anatomic panacea that directly heals, rather than injecting a small chemical cocktail + #define STATUS_EFFECT_EXERCISED /datum/status_effect/exercised //Prevents heart disease #define STATUS_EFFECT_HIPPOCRATIC_OATH /datum/status_effect/hippocraticOath //Gives you an aura of healing as well as regrowing the Rod of Asclepius if lost diff --git a/code/__DEFINES/storage/volumetrics.dm b/code/__DEFINES/storage/volumetrics.dm index c3f45976ce..e6b732e083 100644 --- a/code/__DEFINES/storage/volumetrics.dm +++ b/code/__DEFINES/storage/volumetrics.dm @@ -24,7 +24,10 @@ GLOBAL_LIST_INIT(default_weight_class_to_volume, list( // Let's keep all of this in one place. given what we put above anyways.. // volume amount for items +/// volume for a data disk #define ITEM_VOLUME_DISK 1 +/// volume for a shotgun stripper clip holding 4 shells +#define ITEM_VOLUME_STRIPPER_CLIP (DEFAULT_VOLUME_NORMAL * 0.5) // #define SAMPLE_VOLUME_AMOUNT 2 diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 81b5c5620f..37ca1c66dd 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -93,7 +93,6 @@ // If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child) #define FIRE_PRIORITY_VORE 5 -#define FIRE_PRIORITY_PING 10 #define FIRE_PRIORITY_IDLE_NPC 10 #define FIRE_PRIORITY_SERVER_MAINT 10 #define FIRE_PRIORITY_RESEARCH 10 diff --git a/code/__DEFINES/tgui.dm b/code/__DEFINES/tgui.dm index f5adeadade..467058f27a 100644 --- a/code/__DEFINES/tgui.dm +++ b/code/__DEFINES/tgui.dm @@ -26,3 +26,10 @@ #define TGUI_WINDOW_ID(index) "tgui-window-[index]" /// Get a pool index of the provided window id #define TGUI_WINDOW_INDEX(window_id) text2num(copytext(window_id, 13)) + +/// Creates a message packet for sending via output() +#define TGUI_CREATE_MESSAGE(type, payload) ( \ + url_encode(json_encode(list( \ + "type" = type, \ + "payload" = payload, \ + )))) \ No newline at end of file diff --git a/code/__HELPERS/_cit_helpers.dm b/code/__HELPERS/_cit_helpers.dm index 5e57dd5328..a5ffda36f9 100644 --- a/code/__HELPERS/_cit_helpers.dm +++ b/code/__HELPERS/_cit_helpers.dm @@ -17,7 +17,7 @@ var/matrix/mtrx=new() return mtrx.Scale(0.65) -proc/get_racelist(var/mob/user)//This proc returns a list of species that 'user' has available to them. It searches the list of ckeys attached to the 'whitelist' var for a species and also checks if they're an admin. +/proc/get_racelist(mob/user)//This proc returns a list of species that 'user' has available to them. It searches the list of ckeys attached to the 'whitelist' var for a species and also checks if they're an admin. for(var/spath in subtypesof(/datum/species)) var/datum/species/S = new spath() var/list/wlist = S.whitelist diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 719735392d..0171057286 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -681,3 +681,11 @@ continue if(istype(D, path)) return TRUE + +/proc/safe_json_encode(list/L, default = "") + . = default + return json_encode(L) + +/proc/safe_json_decode(string, default = list()) + . = default + return json_decode(string) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 3155fe2548..11332863f5 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -1103,15 +1103,26 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0 alpha += 25 obj_flags &= ~FROZEN +/// Save file used in icon2base64. Used for converting icons to base64. +GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of icons for the browser output -//Converts an icon to base64. Operates by putting the icon in the iconCache savefile, -// exporting it as text, and then parsing the base64 from that. -// (This relies on byond automatically storing icons in savefiles as base64) -/proc/icon2base64(icon/icon, iconKey = "misc") + +/// Generate a filename for this asset +/// The same asset will always lead to the same asset name +/// (Generated names do not include file extention.) +/proc/generate_asset_name(file) + return "asset.[md5(fcopy_rsc(file))]" + +/** + * Converts an icon to base64. Operates by putting the icon in the iconCache savefile, + * exporting it as text, and then parsing the base64 from that. + * (This relies on byond automatically storing icons in savefiles as base64) + */ +/proc/icon2base64(icon/icon) if (!isicon(icon)) return FALSE - WRITE_FILE(GLOB.iconCache[iconKey], icon) - var/iconData = GLOB.iconCache.ExportText(iconKey) + WRITE_FILE(GLOB.dummySave["dummy"], icon) + var/iconData = GLOB.dummySave.ExportText("dummy") var/list/partial = splittext(iconData, "{") return replacetext(copytext_char(partial[2], 3, -5), "\n", "") @@ -1137,10 +1148,10 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0 if (isfile(thing)) //special snowflake var/name = sanitize_filename("[generate_asset_name(thing)].png") if(!SSassets.cache[name]) - register_asset(name, thing) + SSassets.transport.register_asset(name, thing) for (var/thing2 in targets) - send_asset(thing2, key) - return "" + SSassets.transport.send_assets(thing2, name) + return "" var/atom/A = thing if (isnull(dir)) dir = A.dir @@ -1162,11 +1173,11 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0 key = "[generate_asset_name(I)].png" if(!SSassets.cache[key]) - register_asset(key, I) + SSassets.transport.register_asset(key, I) for (var/thing2 in targets) - send_asset(thing2, key) + SSassets.transport.send_assets(thing2, key) - return "" + return "" /proc/icon2base64html(thing) if (!thing) diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index 045ca2c519..1d09057617 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -358,7 +358,7 @@ roundend_report.stylesheets = list() roundend_report.add_stylesheet("roundend", 'html/browser/roundend.css') roundend_report.add_stylesheet("font-awesome", 'html/font-awesome/css/all.min.css') - roundend_report.open(0) + roundend_report.open(FALSE) /datum/controller/subsystem/ticker/proc/personal_report(client/C, popcount) var/list/parts = list() @@ -402,7 +402,7 @@ for (var/i in GLOB.ai_list) var/mob/living/silicon/ai/aiPlayer = i if(aiPlayer.mind) - parts += "[aiPlayer.name] (Played by: [aiPlayer.mind.key])'s laws [aiPlayer.stat != DEAD ? "at the end of the round" : "when it was deactivated"] were:" + parts += "[aiPlayer.name][aiPlayer.mind.hide_ckey ? "" : " (Played by: [aiPlayer.mind.key])"]'s laws [aiPlayer.stat != DEAD ? "at the end of the round" : "when it was deactivated"] were:" parts += aiPlayer.laws.get_law_list(include_zeroth=TRUE) parts += "Total law changes: [aiPlayer.law_change_counter]" @@ -413,14 +413,14 @@ for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots) borg_num-- if(robo.mind) - robolist += "[robo.name] (Played by: [robo.mind.key])[robo.stat == DEAD ? " (Deactivated)" : ""][borg_num ?", ":""]
" + robolist += "[robo.name][robo.mind.hide_ckey ? "" : " (Played by: [robo.mind.key])"] [robo.stat == DEAD ? " (Deactivated)" : ""][borg_num ?", ":""]
" parts += "[robolist]" if(!borg_spacer) borg_spacer = TRUE for (var/mob/living/silicon/robot/robo in GLOB.silicon_mobs) if (!robo.connected_ai && robo.mind) - parts += "[borg_spacer?"
":""][robo.name] (Played by: [robo.mind.key]) [(robo.stat != DEAD)? "survived as an AI-less borg!" : "was unable to survive the rigors of being a cyborg without an AI."] Its laws were:" + parts += "[borg_spacer?"
":""][robo.name][robo.mind.hide_ckey ? "" : " (Played by: [robo.mind.key])"] [(robo.stat != DEAD)? "survived as an AI-less borg!" : "was unable to survive the rigors of being a cyborg without an AI."] Its laws were:" if(robo) //How the hell do we lose robo between here and the world messages directly above this? parts += robo.laws.get_law_list(include_zeroth=TRUE) @@ -529,7 +529,7 @@ var/jobtext = "" if(ply.assigned_role) jobtext = " the [ply.assigned_role]" - var/text = "[ply.key] was [ply.name][jobtext] and" + var/text = "[ply.hide_ckey ? "[ply.name][jobtext] " : "[ply.key] was [ply.name][jobtext] and "]" if(ply.current) if(ply.current.stat == DEAD) text += " died" diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index 7a18d2ce01..bbbf99c9de 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -462,16 +462,14 @@ else . = max(0, min(255, 138.5177312231 * log(temp - 10) - 305.0447927307)) -/proc/fusionpower2text(power) //used when displaying fusion power on analyzers - switch(power) - if(0 to 5) - return "low" - if(5 to 20) - return "mid" - if(20 to 50) - return "high" - if(50 to INFINITY) - return "super" +/proc/instability2text(instability) //used when displaying fusion power on analyzers + switch(instability) + if(0 to 2) + return "stable, meaning that its heat will always increase." + if(2 to 3) + return "metastable, meaning that its heat will trend upwards." + if (3 to INFINITY) + return "unstable, meaning that its heat will trend downwards." /proc/color2hex(color) //web colors if(!color) @@ -620,6 +618,12 @@ else //regex everything else (works for /proc too) return lowertext(replacetext("[the_type]", "[type2parent(the_type)]/", "")) + +/// Return html to load a url. +/// for use inside of browse() calls to html assets that might be loaded on a cdn. +/proc/url2htmlloader(url) + return {""} + /proc/strtohex(str) if(!istext(str)||!str) return diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index 8225725ffd..71c2b2e13b 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -278,3 +278,8 @@ GLOBAL_LIST_INIT(all_mutant_parts, list("tail_lizard" = "Tail", "mam_tail" = "Ta GLOBAL_LIST_INIT(unlocked_mutant_parts, list("horns", "insect_fluff")) //parts in either of the above two lists that require a second option that allows them to be coloured GLOBAL_LIST_INIT(colored_mutant_parts, list("insect_wings" = "wings_color", "deco_wings" = "wings_color", "horns" = "horns_color")) + +//species ids that have greyscale sprites +GLOBAL_LIST_INIT(greyscale_limb_types, list("human","moth","lizard","pod","plant","jelly","slime","golem","lum","stargazer","mush","ethereal","snail","c_golem","b_golem","mammal","xeno","ipc","insect","synthliz","avian","aquatic")) + +//species ids that need snowflake coloring applied diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm index 865f405442..14a1924e76 100644 --- a/code/_globalvars/lists/maintenance_loot.dm +++ b/code/_globalvars/lists/maintenance_loot.dm @@ -107,13 +107,8 @@ GLOBAL_LIST_INIT(maintenance_loot, list( /obj/item/toy/eightball = 1, /obj/item/reagent_containers/pill/floorpill = 1, /obj/item/reagent_containers/food/snacks/cannedpeaches/maint = 2, - /obj/item/storage/daki = 3, //VERY IMPORTANT CIT CHANGE - adds bodypillows to maint - /obj/item/storage/pill_bottle/penis_enlargement = 2, - /obj/item/storage/pill_bottle/breast_enlargement = 2, /obj/item/clothing/shoes/wheelys = 1, /obj/item/clothing/shoes/kindleKicks = 1, - /obj/item/autosurgeon/penis = 1, - /obj/item/autosurgeon/testicles = 1, /obj/item/storage/box/marshmallow = 2, /obj/item/clothing/gloves/tackler/offbrand = 1, /obj/item/stack/sticky_tape = 1, diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index 4de7c88bf7..706a5ed955 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -13,6 +13,7 @@ GLOBAL_LIST_EMPTY(deliverybeacontags) //list of all tags associated with d GLOBAL_LIST_EMPTY(nuke_list) GLOBAL_LIST_EMPTY(alarmdisplay) //list of all machines or programs that can display station alerts GLOBAL_LIST_EMPTY(singularities) //list of all singularities on the station (actually technically all engines) +GLOBAL_LIST_EMPTY(grounding_rods) //list of all grounding rods on the station GLOBAL_LIST(chemical_reactions_list) //list of all /datum/chemical_reaction datums. Used during chemical reactions GLOBAL_LIST(chemical_reagents_list) //list of all /datum/reagent datums indexed by reagent id. Used by chemistry stuff @@ -41,3 +42,6 @@ GLOBAL_LIST_EMPTY(ai_status_displays) GLOBAL_LIST_EMPTY(mob_spawners) // All mob_spawn objects GLOBAL_LIST_EMPTY(alert_consoles) // Station alert consoles, /obj/machinery/computer/station_alert + +//list of everyone playing rock paper scissors +GLOBAL_LIST_EMPTY(rockpaperscissors_players) diff --git a/code/_onclick/overmind.dm b/code/_onclick/overmind.dm index 8ace273dd8..419524c871 100644 --- a/code/_onclick/overmind.dm +++ b/code/_onclick/overmind.dm @@ -32,4 +32,4 @@ /mob/camera/blob/AltClickOn(atom/A) //Remove a blob var/turf/T = get_turf(A) if(T) - remove_blob(T) \ No newline at end of file + remove_blob(T) diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index 1c6e96f9e4..81f01219b8 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -14,13 +14,15 @@ var/list/modes // allowed modes var/list/gamemode_cache var/list/votable_modes // votable modes - // var/list/ic_filter_regex var/list/storyteller_cache var/list/mode_names var/list/mode_reports var/list/mode_false_report_weight var/motd + // var/policy + + // var/static/regex/ic_filter_regex /datum/controller/configuration/proc/admin_reload() if(IsAdminAdvancedProcCall()) @@ -50,6 +52,11 @@ break loadmaplist(CONFIG_MAPS_FILE) LoadMOTD() + // LoadPolicy() + // LoadChatFilter() + + if (Master) + Master.OnConfigLoad() /datum/controller/configuration/proc/full_wipe() if(IsAdminAdvancedProcCall()) @@ -135,7 +142,7 @@ if(entry == "$include") if(!value) - log_config("LINE [linenumber]: Invalid $include directive: [value]") + log_config("LINE [linenumber]: Warning: Invalid $include directive: [value]") else LoadEntries(value, stack) ++. @@ -143,7 +150,7 @@ var/datum/config_entry/E = _entries[entry] if(!E) - log_config("LINE [linenumber]: Unknown setting: '[entry]'") + log_config("LINE [linenumber]: Unknown setting in configuration: '[entry]'") continue if(lockthis) @@ -153,9 +160,9 @@ var/datum/config_entry/new_ver = entries_by_type[E.deprecated_by] var/new_value = E.DeprecationUpdate(value) var/good_update = istext(new_value) - log_config("LINE [linenumber]: [entry] is deprecated and will be removed soon. Migrate to [new_ver.name]![good_update ? " Suggested new value is: [new_value]" : ""]") + log_config("LINE [linenumber]: Entry [entry] is deprecated and will be removed soon. Migrate to [new_ver.name]![good_update ? " Suggested new value is: [new_value]" : ""]") if(!warned_deprecated_configs) - addtimer(CALLBACK(GLOBAL_PROC, /proc/message_admins, "This server is using deprecated configuration settings. Please check the logs and update accordingly."), 0) + DelayedMessageAdmins("This server is using deprecated configuration settings. Please check the logs and update accordingly.") warned_deprecated_configs = TRUE if(good_update) value = new_value @@ -163,7 +170,7 @@ else warning("[new_ver.type] is deprecated but gave no proper return for DeprecationUpdate()") - var/validated = E.ValidateAndSet(value, TRUE) + var/validated = E.ValidateAndSet(value) if(!validated) log_config("LINE [linenumber]: Failed to validate setting \"[value]\" for [entry]") else @@ -195,13 +202,7 @@ statclick = new/obj/effect/statclick/debug(null, "Edit", src) stat("[name]:", statclick) -/datum/controller/configuration/proc/Get(entry_type) - var/datum/config_entry/E = GetEntryDatum(entry_type) - if((E.protection & CONFIG_ENTRY_HIDDEN) && IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Get" && GLOB.LastAdminCalledTargetRef == "[REF(src)]") - log_admin_private("Config access of [entry_type] attempted by [key_name(usr)]") - return - return E.config_entry_value - +/// Your typical GET but returns a config. /datum/controller/configuration/proc/GetEntryDatum(entry_type) var/datum/config_entry/E = entry_type var/entry_is_abstract = initial(E.abstract_type) == entry_type @@ -210,8 +211,24 @@ E = entries_by_type[entry_type] if(!E) CRASH("Missing config entry for [entry_type]!") + if((E.protection & CONFIG_ENTRY_HIDDEN) && IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Get" && GLOB.LastAdminCalledTargetRef == "[REF(src)]") + log_admin_private("Config access of [entry_type] attempted by [key_name(usr)]") + return return E +/datum/controller/configuration/proc/Get(entry_type) + var/datum/config_entry/E = entry_type + var/entry_is_abstract = initial(E.abstract_type) == entry_type + if(entry_is_abstract) + CRASH("Tried to retrieve an abstract config_entry: [entry_type]") + E = entries_by_type[entry_type] + if(!E) + CRASH("Missing config entry for [entry_type]!") + if((E.protection & CONFIG_ENTRY_HIDDEN) && IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Get" && GLOB.LastAdminCalledTargetRef == "[REF(src)]") + log_admin_private("Config access of [entry_type] attempted by [key_name(usr)]") + return + return E.config_entry_value + /datum/controller/configuration/proc/Set(entry_type, new_val) var/datum/config_entry/E = entry_type var/entry_is_abstract = initial(E.abstract_type) == entry_type @@ -236,7 +253,6 @@ for(var/T in gamemode_cache) // I wish I didn't have to instance the game modes in order to look up // their information, but it is the only way (at least that I know of). - // for future reference: just use initial() lol var/datum/game_mode/M = new T() if(M.config_tag) @@ -258,7 +274,37 @@ var/tm_info = GLOB.revdata.GetTestMergeInfo() if(motd || tm_info) motd = motd ? "[motd]
[tm_info]" : tm_info +/* +Policy file should be a json file with a single object. +Value is raw html. +Possible keywords : +Job titles / Assigned roles (ghost spawners for example) : Assistant , Captain , Ash Walker +Mob types : /mob/living/simple_animal/hostile/carp +Antagonist types : /datum/antagonist/highlander +Species types : /datum/species/lizard +special keywords defined in _DEFINES/admin.dm + +Example config: +{ + "Assistant" : "Don't kill everyone", + "/datum/antagonist/highlander" : "Kill everyone", + "Ash Walker" : "Kill all spacemans" +} + +*/ +/* +/datum/controller/configuration/proc/LoadPolicy() + policy = list() + var/rawpolicy = file2text("[directory]/policy.json") + if(rawpolicy) + var/parsed = safe_json_decode(rawpolicy) + if(!parsed) + log_config("JSON parsing failure for policy.json") + DelayedMessageAdmins("JSON parsing failure for policy.json") + else + policy = parsed +*/ /datum/controller/configuration/proc/loadmaplist(filename) log_config("Loading config file [filename]...") filename = "[directory]/[filename]" @@ -305,6 +351,8 @@ currentmap.voteweight = text2num(data) if ("default","defaultmap") defaultmap = currentmap + //if ("votable") + // currentmap.votable = TRUE if ("endmap") LAZYINITLIST(maplist) maplist[currentmap.map_name] = currentmap @@ -326,6 +374,7 @@ return new T return new /datum/game_mode/extended() +/// For dynamic. /datum/controller/configuration/proc/pick_storyteller(storyteller_name) for(var/T in storyteller_cache) var/datum/dynamic_storyteller/S = T @@ -334,6 +383,32 @@ return T return /datum/dynamic_storyteller/classic +/// Same with this +/datum/controller/configuration/proc/get_runnable_storytellers() + var/list/datum/dynamic_storyteller/runnable_storytellers = new + var/list/probabilities = Get(/datum/config_entry/keyed_list/storyteller_weight) + var/list/repeated_mode_adjust = Get(/datum/config_entry/number_list/repeated_mode_adjust) + var/list/min_player_counts = Get(/datum/config_entry/keyed_list/storyteller_min_players) + for(var/T in storyteller_cache) + var/datum/dynamic_storyteller/S = T + var/config_tag = initial(S.config_tag) + var/probability = (config_tag in probabilities) ? probabilities[config_tag] : initial(S.weight) + var/min_players = (config_tag in min_player_counts) ? min_player_counts[config_tag] : initial(S.min_players) + if(probability <= 0) + continue + if(length(GLOB.player_list) < min_players) + continue + if(SSpersistence.saved_storytellers.len == repeated_mode_adjust.len) + var/name = initial(S.name) + var/recent_round = min(SSpersistence.saved_storytellers.Find(name),3) + var/adjustment = 0 + while(recent_round) + adjustment += repeated_mode_adjust[recent_round] + recent_round = SSpersistence.saved_modes.Find(name,recent_round+1,0) + probability *= ((100-adjustment)/100) + runnable_storytellers[S] = probability + return runnable_storytellers + /datum/controller/configuration/proc/get_runnable_modes() var/list/datum/game_mode/runnable_modes = new var/list/probabilities = Get(/datum/config_entry/keyed_list/probability) @@ -367,32 +442,6 @@ runnable_modes[M] = final_weight return runnable_modes -/datum/controller/configuration/proc/get_runnable_storytellers() - var/list/datum/dynamic_storyteller/runnable_storytellers = new - var/list/probabilities = Get(/datum/config_entry/keyed_list/storyteller_weight) - var/list/repeated_mode_adjust = Get(/datum/config_entry/number_list/repeated_mode_adjust) - var/list/min_player_counts = Get(/datum/config_entry/keyed_list/storyteller_min_players) - for(var/T in storyteller_cache) - var/datum/dynamic_storyteller/S = T - var/config_tag = initial(S.config_tag) - var/probability = (config_tag in probabilities) ? probabilities[config_tag] : initial(S.weight) - var/min_players = (config_tag in min_player_counts) ? min_player_counts[config_tag] : initial(S.min_players) - if(probability <= 0) - continue - if(length(GLOB.player_list) < min_players) - continue - if(SSpersistence.saved_storytellers.len == repeated_mode_adjust.len) - var/name = initial(S.name) - var/recent_round = min(SSpersistence.saved_storytellers.Find(name),3) - var/adjustment = 0 - while(recent_round) - adjustment += repeated_mode_adjust[recent_round] - recent_round = SSpersistence.saved_modes.Find(name,recent_round+1,0) - probability *= ((100-adjustment)/100) - runnable_storytellers[S] = probability - return runnable_storytellers - - /datum/controller/configuration/proc/get_runnable_midround_modes(crew) var/list/datum/game_mode/runnable_modes = new var/list/probabilities = Get(/datum/config_entry/keyed_list/probability) @@ -418,7 +467,6 @@ /* /datum/controller/configuration/proc/LoadChatFilter() var/list/in_character_filter = list() - if(!fexists("[directory]/in_character_filter.txt")) return log_config("Loading config file in_character_filter.txt...") @@ -428,8 +476,8 @@ if(findtextEx(line,"#",1,2)) continue in_character_filter += REGEX_QUOTE(line) - ic_filter_regex = in_character_filter.len ? regex("\\b([jointext(in_character_filter, "|")])\\b", "i") : null - - syncChatRegexes() */ +//Message admins when you can. +/datum/controller/configuration/proc/DelayedMessageAdmins(text) + addtimer(CALLBACK(GLOBAL_PROC, /proc/message_admins, text), 0) diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 2d5e69f149..273ac7fd3e 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -368,6 +368,10 @@ /datum/config_entry/flag/allow_map_voting +/datum/config_entry/number/client_warn_version + config_entry_value = null + min_val = 500 + /datum/config_entry/number/client_warn_version config_entry_value = null min_val = 500 @@ -384,6 +388,10 @@ /datum/config_entry/string/client_error_message config_entry_value = "Your version of byond is too old, may have issues, and is blocked from accessing this server." +/datum/config_entry/number/client_error_build + config_entry_value = null + min_val = 0 + /datum/config_entry/number/minute_topic_limit config_entry_value = null min_val = 0 diff --git a/code/controllers/configuration/entries/resources.dm b/code/controllers/configuration/entries/resources.dm new file mode 100644 index 0000000000..c839ccc078 --- /dev/null +++ b/code/controllers/configuration/entries/resources.dm @@ -0,0 +1,30 @@ +/datum/config_entry/keyed_list/external_rsc_urls + key_mode = KEY_MODE_TEXT + value_mode = VALUE_MODE_FLAG + +/datum/config_entry/flag/asset_simple_preload + +/datum/config_entry/string/asset_transport +/datum/config_entry/string/asset_transport/ValidateAndSet(str_val) + return (lowertext(str_val) in list("simple", "webroot")) && ..(lowertext(str_val)) + +/datum/config_entry/string/asset_cdn_webroot + protection = CONFIG_ENTRY_LOCKED + +/datum/config_entry/string/asset_cdn_webroot/ValidateAndSet(str_var) + if (!str_var || trim(str_var) == "") + return FALSE + if (str_var && str_var[length(str_var)] != "/") + str_var += "/" + return ..(str_var) + +/datum/config_entry/string/asset_cdn_url + protection = CONFIG_ENTRY_LOCKED + default = null + +/datum/config_entry/string/asset_cdn_url/ValidateAndSet(str_var) + if (!str_var || trim(str_var) == "") + return FALSE + if (str_var && str_var[length(str_var)] != "/") + str_var += "/" + return ..(str_var) diff --git a/code/controllers/controller.dm b/code/controllers/controller.dm index 06547d120d..c9d5f1e565 100644 --- a/code/controllers/controller.dm +++ b/code/controllers/controller.dm @@ -16,4 +16,4 @@ /datum/controller/proc/Recover() -/datum/controller/proc/stat_entry() \ No newline at end of file +/datum/controller/proc/stat_entry() diff --git a/code/controllers/master.dm b/code/controllers/master.dm index cdbea1de85..8a381558a9 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -76,7 +76,11 @@ GLOBAL_REAL(Master, /datum/controller/master) = new // Highlander-style: there can only be one! Kill off the old and replace it with the new. if(!random_seed) - random_seed = (TEST_RUN_PARAMETER in world.params) ? 29051994 : rand(1, 1e9) + #ifdef UNIT_TESTS + random_seed = 29051994 + #else + random_seed = rand(1, 1e9) + #endif rand_seed(random_seed) var/list/_subsystems = list() @@ -184,9 +188,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new if(delay) sleep(delay) - if(tgs_prime) - world.TgsInitializationComplete() - if(init_sss) init_subtypes(/datum/controller/subsystem, subsystems) @@ -219,6 +220,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new world.fps = CONFIG_GET(number/fps) var/initialized_tod = REALTIMEOFDAY + if(tgs_prime) + world.TgsInitializationComplete() + if(sleep_offline_after_initializations) world.sleep_offline = TRUE sleep(1) @@ -643,3 +647,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new processing = CONFIG_GET(number/mc_tick_rate/base_mc_tick_rate) else if (client_count > CONFIG_GET(number/mc_tick_rate/high_pop_mc_mode_amount)) processing = CONFIG_GET(number/mc_tick_rate/high_pop_mc_tick_rate) + +/datum/controller/master/proc/OnConfigLoad() + for (var/thing in subsystems) + var/datum/controller/subsystem/SS = thing + SS.OnConfigLoad() diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index 4ee3a01956..ce582f52f9 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -1,39 +1,91 @@ +/** + * # Subsystem base class + * + * Defines a subsystem to be managed by the [Master Controller][/datum/controller/master] + * + * Simply define a child of this subsystem, using the [SUBSYSTEM_DEF] macro, and the MC will handle registration. + * Changing the name is required +**/ /datum/controller/subsystem // Metadata; you should define these. - name = "fire coderbus" //name of the subsystem - var/init_order = INIT_ORDER_DEFAULT //order of initialization. Higher numbers are initialized first, lower numbers later. Use defines in __DEFINES/subsystems.dm for easy understanding of order. - var/wait = 20 //time to wait (in deciseconds) between each call to fire(). Must be a positive integer. - var/priority = FIRE_PRIORITY_DEFAULT //When mutiple subsystems need to run in the same tick, higher priority subsystems will run first and be given a higher share of the tick before MC_TICK_CHECK triggers a sleep - var/flags = 0 //see MC.dm in __DEFINES Most flags must be set on world start to take full effect. (You can also restart the mc to force them to process again) + /// Name of the subsystem - you must change this + name = "fire coderbus" - var/initialized = FALSE //set to TRUE after it has been initialized, will obviously never be set if the subsystem doesn't initialize + /// Order of initialization. Higher numbers are initialized first, lower numbers later. Use or create defines such as [INIT_ORDER_DEFAULT] so we can see the order in one file. + var/init_order = INIT_ORDER_DEFAULT - //set to 0 to prevent fire() calls, mostly for admin use or subsystems that may be resumed later - // use the SS_NO_FIRE flag instead for systems that never fire to keep it from even being added to the list + /// Time to wait (in deciseconds) between each call to fire(). Must be a positive integer. + var/wait = 20 + + /// Priority Weight: When mutiple subsystems need to run in the same tick, higher priority subsystems will be given a higher share of the tick before MC_TICK_CHECK triggers a sleep, higher priority subsystems also run before lower priority subsystems + var/priority = FIRE_PRIORITY_DEFAULT + + /// [Subsystem Flags][SS_NO_INIT] to control binary behavior. Flags must be set at compile time or before preinit finishes to take full effect. (You can also restart the mc to force them to process again) + var/flags = 0 + + /// This var is set to TRUE after the subsystem has been initialized. + var/initialized = FALSE + + /// Set to 0 to prevent fire() calls, mostly for admin use or subsystems that may be resumed later + /// use the [SS_NO_FIRE] flag instead for systems that never fire to keep it from even being added to list that is checked every tick var/can_fire = TRUE - // Bookkeeping variables; probably shouldn't mess with these. - var/last_fire = 0 //last world.time we called fire() - var/next_fire = 0 //scheduled world.time for next fire() - var/cost = 0 //average time to execute - var/tick_usage = 0 //average tick usage - var/tick_overrun = 0 //average tick overrun - var/state = SS_IDLE //tracks the current state of the ss, running, paused, etc. - var/paused_ticks = 0 //ticks this ss is taking to run right now. - var/paused_tick_usage //total tick_usage of all of our runs while pausing this run - var/ticks = 1 //how many ticks does this ss take to run on avg. - var/times_fired = 0 //number of times we have called fire() - var/queued_time = 0 //time we entered the queue, (for timing and priority reasons) - var/queued_priority //we keep a running total to make the math easier, if priority changes mid-fire that would break our running total, so we store it here - //linked list stuff for the queue - var/datum/controller/subsystem/queue_next - var/datum/controller/subsystem/queue_prev - + ///Bitmap of what game states can this subsystem fire at. See [RUNLEVELS_DEFAULT] for more details. var/runlevels = RUNLEVELS_DEFAULT //points of the game at which the SS can fire - var/static/list/failure_strikes //How many times we suspect a subsystem type has crashed the MC, 3 strikes and you're out! + /* + * The following variables are managed by the MC and should not be modified directly. + */ + + /// Last world.time the subsystem completed a run (as in wasn't paused by [MC_TICK_CHECK]) + var/last_fire = 0 + + /// Scheduled world.time for next fire() + var/next_fire = 0 + + /// Running average of the amount of milliseconds it takes the subsystem to complete a run (including all resumes but not the time spent paused) + var/cost = 0 + + /// Running average of the amount of tick usage in percents of a tick it takes the subsystem to complete a run + var/tick_usage = 0 + + /// Running average of the amount of tick usage (in percents of a game tick) the subsystem has spent past its allocated time without pausing + var/tick_overrun = 0 + + /// Tracks the current execution state of the subsystem. Used to handle subsystems that sleep in fire so the mc doesn't run them again while they are sleeping + var/state = SS_IDLE + + /// Tracks how many fires the subsystem has consecutively paused on in the current run + var/paused_ticks = 0 + + /// Tracks how much of a tick the subsystem has consumed in the current run + var/paused_tick_usage + + /// Tracks how many fires the subsystem takes to complete a run on average. + var/ticks = 1 + + /// Tracks the amount of completed runs for the subsystem + var/times_fired = 0 + + /// Time the subsystem entered the queue, (for timing and priority reasons) + var/queued_time = 0 + + /// Priority at the time the subsystem entered the queue. Needed to avoid changes in priority (by admins and the like) from breaking things. + var/queued_priority + + /// How many times we suspect a subsystem type has crashed the MC, 3 strikes and you're out! + var/static/list/failure_strikes + + /// Next subsystem in the queue of subsystems to run this tick + var/datum/controller/subsystem/queue_next + /// Previous subsystem in the queue of subsystems to run this tick + var/datum/controller/subsystem/queue_prev + + //Do not blindly add vars here to the bottom, put it where it goes above + //If your var only has two values, put it in as a flag. + //Do not override ///datum/controller/subsystem/New() @@ -46,6 +98,7 @@ //This is used so the mc knows when the subsystem sleeps. do not override. /datum/controller/subsystem/proc/ignite(resumed = 0) + SHOULD_NOT_OVERRIDE(TRUE) set waitfor = 0 . = SS_SLEEPING fire(resumed) @@ -87,7 +140,7 @@ queue_node_flags = queue_node.flags if (queue_node_flags & SS_TICKER) - if (!(SS_flags & SS_TICKER)) + if ((SS_flags & (SS_TICKER|SS_BACKGROUND)) != SS_TICKER) continue if (queue_node_priority < SS_priority) break @@ -155,6 +208,9 @@ if(SS_SLEEPING) state = SS_PAUSING +/// Called after the config has been loaded or reloaded. +/datum/controller/subsystem/proc/OnConfigLoad() + /datum/controller/subsystem/proc/subsystem_log(msg) return log_subsystem(name, msg) diff --git a/code/controllers/subsystem/assets.dm b/code/controllers/subsystem/assets.dm index 7285298283..4f02d32ad0 100644 --- a/code/controllers/subsystem/assets.dm +++ b/code/controllers/subsystem/assets.dm @@ -4,6 +4,23 @@ SUBSYSTEM_DEF(assets) flags = SS_NO_FIRE var/list/cache = list() var/list/preload = list() + var/datum/asset_transport/transport = new() + +/datum/controller/subsystem/assets/OnConfigLoad() + var/newtransporttype = /datum/asset_transport + switch (CONFIG_GET(string/asset_transport)) + if ("webroot") + newtransporttype = /datum/asset_transport/webroot + + if (newtransporttype == transport.type) + return + + var/datum/asset_transport/newtransport = new newtransporttype () + if (newtransport.validate_config()) + transport = newtransport + transport.Load() + + /datum/controller/subsystem/assets/Initialize(timeofday) for(var/type in typesof(/datum/asset)) @@ -11,8 +28,6 @@ SUBSYSTEM_DEF(assets) if (type != initial(A._abstract)) get_asset_datum(type) - preload = cache.Copy() //don't preload assets generated during the round + transport.Initialize(cache) - for(var/client/C in GLOB.clients) - addtimer(CALLBACK(GLOBAL_PROC, .proc/getFilesSlow, C, preload, FALSE), 10) ..() diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm index ba2794d00f..a4f8dfdc5d 100644 --- a/code/controllers/subsystem/chat.dm +++ b/code/controllers/subsystem/chat.dm @@ -5,91 +5,35 @@ SUBSYSTEM_DEF(chat) priority = FIRE_PRIORITY_CHAT init_order = INIT_ORDER_CHAT - var/list/payload = list() - + var/list/payload_by_client = list() /datum/controller/subsystem/chat/fire() - for(var/i in payload) - var/client/C = i - C << output(payload[C], "browseroutput:output") - payload -= C - + for(var/key in payload_by_client) + var/client/client = key + var/payload = payload_by_client[key] + payload_by_client -= key + if(client) + // Send to tgchat + client.tgui_panel?.window.send_message("chat/message", payload) + // Send to old chat + for(var/msg in payload) + SEND_TEXT(client, msg["text"]) if(MC_TICK_CHECK) return - -/datum/controller/subsystem/chat/proc/queue(target, message, handle_whitespace = TRUE, trailing_newline = TRUE, confidential = TRUE) - if(!target || !message) - return - - if(!istext(message)) - stack_trace("to_chat called with invalid input type") - return - - if(target == world) - target = GLOB.clients - - //Some macros remain in the string even after parsing and fuck up the eventual output - var/original_message = message - - //url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript. - //Do the double-encoding here to save nanoseconds - var/twiceEncoded - +/datum/controller/subsystem/chat/proc/queue(target, text, flags) if(islist(target)) - var/sanitized_message = FALSE - for(var/I in target) - var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible - - if(!C) - continue - - //Send it to the old style output window. - SEND_TEXT(C, original_message) - - if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file. - continue - - if(!sanitized_message) - message = replacetext(message, "\improper", "") - message = replacetext(message, "\proper", "") - if(handle_whitespace) - message = replacetext(message, "\n", "
") - message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]") - if (trailing_newline) - message += "
" - twiceEncoded = url_encode(url_encode(message)) - sanitized_message = TRUE - - if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue - C.chatOutput.messageQueue += message - continue - - payload[C] += twiceEncoded - - else - var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible - - if(!C) - return - - //Send it to the old style output window. - SEND_TEXT(C, original_message) - - if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file. - return - - message = replacetext(message, "\improper", "") - message = replacetext(message, "\proper", "") - if(handle_whitespace) - message = replacetext(message, "\n", "
") - message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]") - if (trailing_newline) - message += "
" - twiceEncoded = url_encode(url_encode(message)) - - if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue - C.chatOutput.messageQueue += message - return - - payload[C] += twiceEncoded + for(var/_target in target) + var/client/client = CLIENT_FROM_VAR(_target) + if(client) + LAZYADD(payload_by_client[client], list(list( + "text" = text, + "flags" = flags, + ))) + return + var/client/client = CLIENT_FROM_VAR(target) + if(client) + LAZYADD(payload_by_client[client], list(list( + "text" = text, + "flags" = flags, + ))) diff --git a/code/controllers/subsystem/ping.dm b/code/controllers/subsystem/ping.dm deleted file mode 100644 index c5c9bb3933..0000000000 --- a/code/controllers/subsystem/ping.dm +++ /dev/null @@ -1,33 +0,0 @@ -SUBSYSTEM_DEF(ping) - name = "Ping" - priority = FIRE_PRIORITY_PING - wait = 3 SECONDS - flags = SS_NO_INIT - runlevels = RUNLEVEL_LOBBY | RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME - - var/list/currentrun = list() - -/datum/controller/subsystem/ping/stat_entry() - ..("P:[GLOB.clients.len]") - - -/datum/controller/subsystem/ping/fire(resumed = 0) - if (!resumed) - src.currentrun = GLOB.clients.Copy() - - //cache for sanic speed (lists are references anyways) - var/list/currentrun = src.currentrun - - while (currentrun.len) - var/client/C = currentrun[currentrun.len] - currentrun.len-- - - if (!C || !C.chatOutput || !C.chatOutput.loaded) - if (MC_TICK_CHECK) - return - continue - - // softPang isn't handled anywhere but it'll always reset the opts.lastPang. - C.chatOutput.ehjax_send(data = C.is_afk(29) ? "softPang" : "pang") - if (MC_TICK_CHECK) - return diff --git a/code/controllers/subsystem/processing/instruments.dm b/code/controllers/subsystem/processing/instruments.dm index a4e0d7703f..ee0fd1ea00 100644 --- a/code/controllers/subsystem/processing/instruments.dm +++ b/code/controllers/subsystem/processing/instruments.dm @@ -4,16 +4,26 @@ PROCESSING_SUBSYSTEM_DEF(instruments) init_order = INIT_ORDER_INSTRUMENTS flags = SS_KEEP_TIMING priority = FIRE_PRIORITY_INSTRUMENTS - var/static/list/datum/instrument/instrument_data = list() //id = datum + /// List of all instrument data, associative id = datum + var/static/list/datum/instrument/instrument_data = list() + /// List of all song datums. var/static/list/datum/song/songs = list() + /// Max lines in songs var/static/musician_maxlines = 600 + /// Max characters per line in songs var/static/musician_maxlinechars = 300 + /// Deciseconds between hearchecks. Too high and instruments seem to lag when people are moving around in terms of who can hear it. Too low and the server lags from this. var/static/musician_hearcheck_mindelay = 5 + /// Maximum instrument channels total instruments are allowed to use. This is so you don't have instruments deadlocking all sound channels. var/static/max_instrument_channels = MAX_INSTRUMENT_CHANNELS + /// Current number of channels allocated for instruments var/static/current_instrument_channels = 0 + /// Single cached list for synthesizer instrument ids, so you don't have to have a new list with every synthesizer. + var/static/list/synthesizer_instrument_ids /datum/controller/subsystem/processing/instruments/Initialize() initialize_instrument_data() + synthesizer_instrument_ids = get_allowed_instrument_ids() return ..() /datum/controller/subsystem/processing/instruments/proc/on_song_new(datum/song/S) @@ -29,7 +39,10 @@ PROCESSING_SUBSYSTEM_DEF(instruments) continue I = new path I.Initialize() - instrument_data[I.id || "[I.type]"] = I + if(!I.id) + qdel(I) + continue + instrument_data[I.id] = I CHECK_TICK /datum/controller/subsystem/processing/instruments/proc/get_instrument(id_or_path) diff --git a/code/controllers/subsystem/server_maint.dm b/code/controllers/subsystem/server_maint.dm index b77c78c4bb..2427fbd277 100644 --- a/code/controllers/subsystem/server_maint.dm +++ b/code/controllers/subsystem/server_maint.dm @@ -76,9 +76,7 @@ SUBSYSTEM_DEF(server_maint) if(!thing) continue var/client/C = thing - var/datum/chatOutput/co = C.chatOutput - if(co) - co.ehjax_send(data = "roundrestart") + C?.tgui_panel?.send_roundrestart() if(server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite C << link("byond://[server]") var/datum/tgs_version/tgsversion = world.TgsVersion() diff --git a/code/datums/accents.dm b/code/datums/accents.dm new file mode 100644 index 0000000000..edfdfb9fee --- /dev/null +++ b/code/datums/accents.dm @@ -0,0 +1,106 @@ +/datum/accent + +/datum/accent/proc/modify_speech(list/speech_args, datum/source, mob/living/carbon/owner) //transforms the message in some way + return speech_args + +/datum/accent/lizard/modify_speech(list/speech_args) + var/message = speech_args[SPEECH_MESSAGE] + var/static/regex/lizard_hiss = new("s+", "g") + var/static/regex/lizard_hiSS = new("S+", "g") + if(message[1] != "*") + message = lizard_hiss.Replace(message, "sss") + message = lizard_hiSS.Replace(message, "SSS") + speech_args[SPEECH_MESSAGE] = message + return speech_args + +/datum/accent/fly/modify_speech(list/speech_args) + var/message = speech_args[SPEECH_MESSAGE] + var/static/regex/fly_buzz = new("z+", "g") + var/static/regex/fly_buZZ = new("Z+", "g") + if(message[1] != "*") + message = fly_buzz.Replace(message, "zzz") + message = fly_buZZ.Replace(message, "ZZZ") + speech_args[SPEECH_MESSAGE] = message + return speech_args + +/datum/accent/abductor/modify_speech(list/speech_args, datum/source) + var/message = speech_args[SPEECH_MESSAGE] + var/mob/living/carbon/human/user = source + var/rendered = "[user.name]: [message]" + user.log_talk(message, LOG_SAY, tag="abductor") + for(var/mob/living/carbon/human/H in GLOB.alive_mob_list) + var/obj/item/organ/tongue/T = H.getorganslot(ORGAN_SLOT_TONGUE) + if(!T || T.type != type) + continue + if(H.dna && H.dna.species.id == "abductor" && user.dna && user.dna.species.id == "abductor") + var/datum/antagonist/abductor/A = user.mind.has_antag_datum(/datum/antagonist/abductor) + if(!A || !(H.mind in A.team.members)) + continue + to_chat(H, rendered) + for(var/mob/M in GLOB.dead_mob_list) + var/link = FOLLOW_LINK(M, user) + to_chat(M, "[link] [rendered]") + speech_args[SPEECH_MESSAGE] = "" + return speech_args + +/datum/accent/zombie/modify_speech(list/speech_args) + var/message = speech_args[SPEECH_MESSAGE] + var/list/message_list = splittext(message, " ") + var/maxchanges = max(round(message_list.len / 1.5), 2) + + for(var/i = rand(maxchanges / 2, maxchanges), i > 0, i--) + var/insertpos = rand(1, message_list.len - 1) + var/inserttext = message_list[insertpos] + + if(!(copytext(inserttext, -3) == "..."))//3 == length("...") + message_list[insertpos] = inserttext + "..." + + if(prob(20) && message_list.len > 3) + message_list.Insert(insertpos, "[pick("BRAINS", "Brains", "Braaaiinnnsss", "BRAAAIIINNSSS")]...") + + speech_args[SPEECH_MESSAGE] = jointext(message_list, " ") + return speech_args + +/datum/accent/alien/modify_speech(list/speech_args, datum/source) + playsound(source, "hiss", 25, 1, 1) + return speech_args + +/datum/accent/fluffy/modify_speech(list/speech_args) + var/message = speech_args[SPEECH_MESSAGE] + if(message[1] != "*") + message = replacetext(message, "ne", "nye") + message = replacetext(message, "nu", "nyu") + message = replacetext(message, "na", "nya") + message = replacetext(message, "no", "nyo") + message = replacetext(message, "ove", "uv") + message = replacetext(message, "l", "w") + message = replacetext(message, "r", "w") + speech_args[SPEECH_MESSAGE] = lowertext(message) + return speech_args + +/datum/accent/bone + var/span_flag + +/datum/accent/bone/modify_speech(list/speech_args) + speech_args[SPEECH_SPANS] = span_flag + return speech_args + +//bone tongues either have the sans accent or the papyrus accent +/datum/accent/bone/sans + span_flag = SPAN_SANS + +/datum/accent/bone/papyrus + span_flag = SPAN_PAPYRUS + +/datum/accent/robot/modify_speech(list/speech_args) + speech_args[SPEECH_SPANS] = SPAN_ROBOT + +/datum/accent/dullahan/modify_speech(list/speech_args, datum/source, mob/living/carbon/owner) + if(owner) + if(isdullahan(owner)) + var/datum/species/dullahan/D = owner.dna.species + if(isobj(D.myhead.loc)) + var/obj/O = D.myhead.loc + O.say(speech_args[SPEECH_MESSAGE]) + speech_args[SPEECH_MESSAGE] = "" + return speech_args diff --git a/code/datums/browser.dm b/code/datums/browser.dm index 96b2a2a294..dbe60817bd 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -8,14 +8,14 @@ var/window_options = "can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id var/stylesheets[0] var/scripts[0] - var/title_image var/head_elements var/body_elements var/head_content = "" var/content = "" + var/static/datum/asset/simple/namespaced/common/common_asset = get_asset_datum(/datum/asset/simple/namespaced/common) -/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null) +/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, atom/nref = null) user = nuser window_id = nwindow_id @@ -27,7 +27,6 @@ height = nheight if (nref) ref = nref - add_stylesheet("common", 'html/browser/common.css') // this CSS sheet is common to all UIs /datum/browser/proc/add_head_content(nhead_content) head_content = nhead_content @@ -35,22 +34,21 @@ /datum/browser/proc/set_window_options(nwindow_options) window_options = nwindow_options -/datum/browser/proc/set_title_image(ntitle_image) - //title_image = ntitle_image - /datum/browser/proc/add_stylesheet(name, file) if(istype(name, /datum/asset/spritesheet)) var/datum/asset/spritesheet/sheet = name stylesheets["spritesheet_[sheet.name].css"] = "data/spritesheets/[sheet.name]" else var/asset_name = "[name].css" + stylesheets[asset_name] = file - if(!SSassets.cache[asset_name]) - register_asset(asset_name, file) + + if (!SSassets.cache[asset_name]) + SSassets.transport.register_asset(asset_name, file) /datum/browser/proc/add_script(name, file) scripts["[ckey(name)].js"] = file - register_asset("[ckey(name)].js", file) + SSassets.transport.register_asset("[ckey(name)].js", file) /datum/browser/proc/set_content(ncontent) content = ncontent @@ -60,15 +58,13 @@ /datum/browser/proc/get_header() var/file + head_content += "" for (file in stylesheets) - head_content += "" + head_content += "" + for (file in scripts) - head_content += "" - - var/title_attributes = "class='uiTitle'" - if (title_image) - title_attributes = "class='uiTitle icon' style='background-image: url([title_image]);'" + head_content += "" return {" @@ -79,7 +75,7 @@
- [title ? "
[title]
" : ""] + [title ? "
[title]
" : ""]
"} //" This is here because else the rest of the file looks like a string in notepad++. @@ -105,10 +101,11 @@ var/window_size = "" if(width && height) window_size = "size=[width]x[height];" + common_asset.send(user) if(stylesheets.len) - send_asset_list(user, stylesheets) + SSassets.transport.send_assets(user, stylesheets) if(scripts.len) - send_asset_list(user, scripts) + SSassets.transport.send_assets(user, scripts) user << browse(get_content(), "window=[window_id];[window_size][window_options]") if(use_onclose) setup_onclose() @@ -169,7 +166,7 @@ return Button3 //Same shit, but it returns the button number, could at some point support unlimited button amounts. -/proc/askuser(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000) +/proc/askuser(mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000) if (!istype(User)) if (istype(User, /client/)) var/client/C = User @@ -188,7 +185,7 @@ var/selectedbutton = 0 var/stealfocus -/datum/browser/modal/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null, StealFocus = 1, Timeout = 6000) +/datum/browser/modal/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, atom/nref = null, StealFocus = 1, Timeout = 6000) ..() stealfocus = StealFocus if (!StealFocus) diff --git a/code/datums/components/honkspam.dm b/code/datums/components/honkspam.dm new file mode 100644 index 0000000000..73b5e3335a --- /dev/null +++ b/code/datums/components/honkspam.dm @@ -0,0 +1,22 @@ +// This used to be in paper.dm, it was some snowflake code that was +// used ONLY on april's fool. I moved it to a component so it could be +// used in other places + +/datum/component/honkspam + dupe_mode = COMPONENT_DUPE_UNIQUE + var/spam_flag = FALSE + +/datum/component/honkspam/Initialize() + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/interact) + +/datum/component/honkspam/proc/reset_spamflag() + spam_flag = FALSE + +/datum/component/honkspam/proc/interact(mob/user) + if(!spam_flag) + spam_flag = TRUE + var/obj/item/parent_item = parent + playsound(parent_item.loc, 'sound/items/bikehorn.ogg', 50, TRUE) + addtimer(CALLBACK(src, .proc/reset_spamflag), 2 SECONDS) diff --git a/code/datums/components/label.dm b/code/datums/components/label.dm new file mode 100644 index 0000000000..c6d0c595eb --- /dev/null +++ b/code/datums/components/label.dm @@ -0,0 +1,87 @@ +/** + The label component. + + This component is used to manage labels applied by the hand labeler. + + Atoms can only have one instance of this component, and therefore only one label at a time. + This is to avoid having names like "Backpack (label1) (label2) (label3)". This is annoying and abnoxious to read. + + When a player clicks the atom with a hand labeler to apply a label, this component gets applied to it. + If the labeler is off, the component will be removed from it, and the label will be removed from its name. + */ +/datum/component/label + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + /// The name of the label the player is applying to the parent. + var/label_name + +/datum/component/label/Initialize(_label_name) + if(!isatom(parent)) + return COMPONENT_INCOMPATIBLE + + label_name = _label_name + apply_label() + +/datum/component/label/RegisterWithParent() + RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/OnAttackby) + RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/Examine) + +/datum/component/label/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_PARENT_ATTACKBY, COMSIG_PARENT_EXAMINE)) + +/** + This proc will fire after the parent is hit by a hand labeler which is trying to apply another label. + Since the parent already has a label, it will remove the old one from the parent's name, and apply the new one. +*/ +/datum/component/label/InheritComponent(datum/component/label/new_comp , i_am_original, _label_name) + remove_label() + if(new_comp) + label_name = new_comp.label_name + else + label_name = _label_name + apply_label() + +/** + This proc will trigger when any object is used to attack the parent. + + If the attacking object is not a hand labeler, it will return. + If the attacking object is a hand labeler it will restore the name of the parent to what it was before this component was added to it, and the component will be deleted. + + Arguments: + * source: The parent. + * attacker: The object that is hitting the parent. + * user: The mob who is wielding the attacking object. +*/ +/datum/component/label/proc/OnAttackby(datum/source, obj/item/attacker, mob/user) + // If the attacking object is not a hand labeler or its mode is 1 (has a label ready to apply), return. + // The hand labeler should be off (mode is 0), in order to remove a label. + var/obj/item/hand_labeler/labeler = attacker + if(!istype(labeler) || labeler.mode) + return + + remove_label() + playsound(parent, 'sound/items/poster_ripped.ogg', 20, TRUE) + to_chat(user, "You remove the label from [parent].") + qdel(src) // Remove the component from the object. + +/** + This proc will trigger when someone examines the parent. + It will attach the text found in the body of the proc to the `examine_list` and display it to the player examining the parent. + + Arguments: + * source: The parent. + * user: The mob exmaining the parent. + * examine_list: The current list of text getting passed from the parent's normal examine() proc. +*/ +/datum/component/label/proc/Examine(datum/source, mob/user, list/examine_list) + examine_list += "It has a label with some words written on it. Use a hand labeler to remove it." + +/// Applies a label to the name of the parent in the format of: "parent_name (label)" +/datum/component/label/proc/apply_label() + var/atom/owner = parent + owner.name += " ([label_name])" + +/// Removes the label from the parent's name +/datum/component/label/proc/remove_label() + var/atom/owner = parent + owner.name = replacetext(owner.name, "([label_name])", "") // Remove the label text from the parent's name, wherever it's located. + owner.name = trim(owner.name) // Shave off any white space from the beginning or end of the parent's name. diff --git a/code/datums/components/ntnet_interface.dm b/code/datums/components/ntnet_interface.dm index 6159c7c2c4..06d69f0ce3 100644 --- a/code/datums/components/ntnet_interface.dm +++ b/code/datums/components/ntnet_interface.dm @@ -1,4 +1,4 @@ -//Thing meant for allowing datums and objects to access a NTnet network datum. +//Thing meant for allowing datums and objects to access an NTnet network datum. /datum/proc/ntnet_receive(datum/netdata/data) return diff --git a/code/datums/elements/decal.dm b/code/datums/elements/decal.dm index 50519b08e7..5ddd5bd03e 100644 --- a/code/datums/elements/decal.dm +++ b/code/datums/elements/decal.dm @@ -32,6 +32,7 @@ RegisterSignal(A, COMSIG_COMPONENT_CLEAN_ACT, .proc/clean_react) if(description) RegisterSignal(A, COMSIG_PARENT_EXAMINE, .proc/examine) + RegisterSignal(A, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_overlay, TRUE) num_decals_per_atom[A]++ apply(A) @@ -39,21 +40,20 @@ /datum/element/decal/Detach(datum/target) var/atom/A = target num_decals_per_atom[A]-- - apply(A, TRUE) if(!num_decals_per_atom[A]) UnregisterSignal(A, list(COMSIG_ATOM_DIR_CHANGE, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_PARENT_EXAMINE, COMSIG_ATOM_UPDATE_OVERLAYS)) LAZYREMOVE(num_decals_per_atom, A) + apply(A) return ..() -/datum/element/decal/proc/apply(atom/target, removing = FALSE) - if(num_decals_per_atom[target] == 1 && !removing) - RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_overlay, TRUE) +/datum/element/decal/proc/apply(atom/target) target.update_icon() if(isitem(target)) addtimer(CALLBACK(target, /obj/item/.proc/update_slot_icon), 0, TIMER_UNIQUE) /datum/element/decal/proc/apply_overlay(atom/source, list/overlay_list) - pic.dir = first_dir == NORTH ? source.dir : turn(first_dir, dir2angle(source.dir)) + if(first_dir) + pic.dir = turn(first_dir, -dir2angle(source.dir)) for(var/i in 1 to num_decals_per_atom[source]) overlay_list += pic diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm index 6660bafcaf..e1147df225 100644 --- a/code/datums/emotes.dm +++ b/code/datums/emotes.dm @@ -102,8 +102,9 @@ /datum/emote/proc/can_run_emote(mob/user, status_check = TRUE, intentional = FALSE) . = TRUE - if(!is_type_in_typecache(user, mob_type_allowed_typecache)) - return FALSE + if(mob_type_allowed_typecache) //empty list = anyone can use it unless specifically blacklisted + if(!is_type_in_typecache(user, mob_type_allowed_typecache)) + return FALSE if(is_type_in_typecache(user, mob_type_blacklist_typecache)) return FALSE if(status_check && !is_type_in_typecache(user, mob_type_ignore_stat_typecache)) diff --git a/code/datums/explosion.dm b/code/datums/explosion.dm index dc9569a4d5..246226ceba 100644 --- a/code/datums/explosion.dm +++ b/code/datums/explosion.dm @@ -103,13 +103,21 @@ GLOBAL_LIST_EMPTY(explosions) // 3/7/14 will calculate to 80 + 35 var/far_dist = 0 - far_dist += heavy_impact_range * 5 + far_dist += heavy_impact_range * 15 // Large explosions carry further far_dist += devastation_range * 20 if(!silent) var/frequency = get_rand_frequency() var/sound/explosion_sound = sound(get_sfx("explosion")) var/sound/far_explosion_sound = sound('sound/effects/explosionfar.ogg') + var/sound/creaking_explosion_sound = sound(get_sfx("explosion_creaking")) + var/sound/hull_creaking_sound = sound(get_sfx("hull_creaking")) + var/sound/explosion_echo_sound = sound('sound/effects/explosion_distant.ogg') + var/on_station = SSmapping.level_trait(epicenter.z, ZTRAIT_STATION) + var/creaking_explosion = FALSE + + if(prob(devastation_range*30+heavy_impact_range*5) && on_station) // Huge explosions are near guaranteed to make the station creak and whine, smaller ones might. + creaking_explosion = TRUE // prob over 100 always returns true for(var/mob/M in GLOB.player_list) // Double check for client @@ -126,11 +134,29 @@ GLOBAL_LIST_EMPTY(explosions) shake_camera(M, 25, clamp(baseshakeamount, 0, 10)) // You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station. else if(dist <= far_dist) - var/far_volume = clamp(far_dist, 30, 50) // Volume is based on explosion size and dist - far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion - M.playsound_local(epicenter, null, far_volume, 1, frequency, falloff = 5, S = far_explosion_sound) - if(baseshakeamount > 0) + var/far_volume = clamp(far_dist/2, 40, 60) // Volume is based on explosion size and dist + if(creaking_explosion) + M.playsound_local(epicenter, null, far_volume, 1, frequency, S = creaking_explosion_sound, distance_multiplier = 0) + else if(prob(75)) + M.playsound_local(epicenter, null, far_volume, 1, frequency, S = far_explosion_sound, distance_multiplier = 0) // Far sound + else + M.playsound_local(epicenter, null, far_volume, 1, frequency, S = explosion_echo_sound, distance_multiplier = 0) // Echo sound + + if(baseshakeamount > 0 || devastation_range) + if(!baseshakeamount) // Devastating explosions rock the station and ground + baseshakeamount = devastation_range*3 shake_camera(M, 10, clamp(baseshakeamount*0.25, 0, 2.5)) + + else if(M.can_hear() && !isspaceturf(get_turf(M)) && heavy_impact_range) // Big enough explosions echo throughout the hull + var/echo_volume = 40 + if(devastation_range) + baseshakeamount = devastation_range + shake_camera(M, 10, clamp(baseshakeamount*0.25, 0, 2.5)) + echo_volume = 60 + M.playsound_local(epicenter, null, echo_volume, 1, frequency, S = explosion_echo_sound, distance_multiplier = 0) + + if(creaking_explosion) // 5 seconds after the bang, the station begins to creak + addtimer(CALLBACK(M, /mob/proc/playsound_local, epicenter, null, rand(25, 40), 1, frequency, null, null, FALSE, hull_creaking_sound, null, null, null, null, 0), 5 SECONDS) EX_PREPROCESS_CHECK_TICK //postpone processing for a bit diff --git a/code/datums/mind.dm b/code/datums/mind.dm index cb99fdc5a3..0731cf8bf4 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -41,6 +41,8 @@ var/special_role var/list/restricted_roles = list() + var/hide_ckey = FALSE //hide ckey from round-end report + var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button. var/linglink @@ -69,6 +71,7 @@ ///What character we spawned in as- either at roundstart or latejoin, so we know for persistent scars if we ended as the same person or not var/mob/original_character + /datum/mind/New(var/key) skill_holder = new(src) src.key = key @@ -137,6 +140,8 @@ if(L.client?.prefs && L.client.prefs.auto_ooc && L.client.prefs.chat_toggles & CHAT_OOC) DISABLE_BITFIELD(L.client.prefs.chat_toggles,CHAT_OOC) + hide_ckey = current.client?.prefs?.hide_ckey + SEND_SIGNAL(src, COMSIG_MIND_TRANSFER, new_character, old_character) SEND_SIGNAL(new_character, COMSIG_MOB_ON_NEW_MIND) @@ -780,6 +785,7 @@ if(!mind.name) mind.name = real_name mind.current = src + mind.hide_ckey = client?.prefs?.hide_ckey /mob/living/carbon/mind_initialize() ..() diff --git a/code/datums/mutations/antenna.dm b/code/datums/mutations/antenna.dm index 978802fd80..ad08b8ebdc 100644 --- a/code/datums/mutations/antenna.dm +++ b/code/datums/mutations/antenna.dm @@ -90,6 +90,8 @@ to_chat(user, "You catch some drifting memories of their past conversations...") for(var/spoken_memory in recent_speech) to_chat(user, "[recent_speech[spoken_memory]]") + if(usr in GLOB.rockpaperscissors_players) + to_chat(user, "They're planning on playing [GLOB.rockpaperscissors_players[usr][1]]") if(iscarbon(M)) var/mob/living/carbon/human/H = M to_chat(user, "You find that their intent is to [H.a_intent]...") diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 179ed765c5..ef3979d822 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -580,4 +580,63 @@ /datum/status_effect/regenerative_core/on_remove() . = ..() REMOVE_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, "regenerative_core") - owner.updatehealth() \ No newline at end of file + owner.updatehealth() + +/datum/status_effect/panacea + id = "Anatomic Panacea" + duration = 100 + tick_interval = 10 + alert_type = /obj/screen/alert/status_effect/panacea + +/obj/screen/alert/status_effect/panacea + name = "Panacea" + desc = "We purge the impurities from our body." + icon_state = "panacea" + +// Changeling's anatomic panacea now in buff form. Directly fixes issues instead of injecting chems +/datum/status_effect/panacea/tick() + var/mob/living/carbon/M = owner + + //Heal brain damage and toxyloss, alongside trauma + owner.adjustOrganLoss(ORGAN_SLOT_BRAIN, -8) + owner.adjustToxLoss(-6, forced = TRUE) + M.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC) + //Purges 50 rads per tick + if(owner.radiation > 0) + owner.radiation -= min(owner.radiation, 50) + //Mutadone effects + owner.jitteriness = 0 + if(owner.has_dna()) + M.dna.remove_all_mutations(mutadone = TRUE) + if(!QDELETED(owner)) //We were a monkey, now a human + ..() + // Purges toxins + for(var/datum/reagent/toxin/R in owner.reagents.reagent_list) + owner.reagents.remove_reagent(R.type, 5) + //Antihol effects + M.reagents.remove_all_type(/datum/reagent/consumable/ethanol, 10, 0, 1) + M.drunkenness = max(M.drunkenness - 10, 0) + owner.dizziness = 0 + owner.drowsyness = 0 + owner.slurring = 0 + owner.confused = 0 + //Organ and disease cure moved from panacea.dm to buff proc + var/list/bad_organs = list( + owner.getorgan(/obj/item/organ/body_egg), + owner.getorgan(/obj/item/organ/zombie_infection)) + for(var/o in bad_organs) + var/obj/item/organ/O = o + if(!istype(O)) + continue + O.Remove() + if(iscarbon(owner)) + var/mob/living/carbon/C = owner + C.vomit(0, toxic = TRUE) + O.forceMove(get_turf(owner)) + if(isliving(owner)) + var/mob/living/L = owner + for(var/thing in L.diseases) + var/datum/disease/D = thing + if(D.severity == DISEASE_SEVERITY_POSITIVE) + continue + D.cure() diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm index 63574c6475..d2fa8bcc70 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -200,13 +200,15 @@ /datum/dynamic_ruleset/latejoin/heretic_smuggler name = "Heretic Smuggler" antag_datum = /datum/antagonist/heretic - antag_flag = ROLE_HERETIC + antag_flag = "latejoin_heretic" protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") restricted_roles = list("AI","Cyborg") required_candidates = 1 weight = 4 - cost = 10 - requirements = list(40,30,20,10,10,10,10,10,10,10) + cost = 25 + requirements = list(60,60,60,55,50,50,50,50,50,50) + high_population_requirement = 50 + property_weights = list("story_potential" = 1, "trust" = -1, "chaos" = 2, "extended" = -1, "valid" = 2) repeatable = TRUE ////////////////////////////////////////////// diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 6a7671cd5b..b29584aa58 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -538,7 +538,7 @@ name = "Slaughter Demon" config_tag = "slaughter_demon" antag_flag = ROLE_ALIEN - enemy_roles = list("Security Officer","Shaft Miner","Head of Security","Captain","Janitor","AI","Cyborg") + enemy_roles = list("Security Officer","Shaft Miner","Head of Security","Captain","Janitor","AI","Cyborg","Bartender") required_enemies = list(3,2,2,2,2,1,1,1,1,0) required_candidates = 1 weight = 4 diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index 766ddcefc7..db4ec99558 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -151,16 +151,18 @@ /datum/dynamic_ruleset/roundstart/heretics name = "Heretics" - antag_flag = ROLE_HERETIC + antag_flag = "heretic" antag_datum = /datum/antagonist/heretic protected_roles = list("Prisoner","Security Officer", "Warden", "Detective", "Head of Security", "Captain") restricted_roles = list("AI", "Cyborg") required_candidates = 1 weight = 3 - cost = 20 + cost = 25 scaling_cost = 15 - requirements = list(50,45,45,40,35,20,20,15,10,10) + requirements = list(60,60,60,55,50,50,50,50,50,50) + property_weights = list("story_potential" = 1, "trust" = -1, "chaos" = 2, "extended" = -1, "valid" = 2) antag_cap = list(1,1,1,1,2,2,2,2,3,3) + high_population_requirement = 50 /datum/dynamic_ruleset/roundstart/heretics/pre_execute() diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 148de9568a..dd281c456f 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -22,14 +22,14 @@ var/datum/game_mode/dynamic/mode = null // Cached as soon as it's made, by dynamic. /** -Property weights are: +Property weights are added to the config weight of the ruleset. They are: "story_potential" -- essentially how many different ways the antag can be played. "trust" -- How much it makes the crew trust each other. Negative values means they're suspicious. Team antags are like this. "chaos" -- How chaotic it makes the round. Has some overlap with "valid" and somewhat contradicts "extended". "valid" -- How likely the non-antag-enemy crew are to get involved, e.g. nukies encouraging the warden to let everyone into the armory, wizard moving around and being a nuisance, nightmare busting lights. "extended" -- How much the antag is conducive to a long round. Nukies and cults are bad for this; Wizard is less bad; and so on. -"conversion" -- Basically a bool. Conversion antags, well, convert. It's its own class for a good reason. +"conversion" -- Basically a bool. Conversion antags, well, convert. It's in its own class 'cause people kinda hate conversion. */ /datum/dynamic_storyteller/proc/start_injection_cooldowns() @@ -126,8 +126,9 @@ Property weights are: for(var/property in property_weights) if(property in rule.property_weights) // just treat it as 0 if it's not in there property_weight += rule.property_weights[property] * property_weights[property] - if(property_weight > 0) - drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult + var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult + if(calced_weight > 0) // negatives in the list might cause problems + drafted_rules[rule] = calced_weight return drafted_rules /datum/dynamic_storyteller/proc/midround_draft() @@ -144,21 +145,24 @@ Property weights are: for(var/property in property_weights) if(property in rule.property_weights) // just treat it as 0 if it's not in there property_weight += rule.property_weights[property] * property_weights[property] - if(property_weight > 0) - var/threat_weight = 1 - if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway - var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat)) - /* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to - pick this particular ruleset. - Let's use a toy example: there's 60 threat level and 10 threat spent. - We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets. - Ruleset 1 has 30 cost, ruleset 2 has 5 cost. - When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1 - is 2.26 times as likely to be picked, all other things considered. - Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight. - */ - threat_weight = abs(1-abs(1-LOGISTIC_FUNCTION(2,0.05,cost_difference,0))) - drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult * threat_weight + var/threat_weight = 1 + if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway + var/cost_difference = rule.cost-(mode.threat_level-mode.threat) + /* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to + pick this particular ruleset. + Let's use a toy example: there's 60 threat level and 10 threat spent. + We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets. + Ruleset 1 has 30 cost, ruleset 2 has 5 cost. + When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1 + is 2.26 times as likely to be picked, all other things considered. + Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight. + */ + threat_weight = abs(1-abs(1-LOGISTIC_FUNCTION(2,0.05,abs(cost_difference),0))) + if(cost_difference > 0) + threat_weight /= (1+(cost_difference*0.1)) + var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult * threat_weight + if(calced_weight > 0) + drafted_rules[rule] = calced_weight return drafted_rules /datum/dynamic_storyteller/proc/latejoin_draft(mob/living/carbon/human/newPlayer) @@ -180,12 +184,15 @@ Property weights are: for(var/property in property_weights) if(property in rule.property_weights) property_weight += rule.property_weights[property] * property_weights[property] - if(property_weight > 0) - var/threat_weight = 1 - if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)) - var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat)) - threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,cost_difference,0))) - drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult * threat_weight + var/threat_weight = 1 + if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)) + var/cost_difference = rule.cost-(mode.threat_level-mode.threat) + threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,abs(cost_difference),0))) + if(cost_difference > 0) + threat_weight /= (1+(cost_difference*0.1)) + var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult * threat_weight + if(calced_weight > 0) + drafted_rules[rule] = calced_weight return drafted_rules /datum/dynamic_storyteller/proc/event_draft() @@ -196,8 +203,9 @@ Property weights are: for(var/property in property_weights) if(property in rule.property_weights) property_weight += rule.property_weights[property] * property_weights[property] - if(property_weight > 0) - drafted_rules[rule] = rule.get_weight() + property_weight * rule.weight_mult + var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult + if(calced_weight > 0) + drafted_rules[rule] = calced_weight return drafted_rules @@ -327,12 +335,6 @@ Property weights are: flags = USE_PREV_ROUND_WEIGHTS property_weights = list("story_potential" = 2) - -/datum/dynamic_storyteller/story/calculate_threat() - var/current_time = (world.time / SSautotransfer.targettime)*180 - mode.threat_level = round((mode.initial_threat_level*(sin(current_time)/2)+0.75),0.1) - return ..() - /datum/dynamic_storyteller/classic name = "Classic" config_tag = "classic" diff --git a/code/game/machinery/computer/arcade/battle.dm b/code/game/machinery/computer/arcade/battle.dm index fc99edd3eb..a6c98c6c9c 100644 --- a/code/game/machinery/computer/arcade/battle.dm +++ b/code/game/machinery/computer/arcade/battle.dm @@ -49,7 +49,6 @@ dat += "" var/datum/browser/popup = new(user, "arcade", "Space Villain 2000") popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) popup.open() /obj/machinery/computer/arcade/battle/Topic(href, href_list) diff --git a/code/game/machinery/computer/arcade/orion_trail.dm b/code/game/machinery/computer/arcade/orion_trail.dm index 8b81c69ed2..441010906c 100644 --- a/code/game/machinery/computer/arcade/orion_trail.dm +++ b/code/game/machinery/computer/arcade/orion_trail.dm @@ -160,7 +160,6 @@ dat += "

Close

" var/datum/browser/popup = new(user, "arcade", "The Orion Trail",400,700) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) popup.open() return diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index 74cceacd12..46d419a8fe 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -353,7 +353,6 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) dat = list("", header.Join(), body, "
") var/datum/browser/popup = new(user, "id_com", src.name, 900, 620) popup.set_content(dat.Join()) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() /obj/machinery/computer/card/Topic(href, href_list) diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index 400ce041c7..2a05b359d8 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -276,7 +276,6 @@ var/datum/browser/popup = new(user, "cloning", "Cloning System Control") popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() /obj/machinery/computer/cloning/Topic(href, href_list) diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 6a99b248e3..3ef887b156 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -1,3 +1,15 @@ +#define STATE_DEFAULT 1 +#define STATE_CALLSHUTTLE 2 +#define STATE_CANCELSHUTTLE 3 +#define STATE_MESSAGELIST 4 +#define STATE_VIEWMESSAGE 5 +#define STATE_DELMESSAGE 6 +#define STATE_STATUSDISPLAY 7 +#define STATE_ALERT_LEVEL 8 +#define STATE_CONFIRM_LEVEL 9 +#define STATE_TOGGLE_EMERGENCY 10 +#define STATE_PURCHASE 11 + // The communications computer /obj/machinery/computer/communications name = "communications console" @@ -6,6 +18,7 @@ icon_keyboard = "tech_key" req_access = list(ACCESS_HEADS) circuit = /obj/item/circuitboard/computer/communications + light_color = LIGHT_COLOR_BLUE var/auth_id = "Unknown" //Who is currently logged in? var/list/datum/comm_message/messages = list() var/datum/comm_message/currmsg @@ -16,22 +29,10 @@ var/ai_message_cooldown = 0 var/tmp_alertlevel = 0 var/static/security_level_cd // used to stop mass spam. - var/const/STATE_DEFAULT = 1 - var/const/STATE_CALLSHUTTLE = 2 - var/const/STATE_CANCELSHUTTLE = 3 - var/const/STATE_MESSAGELIST = 4 - var/const/STATE_VIEWMESSAGE = 5 - var/const/STATE_DELMESSAGE = 6 - var/const/STATE_STATUSDISPLAY = 7 - var/const/STATE_ALERT_LEVEL = 8 - var/const/STATE_CONFIRM_LEVEL = 9 - var/const/STATE_TOGGLE_EMERGENCY = 10 - var/const/STATE_PURCHASE = 11 var/stat_msg1 var/stat_msg2 - light_color = LIGHT_COLOR_BLUE /obj/machinery/computer/communications/proc/checkCCcooldown() var/obj/item/circuitboard/computer/communications/CM = circuit @@ -46,7 +47,7 @@ /obj/machinery/computer/communications/Topic(href, href_list) if(..()) return - if(!usr.canUseTopic(src)) + if(!usr.canUseTopic(src, !issilicon(usr))) return if(!is_station_level(z) && !is_reserved_level(z)) //Can only use in transit and on SS13 to_chat(usr, "Unable to establish a connection: \black You're too far away from the station!") @@ -132,15 +133,20 @@ if("crossserver") if(authenticated==2) + var/dest = href_list["cross_dest"] if(!checkCCcooldown()) to_chat(usr, "Arrays recycling. Please stand by.") playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) return - var/input = stripped_multiline_input(usr, "Please choose a message to transmit to allied stations. Please be aware that this process is very expensive, and abuse will lead to... termination.", "Send a message to an allied station.", "") + var/warning = dest == "all" ? "Please choose a message to transmit to allied stations." : "Please choose a message to transmit to [dest] sector station." + var/input = stripped_multiline_input(usr, "[warning] Please be aware that this process is very expensive, and abuse will lead to... termination.", "Send a message to an allied station.", "") if(!input || !(usr in view(1,src)) || !checkCCcooldown()) return playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) - send2otherserver("[station_name()]", input,"Comms_Console") + if(dest == "all") + send2otherserver("[station_name()]", input,"Comms_Console") + else + send2otherserver("[station_name()]", input,"Comms_Console", list(dest)) minor_announce(input, title = "Outgoing message to allied station") usr.log_talk(input, LOG_SAY, tag="message to the other server") message_admins("[ADMIN_LOOKUPFLW(usr)] has sent a message to the other server.") @@ -156,12 +162,12 @@ var/datum/map_template/shuttle/S = locate(href_list["chosen_shuttle"]) in shuttles if(S && istype(S)) if(SSshuttle.emergency.mode != SHUTTLE_RECALL && SSshuttle.emergency.mode != SHUTTLE_IDLE) - to_chat(usr, "It's a bit late to buy a new shuttle, don't you think?") + to_chat(usr, "It's a bit late to buy a new shuttle, don't you think?") return if(SSshuttle.shuttle_purchased) - to_chat(usr, "A replacement shuttle has already been purchased.") + to_chat(usr, "A replacement shuttle has already been purchased.") else if(!S.prerequisites_met()) - to_chat(usr, "You have not met the requirements for purchasing this shuttle.") + to_chat(usr, "You have not met the requirements for purchasing this shuttle.") else var/points_to_check var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR) @@ -183,7 +189,7 @@ if("callshuttle") state = STATE_DEFAULT - if(authenticated) + if(authenticated && SSshuttle.canEvac(usr)) state = STATE_CALLSHUTTLE if("callshuttle2") if(authenticated) @@ -284,12 +290,12 @@ if("MessageCentCom") if(authenticated) if(!checkCCcooldown()) - to_chat(usr, "Arrays recycling. Please stand by.") + to_chat(usr, "Arrays recycling. Please stand by.") return var/input = stripped_input(usr, "Please choose a message to transmit to CentCom via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "Send a message to CentCom.", "") if(!input || !(usr in view(1,src)) || !checkCCcooldown()) return - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) CentCom_announce(input, usr) to_chat(usr, "Message transmitted to Central Command.") for(var/client/X in GLOB.admins) @@ -302,7 +308,7 @@ // OMG SYNDICATE ...LETTERHEAD if("MessageSyndicate") - if((authenticated==2) && (obj_flags & EMAGGED)) + if((authenticated) && (obj_flags & EMAGGED)) if(!checkCCcooldown()) to_chat(usr, "Arrays recycling. Please stand by.") playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) @@ -332,7 +338,7 @@ if(!checkCCcooldown()) to_chat(usr, "Arrays recycling. Please stand by.") return - var/input = stripped_input(usr, "Please enter the reason for requesting the nuclear self-destruct codes. Misuse of the nuclear request system will not be tolerated under any circumstances. Transmission does not guarantee a response.", "Self Destruct Code Request.","") + var/input = stripped_input(usr, "Please enter the reason for requesting the nuclear self-destruct codes. Misuse of the nuclear request system will not be tolerated under any circumstances. Transmission does not guarantee a response.", "Self-Destruct Code Request.","") if(!input || !(usr in view(1,src)) || !checkCCcooldown()) return Nuke_request(input, usr) @@ -347,7 +353,9 @@ aicurrmsg = null aistate = STATE_DEFAULT if("ai-callshuttle") - aistate = STATE_CALLSHUTTLE + aistate = STATE_DEFAULT + if(SSshuttle.canEvac(usr)) + aistate = STATE_CALLSHUTTLE if("ai-callshuttle2") SSshuttle.requestEvac(usr, href_list["call"]) aistate = STATE_DEFAULT @@ -460,9 +468,8 @@ var/datum/browser/popup = new(user, "communications", "Communications Console", 400, 500) - popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) - if(issilicon(user) || (hasSiliconAccessInArea(user) && !in_range(user,src))) + if(issilicon(user)) var/dat2 = interact_ai(user) // give the AI a different interact proc to limit its access if(dat2) dat += dat2 @@ -493,9 +500,15 @@ if (authenticated==2) dat += "

Captain Functions" dat += "
\[ Make a Captain's Announcement \]" - var/cross_servers_count = length(CONFIG_GET(keyed_list/cross_server)) - if(cross_servers_count) - dat += "
\[ Send a message to [cross_servers_count == 1 ? "an " : ""]allied station[cross_servers_count > 1 ? "s" : ""] \]" + var/list/cross_servers = CONFIG_GET(keyed_list/cross_server) + var/our_id = CONFIG_GET(string/cross_comms_name) + if(cross_servers.len) + for(var/server in cross_servers) + if(server == our_id) + continue + dat += "
\[ Send a message to station in [server] sector. \]" + if(cross_servers.len > 2) + dat += "
\[ Send a message to all allied stations \]" if(SSmapping.config.allow_custom_shuttles) dat += "
\[ Purchase Shuttle \]" dat += "
\[ Change Alert Level \]" @@ -721,8 +734,13 @@ to_chat(user, "Intercomms recharging. Please stand by.") return var/input = stripped_input(user, "Please choose a message to announce to the station crew.", "What?") - if(!input || !user.canUseTopic(src)) + if(!input || !user.canUseTopic(src, !issilicon(usr))) return + if(!(user.can_speak())) //No more cheating, mime/random mute guy! + input = "..." + to_chat(user, "You find yourself unable to speak.") + else + input = user.treat_message(input) //Adds slurs and so on. Someone should make this use languages too. SScommunications.make_announcement(user, is_silicon, input) deadchat_broadcast("[user.real_name] made an priority announcement from [get_area_name(usr, TRUE)].", user) @@ -771,3 +789,15 @@ content = new_content if(new_possible_answers) possible_answers = new_possible_answers + +#undef STATE_DEFAULT +#undef STATE_CALLSHUTTLE +#undef STATE_CANCELSHUTTLE +#undef STATE_MESSAGELIST +#undef STATE_VIEWMESSAGE +#undef STATE_DELMESSAGE +#undef STATE_STATUSDISPLAY +#undef STATE_ALERT_LEVEL +#undef STATE_CONFIRM_LEVEL +#undef STATE_TOGGLE_EMERGENCY +#undef STATE_PURCHASE diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm index 286c106788..3d212ec0cb 100644 --- a/code/game/machinery/computer/dna_console.dm +++ b/code/game/machinery/computer/dna_console.dm @@ -217,9 +217,6 @@ // already discovered mutations stored_research = SSresearch.science_tech -/obj/machinery/computer/scan_consolenew/examine(mob/user) - . = ..() - /obj/machinery/computer/scan_consolenew/ui_interact(mob/user, datum/tgui/ui) // Most of ui_interact is spent setting variables for passing to the tgui // interface. @@ -266,6 +263,10 @@ if(!ui) ui = new(user, src, "DnaConsole") ui.open() + +/obj/machinery/computer/scan_consolenew/ui_assets() + . = ..() || list() + . += get_asset_datum(/datum/asset/simple/genetics) /obj/machinery/computer/scan_consolenew/ui_data(mob/user) var/list/data = list() @@ -357,7 +358,7 @@ return data -/obj/machinery/computer/scan_consolenew/ui_act(action, var/list/params) +/obj/machinery/computer/scan_consolenew/ui_act(action, list/params) if(..()) return TRUE @@ -482,6 +483,7 @@ // Resolve mutation's BYOND path from the alias var/alias = params["alias"] var/path = GET_MUTATION_TYPE_FROM_ALIAS(alias) + // Make sure the occupant still has this mutation if(!(path in scanner_occupant.dna.mutation_index)) return diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index d8a5f856f1..4e99f67157 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -178,7 +178,6 @@ dat += "{Log In}" var/datum/browser/popup = new(user, "med_rec", "Medical Records Console", 600, 400) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) popup.open() /obj/machinery/computer/med_data/Topic(href, href_list) diff --git a/code/game/machinery/computer/pod.dm b/code/game/machinery/computer/pod.dm index 53f7cb7e32..ca64d538b9 100644 --- a/code/game/machinery/computer/pod.dm +++ b/code/game/machinery/computer/pod.dm @@ -67,7 +67,6 @@ add_fingerprint(usr) var/datum/browser/popup = new(user, "computer", title, 400, 500) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) popup.open() /obj/machinery/computer/pod/process() diff --git a/code/game/machinery/computer/prisoner/management.dm b/code/game/machinery/computer/prisoner/management.dm index 4b4b39740a..43aa978558 100644 --- a/code/game/machinery/computer/prisoner/management.dm +++ b/code/game/machinery/computer/prisoner/management.dm @@ -66,7 +66,6 @@ dat += "
{Log Out}" var/datum/browser/popup = new(user, "computer", "Prisoner Management Console", 400, 500) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() return diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index 5c280eeace..844f14465a 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -250,7 +250,6 @@ dat += "{Log In}" var/datum/browser/popup = new(user, "secure_rec", "Security Records Console", 600, 400) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() return diff --git a/code/game/machinery/computer/telecrystalconsoles.dm b/code/game/machinery/computer/telecrystalconsoles.dm index 82e8f46ab6..87b7159125 100644 --- a/code/game/machinery/computer/telecrystalconsoles.dm +++ b/code/game/machinery/computer/telecrystalconsoles.dm @@ -103,7 +103,6 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E var/datum/browser/popup = new(user, "computer", "Telecrystal Upload/Receive Station", 700, 500) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() /obj/machinery/computer/telecrystals/uplinker/Topic(href, href_list) @@ -185,7 +184,6 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E var/datum/browser/popup = new(user, "computer", "Team Telecrystal Management Console", 700, 500) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() /obj/machinery/computer/telecrystals/boss/Topic(href, href_list) diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index 9330a30555..f7019e75ef 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -76,7 +76,6 @@ var/datum/browser/popup = new(user, "cryopod_console", "Cryogenic System Control") popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() /obj/machinery/computer/cryopod/Topic(href, href_list) @@ -308,7 +307,7 @@ var/mob/living/mob_occupant = occupant var/list/obj/item/cryo_items = list() - + investigate_log("Despawning [key_name(mob_occupant)].", INVESTIGATE_CRYOGENICS) //Handle Borg stuff first diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 228c2e1f52..d88a9c9072 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -74,12 +74,6 @@ /obj/machinery/door/firedoor/Bumped(atom/movable/AM) if(panel_open || operating || welded) return - if(ismob(AM)) - var/mob/user = AM - if(density && !welded && !operating && !(stat & NOPOWER) && (!density || allow_hand_open(user))) - add_fingerprint(user) - open() - return TRUE return FALSE /obj/machinery/door/firedoor/power_change() @@ -90,14 +84,6 @@ stat |= NOPOWER /obj/machinery/door/firedoor/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) - if(!welded && !operating && !(stat & NOPOWER) && (!density || allow_hand_open(user))) - add_fingerprint(user) - if(density) - emergency_close_timer = world.time + 30 // prevent it from instaclosing again if in space - open() - else - close() - return TRUE if(operating || !density) return diff --git a/code/game/machinery/embedded_controller/access_controller.dm b/code/game/machinery/embedded_controller/access_controller.dm index f74de23171..8eebd779f4 100644 --- a/code/game/machinery/embedded_controller/access_controller.dm +++ b/code/game/machinery/embedded_controller/access_controller.dm @@ -260,7 +260,6 @@ /obj/machinery/doorButtons/airlock_controller/ui_interact(mob/user) var/datum/browser/popup = new(user, "computer", name) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.set_content(returnText()) popup.open() diff --git a/code/game/machinery/embedded_controller/embedded_controller_base.dm b/code/game/machinery/embedded_controller/embedded_controller_base.dm index 6fd351bcff..5d0165189d 100644 --- a/code/game/machinery/embedded_controller/embedded_controller_base.dm +++ b/code/game/machinery/embedded_controller/embedded_controller_base.dm @@ -29,7 +29,6 @@ . = ..() user.set_machine(src) var/datum/browser/popup = new(user, "computer", name) // Set up the popup browser window - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.set_content(return_text()) popup.open() diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index bf71786a05..ff6f96a29f 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -3,13 +3,14 @@ /obj/machinery/iv_drip name = "\improper IV drip" - desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate." + desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. Alt-Click to change the transfer rate." icon = 'icons/obj/iv_drip.dmi' icon_state = "iv_drip" anchored = FALSE mouse_drag_pointer = MOUSE_ACTIVE_POINTER var/mob/living/carbon/attached var/mode = IV_INJECTING + var/dripfeed = FALSE var/obj/item/reagent_containers/beaker var/static/list/drip_containers = typecacheof(list(/obj/item/reagent_containers/blood, /obj/item/reagent_containers/food, @@ -132,9 +133,11 @@ if(mode) if(beaker.reagents.total_volume) var/transfer_amount = 5 + if (dripfeed) + transfer_amount = 1 if(istype(beaker, /obj/item/reagent_containers/blood)) // speed up transfer on blood packs - transfer_amount = 10 + transfer_amount *= 2 var/fraction = min(transfer_amount/beaker.reagents.total_volume, 1) //the fraction that is transfered of the total volume beaker.reagents.reaction(attached, INJECT, fraction, FALSE) //make reagents reacts, but don't spam messages beaker.reagents.trans_to(attached, transfer_amount) @@ -169,6 +172,16 @@ else toggle_mode() +/obj/machinery/iv_drip/AltClick(mob/living/user) + if(!user.canUseTopic(src, be_close=TRUE)) + return + if(dripfeed) + dripfeed = FALSE + to_chat(usr, "You loosen the valve to speed up the [src].") + else + dripfeed = TRUE + to_chat(usr, "You tighten the valve to slowly drip-feed the contents of [src].") + /obj/machinery/iv_drip/attack_robot(mob/user) if(Adjacent(user)) attack_hand(user) @@ -227,7 +240,7 @@ /obj/machinery/iv_drip/telescopic name = "telescopic IV drip" - desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. This one is telescopic, and can be picked up and put down." + desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. This one is telescopic, and can be picked up and put down.Alt-Click with a beaker attached to change the transfer rate." icon_state = "iv_drip" /obj/machinery/iv_drip/telescopic/update_icon_state() diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index e1f55da551..2915c2f34b 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -218,10 +218,10 @@ GLOBAL_LIST_EMPTY(allConsoles) dat += "Message Authentication

" dat += "Message for [dpt]: [message]

" dat += "
You may authenticate your message now by scanning your ID or your stamp

" - + dat += "Validated by: [msgVerified ? "[msgVerified]" : "Not Validated"]
" dat += "Stamped by: [msgStamped ? "[msgStamped]" : "Not Stamped"]

" - + dat += "Send Message

" dat += "<< Discard Message
" @@ -271,7 +271,6 @@ GLOBAL_LIST_EMPTY(allConsoles) var/datum/browser/popup = new(user, "req_console", "[department] Requests Console", 450, 440) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() /obj/machinery/requests_console/Topic(href, href_list) @@ -279,7 +278,7 @@ GLOBAL_LIST_EMPTY(allConsoles) return usr.set_machine(src) add_fingerprint(usr) - + if(href_list["write"]) dpt = ckey(reject_bad_text(href_list["write"])) //write contains the string of the receiving department's name var/new_message = stripped_input(usr, "Write your message:", "Awaiting Input", "", MAX_MESSAGE_LEN) @@ -358,7 +357,7 @@ GLOBAL_LIST_EMPTY(allConsoles) workingServer = TRUE if(!workingServer) - screen = 7 + screen = 7 say("NOTICE: No server detected! Please contact your local engineering team.") updateUsrDialog() return @@ -539,7 +538,7 @@ GLOBAL_LIST_EMPTY(allConsoles) to_chat(user, "You are not authorized to send announcements!") updateUsrDialog() return - + if(istype(O, /obj/item/stamp)) if(screen == 9) var/obj/item/stamp/T = O diff --git a/code/game/machinery/slotmachine.dm b/code/game/machinery/slotmachine.dm index 84b205b585..4740adaffb 100644 --- a/code/game/machinery/slotmachine.dm +++ b/code/game/machinery/slotmachine.dm @@ -132,7 +132,6 @@ var/datum/browser/popup = new(user, "slotmachine", "Slot Machine") popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) popup.open() /obj/machinery/computer/slot_machine/Topic(href, href_list) diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm index 40336fb01e..e2d3af149f 100644 --- a/code/game/mecha/mecha_defense.dm +++ b/code/game/mecha/mecha_defense.dm @@ -1,12 +1,10 @@ /obj/mecha/proc/get_armour_facing(relative_dir) switch(relative_dir) - if(0) // BACKSTAB! + if(180) // BACKSTAB! return facing_modifiers[BACK_ARMOUR] - if(45, 90, 270, 315) - return facing_modifiers[SIDE_ARMOUR] - if(225, 180, 135) + if(0, 45) // direct or 45 degrees off return facing_modifiers[FRONT_ARMOUR] - return 1 //always return non-0 + return facing_modifiers[SIDE_ARMOUR] //if its not a front hit or back hit then assume its from the side /obj/mecha/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) . = ..() @@ -43,7 +41,7 @@ break if(attack_dir) - var/facing_modifier = get_armour_facing(dir2angle(attack_dir) - dir2angle(src)) + var/facing_modifier = get_armour_facing(abs(dir2angle(dir) - dir2angle(attack_dir))) booster_damage_modifier /= facing_modifier booster_deflection_modifier *= facing_modifier if(prob(deflect_chance * booster_deflection_modifier)) diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm index 41270bb09e..871fe838d7 100644 --- a/code/game/objects/effects/anomalies.dm +++ b/code/game/objects/effects/anomalies.dm @@ -285,7 +285,7 @@ S.rabid = TRUE S.amount_grown = SLIME_EVOLUTION_THRESHOLD S.Evolve() - offer_control(S) + offer_control(S,POLL_IGNORE_SENTIENCE_POTION) ///////////////////// diff --git a/code/game/objects/effects/decals/decal.dm b/code/game/objects/effects/decals/decal.dm index 25b262a146..b280851888 100644 --- a/code/game/objects/effects/decals/decal.dm +++ b/code/game/objects/effects/decals/decal.dm @@ -46,4 +46,4 @@ var/turf/T = loc if(!istype(T)) //you know this will happen somehow CRASH("Turf decal initialized in an object/nullspace") - T.AddElement(/datum/element/decal, icon, icon_state, turn(dir, -dir2angle(T.dir)), CLEAN_GOD, color, null, null, alpha) + T.AddElement(/datum/element/decal, icon, icon_state, dir, CLEAN_GOD, color, null, null, alpha) diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm index c89e318714..07ffe8896e 100644 --- a/code/game/objects/items/RCD.dm +++ b/code/game/objects/items/RCD.dm @@ -242,7 +242,6 @@ RLD var/datum/browser/popup = new(user, "rcd_access", "Access Control", 900, 500, src) popup.set_content(t1) - popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) popup.open() /obj/item/construction/rcd/Topic(href, href_list) diff --git a/code/game/objects/items/broom.dm b/code/game/objects/items/broom.dm index 225644109f..4cbd75ed94 100644 --- a/code/game/objects/items/broom.dm +++ b/code/game/objects/items/broom.dm @@ -28,39 +28,37 @@ /// triggered on wield of two handed item /obj/item/broom/proc/on_wield(obj/item/source, mob/user) to_chat(user, "You brace the [src] against the ground in a firm sweeping stance.") - RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/sweep) + RegisterSignal(user, COMSIG_MOVABLE_PRE_MOVE, .proc/sweep) /// triggered on unwield of two handed item /obj/item/broom/proc/on_unwield(obj/item/source, mob/user) - UnregisterSignal(user, COMSIG_MOVABLE_MOVED) + UnregisterSignal(user, COMSIG_MOVABLE_PRE_MOVE) /obj/item/broom/afterattack(atom/A, mob/user, proximity) . = ..() if(!proximity) return - sweep(user, A, FALSE) + sweep(user, A) -/obj/item/broom/proc/sweep(mob/user, atom/A, moving = TRUE) - var/turf/target - if (!moving) - if (isturf(A)) - target = A - else - target = A.loc - else - target = user.loc - if (!isturf(target)) +/obj/item/broom/proc/sweep(datum/source, atom/newLoc) + if(!ismob(source) || !isturf(newLoc) || (get_dist(source, newLoc) > 1)) return - if (locate(/obj/structure/table) in target.contents) + var/turf/target = newLoc + var/atom/movable/AM + var/sweep_dir = get_dir(source, target) + if(!sweep_dir) return + for(var/i in target.contents) + AM = i + if(AM.density) // eh good enough heuristic check + return var/i = 0 for(var/obj/item/garbage in target.contents) if(!garbage.anchored) - garbage.Move(get_step(target, user.dir), user.dir) - i++ - if(i >= 20) + step(garbage, sweep_dir) + if(++i > 20) break - if(i >= 1) + if(i) playsound(loc, 'sound/weapons/thudswoosh.ogg', 30, TRUE, -1) /obj/item/broom/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J) //bless you whoever fixes this copypasta diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index ec68cdb40c..10b2b68646 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -266,7 +266,7 @@ GLOBAL_LIST_EMPTY(PDAs) var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/simple/pda) assets.send(user) - var/datum/asset/spritesheet/emoji_s = get_asset_datum(/datum/asset/spritesheet/goonchat) + var/datum/asset/spritesheet/emoji_s = get_asset_datum(/datum/asset/spritesheet/chat) emoji_s.send(user) //Already sent by chat but no harm doing this user.set_machine(src) diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm index 6eae9f127a..4ca0b86bc0 100644 --- a/code/game/objects/items/devices/PDA/cart.dm +++ b/code/game/objects/items/devices/PDA/cart.dm @@ -590,7 +590,7 @@ Code: var/static/list/emoji_icon_states var/static/emoji_table if(!emoji_table) - var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/goonchat) + var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat) var/list/collate = list("
") for(var/emoji in sortList(icon_states(icon('icons/emoji.dmi')))) var/tag = sheet.icon_tag("emoji-[emoji]") diff --git a/code/game/objects/items/devices/portable_chem_mixer.dm b/code/game/objects/items/devices/portable_chem_mixer.dm new file mode 100644 index 0000000000..25ecef5955 --- /dev/null +++ b/code/game/objects/items/devices/portable_chem_mixer.dm @@ -0,0 +1,207 @@ +/obj/item/storage/portable_chem_mixer + name = "Portable Chemical Mixer" + desc = "A portable device that dispenses and mixes chemicals. All necessary reagents need to be supplied with beakers. A label indicates that a screwdriver is required to open it for refills. This device can be worn on a belt. The letters 'S&T' are imprinted on the side." + icon = 'icons/obj/chemical.dmi' + icon_state = "portablechemicalmixer_open" + w_class = WEIGHT_CLASS_HUGE + slot_flags = ITEM_SLOT_BELT + custom_price = 2000 + custom_premium_price = 2000 + + var/obj/item/reagent_containers/beaker = null ///Creating an empty slot for a beaker that can be added to dispense into + var/amount = 30 ///The amount of reagent that is to be dispensed currently + + var/list/dispensable_reagents = list() ///List in which all currently dispensable reagents go + +/obj/item/storage/portable_chem_mixer/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_combined_w_class = 200 + STR.max_items = 50 + STR.insert_preposition = "in" + STR.can_hold = typecacheof(list( + /obj/item/reagent_containers/glass/beaker, + )) + +/obj/item/storage/portable_chem_mixer/Destroy() + QDEL_NULL(beaker) + return ..() + +/obj/item/storage/portable_chem_mixer/ex_act(severity, target) + if(severity < 3) + ..() + +/obj/item/storage/portable_chem_mixer/attackby(obj/item/I, mob/user, params) + var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED) + if (I.tool_behaviour == TOOL_SCREWDRIVER) + SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, !locked) + if (!locked) + update_contents() + if (locked) + replace_beaker(user) + update_icon() + I.play_tool_sound(src, 50) + return + + else if (istype(I, /obj/item/reagent_containers) && !(I.item_flags & ABSTRACT) && I.is_open_container() && locked) + var/obj/item/reagent_containers/B = I + . = TRUE //no afterattack + if(!user.transferItemToLoc(B, src)) + return + replace_beaker(user, B) + update_icon() + updateUsrDialog() + return + + return ..() + +/** + * Updates the contents of the portable chemical mixer + * + * A list of dispensable reagents is created by iterating through each source beaker in the portable chemical beaker and reading its contents + */ +/obj/item/storage/portable_chem_mixer/proc/update_contents() + dispensable_reagents.Cut() + + for (var/obj/item/reagent_containers/glass/beaker/B in contents) + var/key = B.reagents.get_master_reagent_id() + if (!(key in dispensable_reagents)) + dispensable_reagents[key] = list() + dispensable_reagents[key]["reagents"] = list() + dispensable_reagents[key]["reagents"] += B.reagents + + return + +/obj/item/storage/portable_chem_mixer/update_icon_state() + var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED) + if (!locked) + icon_state = "portablechemicalmixer_open" + else if (beaker) + icon_state = "portablechemicalmixer_full" + else + icon_state = "portablechemicalmixer_empty" + + +/obj/item/storage/portable_chem_mixer/AltClick(mob/living/user) + var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED) + if (!locked) + return ..() + if(!can_interact(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) + return + replace_beaker(user) + update_icon() + +/** + * Replaces the beaker of the portable chemical mixer with another beaker, or simply adds the new beaker if none is in currently + * + * Checks if a valid user and a valid new beaker exist and attempts to replace the current beaker in the portable chemical mixer with the one in hand. Simply places the new beaker in if no beaker is currently loaded + * Arguments: + * * mob/living/user - The user who is trying to exchange beakers + * * obj/item/reagent_containers/new_beaker - The new beaker that the user wants to put into the device + */ +/obj/item/storage/portable_chem_mixer/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker) + if(!user) + return FALSE + if(beaker) + user.put_in_hands(beaker) + beaker = null + if(new_beaker) + beaker = new_beaker + return TRUE + +/obj/item/storage/portable_chem_mixer/attack_hand(mob/user) + if (loc != user) + return ..() + if(SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)) + ui_interact(user) + return + +/obj/item/storage/portable_chem_mixer/attack_self(mob/user) + if(loc == user) + var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED) + if (locked) + ui_interact(user) + return + else + to_chat(user, "The portable chemical mixer is currently open and its contents can be accessed.") + return + return + +/obj/item/storage/portable_chem_mixer/MouseDrop(obj/over_object) + . = ..() + if(ismob(loc)) + var/mob/M = loc + if(!M.incapacitated() && istype(over_object, /obj/screen/inventory/hand)) + var/obj/screen/inventory/hand/H = over_object + M.putItemFromInventoryInHandIfPossible(src, H.held_index) + +/obj/item/storage/portable_chem_mixer/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PortableChemMixer", name) + if(user.hallucinating()) + // to not ruin the immersion by constantly changing the fake chemicals + ui.set_autoupdate(FALSE) + ui.open() + +/obj/item/storage/portable_chem_mixer/ui_data(mob/user) + var/list/data = list() + data["amount"] = amount + data["isBeakerLoaded"] = beaker ? 1 : 0 + data["beakerCurrentVolume"] = beaker ? beaker.reagents.total_volume : null + data["beakerMaxVolume"] = beaker ? beaker.volume : null + data["beakerTransferAmounts"] = beaker ? beaker.possible_transfer_amounts : null + var/chemicals[0] + var/is_hallucinating = user.hallucinating() + if(user.hallucinating()) + is_hallucinating = TRUE + for(var/re in dispensable_reagents) + var/value = dispensable_reagents[re] + var/datum/reagent/temp = GLOB.chemical_reagents_list[re] + if(temp) + var/chemname = temp.name + var/total_volume = 0 + for (var/datum/reagents/rs in value["reagents"]) + total_volume += rs.total_volume + if(is_hallucinating && prob(5)) + chemname = "[pick_list_replacements("hallucination.json", "chemicals")]" + chemicals.Add(list(list("title" = chemname, "id" = ckey(temp.name), "volume" = total_volume ))) + data["chemicals"] = chemicals + var/beakerContents[0] + if(beaker) + for(var/datum/reagent/R in beaker.reagents.reagent_list) + beakerContents.Add(list(list("name" = R.name, "id" = ckey(R.name), "volume" = R.volume))) // list in a list because Byond merges the first list... + data["beakerContents"] = beakerContents + return data + +/obj/item/storage/portable_chem_mixer/ui_act(action, params) + if(..()) + return + switch(action) + if("amount") + var/target = text2num(params["target"]) + amount = target + . = TRUE + if("dispense") + var/reagent_name = params["reagent"] + var/datum/reagent/reagent = GLOB.name2reagent[reagent_name] + var/entry = dispensable_reagents[reagent] + if(beaker) + var/datum/reagents/R = beaker.reagents + var/actual = min(amount, 1000, R.maximum_volume - R.total_volume) + // todo: add check if we have enough reagent left + for (var/datum/reagents/source in entry["reagents"]) + var/to_transfer = min(source.total_volume, actual) + source.trans_to(beaker, to_transfer) + actual -= to_transfer + if (actual <= 0) + break + . = TRUE + if("remove") + var/amount = text2num(params["amount"]) + beaker.reagents.remove_all(amount) + . = TRUE + if("eject") + replace_beaker(usr) + update_icon() + . = TRUE diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm index e65325587c..c51edc8106 100644 --- a/code/game/objects/items/devices/radio/electropack.dm +++ b/code/game/objects/items/devices/radio/electropack.dm @@ -16,9 +16,6 @@ var/on = TRUE var/shock_cooldown = FALSE - var/ui_x = 260 - var/ui_y = 137 - /obj/item/electropack/suicide_act(mob/living/carbon/user) user.visible_message("[user] hooks [user.p_them()]self to the electropack and spams the trigger! It looks like [user.p_theyre()] trying to commit suicide!") return (FIRELOSS) @@ -201,17 +198,7 @@ else return ..() -/obj/item/electropack/shockcollar/ui_interact(mob/user) //note to src: use tgooey - var/dat = {" - -Frequency/Code for shock collar:
-Frequency: -[format_frequency(src.frequency)] -Set
-Code: -[src.code] -Set
-
"} - user << browse(dat, "window=radio") - onclose(user, "radio") - return +/obj/item/electropack/ui_act(action, params) + if(action == "power") // DO. NOT. + return FALSE + return ..() diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index fae2833c8a..8fdeaa0f9f 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -729,10 +729,10 @@ GENETICS SCANNER to_chat(user, "[target] is empty!") if(cached_scan_results && cached_scan_results["fusion"]) //notify the user if a fusion reaction was detected - var/fusion_power = round(cached_scan_results["fusion"], 0.01) - var/tier = fusionpower2text(fusion_power) + var/instability = round(cached_scan_results["fusion"], 0.01) + var/tier = instability2text(instability) to_chat(user, "Large amounts of free neutrons detected in the air indicate that a fusion reaction took place.") - to_chat(user, "Power of the last fusion reaction: [fusion_power]\n This power indicates it was a [tier]-tier fusion reaction.") + to_chat(user, "Instability of the last fusion reaction: [instability]\n This indicates it was [tier].") return /obj/item/analyzer/proc/scan_turf(mob/user, turf/location) @@ -783,10 +783,10 @@ GENETICS SCANNER to_chat(user, "Temperature: [round(environment.return_temperature()-T0C, 0.01)] °C ([round(environment.return_temperature(), 0.01)] K)") if(cached_scan_results && cached_scan_results["fusion"]) //notify the user if a fusion reaction was detected - var/fusion_power = round(cached_scan_results["fusion"], 0.01) - var/tier = fusionpower2text(fusion_power) + var/instability = round(cached_scan_results["fusion"], 0.01) + var/tier = instability2text(instability) to_chat(user, "Large amounts of free neutrons detected in the air indicate that a fusion reaction took place.") - to_chat(user, "Power of the last fusion reaction: [fusion_power]\n This power indicates it was a [tier]-tier fusion reaction.") + to_chat(user, "Instability of the last fusion reaction: [instability]\n This indicates it was [tier].") /obj/item/analyzer/ranged desc = "A hand-held scanner which uses advanced spectroscopy and infrared readings to analyze gases as a distance. Alt-Click to use the built in barometer function." @@ -992,4 +992,4 @@ GENETICS SCANNER #undef SCANMODE_CHEMICAL #undef SCANMODE_WOUND #undef SCANNER_CONDENSED -#undef SCANNER_VERBOSE \ No newline at end of file +#undef SCANNER_VERBOSE diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index 01d2924a90..52ff0f740e 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -234,6 +234,9 @@ /obj/item/melee/rapier/attack(mob/living/target, mob/living/user) . = ..() if(iscarbon(target)) + if(HAS_TRAIT(user, TRAIT_PACIFISM)) + visible_message("[user] gently taps [target] with [src].",null,null,COMBAT_MESSAGE_RANGE) + log_combat(user, target, "slept", src) var/mob/living/carbon/H = target H.Dizzy(10) H.adjustStaminaLoss(30) diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index f462050789..653e95c21e 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -291,7 +291,8 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK w_class = WEIGHT_CLASS_BULKY - force = 9 + force = 7 //how much harm mode damage we do + var/stamina_damage_increment = 4 //how much extra damage do we do when in non-harm mode throwforce = 10 damtype = STAMINA attack_verb = list("whacked", "smacked", "struck") @@ -342,17 +343,19 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 /obj/item/melee/bokken/Initialize() . = ..() AddElement(/datum/element/sword_point) + if(!harm) //if initialised in non-harm mode, setup force accordingly + force = force + stamina_damage_increment /obj/item/melee/bokken/attack_self(mob/user) harm = !harm if(harm) - force -= 2 + force -= stamina_damage_increment damtype = BRUTE attack_verb = list("bashed", "smashed", "attacked") bare_wound_bonus = 15 // having your leg smacked by a wooden stick is probably not great for it if it's naked wound_bonus = 0 else - force += 2 + force += stamina_damage_increment damtype = STAMINA attack_verb = list("whacked", "smacked", "struck") bare_wound_bonus = 0 diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index f5003e035b..bcdf509fbe 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -143,10 +143,18 @@ var/amt = max(0, ((force - (move_resist * MOVE_FORCE_CRUSH_RATIO)) / (move_resist * MOVE_FORCE_CRUSH_RATIO)) * 10) take_damage(amt, BRUTE) +#define BLACKLISTED_OBJECTS list(/obj/machinery/power/apc, /obj/machinery/airalarm, /obj/machinery/power/smes, /obj/structure/cable) + /obj/attack_slime(mob/living/simple_animal/slime/user) if(!user.is_adult) return - attack_generic(user, rand(10, 15), "melee", 1) + if(src.type in BLACKLISTED_OBJECTS) + return + if(istype(src, /obj/machinery/atmospherics)) + return + attack_generic(user, rand(10, 15), BRUTE, "melee", 1) + +#undef BLACKLISTED_OBJECTS /obj/mech_melee_attack(obj/mecha/M) M.do_attack_animation(src) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 99b302e9ce..3abee4db33 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -304,18 +304,20 @@ /obj/proc/reskin_obj(mob/M) if(!LAZYLEN(unique_reskin)) return - var/dat = "Reskin options for [name]:\n" - for(var/V in unique_reskin) - var/output = icon2html(src, M, unique_reskin[V]) - dat += "[V]: [output]\n" - to_chat(M, dat) - - var/choice = input(M, always_reskinnable ? "Choose the a reskin for [src]" : "Warning, you can only reskin [src] once!","Reskin Object") as null|anything in unique_reskin - if(QDELETED(src) || !choice || (current_skin && !always_reskinnable) || M.incapacitated() || !in_range(M,src) || !unique_reskin[choice] || unique_reskin[choice] == current_skin) - return - current_skin = choice + var/list/skins = list() + for(var/S in unique_reskin) + skins[S] = image(icon = icon, icon_state = unique_reskin[S]) + var/choice = show_radial_menu(M, src, skins, custom_check = CALLBACK(src, .proc/check_skinnable, M), radius = 40, require_near = TRUE) + if(!choice) + return FALSE icon_state = unique_reskin[choice] - to_chat(M, "[src] is now skinned as '[choice]'.") + current_skin = choice + return + +/obj/proc/check_skinnable(/mob/M) + if(current_skin || !always_reskinnable) + return FALSE + return TRUE /obj/update_overlays() . = ..() diff --git a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm index beb14ff48c..d127a87b20 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm @@ -4,25 +4,6 @@ req_access = list(ACCESS_ALL_PERSONAL_LOCKERS) var/registered_name = null -/obj/structure/closet/secure_closet/personal/examine(mob/user) - . = ..() - if(registered_name) - . += "The display reads, \"Owned by [registered_name]\"." - -/obj/structure/closet/secure_closet/personal/check_access(obj/item/I) - . = ..() - if(!I || !istype(I)) - return - if(istype(I,/obj/item/modular_computer/tablet)) - var/obj/item/modular_computer/tablet/ourTablet = I - var/obj/item/computer_hardware/card_slot/card_slot = ourTablet.all_components[MC_CARD] - if(card_slot) - return registered_name == card_slot.stored_card.registered_name || registered_name == card_slot.stored_card2.registered_name - var/obj/item/card/id/ID = I.GetID() - if(ID && registered_name == ID.registered_name) - return TRUE - return FALSE - /obj/structure/closet/secure_closet/personal/PopulateContents() ..() if(prob(50)) @@ -54,15 +35,24 @@ /obj/structure/closet/secure_closet/personal/attackby(obj/item/W, mob/user, params) var/obj/item/card/id/I = W.GetID() - if(!I || !istype(I)) - return ..() - if(!can_lock(user, FALSE)) //Can't do anything if there isn't a lock! - return - if(I.registered_name && !registered_name) - to_chat(user, "You claim [src].") - registered_name = I.registered_name + if(istype(I)) + if(broken) + to_chat(user, "It appears to be broken.") + return + if(!I || !I.registered_name) + return + if(allowed(user) || !registered_name || (istype(I) && (registered_name == I.registered_name))) + //they can open all lockers, or nobody owns this, or they own this locker + locked = !locked + update_icon() + + if(!registered_name) + registered_name = I.registered_name + desc = "Owned by [I.registered_name]." + else + to_chat(user, "Access Denied.") else - ..() + return ..() /obj/structure/closet/secure_closet/personal/handle_lock_addition() //If lock construction is successful we don't care what access the electronics had, so we override it if(..()) diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 36e4f825da..7853b9619c 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -86,6 +86,10 @@ /obj/structure/grille/attack_animal(mob/user) . = ..() + if(!user.CheckActionCooldown(CLICK_CD_MELEE)) + return + user.DelayNextAction(flush = TRUE) + user.do_attack_animation(src) if(!shock(user, 70) && !QDELETED(src)) //Last hit still shocks but shouldn't deal damage to the grille) take_damage(rand(5,10), BRUTE, "melee", 1) @@ -114,12 +118,12 @@ /obj/structure/grille/attack_alien(mob/living/user) if(!user.CheckActionCooldown(CLICK_CD_MELEE)) return + user.DelayNextAction(flush = TRUE) user.do_attack_animation(src) user.visible_message("[user] mangles [src].", null, null, COMBAT_MESSAGE_RANGE) if(!shock(user, 70)) take_damage(20, BRUTE, "melee", 1) - /obj/structure/grille/CanPass(atom/movable/mover, turf/target) if(istype(mover) && (mover.pass_flags & PASSGRILLE)) return TRUE diff --git a/code/game/sound.dm b/code/game/sound.dm index 0feb01c223..b012ba4e2a 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -130,6 +130,10 @@ /proc/get_sfx(soundin) if(istext(soundin)) switch(soundin) + if ("explosion_creaking") // from skyrat-ss13/skyrat13/pull/3295 + soundin = pick('sound/effects/explosioncreak1.ogg', 'sound/effects/explosioncreak2.ogg') + if ("hull_creaking") // from skyrat-ss13/skyrat13/pull/3295 + soundin = pick('sound/effects/creak1.ogg', 'sound/effects/creak2.ogg', 'sound/effects/creak3.ogg') if ("shatter") soundin = pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg') if ("explosion") diff --git a/code/game/world.dm b/code/game/world.dm index a342200b3d..2d174c86e5 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -20,8 +20,6 @@ GLOBAL_LIST(topic_status_cache) log_world("World loaded at [TIME_STAMP("hh:mm:ss", FALSE)]!") - SetupExternalRSC() - GLOB.config_error_log = GLOB.world_manifest_log = GLOB.world_pda_log = GLOB.world_job_debug_log = GLOB.sql_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = "data/logs/config_error.[GUID()].log" //temporary file used to record errors with loading config, moved to log directory once logging is set bl make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once) @@ -87,17 +85,6 @@ GLOBAL_LIST(topic_status_cache) #endif SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, /proc/addtimer, cb, 10 SECONDS)) -/world/proc/SetupExternalRSC() -#if (PRELOAD_RSC == 0) - GLOB.external_rsc_urls = world.file2list("[global.config.directory]/external_rsc_urls.txt","\n") - var/i=1 - while(i<=GLOB.external_rsc_urls.len) - if(GLOB.external_rsc_urls[i]) - i++ - else - GLOB.external_rsc_urls.Cut(i,i+1) -#endif - /world/proc/SetupLogs() var/override_dir = params[OVERRIDE_LOG_DIRECTORY_PARAMETER] if(!override_dir) diff --git a/code/modules/NTNet/network.dm b/code/modules/NTNet/network.dm index d86ad792fe..2a2820d289 100644 --- a/code/modules/NTNet/network.dm +++ b/code/modules/NTNet/network.dm @@ -206,7 +206,7 @@ for(var/datum/ntnet_conversation/chan in chat_channels) if(chan.id == id) return chan - + // Resets the IDS alarm /datum/ntnet/proc/resetIDS() intrusion_detection_alarm = FALSE diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 8cfae3820a..8421d9955d 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -1,12 +1,12 @@ //////////////////////////////// /proc/message_admins(msg) - msg = "ADMIN LOG: [msg]" - to_chat(GLOB.admins, msg) + msg = "ADMIN LOG: [msg]" + to_chat(GLOB.admins, msg, confidential = TRUE) /proc/relay_msg_admins(msg) - msg = "RELAY: [msg]" - to_chat(GLOB.admins, msg) + msg = "RELAY: [msg]" + to_chat(GLOB.admins, msg, confidential = TRUE) ///////////////////////////////////////////////////////////////////////////////////////////////Panels @@ -22,7 +22,7 @@ log_admin("[key_name(usr)] checked the individual player panel for [key_name(M)][isobserver(usr)?"":" while in game"].") if(!M) - to_chat(usr, "You seem to be selecting a mob that doesn't exist anymore.") + to_chat(usr, "You seem to be selecting a mob that doesn't exist anymore.", confidential = TRUE) return var/body = "Options for [M.key]" @@ -65,6 +65,7 @@ body += "VV - " if(M.mind) body += "TP - " + // body += "SKILLS - " else body += "Init Mind - " if (iscyborg(M)) @@ -122,6 +123,7 @@ body += "Traitor panel | " body += "Narrate to | " body += "Subtle message | " + // body += "Play sound to | " body += "Language Menu" if (M.client) @@ -216,7 +218,7 @@ if (!istype(src, /datum/admins)) src = usr.client.holder if (!istype(src, /datum/admins)) - to_chat(usr, "Error: you are not an admin!") + to_chat(usr, "Error: you are not an admin!", confidential = TRUE) return var/dat dat = text("Admin Newscaster

Admin Newscaster Unit

") @@ -242,7 +244,7 @@ dat+="

The newscaster recognises you as:
[src.admin_signature]
" if(1) dat+= "Station Feed Channels
" - if( isemptylist(GLOB.news_network.network_channels) ) + if( !length(GLOB.news_network.network_channels) ) dat+="No active channels found..." else for(var/datum/news/feed_channel/CHANNEL in GLOB.news_network.network_channels) @@ -295,7 +297,7 @@ dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a Nanotrasen D-Notice.
" dat+="No further feed story additions are allowed while the D-Notice is in effect.

" else - if( isemptylist(src.admincaster_feed_channel.messages) ) + if( !length(src.admincaster_feed_channel.messages) ) dat+="No feed messages found in channel...
" else var/i = 0 @@ -317,7 +319,7 @@ dat+="NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.
" dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.
" dat+="
Select Feed channel to get Stories from:
" - if(isemptylist(GLOB.news_network.network_channels)) + if(!length(GLOB.news_network.network_channels)) dat+="No feed channels found active...
" else for(var/datum/news/feed_channel/CHANNEL in GLOB.news_network.network_channels) @@ -328,7 +330,7 @@ dat+="A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the station's" dat+="morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed" dat+="stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.
" - if(isemptylist(GLOB.news_network.network_channels)) + if(!length(GLOB.news_network.network_channels)) dat+="No feed channels found active...
" else for(var/datum/news/feed_channel/CHANNEL in GLOB.news_network.network_channels) @@ -339,7 +341,7 @@ dat+="[src.admincaster_feed_channel.channel_name]: \[ created by: [src.admincaster_feed_channel.returnAuthor(-1)] \]
" dat+="[(src.admincaster_feed_channel.authorCensor) ? ("Undo Author censorship") : ("Censor channel Author")]
" - if( isemptylist(src.admincaster_feed_channel.messages) ) + if( !length(src.admincaster_feed_channel.messages) ) dat+="No feed messages found in channel...
" else for(var/datum/news/feed_message/MESSAGE in src.admincaster_feed_channel.messages) @@ -356,7 +358,7 @@ dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a Nanotrasen D-Notice.
" dat+="No further feed story additions are allowed while the D-Notice is in effect.

" else - if( isemptylist(src.admincaster_feed_channel.messages) ) + if( !length(src.admincaster_feed_channel.messages) ) dat+="No feed messages found in channel...
" else for(var/datum/news/feed_message/MESSAGE in src.admincaster_feed_channel.messages) @@ -426,7 +428,6 @@ "} if(GLOB.master_mode == "secret") dat += "(Force Secret Mode)
" - if(GLOB.master_mode == "dynamic") if(SSticker.current_state <= GAME_STATE_PREGAME) dat += "(Force Roundstart Rulesets)
" @@ -449,7 +450,6 @@ dat += "
" if(SSticker.IsRoundInProgress()) dat += "(Game Mode Panel)
" - dat += {"
Create Object
@@ -461,7 +461,7 @@ if(marked_datum && istype(marked_datum, /atom)) dat += "Duplicate Marked Datum
" - usr << browse(dat, "window=admin2;size=210x200") + usr << browse(dat, "window=admin2;size=240x280") return /////////////////////////////////////////////////////////////////////////////////////////////////admins2.dm merge @@ -475,33 +475,42 @@ if (!usr.client.holder) return - var/list/options = list("Regular Restart", "Hard Restart (No Delay/Feeback Reason)", "Hardest Restart (No actions, just reboot)") + var/localhost_addresses = list("127.0.0.1", "::1") + var/list/options = list("Regular Restart", "Regular Restart (with delay)", "Hard Restart (No Delay/Feeback Reason)", "Hardest Restart (No actions, just reboot)") if(world.TgsAvailable()) options += "Server Restart (Kill and restart DD)"; - var/rebootconfirm if(SSticker.admin_delay_notice) - if(alert(usr, "Are you sure? An admin has already delayed the round end for the following reason: [SSticker.admin_delay_notice]", "Confirmation", "Yes", "No") == "Yes") - rebootconfirm = TRUE - else - rebootconfirm = TRUE - if(rebootconfirm) - var/result = input(usr, "Select reboot method", "World Reboot", options[1]) as null|anything in options - if(result) - SSblackbox.record_feedback("tally", "admin_verb", 1, "Reboot World") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - var/init_by = "Initiated by [usr.client.holder.fakekey ? "Admin" : usr.key]." - switch(result) - if("Regular Restart") - SSticker.Reboot(init_by, "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", 10) - if("Hard Restart (No Delay, No Feeback Reason)") - to_chat(world, "World reboot - [init_by]") - world.Reboot() - if("Hardest Restart (No actions, just reboot)") - to_chat(world, "Hard world reboot - [init_by]") - world.Reboot(fast_track = TRUE) - if("Server Restart (Kill and restart DD)") - to_chat(world, "Server restart - [init_by]") - world.TgsEndProcess() + if(alert(usr, "Are you sure? An admin has already delayed the round end for the following reason: [SSticker.admin_delay_notice]", "Confirmation", "Yes", "No") != "Yes") + return FALSE + + var/result = input(usr, "Select reboot method", "World Reboot", options[1]) as null|anything in options + if(result) + SSblackbox.record_feedback("tally", "admin_verb", 1, "Reboot World") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + var/init_by = "Initiated by [usr.client.holder.fakekey ? "Admin" : usr.key]." + switch(result) + if("Regular Restart") + if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses))) + if(alert("Are you sure you want to restart the server?","This server is live","Restart","Cancel") != "Restart") + return FALSE + SSticker.Reboot(init_by, "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", 10) + if("Regular Restart (with delay)") + var/delay = input("What delay should the restart have (in seconds)?", "Restart Delay", 5) as num|null + if(!delay) + return FALSE + if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses))) + if(alert("Are you sure you want to restart the server?","This server is live","Restart","Cancel") != "Restart") + return FALSE + SSticker.Reboot(init_by, "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", delay * 10) + if("Hard Restart (No Delay, No Feeback Reason)") + to_chat(world, "World reboot - [init_by]") + world.Reboot() + if("Hardest Restart (No actions, just reboot)") + to_chat(world, "Hard world reboot - [init_by]") + world.Reboot(fast_track = TRUE) + if("Server Restart (Kill and restart DD)") + to_chat(world, "Server restart - [init_by]") + world.TgsEndProcess() /datum/admins/proc/end_round() set category = "Server" @@ -529,7 +538,7 @@ if(message) if(!check_rights(R_SERVER,0)) message = adminscrub(message,500) - to_chat(world, "[usr.client.holder.fakekey ? "Administrator" : usr.key] Announces:\n \t [message]") + to_chat(world, "[usr.client.holder.fakekey ? "Administrator" : usr.key] Announces:\n \t [message]", confidential = TRUE) log_admin("Announce: [key_name(usr)] : [message]") SSblackbox.record_feedback("tally", "admin_verb", 1, "Announce") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -551,7 +560,7 @@ else message_admins("[key_name(usr)] set the admin notice.") log_admin("[key_name(usr)] set the admin notice:\n[new_admin_notice]") - to_chat(world, "Admin Notice:\n \t [new_admin_notice]") + to_chat(world, "Admin Notice:\n \t [new_admin_notice]", confidential = TRUE) SSblackbox.record_feedback("tally", "admin_verb", 1, "Set Admin Notice") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! GLOB.admin_notice = new_admin_notice return @@ -598,20 +607,29 @@ set desc="Start the round RIGHT NOW" set name="Start Now" if(SSticker.current_state == GAME_STATE_PREGAME || SSticker.current_state == GAME_STATE_STARTUP) - SSticker.start_immediately = TRUE - log_admin("[usr.key] has started the game.") - var/msg = "" - if(SSticker.current_state == GAME_STATE_STARTUP) - msg = " (The server is still setting up, but the round will be \ - started as soon as possible.)" - message_admins("\ - [usr.key] has started the game.[msg]") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Start Now") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - return 1 + if(!SSticker.start_immediately) + var/localhost_addresses = list("127.0.0.1", "::1") + if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses))) + if(alert("Are you sure you want to start the round?","Start Now","Start Now","Cancel") != "Start Now") + return FALSE + SSticker.start_immediately = TRUE + log_admin("[usr.key] has started the game.") + var/msg = "" + if(SSticker.current_state == GAME_STATE_STARTUP) + msg = " (The server is still setting up, but the round will be \ + started as soon as possible.)" + message_admins("[usr.key] has started the game.[msg]") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Start Now") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return TRUE + SSticker.start_immediately = FALSE + SSticker.SetTimeLeft(1800) + to_chat(world, "The game will start in 180 seconds.") + SEND_SOUND(world, sound(get_announcer_sound("attention"))) + message_admins("[usr.key] has cancelled immediate game start. Game will start in 180 seconds.") + log_admin("[usr.key] has cancelled immediate game start.") else to_chat(usr, "Error: Start Now: Game has already started.") - - return 0 + return FALSE /datum/admins/proc/toggleenter() set category = "Server" @@ -619,9 +637,9 @@ set name="Toggle Entering" GLOB.enter_allowed = !( GLOB.enter_allowed ) if (!( GLOB.enter_allowed )) - to_chat(world, "New players may no longer enter the game.") + to_chat(world, "New players may no longer enter the game.", confidential = TRUE) else - to_chat(world, "New players may now enter the game.") + to_chat(world, "New players may now enter the game.", confidential = TRUE) log_admin("[key_name(usr)] toggled new player game entering.") message_admins("[key_name_admin(usr)] toggled new player game entering.") world.update_status() @@ -634,9 +652,9 @@ var/alai = CONFIG_GET(flag/allow_ai) CONFIG_SET(flag/allow_ai, !alai) if (alai) - to_chat(world, "The AI job is no longer chooseable.") + to_chat(world, "The AI job is no longer chooseable.", confidential = TRUE) else - to_chat(world, "The AI job is chooseable now.") + to_chat(world, "The AI job is chooseable now.", confidential = TRUE) log_admin("[key_name(usr)] toggled AI allowed.") world.update_status() SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle AI", "[!alai ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -654,7 +672,7 @@ aiPlayer.end_multicam() log_admin("[key_name(usr)] toggled AI multicam.") world.update_status() - to_chat(GLOB.ai_list | GLOB.admins, "The AI [almcam ? "no longer" : "now"] has multicam.") + to_chat(GLOB.ai_list | GLOB.admins, "The AI [almcam ? "no longer" : "now"] has multicam.", confidential = TRUE) SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Multicam", "[!almcam ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /datum/admins/proc/toggleaban() @@ -664,9 +682,9 @@ var/new_nores = !CONFIG_GET(flag/norespawn) CONFIG_SET(flag/norespawn, new_nores) if (!new_nores) - to_chat(world, "You may now respawn.") + to_chat(world, "You may now respawn.", confidential = TRUE) else - to_chat(world, "You may no longer respawn :(") + to_chat(world, "You may no longer respawn :(", confidential = TRUE) message_admins("[key_name_admin(usr)] toggled respawn to [!new_nores ? "On" : "Off"].") log_admin("[key_name(usr)] toggled respawn to [!new_nores ? "On" : "Off"].") world.update_status() @@ -675,7 +693,7 @@ /datum/admins/proc/delay() set category = "Server" set desc="Delay the game start" - set name="Delay pre-game" + set name="Delay Pre-Game" var/newtime = input("Set a new time in seconds. Set -1 for indefinite delay.","Set Delay",round(SSticker.GetTimeLeft()/10)) as num|null if(SSticker.current_state > GAME_STATE_PREGAME) @@ -683,11 +701,12 @@ if(newtime) newtime = newtime*10 SSticker.SetTimeLeft(newtime) + SSticker.start_immediately = FALSE if(newtime < 0) - to_chat(world, "The game start has been delayed.") + to_chat(world, "The game start has been delayed.", confidential = TRUE) log_admin("[key_name(usr)] delayed the round start.") else - to_chat(world, "The game will start in [DisplayTimeText(newtime)].") + to_chat(world, "The game will start in [DisplayTimeText(newtime)].", confidential = TRUE) SEND_SOUND(world, sound(get_announcer_sound("attention"))) log_admin("[key_name(usr)] set the pre-game delay to [DisplayTimeText(newtime)].") SSblackbox.record_feedback("tally", "admin_verb", 1, "Delay Game Start") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -724,20 +743,28 @@ set desc = "(atom path) Spawn an atom" set name = "Spawn" - if(!check_rights(R_SPAWN)) + if(!check_rights(R_SPAWN) || !object) + return + + var/list/preparsed = splittext(object,":") + var/path = preparsed[1] + var/amount = 1 + if(preparsed.len > 1) + amount = clamp(text2num(preparsed[2]),1, 50) //50 at a time! + + var/chosen = pick_closest_path(path) + if(!chosen) return var/turf/T = get_turf(usr) - var/chosen = pick_closest_path(object) - if(!chosen) - return if(ispath(chosen, /turf)) T.ChangeTurf(chosen) else - var/atom/A = new chosen(T) - A.flags_1 |= ADMIN_SPAWNED_1 + for(var/i in 1 to amount) + var/atom/A = new chosen(T) + A.flags_1 |= ADMIN_SPAWNED_1 - log_admin("[key_name(usr)] spawned [chosen] at [AREACOORD(usr)]") + log_admin("[key_name(usr)] spawned [amount] x [chosen] at [AREACOORD(usr)]") SSblackbox.record_feedback("tally", "admin_verb", 1, "Spawn Atom") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /datum/admins/proc/podspawn_atom(object as text) @@ -782,20 +809,18 @@ log_admin("[key_name(usr)] spawned cargo pack [chosen] at [AREACOORD(usr)]") SSblackbox.record_feedback("tally", "admin_verb", 1, "Spawn Cargo") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/datum/admins/proc/show_traitor_panel(mob/M in GLOB.mob_list) +/datum/admins/proc/show_traitor_panel(mob/target_mob in GLOB.mob_list) set category = "Admin" set desc = "Edit mobs's memory and role" set name = "Show Traitor Panel" - - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") + var/datum/mind/target_mind = target_mob.mind + if(!target_mind) + to_chat(usr, "This mob has no mind!", confidential = TRUE) return - if(!M.mind) - to_chat(usr, "This mob has no mind!") + if(!istype(target_mob) && !istype(target_mind)) + to_chat(usr, "This can only be used on instances of type /mob and /mind", confidential = TRUE) return - - M.mind.traitor_panel() + target_mind.traitor_panel() SSblackbox.record_feedback("tally", "admin_verb", 1, "Traitor Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -805,9 +830,9 @@ set name="Toggle tinted welding helmes" GLOB.tinted_weldhelh = !( GLOB.tinted_weldhelh ) if (GLOB.tinted_weldhelh) - to_chat(world, "The tinted_weldhelh has been enabled!") + to_chat(world, "The tinted_weldhelh has been enabled!", confidential = TRUE) else - to_chat(world, "The tinted_weldhelh has been disabled!") + to_chat(world, "The tinted_weldhelh has been disabled!", confidential = TRUE) log_admin("[key_name(usr)] toggled tinted_weldhelh.") message_admins("[key_name_admin(usr)] toggled tinted_weldhelh.") SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Tinted Welding Helmets", "[GLOB.tinted_weldhelh ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -819,9 +844,9 @@ var/new_guest_ban = !CONFIG_GET(flag/guest_ban) CONFIG_SET(flag/guest_ban, new_guest_ban) if (new_guest_ban) - to_chat(world, "Guests may no longer enter the game.") + to_chat(world, "Guests may no longer enter the game.", confidential = TRUE) else - to_chat(world, "Guests may now enter the game.") + to_chat(world, "Guests may now enter the game.", confidential = TRUE) log_admin("[key_name(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.") message_admins("[key_name_admin(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.") SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Guests", "[!new_guest_ban ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -832,37 +857,37 @@ var/mob/living/silicon/S = i ai_number++ if(isAI(S)) - to_chat(usr, "AI [key_name(S, usr)]'s laws:") + to_chat(usr, "AI [key_name(S, usr)]'s laws:", confidential = TRUE) else if(iscyborg(S)) var/mob/living/silicon/robot/R = S - to_chat(usr, "CYBORG [key_name(S, usr)] [R.connected_ai?"(Slaved to: [key_name(R.connected_ai)])":"(Independent)"]: laws:") + to_chat(usr, "CYBORG [key_name(S, usr)] [R.connected_ai?"(Slaved to: [key_name(R.connected_ai)])":"(Independent)"]: laws:", confidential = TRUE) else if (ispAI(S)) - to_chat(usr, "pAI [key_name(S, usr)]'s laws:") + to_chat(usr, "pAI [key_name(S, usr)]'s laws:", confidential = TRUE) else - to_chat(usr, "SOMETHING SILICON [key_name(S, usr)]'s laws:") + to_chat(usr, "SOMETHING SILICON [key_name(S, usr)]'s laws:", confidential = TRUE) if (S.laws == null) - to_chat(usr, "[key_name(S, usr)]'s laws are null?? Contact a coder.") + to_chat(usr, "[key_name(S, usr)]'s laws are null?? Contact a coder.", confidential = TRUE) else S.laws.show_laws(usr) if(!ai_number) - to_chat(usr, "No AIs located" ) + to_chat(usr, "No AIs located" , confidential = TRUE) /datum/admins/proc/output_all_devil_info() var/devil_number = 0 for(var/datum/mind/D in SSticker.mode.devils) devil_number++ var/datum/antagonist/devil/devil = D.has_antag_datum(/datum/antagonist/devil) - to_chat(usr, "Devil #[devil_number]:

" + devil.printdevilinfo()) + to_chat(usr, "Devil #[devil_number]:

" + devil.printdevilinfo(), confidential = TRUE) if(!devil_number) - to_chat(usr, "No Devils located" ) + to_chat(usr, "No Devils located" , confidential = TRUE) /datum/admins/proc/output_devil_info(mob/living/M) if(is_devil(M)) var/datum/antagonist/devil/devil = M.mind.has_antag_datum(/datum/antagonist/devil) - to_chat(usr, devil.printdevilinfo()) + to_chat(usr, devil.printdevilinfo(), confidential = TRUE) else - to_chat(usr, "[M] is not a devil.") + to_chat(usr, "[M] is not a devil.", confidential = TRUE) /datum/admins/proc/manage_free_slots() if(!check_rights()) @@ -965,21 +990,21 @@ if(kick_only_afk && !C.is_afk()) //Ignore clients who are not afk continue if(message) - to_chat(C, message) + to_chat(C, message, confidential = TRUE) kicked_client_names.Add("[C.key]") qdel(C) return kicked_client_names -//returns 1 to let the dragdrop code know we are trapping this event -//returns 0 if we don't plan to trap the event +//returns TRUE to let the dragdrop code know we are trapping this event +//returns FALSE if we don't plan to trap the event /datum/admins/proc/cmd_ghost_drag(mob/dead/observer/frommob, mob/tomob) //this is the exact two check rights checks required to edit a ckey with vv. if (!check_rights(R_VAREDIT,0) || !check_rights(R_SPAWN|R_DEBUG,0)) - return 0 + return FALSE if (!frommob.ckey) - return 0 + return FALSE var/question = "" if (tomob.ckey) @@ -988,12 +1013,18 @@ var/ask = alert(question, "Place ghost in control of mob?", "Yes", "No") if (ask != "Yes") - return 1 + return TRUE if (!frommob || !tomob) //make sure the mobs don't go away while we waited for a response - return 1 + return TRUE - tomob.ghostize(0) + // Disassociates observer mind from the body mind + if(tomob.client) + tomob.ghostize(FALSE) + else + for(var/mob/dead/observer/ghost in GLOB.dead_mob_list) + if(tomob.mind == ghost.mind) + ghost.mind = null message_admins("[key_name_admin(usr)] has put [frommob.key] in control of [tomob.name].") log_admin("[key_name(usr)] stuffed [frommob.key] into [tomob.name].") @@ -1002,7 +1033,7 @@ tomob.ckey = frommob.ckey qdel(frommob) - return 1 + return TRUE /client/proc/adminGreet(logout) if(SSticker.HasRoundStarted()) diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm index 99bb988be6..7e5c104d90 100644 --- a/code/modules/admin/admin_investigate.dm +++ b/code/modules/admin/admin_investigate.dm @@ -4,19 +4,39 @@ var/F = file("[GLOB.log_directory]/[subject].html") WRITE_FILE(F, "[TIME_STAMP("hh:mm:ss", FALSE)] [REF(src)] ([x],[y],[z]) || [src] [message]
") -/client/proc/investigate_show(subject in list("notes, memos, watchlist", INVESTIGATE_RCD, INVESTIGATE_RESEARCH, INVESTIGATE_EXONET, INVESTIGATE_PORTAL, INVESTIGATE_SINGULO, INVESTIGATE_WIRES, INVESTIGATE_TELESCI, INVESTIGATE_GRAVITY, INVESTIGATE_RECORDS, INVESTIGATE_CARGO, INVESTIGATE_SUPERMATTER, INVESTIGATE_ATMOS, INVESTIGATE_EXPERIMENTOR, INVESTIGATE_BOTANY, INVESTIGATE_HALLUCINATIONS, INVESTIGATE_RADIATION, INVESTIGATE_CIRCUIT, INVESTIGATE_NANITES, INVESTIGATE_CRYOGENICS) ) +/client/proc/investigate_show() set name = "Investigate" set category = "Admin" if(!holder) return - switch(subject) - if("notes, memos, watchlist") - if(!check_rights(R_ADMIN)) - return - browse_messages() + + var/list/investigates = list(INVESTIGATE_RCD, INVESTIGATE_RESEARCH, INVESTIGATE_EXONET, INVESTIGATE_PORTAL, INVESTIGATE_SINGULO, INVESTIGATE_WIRES, INVESTIGATE_TELESCI, INVESTIGATE_GRAVITY, INVESTIGATE_RECORDS, INVESTIGATE_CARGO, INVESTIGATE_SUPERMATTER, INVESTIGATE_ATMOS, INVESTIGATE_EXPERIMENTOR, INVESTIGATE_BOTANY, INVESTIGATE_HALLUCINATIONS, INVESTIGATE_RADIATION, INVESTIGATE_CIRCUIT, INVESTIGATE_NANITES, INVESTIGATE_CRYOGENICS) + + var/list/logs_present = list("notes, memos, watchlist") + var/list/logs_missing = list("---") + + for(var/subject in investigates) + var/temp_file = file("[GLOB.log_directory]/[subject].html") + if(fexists(temp_file)) + logs_present += subject else - var/F = file("[GLOB.log_directory]/[subject].html") - if(!fexists(F)) - to_chat(src, "No [subject] logfile was found.") - return - src << browse(F,"window=investigate[subject];size=800x300") + logs_missing += "[subject] (empty)" + + var/list/combined = sortList(logs_present) + sortList(logs_missing) + + var/selected = input("Investigate what?", "Investigate") as null|anything in combined + + if(!(selected in combined) || selected == "---") + return + + selected = replacetext(selected, " (empty)", "") + + if(selected == "notes, memos, watchlist" && check_rights(R_ADMIN)) + browse_messages() + return + + var/F = file("[GLOB.log_directory]/[selected].html") + if(!fexists(F)) + to_chat(src, "No [selected] logfile was found.", confidential = TRUE) + return + src << browse(F,"window=investigate[selected];size=800x300") diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index 525e4e82c0..257c1d275a 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -3,7 +3,7 @@ set desc = "Area to jump to" set category = "Admin" if(!src.holder) - to_chat(src, "Only administrators may use this command.") + to_chat(src, "Only administrators may use this command.", confidential = TRUE) return if(!A) @@ -15,20 +15,22 @@ continue turfs.Add(T) - var/turf/T = safepick(turfs) - if(!T) - to_chat(src, "Nowhere to jump to!") + if(length(turfs)) + var/turf/T = pick(turfs) + usr.forceMove(T) + log_admin("[key_name(usr)] jumped to [AREACOORD(T)]") + message_admins("[key_name_admin(usr)] jumped to [AREACOORD(T)]") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Jump To Area") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + else + to_chat(src, "Nowhere to jump to!", confidential = TRUE) return - usr.forceMove(T) - log_admin("[key_name(usr)] jumped to [AREACOORD(A)]") - message_admins("[key_name_admin(usr)] jumped to [AREACOORD(A)]") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Jump To Area") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + /client/proc/jumptoturf(turf/T in world) set name = "Jump to Turf" set category = "Admin" if(!src.holder) - to_chat(src, "Only administrators may use this command.") + to_chat(src, "Only administrators may use this command.", confidential = TRUE) return log_admin("[key_name(usr)] jumped to [AREACOORD(T)]") @@ -42,7 +44,7 @@ set name = "Jump to Mob" if(!src.holder) - to_chat(src, "Only administrators may use this command.") + to_chat(src, "Only administrators may use this command.", confidential = TRUE) return log_admin("[key_name(usr)] jumped to [key_name(M)]") @@ -54,14 +56,14 @@ SSblackbox.record_feedback("tally", "admin_verb", 1, "Jump To Mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! A.forceMove(M.loc) else - to_chat(A, "This mob is not located in the game world.") + to_chat(A, "This mob is not located in the game world.", confidential = TRUE) /client/proc/jumptocoord(tx as num, ty as num, tz as num) set category = "Admin" set name = "Jump to Coordinate" if (!holder) - to_chat(src, "Only administrators may use this command.") + to_chat(src, "Only administrators may use this command.", confidential = TRUE) return if(src.mob) @@ -76,7 +78,7 @@ set name = "Jump to Key" if(!src.holder) - to_chat(src, "Only administrators may use this command.") + to_chat(src, "Only administrators may use this command.", confidential = TRUE) return var/list/keys = list() @@ -84,7 +86,7 @@ keys += M.client var/client/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in sortKey(keys) if(!selection) - to_chat(src, "No keys found.") + to_chat(src, "No keys found.", confidential = TRUE) return var/mob/M = selection.mob log_admin("[key_name(usr)] jumped to [key_name(M)]") @@ -99,7 +101,7 @@ set name = "Get Mob" set desc = "Mob to teleport" if(!src.holder) - to_chat(src, "Only administrators may use this command.") + to_chat(src, "Only administrators may use this command.", confidential = TRUE) return var/atom/loc = get_turf(usr) @@ -116,7 +118,7 @@ set desc = "Key to teleport" if(!src.holder) - to_chat(src, "Only administrators may use this command.") + to_chat(src, "Only administrators may use this command.", confidential = TRUE) return var/list/keys = list() @@ -142,16 +144,17 @@ set category = "Admin" set name = "Send Mob" if(!src.holder) - to_chat(src, "Only administrators may use this command.") + to_chat(src, "Only administrators may use this command.", confidential = TRUE) return var/area/A = input(usr, "Pick an area.", "Pick an area") in GLOB.sortedAreas|null if(A && istype(A)) - if(M.forceMove(safepick(get_area_turfs(A)))) + var/list/turfs = get_area_turfs(A) + if(length(turfs) && M.forceMove(pick(turfs))) - log_admin("[key_name(usr)] teleported [key_name(M)] to [AREACOORD(A)]") - var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)] to [AREACOORD(A)]" + log_admin("[key_name(usr)] teleported [key_name(M)] to [AREACOORD(M)]") + var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)] to [AREACOORD(M)]" message_admins(msg) admin_ticket_log(M, msg) else - to_chat(src, "Failed to move mob to a valid location.") + to_chat(src, "Failed to move mob to a valid location.", confidential = TRUE) SSblackbox.record_feedback("tally", "admin_verb", 1, "Send Mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index b7f05740a3..2931c52a5c 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -1,12 +1,11 @@ -#define IRCREPLYCOUNT 2 - +#define EXTERNALREPLYCOUNT 2 //allows right clicking mobs to send an admin PM to their client, forwards the selected mob's client to cmd_admin_pm /client/proc/cmd_admin_pm_context(mob/M in GLOB.mob_list) set category = null set name = "Admin PM Mob" if(!holder) - to_chat(src, "Error: Admin-PM-Context: Only administrators may use this command.") + to_chat(src, "Error: Admin-PM-Context: Only administrators may use this command.", confidential = TRUE) return if( !ismob(M) || !M.client ) return @@ -18,7 +17,7 @@ set category = "Admin" set name = "Admin PM" if(!holder) - to_chat(src, "Error: Admin-PM-Panel: Only administrators may use this command.") + to_chat(src, "Error: Admin-PM-Panel: Only administrators may use this command.", confidential = TRUE) return var/list/client/targets[0] for(var/client/T) @@ -37,7 +36,7 @@ /client/proc/cmd_ahelp_reply(whom) if(prefs.muted & MUTE_ADMINHELP) - to_chat(src, "Error: Admin-PM: You are unable to use admin PM-s (muted).") + to_chat(src, "Error: Admin-PM: You are unable to use admin PM-s (muted).", confidential = TRUE) return var/client/C if(istext(whom)) @@ -48,45 +47,61 @@ C = whom if(!C) if(holder) - to_chat(src, "Error: Admin-PM: Client not found.") + to_chat(src, "Error: Admin-PM: Client not found.", confidential = TRUE) return var/datum/admin_help/AH = C.current_ticket if(AH) - message_admins("[key_name_admin(src)] has started replying to [key_name(C, 0, 0)]'s admin help.") + message_admins("[key_name_admin(src)] has started replying to [key_name_admin(C, 0, 0)]'s admin help.") var/msg = input(src,"Message:", "Private message to [C.holder?.fakekey ? "an Administrator" : key_name(C, 0, 0)].") as message|null if (!msg) - message_admins("[key_name_admin(src)] has cancelled their reply to [key_name(C, 0, 0)]'s admin help.") + message_admins("[key_name_admin(src)] has cancelled their reply to [key_name_admin(C, 0, 0)]'s admin help.") return + if(!C) //We lost the client during input, disconnected or relogged. + if(GLOB.directory[AH.initiator_ckey]) // Client has reconnected, lets try to recover + whom = GLOB.directory[AH.initiator_ckey] + else + to_chat(src, "Error: Admin-PM: Client not found.", confidential = TRUE) + to_chat(src, "Message not sent:
[msg]", confidential = TRUE) + AH.AddInteraction("No client found, message not sent:
[msg]") + return cmd_admin_pm(whom, msg) //takes input from cmd_admin_pm_context, cmd_admin_pm_panel or /client/Topic and sends them a PM. //Fetching a message if needed. src is the sender and C is the target client /client/proc/cmd_admin_pm(whom, msg) if(prefs.muted & MUTE_ADMINHELP) - to_chat(src, "Error: Admin-PM: You are unable to use admin PM-s (muted).") + to_chat(src, "Error: Admin-PM: You are unable to use admin PM-s (muted).", confidential = TRUE) return if(!holder && !current_ticket) //no ticket? https://www.youtube.com/watch?v=iHSPf6x1Fdo - to_chat(src, "You can no longer reply to this ticket, please open another one by using the Adminhelp verb if need be.") - to_chat(src, "Message: [msg]") + to_chat(src, "You can no longer reply to this ticket, please open another one by using the Adminhelp verb if need be.", confidential = TRUE) + to_chat(src, "Message: [msg]", confidential = TRUE) return var/client/recipient - var/irc = 0 + var/recipient_ckey // Stored in case client is deleted between this and after the message is input + var/datum/admin_help/recipient_ticket // Stored in case client is deleted between this and after the message is input + var/external = 0 if(istext(whom)) if(whom[1] == "@") whom = findStealthKey(whom) if(whom == "IRCKEY") - irc = 1 + external = 1 else recipient = GLOB.directory[whom] else if(istype(whom, /client)) recipient = whom + if(!recipient) + to_chat(src, "Error: Admin-PM: Client not found.", confidential = TRUE) + return - if(irc) + recipient_ckey = recipient.ckey + recipient_ticket = recipient.current_ticket + + if(external) if(!ircreplyamount) //to prevent people from spamming irc/discord return if(!msg) @@ -95,21 +110,11 @@ if(!msg) return if(holder) - to_chat(src, "Error: Use the admin IRC channel, nerd.") + to_chat(src, "Error: Use the admin IRC/Discord channel, nerd.", confidential = TRUE) return else - if(!recipient) - if(holder) - to_chat(src, "Error: Admin-PM: Client not found.") - if(msg) - to_chat(src, msg) - return - else if(msg) // you want to continue if there's no message instead of returning now - current_ticket.MessageNoRecipient(msg) - return - //get message text, limit it's length.and clean/escape html if(!msg) msg = input(src,"Message:", "Private message to [recipient.holder?.fakekey ? "an Administrator" : key_name(recipient, 0, 0)].") as message|null @@ -117,22 +122,30 @@ if(!msg) return - if(prefs.muted & MUTE_ADMINHELP) - to_chat(src, "Error: Admin-PM: You are unable to use admin PM-s (muted).") - return - - if(!recipient) + if(!recipient) + if(GLOB.directory[recipient_ckey]) // Client has reconnected, lets try to recover + recipient = GLOB.directory[recipient_ckey] + else if(holder) - to_chat(src, "Error: Admin-PM: Client not found.") + to_chat(src, "Error: Admin-PM: Client not found.", confidential = TRUE) + to_chat(src, "Message not sent:
[msg]", confidential = TRUE) + if(recipient_ticket) + recipient_ticket.AddInteraction("No client found, message not sent:
[msg]") + return else current_ticket.MessageNoRecipient(msg) - return + return + + + if(prefs.muted & MUTE_ADMINHELP) + to_chat(src, "Error: Admin-PM: You are unable to use admin PM-s (muted).", confidential = TRUE) + return if (src.handle_spam_prevention(msg,MUTE_ADMINHELP)) return //clean the message if it's not sent by a high-rank admin - if(!check_rights(R_SERVER|R_DEBUG,0)||irc)//no sending html to the poor bots + if(!check_rights(R_SERVER|R_DEBUG,0)||external)//no sending html to the poor bots msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN)) if(!msg) return @@ -144,28 +157,33 @@ var/keywordparsedmsg = keywords_lookup(msg) - if(irc) - to_chat(src, "PM to-Admins: [rawmsg]") - var/datum/admin_help/AH = admin_ticket_log(src, "Reply PM from-[key_name(src, TRUE, TRUE)] to IRC: [keywordparsedmsg]") + if(external) + to_chat(src, "PM to-Admins: [rawmsg]", confidential = TRUE) + var/datum/admin_help/AH = admin_ticket_log(src, "Reply PM from-[key_name(src, TRUE, TRUE)] to External: [keywordparsedmsg]") ircreplyamount-- send2irc("[AH ? "#[AH.id] " : ""]Reply: [ckey]", rawmsg) + else - if(recipient.holder) - if(holder) //both are admins - to_chat(recipient, "Admin PM from-[key_name(src, recipient, 1)]: [keywordparsedmsg]") - to_chat(src, "Admin PM to-[key_name(recipient, src, 1)]: [keywordparsedmsg]") + var/badmin = FALSE //Lets figure out if an admin is getting bwoinked. + if(holder && recipient.holder && !current_ticket) //Both are admins, and this is not a reply to our own ticket. + badmin = TRUE + if(recipient.holder && !badmin) + if(holder) + to_chat(recipient, "Admin PM from-[key_name(src, recipient, 1)]: [keywordparsedmsg]", confidential = TRUE) + to_chat(src, "Admin PM to-[key_name(recipient, src, 1)]: [keywordparsedmsg]", confidential = TRUE) //omg this is dumb, just fill in both their tickets var/interaction_message = "PM from-[key_name(src, recipient, 1)] to-[key_name(recipient, src, 1)]: [keywordparsedmsg]" admin_ticket_log(src, interaction_message) if(recipient != src) //reeee admin_ticket_log(recipient, interaction_message) - + // SSblackbox.LogAhelp(current_ticket.id, "Reply", msg, recipient.ckey, src.ckey) else //recipient is an admin but sender is not var/replymsg = "Reply PM from-[key_name(src, recipient, 1)]: [keywordparsedmsg]" admin_ticket_log(src, "[replymsg]") - to_chat(recipient, "[replymsg]") - to_chat(src, "PM to-Admins: [msg]") + to_chat(recipient, "[replymsg]", confidential = TRUE) + to_chat(src, "PM to-Admins: [msg]", confidential = TRUE) + // SSblackbox.LogAhelp(current_ticket.id, "Reply", msg, recipient.ckey, src.ckey) //play the receiving admin the adminhelp sound (if they have them enabled) if(recipient.prefs.toggles & SOUND_ADMINHELP) @@ -173,78 +191,88 @@ else if(holder) //sender is an admin but recipient is not. Do BIG RED TEXT + //var/already_logged = FALSE if(!recipient.current_ticket) new /datum/admin_help(msg, recipient, TRUE) + //already_logged = TRUE + // SSblackbox.LogAhelp(recipient.current_ticket.id, "Ticket Opened", msg, recipient.ckey, src.ckey) - to_chat(recipient, "-- Administrator private message --") - to_chat(recipient, "Admin PM from-[key_name(src, recipient, 0)]: [msg]") - to_chat(recipient, "Click on the administrator's name to reply.") - to_chat(src, "Admin PM to-[key_name(recipient, src, 1)]: [msg]") + to_chat(recipient, "-- Administrator private message --", confidential = TRUE) + to_chat(recipient, "Admin PM from-[key_name(src, recipient, 0)]: [msg]", confidential = TRUE) + to_chat(recipient, "Click on the administrator's name to reply.", confidential = TRUE) + to_chat(src, "Admin PM to-[key_name(recipient, src, 1)]: [msg]", confidential = TRUE) admin_ticket_log(recipient, "PM From [key_name_admin(src)]: [keywordparsedmsg]") + // if(!already_logged) //Reply to an existing ticket + // SSblackbox.LogAhelp(recipient.current_ticket.id, "Reply", msg, recipient.ckey, src.ckey) + + //always play non-admin recipients the adminhelp sound SEND_SOUND(recipient, sound('sound/effects/adminhelp.ogg')) //AdminPM popup for ApocStation and anybody else who wants to use it. Set it with POPUP_ADMIN_PM in config.txt ~Carn if(CONFIG_GET(flag/popup_admin_pm)) - spawn() //so we don't hold the caller proc up. Please functionalize this - var/sender = src - var/sendername = key - var/reply = input(recipient, msg,"Admin PM from-[sendername]", "") as message|null //show message and await a reply - if(recipient && reply) - if(sender) - recipient.cmd_admin_pm(sender,reply) //sender is still about, let's reply to them - else - adminhelp(reply) //sender has left, adminhelp instead - return + INVOKE_ASYNC(src, .proc/popup_admin_pm, recipient, msg) else //neither are admins - to_chat(src, "Error: Admin-PM: Non-admin to non-admin PM communication is forbidden.") + to_chat(src, "Error: Admin-PM: Non-admin to non-admin PM communication is forbidden.", confidential = TRUE) return - if(irc) - log_admin_private("PM: [key_name(src)]->IRC: [rawmsg]") + if(external) + log_admin_private("PM: [key_name(src)]->External: [rawmsg]") for(var/client/X in GLOB.admins) - to_chat(X, "PM: [key_name(src, X, 0)]->IRC: [keywordparsedmsg]") + to_chat(X, "PM: [key_name(src, X, 0)]->External: [keywordparsedmsg]", confidential = TRUE) else window_flash(recipient, ignorepref = TRUE) log_admin_private("PM: [key_name(src)]->[key_name(recipient)]: [rawmsg]") //we don't use message_admins here because the sender/receiver might get it too for(var/client/X in GLOB.admins) if(X.key!=key && X.key!=recipient.key) //check client/X is an admin and isn't the sender or recipient - to_chat(X, "PM: [key_name(src, X, 0)]->[key_name(recipient, X, 0)]: [keywordparsedmsg]" ) + to_chat(X, "PM: [key_name(src, X, 0)]->[key_name(recipient, X, 0)]: [keywordparsedmsg]" , confidential = TRUE) + +/client/proc/popup_admin_pm(client/recipient, msg) + var/sender = src + var/sendername = key + var/reply = input(recipient, msg,"Admin PM from-[sendername]", "") as message|null //show message and await a reply + if(recipient && reply) + if(sender) + recipient.cmd_admin_pm(sender,reply) //sender is still about, let's reply to them + else + adminhelp(reply) //sender has left, adminhelp instead - -#define IRC_AHELP_USAGE "Usage: ticket " /proc/IrcPm(target,msg,sender) + return TgsPm(target,msg,sender) //compatability moment. + +#define TGS_AHELP_USAGE "Usage: ticket " +/proc/TgsPm(target,msg,sender) target = ckey(target) var/client/C = GLOB.directory[target] var/datum/admin_help/ticket = C ? C.current_ticket : GLOB.ahelp_tickets.CKey2ActiveTicket(target) var/compliant_msg = trim(lowertext(msg)) - var/irc_tagged = "[sender](IRC)" + var/tgs_tagged = "[sender](TGS/External)" var/list/splits = splittext(compliant_msg, " ") if(splits.len && splits[1] == "ticket") if(splits.len < 2) - return IRC_AHELP_USAGE + return TGS_AHELP_USAGE switch(splits[2]) if("close") if(ticket) - ticket.Close(irc_tagged) + ticket.Close(tgs_tagged) return "Ticket #[ticket.id] successfully closed" if("resolve") if(ticket) - ticket.Resolve(irc_tagged) + ticket.Resolve(tgs_tagged) return "Ticket #[ticket.id] successfully resolved" if("icissue") if(ticket) - ticket.ICIssue(irc_tagged) + ticket.ICIssue(tgs_tagged) return "Ticket #[ticket.id] successfully marked as IC issue" if("reject") if(ticket) - ticket.Reject(irc_tagged) + ticket.Reject(tgs_tagged) return "Ticket #[ticket.id] successfully rejected" if("reopen") if(ticket) @@ -253,7 +281,7 @@ if(!isnull(fail)) fail = text2num(splits[3]) if(isnull(fail)) - return "Error: No/Invalid ticket id specified. [IRC_AHELP_USAGE]" + return "Error: No/Invalid ticket id specified. [TGS_AHELP_USAGE]" var/datum/admin_help/AH = GLOB.ahelp_tickets.TicketByID(fail) if(!AH) return "Error: Ticket #[fail] not found" @@ -275,41 +303,42 @@ . += "#[AH.id]" return else - return IRC_AHELP_USAGE + return TGS_AHELP_USAGE return "Error: Ticket could not be found" var/static/stealthkey - var/adminname = CONFIG_GET(flag/show_irc_name) ? irc_tagged : "Administrator" + var/adminname = CONFIG_GET(flag/show_irc_name) ? tgs_tagged : "Administrator" if(!C) return "Error: No client" if(!stealthkey) - stealthkey = GenIrcStealthKey() + stealthkey = GenTgsStealthKey() msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN)) if(!msg) return "Error: No message" - message_admins("IRC message from [sender] to [key_name_admin(C)] : [msg]") - log_admin_private("IRC PM: [sender] -> [key_name(C)] : [msg]") + message_admins("External message from [sender] to [key_name_admin(C)] : [msg]") + log_admin_private("External PM: [sender] -> [key_name(C)] : [msg]") msg = emoji_parse(msg) - to_chat(C, "-- Administrator private message --") - to_chat(C, "Admin PM from-[adminname]: [msg]") - to_chat(C, "Click on the administrator's name to reply.") + to_chat(C, "-- Administrator private message --", confidential = TRUE) + to_chat(C, "Admin PM from-[adminname]: [msg]", confidential = TRUE) + to_chat(C, "Click on the administrator's name to reply.", confidential = TRUE) - admin_ticket_log(C, "PM From [irc_tagged]: [msg]") + admin_ticket_log(C, "PM From [tgs_tagged]: [msg]") window_flash(C, ignorepref = TRUE) //always play non-admin recipients the adminhelp sound SEND_SOUND(C, 'sound/effects/adminhelp.ogg') - C.ircreplyamount = IRCREPLYCOUNT + // C.externalreplyamount = EXTERNALREPLYCOUNT + C.ircreplyamount = EXTERNALREPLYCOUNT return "Message Successful" -/proc/GenIrcStealthKey() +/proc/GenTgsStealthKey() var/num = (rand(0,1000)) var/i = 0 while(i == 0) @@ -322,4 +351,4 @@ GLOB.stealthminID["IRCKEY"] = stealth return stealth -#undef IRCREPLYCOUNT +#undef EXTERNALREPLYCOUNT diff --git a/code/modules/admin/verbs/adminsay.dm b/code/modules/admin/verbs/adminsay.dm index 9081357ef6..66653020d4 100644 --- a/code/modules/admin/verbs/adminsay.dm +++ b/code/modules/admin/verbs/adminsay.dm @@ -13,7 +13,7 @@ msg = keywords_lookup(msg) msg = "ADMIN: [key_name(usr, 1)] [ADMIN_FLW(mob)]: [msg]" - to_chat(GLOB.admins, msg) + to_chat(GLOB.admins, msg, confidential = TRUE) SSblackbox.record_feedback("tally", "admin_verb", 1, "Asay") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/bluespacearty.dm b/code/modules/admin/verbs/bluespacearty.dm index 2910d6dd85..23fff5ece9 100644 --- a/code/modules/admin/verbs/bluespacearty.dm +++ b/code/modules/admin/verbs/bluespacearty.dm @@ -5,7 +5,7 @@ var/mob/living/target = M if(!isliving(target)) - to_chat(usr, "This can only be used on instances of type /mob/living") + to_chat(usr, "This can only be used on instances of type /mob/living", confidential = TRUE) return explosion(target.loc, 0, 0, 0, 0) diff --git a/code/modules/admin/verbs/borgpanel.dm b/code/modules/admin/verbs/borgpanel.dm index 35f4ddb3e5..2dd5bcb806 100644 --- a/code/modules/admin/verbs/borgpanel.dm +++ b/code/modules/admin/verbs/borgpanel.dm @@ -7,9 +7,9 @@ return if (!istype(borgo, /mob/living/silicon/robot)) - borgo = input("Select a borg", "Select a borg", null, null) as null|anything in GLOB.silicon_mobs + borgo = input("Select a borg", "Select a borg", null, null) as null|anything in sortNames(GLOB.silicon_mobs) if (!istype(borgo, /mob/living/silicon/robot)) - to_chat(usr, "Borg is required for borgpanel") + to_chat(usr, "Borg is required for borgpanel", confidential = TRUE) var/datum/borgpanel/borgpanel = new(usr, borgo) @@ -25,18 +25,18 @@ if(!istype(to_borg)) qdel(src) CRASH("Borg panel is only available for borgs") - user = CLIENT_FROM_VAR(to_user) - if (!user) CRASH("Borg panel attempted to open to a mob without a client") - borg = to_borg -/datum/borgpanel/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.admin_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) +/datum/borgpanel/ui_state(mob/user) + return GLOB.admin_state + +/datum/borgpanel/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "BorgPanel", "Borg Panel", 700, 700, master_ui, state) + ui = new(user, src, "BorgPanel") ui.open() /datum/borgpanel/ui_data(mob/user) @@ -53,13 +53,13 @@ .["upgrades"] = list() for (var/upgradetype in subtypesof(/obj/item/borg/upgrade)-/obj/item/borg/upgrade/hypospray) //hypospray is a dummy parent for hypospray upgrades var/obj/item/borg/upgrade/upgrade = upgradetype - if (initial(upgrade.module_type) && !istype(borg.module, initial(upgrade.module_type))) // Upgrade requires a different module + if (initial(upgrade.module_type) && !is_type_in_list(borg.module, initial(upgrade.module_type))) // Upgrade requires a different module continue var/installed = FALSE if (locate(upgradetype) in borg) installed = TRUE .["upgrades"] += list(list("name" = initial(upgrade.name), "installed" = installed, "type" = upgradetype)) - .["laws"] = borg.laws ? borg.laws.get_law_list(include_zeroth = TRUE) : list() + .["laws"] = borg.laws ? borg.laws.get_law_list(include_zeroth = TRUE, render_html = FALSE) : list() .["channels"] = list() for (var/k in GLOB.radiochannels) if (k == RADIO_CHANNEL_COMMON) diff --git a/code/modules/admin/verbs/deadsay.dm b/code/modules/admin/verbs/deadsay.dm index 4df6f22686..66acc0f667 100644 --- a/code/modules/admin/verbs/deadsay.dm +++ b/code/modules/admin/verbs/deadsay.dm @@ -2,16 +2,16 @@ set category = "Special Verbs" set name = "Dsay" set hidden = 1 - if(!src.holder) - to_chat(src, "Only administrators may use this command.") + if(!holder) + to_chat(src, "Only administrators may use this command.", confidential = TRUE) return - if(!src.mob) + if(!mob) return if(prefs.muted & MUTE_DEADCHAT) - to_chat(src, "You cannot send DSAY messages (muted).") + to_chat(src, "You cannot send DSAY messages (muted).", confidential = TRUE) return - if (src.handle_spam_prevention(msg,MUTE_DEADCHAT)) + if (handle_spam_prevention(msg,MUTE_DEADCHAT)) return msg = copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN) @@ -23,14 +23,25 @@ var/rendered = "DEAD: [uppertext(holder.rank)]([src.holder.fakekey ? pick(nicknames) : src.key]) says, \"[emoji_parse(msg)]\"" + // var/rank_name = holder.rank + // var/admin_name = key + // if(holder.fakekey) + // rank_name = pick(strings("admin_nicknames.json", "ranks", "config")) please use this soon. + // admin_name = pick(strings("admin_nicknames.json", "names", "config")) + // var/rendered = "DEAD: [rank_name]([admin_name]) says, \"[emoji_parse(msg)]\"" + for (var/mob/M in GLOB.player_list) if(isnewplayer(M)) continue - if (M.stat == DEAD || (M.client && M.client.holder && (M.client.prefs.chat_toggles & CHAT_DEAD))) //admins can toggle deadchat on and off. This is a proc in admin.dm and is only give to Administrators and above - to_chat(M, rendered) + if (M.stat == DEAD || (M.client.holder && (M.client.prefs.chat_toggles & CHAT_DEAD))) //admins can toggle deadchat on and off. This is a proc in admin.dm and is only give to Administrators and above + to_chat(M, rendered, confidential = TRUE) SSblackbox.record_feedback("tally", "admin_verb", 1, "Dsay") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/get_dead_say() - var/msg = input(src, null, "dsay \"text\"") as text + var/msg = input(src, null, "dsay \"text\"") as text|null + + if (isnull(msg)) + return + dsay(msg) diff --git a/code/modules/admin/verbs/getlogs.dm b/code/modules/admin/verbs/getlogs.dm index 21a722d32f..4cbb0214f7 100644 --- a/code/modules/admin/verbs/getlogs.dm +++ b/code/modules/admin/verbs/getlogs.dm @@ -31,5 +31,5 @@ src << ftp(file(path)) else return - to_chat(src, "Attempting to send [path], this may take a fair few minutes if the file is very large.") - return \ No newline at end of file + to_chat(src, "Attempting to send [path], this may take a fair few minutes if the file is very large.", confidential = TRUE) + return diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm index e7b9342645..fc2ba55f54 100644 --- a/code/modules/admin/verbs/playsound.dm +++ b/code/modules/admin/verbs/playsound.dm @@ -34,9 +34,7 @@ for(var/mob/M in GLOB.player_list) if(M.client.prefs.toggles & SOUND_MIDI) - var/user_vol = M.client.chatOutput.adminMusicVolume - if(user_vol) - admin_sound.volume = vol * (user_vol / 100) + admin_sound.volume = vol * M.client.admin_music_volume SEND_SOUND(M, admin_sound) admin_sound.volume = vol @@ -69,7 +67,7 @@ if(istext(web_sound_input)) var/web_sound_url = "" var/stop_web_sounds = FALSE - var/pitch + var/list/music_extra_data = list() if(length(web_sound_input)) web_sound_input = trim(web_sound_input) @@ -97,11 +95,10 @@ var/webpage_url = title if (data["webpage_url"]) webpage_url = "[title]" - - var/freq = input(usr, "What frequency would you like the sound to play at?",, 1) as null|num - if(!freq) - freq = 1 - pitch = freq + music_extra_data["start"] = data["start_time"] + music_extra_data["end"] = data["end_time"] + music_extra_data["link"] = data["webpage_url"] + music_extra_data["title"] = data["title"] var/res = alert(usr, "Show the title of and link to this song to the players?\n[title]",, "No", "Yes", "Cancel") switch(res) @@ -130,11 +127,11 @@ for(var/m in GLOB.player_list) var/mob/M = m var/client/C = M.client - if((C.prefs.toggles & SOUND_MIDI) && C.chatOutput && !C.chatOutput.broken && C.chatOutput.loaded) + if(C.prefs.toggles & SOUND_MIDI) if(!stop_web_sounds) - C.chatOutput.sendMusic(web_sound_url, pitch) + C.tgui_panel?.play_music(web_sound_url, music_extra_data) else - C.chatOutput.stopMusic() + C.tgui_panel?.stop_music() SSblackbox.record_feedback("tally", "admin_verb", 1, "Play Internet Sound") @@ -144,7 +141,7 @@ if(!check_rights(R_SOUNDS)) return - var/web_sound_input = input("Enter content stream URL (fetch this from local youtube-dl!)", "Play Internet Sound via direct URL") as text|null + var/web_sound_input = input("Enter content stream URL (must be a direct link)", "Play Internet Sound via direct URL") as text|null if(istext(web_sound_input)) if(!length(web_sound_input)) log_admin("[key_name(src)] stopped web sound") @@ -152,34 +149,37 @@ var/mob/M for(var/i in GLOB.player_list) M = i - M?.client?.chatOutput?.stopMusic() + M?.client?.tgui_panel?.stop_music() return - else - if(web_sound_input && !findtext(web_sound_input, GLOB.is_http_protocol)) - to_chat(src, "BLOCKED: Content URL not using http(s) protocol") - return - var/freq = input(usr, "What frequency would you like the sound to play at?",, 1) as null|num - if(isnull(freq)) - return - if(!freq) - freq = 1 - SSblackbox.record_feedback("nested tally", "played_url", 1, list("[ckey]", "[web_sound_input]")) - var/logstr = "[key_name(src)] played web sound at freq [freq]: [web_sound_input]" - log_admin(logstr) - message_admins(logstr) - var/mob/M - var/client/C - var/datum/chatOutput/O - for(var/i in GLOB.player_list) - M = i - C = M.client - if(!(C?.prefs?.toggles & SOUND_MIDI)) - continue - O = C.chatOutput - if(!O || O.broken || !O.loaded) - continue - O.sendMusic(web_sound_input, freq) - SSblackbox.record_feedback("tally", "admin_verb", 1, "Manual Play Internet Sound") + + var/list/music_extra_data = list() + web_sound_input = trim(web_sound_input) + if(web_sound_input && (findtext(web_sound_input, ":") && !findtext(web_sound_input, GLOB.is_http_protocol))) + to_chat(src, "Non-http(s) URIs are not allowed.", confidential = TRUE) + return + + var/list/explode = splittext(web_sound_input, "/") //if url=="https://fixthisshit.com/pogchamp.ogg"then title="pogchamp.ogg" + var/title = "[explode[explode.len]]" + + if(!findtext(title, ".mp3") && !findtext(title, ".mp4")) // IE sucks. + to_chat(src, "The format is not .mp3/.mp4, IE 8 and above can only support the .mp3/.mp4 format, the music might not play.", confidential = TRUE) + + if(length(title) > 50) //kev no. + title = "Unknown.mp3" + + music_extra_data["title"] = title + + SSblackbox.record_feedback("nested tally", "played_url", 1, list("[ckey]", "[web_sound_input]")) + log_admin("[key_name(src)] played web sound: [web_sound_input]") + message_admins("[key_name(src)] played web sound: [web_sound_input]") + + for(var/m in GLOB.player_list) + var/mob/M = m + var/client/C = M.client + if(C.prefs.toggles & SOUND_MIDI) + C.tgui_panel?.play_music(web_sound_input, music_extra_data) + + SSblackbox.record_feedback("tally", "admin_verb", 1, "Manual Play Internet Sound") /client/proc/set_round_end_sound(S as sound) set category = "Fun" @@ -193,42 +193,6 @@ message_admins("[key_name_admin(src)] set the round end sound to [S]") SSblackbox.record_feedback("tally", "admin_verb", 1, "Set Round End Sound") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/client/proc/play_web_sound_manual() - set category = "Fun" - set name = "Manual Play Internet Sound" - if(!check_rights(R_SOUNDS)) - return - - var/web_sound_input = input("Enter youtube-dl fetched content URL (supported sites only, leave blank to stop playing)", "Send youtube-dl media link") as text|null - if(!istext(web_sound_input)) - return - web_sound_input = trim(web_sound_input) - if(!length(web_sound_input)) - log_admin("[key_name(src)] stopped web sound") - message_admins("[key_name(src)] stopped web sound") - for(var/m in GLOB.player_list) - var/mob/M = m - var/client/C = M.client - if((C.prefs.toggles & SOUND_MIDI) && C.chatOutput && !C.chatOutput.broken && C.chatOutput.loaded) - C.chatOutput.stopMusic() - return - var/freq = input(usr, "What frequency would you like the sound to play at?",, 1) as null|num - if(!freq) - return - if(web_sound_input && !findtext(web_sound_input, GLOB.is_http_protocol)) - to_chat(src, "BLOCKED: Content URL not using http(s) protocol") - to_chat(src, "The media provider returned a content URL that isn't using the HTTP or HTTPS protocol") - return - - SSblackbox.record_feedback("nested tally", "played_url_manual", 1, list("[ckey]", "[web_sound_input]")) - log_admin("[key_name(src)] manually played web sound: [web_sound_input]") - message_admins("[key_name(src)] manually played web sound: HREF") - for(var/m in GLOB.player_list) - var/mob/M = m - var/client/C = M.client - if((C.prefs.toggles & SOUND_MIDI) && C.chatOutput && !C.chatOutput.broken && C.chatOutput.loaded) - C.chatOutput.sendMusic(web_sound_input, freq) - /client/proc/stop_sounds() set category = "Debug" set name = "Stop All Playing Sounds" @@ -238,9 +202,7 @@ log_admin("[key_name(src)] stopped all currently playing sounds.") message_admins("[key_name_admin(src)] stopped all currently playing sounds.") for(var/mob/M in GLOB.player_list) - if(M.client) - SEND_SOUND(M, sound(null)) - var/client/C = M.client - if(C && C.chatOutput && !C.chatOutput.broken && C.chatOutput.loaded) - C.chatOutput.stopMusic() + SEND_SOUND(M, sound(null)) + var/client/C = M.client + C?.tgui_panel?.stop_music() SSblackbox.record_feedback("tally", "admin_verb", 1, "Stop All Playing Sounds") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/view_variables/mass_edit_variables.dm b/code/modules/admin/view_variables/mass_edit_variables.dm index 4e78e1aed7..a498868436 100644 --- a/code/modules/admin/view_variables/mass_edit_variables.dm +++ b/code/modules/admin/view_variables/mass_edit_variables.dm @@ -38,7 +38,7 @@ var/var_value = O.vars[variable] if(variable in GLOB.VVckey_edit) - to_chat(src, "It's forbidden to mass-modify ckeys. It'll crash everyone's client you dummy.") + to_chat(src, "It's forbidden to mass-modify ckeys. It'll crash everyone's client you dummy.", confidential = TRUE) return if(variable in GLOB.VVlocked) if(!check_rights(R_DEBUG)) @@ -56,11 +56,11 @@ default = vv_get_class(variable, var_value) if(isnull(default)) - to_chat(src, "Unable to determine variable type.") + to_chat(src, "Unable to determine variable type.", confidential = TRUE) else - to_chat(src, "Variable appears to be [uppertext(default)].") + to_chat(src, "Variable appears to be [uppertext(default)].", confidential = TRUE) - to_chat(src, "Variable contains: [var_value]") + to_chat(src, "Variable contains: [var_value]", confidential = TRUE) if(default == VV_NUM) var/dir_text = "" @@ -75,7 +75,7 @@ dir_text += "WEST" if(dir_text) - to_chat(src, "If a direction, direction is: [dir_text]") + to_chat(src, "If a direction, direction is: [dir_text]", confidential = TRUE) var/value = vv_get_value(default_class = default) var/new_value = value["value"] @@ -97,9 +97,9 @@ switch(class) if(VV_RESTORE_DEFAULT) - to_chat(src, "Finding items...") + to_chat(src, "Finding items...", confidential = TRUE) var/list/items = get_all_of_type(O.type, method) - to_chat(src, "Changing [items.len] items...") + to_chat(src, "Changing [items.len] items...", confidential = TRUE) for(var/thing in items) if (!thing) continue @@ -123,9 +123,9 @@ for(var/V in varsvars) new_value = replacetext(new_value,"\[[V]]","[O.vars[V]]") - to_chat(src, "Finding items...") + to_chat(src, "Finding items...", confidential = TRUE) var/list/items = get_all_of_type(O.type, method) - to_chat(src, "Changing [items.len] items...") + to_chat(src, "Changing [items.len] items...", confidential = TRUE) for(var/thing in items) if (!thing) continue @@ -151,9 +151,9 @@ many = FALSE var/type = value["type"] - to_chat(src, "Finding items...") + to_chat(src, "Finding items...", confidential = TRUE) var/list/items = get_all_of_type(O.type, method) - to_chat(src, "Changing [items.len] items...") + to_chat(src, "Changing [items.len] items...", confidential = TRUE) for(var/thing in items) if (!thing) continue @@ -169,9 +169,9 @@ CHECK_TICK else - to_chat(src, "Finding items...") + to_chat(src, "Finding items...", confidential = TRUE) var/list/items = get_all_of_type(O.type, method) - to_chat(src, "Changing [items.len] items...") + to_chat(src, "Changing [items.len] items...", confidential = TRUE) for(var/thing in items) if (!thing) continue @@ -185,20 +185,20 @@ var/count = rejected+accepted if (!count) - to_chat(src, "No objects found") + to_chat(src, "No objects found", confidential = TRUE) return if (!accepted) - to_chat(src, "Every object rejected your edit") + to_chat(src, "Every object rejected your edit", confidential = TRUE) return if (rejected) - to_chat(src, "[rejected] out of [count] objects rejected your edit") + to_chat(src, "[rejected] out of [count] objects rejected your edit", confidential = TRUE) log_world("### MassVarEdit by [src]: [O.type] (A/R [accepted]/[rejected]) [variable]=[html_encode("[O.vars[variable]]")]([list2params(value)])") log_admin("[key_name(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)") message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)") //not using global lists as vv is a debug function and debug functions should rely on as less things as possible. -/proc/get_all_of_type(var/T, subtypes = TRUE) +/proc/get_all_of_type(T, subtypes = TRUE) var/list/typecache = list() typecache[T] = 1 if (subtypes) @@ -253,7 +253,7 @@ CHECK_TICK else if (ispath(T, /client)) - for(var/client/thing in world) + for(var/client/thing in GLOB.clients) if (typecache[thing.type]) . += thing CHECK_TICK diff --git a/code/modules/admin/view_variables/modify_variables.dm b/code/modules/admin/view_variables/modify_variables.dm index 5f80b3a5e4..a8871a6467 100644 --- a/code/modules/admin/view_variables/modify_variables.dm +++ b/code/modules/admin/view_variables/modify_variables.dm @@ -17,7 +17,7 @@ GLOBAL_PROTECT(VVpixelmovement) //FALSE = no subtypes, strict exact type pathing (or the type doesn't have subtypes) //TRUE = Yes subtypes //NULL = User cancelled at the prompt or invalid type given -/client/proc/vv_subtype_prompt(var/type) +/client/proc/vv_subtype_prompt(type) if (!ispath(type)) return var/list/subtypes = subtypesof(type) @@ -102,7 +102,7 @@ GLOBAL_PROTECT(VVpixelmovement) L[var_value] = mod_list_add_ass(O) //hehe if (O) if (O.vv_edit_var(objectvar, L) == FALSE) - to_chat(src, "Your edit was rejected by the object.") + to_chat(src, "Your edit was rejected by the object.", confidential = TRUE) return log_world("### ListVarEdit by [src]: [(O ? O.type : "/list")] [objectvar]: ADDED=[var_value]") log_admin("[key_name(src)] modified [original_name]'s [objectvar]: ADDED=[var_value]") @@ -112,7 +112,7 @@ GLOBAL_PROTECT(VVpixelmovement) if(!check_rights(R_VAREDIT)) return if(!istype(L, /list)) - to_chat(src, "Not a List.") + to_chat(src, "Not a List.", confidential = TRUE) return if(L.len > 1000) @@ -121,7 +121,6 @@ GLOBAL_PROTECT(VVpixelmovement) return var/is_normal_list = IS_NORMAL_LIST(L) - var/list/names = list() for (var/i in 1 to L.len) var/key = L[i] @@ -145,7 +144,7 @@ GLOBAL_PROTECT(VVpixelmovement) L = L.Copy() listclearnulls(L) if (!O.vv_edit_var(objectvar, L)) - to_chat(src, "Your edit was rejected by the object.") + to_chat(src, "Your edit was rejected by the object.", confidential = TRUE) return log_world("### ListVarEdit by [src]: [O.type] [objectvar]: CLEAR NULLS") log_admin("[key_name(src)] modified [original_name]'s [objectvar]: CLEAR NULLS") @@ -155,7 +154,7 @@ GLOBAL_PROTECT(VVpixelmovement) if(variable == "(CLEAR DUPES)") L = uniqueList(L) if (!O.vv_edit_var(objectvar, L)) - to_chat(src, "Your edit was rejected by the object.") + to_chat(src, "Your edit was rejected by the object.", confidential = TRUE) return log_world("### ListVarEdit by [src]: [O.type] [objectvar]: CLEAR DUPES") log_admin("[key_name(src)] modified [original_name]'s [objectvar]: CLEAR DUPES") @@ -165,7 +164,7 @@ GLOBAL_PROTECT(VVpixelmovement) if(variable == "(SHUFFLE)") L = shuffle(L) if (!O.vv_edit_var(objectvar, L)) - to_chat(src, "Your edit was rejected by the object.") + to_chat(src, "Your edit was rejected by the object.", confidential = TRUE) return log_world("### ListVarEdit by [src]: [O.type] [objectvar]: SHUFFLE") log_admin("[key_name(src)] modified [original_name]'s [objectvar]: SHUFFLE") @@ -202,9 +201,9 @@ GLOBAL_PROTECT(VVpixelmovement) default = vv_get_class(objectvar, variable) - to_chat(src, "Variable appears to be [uppertext(default)].") + to_chat(src, "Variable appears to be [uppertext(default)].", confidential = TRUE) - to_chat(src, "Variable contains: [variable]") + to_chat(src, "Variable contains: [variable]", confidential = TRUE) if(default == VV_NUM) var/dir_text = "" @@ -220,7 +219,7 @@ GLOBAL_PROTECT(VVpixelmovement) dir_text += "WEST" if(dir_text) - to_chat(usr, "If a direction, direction is: [dir_text]") + to_chat(usr, "If a direction, direction is: [dir_text]", confidential = TRUE) var/original_var = variable @@ -248,7 +247,7 @@ GLOBAL_PROTECT(VVpixelmovement) L.Cut(index, index+1) if (O) if (O.vv_edit_var(objectvar, L)) - to_chat(src, "Your edit was rejected by the object.") + to_chat(src, "Your edit was rejected by the object.", confidential = TRUE) return log_world("### ListVarEdit by [src]: [O.type] [objectvar]: REMOVED=[html_encode("[original_var]")]") log_admin("[key_name(src)] modified [original_name]'s [objectvar]: REMOVED=[original_var]") @@ -260,6 +259,7 @@ GLOBAL_PROTECT(VVpixelmovement) for(var/V in varsvars) new_var = replacetext(new_var,"\[[V]]","[O.vars[V]]") + if(is_normal_list) if(assoc) L[assoc_key] = new_var @@ -269,7 +269,7 @@ GLOBAL_PROTECT(VVpixelmovement) L[new_var] = old_assoc_value if (O) if (O.vv_edit_var(objectvar, L) == FALSE) - to_chat(src, "Your edit was rejected by the object.") + to_chat(src, "Your edit was rejected by the object.", confidential = TRUE) return log_world("### ListVarEdit by [src]: [(O ? O.type : "/list")] [objectvar]: [original_var]=[new_var]") log_admin("[key_name(src)] modified [original_name]'s [objectvar]: [original_var]=[new_var]") @@ -297,7 +297,7 @@ GLOBAL_PROTECT(VVpixelmovement) if(param_var_name) if(!(param_var_name in O.vars)) - to_chat(src, "A variable with this name ([param_var_name]) doesn't exist in this datum ([O])") + to_chat(src, "A variable with this name ([param_var_name]) doesn't exist in this datum ([O])", confidential = TRUE) return variable = param_var_name @@ -322,11 +322,11 @@ GLOBAL_PROTECT(VVpixelmovement) var/default = vv_get_class(variable, var_value) if(isnull(default)) - to_chat(src, "Unable to determine variable type.") + to_chat(src, "Unable to determine variable type.", confidential = TRUE) else - to_chat(src, "Variable appears to be [uppertext(default)].") + to_chat(src, "Variable appears to be [uppertext(default)].", confidential = TRUE) - to_chat(src, "Variable contains: [var_value]") + to_chat(src, "Variable contains: [var_value]", confidential = TRUE) if(default == VV_NUM) var/dir_text = "" @@ -341,7 +341,7 @@ GLOBAL_PROTECT(VVpixelmovement) dir_text += "WEST" if(dir_text) - to_chat(src, "If a direction, direction is: [dir_text]") + to_chat(src, "If a direction, direction is: [dir_text]", confidential = TRUE) if(autodetect_class && default != VV_NULL) if (default == VV_TEXT) @@ -378,7 +378,7 @@ GLOBAL_PROTECT(VVpixelmovement) if (O.vv_edit_var(variable, var_new) == FALSE) - to_chat(src, "Your edit was rejected by the object.") + to_chat(src, "Your edit was rejected by the object.", confidential = TRUE) return vv_update_display(O, "varedited", VV_MSG_EDITED) log_world("### VarEdit by [key_name(src)]: [O.type] [variable]=[var_value] => [var_new]") diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm index 626e75fa10..9f61781f01 100644 --- a/code/modules/admin/view_variables/topic.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -25,7 +25,7 @@ var/mob/M = locate(href_list["rename"]) in GLOB.mob_list if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") + to_chat(usr, "This can only be used on instances of type /mob", confidential = TRUE) return var/new_name = stripped_input(usr,"What would you like to name this mob?","Input a name",M.real_name,MAX_NAME_LEN) @@ -43,7 +43,7 @@ var/atom/A = locate(href_list["rotatedatum"]) if(!istype(A)) - to_chat(usr, "This can only be done to instances of type /atom") + to_chat(usr, "This can only be done to instances of type /atom", confidential = TRUE) return switch(href_list["rotatedir"]) @@ -60,13 +60,13 @@ var/mob/living/carbon/monkey/Mo = locate(href_list["makehuman"]) in GLOB.mob_list if(!istype(Mo)) - to_chat(usr, "This can only be done to instances of type /mob/living/carbon/monkey") + to_chat(usr, "This can only be done to instances of type /mob/living/carbon/monkey", confidential = TRUE) return if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") return if(!Mo) - to_chat(usr, "Mob doesn't exist anymore") + to_chat(usr, "Mob doesn't exist anymore", confidential = TRUE) return holder.Topic(href, list("humanone"=href_list["makehuman"])) @@ -80,10 +80,13 @@ var/Text = href_list["adjustDamage"] - var/amount = input("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num + var/amount = input("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num|null + + if (isnull(amount)) + return if(!L) - to_chat(usr, "Mob doesn't exist anymore") + to_chat(usr, "Mob doesn't exist anymore", confidential = TRUE) return var/newamt @@ -110,7 +113,7 @@ L.adjustStaminaLoss(amount) newamt = L.getStaminaLoss() else - to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]") + to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]", confidential = TRUE) return if(amount != 0) @@ -124,5 +127,5 @@ //Finally, refresh if something modified the list. if(href_list["datumrefresh"]) var/datum/DAT = locate(href_list["datumrefresh"]) - if(istype(DAT, /datum) || istype(DAT, /client)) + if(istype(DAT, /datum) || istype(DAT, /client) || islist(DAT)) debug_variables(DAT) diff --git a/code/modules/admin/view_variables/topic_basic.dm b/code/modules/admin/view_variables/topic_basic.dm index 9ee7103562..b5d7632515 100644 --- a/code/modules/admin/view_variables/topic_basic.dm +++ b/code/modules/admin/view_variables/topic_basic.dm @@ -34,11 +34,11 @@ if (!C) return if(!target) - to_chat(usr, "The object you tried to expose to [C] no longer exists (nulled or hard-deled)") + to_chat(usr, "The object you tried to expose to [C] no longer exists (nulled or hard-deled)", confidential = TRUE) return message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a VV window") log_admin("Admin [key_name(usr)] Showed [key_name(C)] a VV window of a [target]") - to_chat(C, "[holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window") + to_chat(C, "[holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window", confidential = TRUE) C.debug_variables(target) if(check_rights(R_DEBUG)) if(href_list[VV_HK_DELETE]) @@ -46,31 +46,33 @@ if (isturf(src)) // show the turf that took its place usr.client.debug_variables(src) return - #ifdef REFERENCE_TRACKING - if(href_list[VV_HK_VIEW_REFERENCES]) - var/datum/D = locate(href_list[VV_HK_TARGET]) - if(!D) - to_chat(usr, "Unable to locate item.") + + #ifdef REFERENCE_TRACKING //people with debug can only access this putnam! + if(href_list[VV_HK_VIEW_REFERENCES]) + var/datum/D = locate(href_list[VV_HK_TARGET]) + if(!D) + to_chat(usr, "Unable to locate item.") + return + usr.client.holder.view_refs(target) return - usr.client.holder.view_refs(target) - return - #endif + #endif + if(href_list[VV_HK_MARK]) usr.client.mark_datum(target) if(href_list[VV_HK_ADDCOMPONENT]) if(!check_rights(NONE)) return var/list/names = list() - var/list/componentsubtypes = subtypesof(/datum/component) + var/list/componentsubtypes = sortList(subtypesof(/datum/component), /proc/cmp_typepaths_asc) names += "---Components---" names += componentsubtypes names += "---Elements---" - names += subtypesof(/datum/element) + names += sortList(subtypesof(/datum/element), /proc/cmp_typepaths_asc) var/result = input(usr, "Choose a component/element to add","better know what ur fuckin doin pal") as null|anything in names if(!usr || !result || result == "---Components---" || result == "---Elements---") return if(QDELETED(src)) - to_chat(usr, "That thing doesn't exist anymore!") + to_chat(usr, "That thing doesn't exist anymore!", confidential = TRUE) return var/list/lst = get_callproc_args() if(!lst) @@ -83,7 +85,7 @@ else datumname = "element" target._AddElement(lst) - log_admin("[key_name(usr)] has added [result] [datumname] to [key_name(src)].") - message_admins("[key_name_admin(usr)] has added [result] [datumname] to [key_name_admin(src)].") + log_admin("[key_name(usr)] has added [result] [datumname] to [key_name(target)].") + message_admins("[key_name_admin(usr)] has added [result] [datumname] to [key_name_admin(target)].") if(href_list[VV_HK_CALLPROC]) usr.client.callproc_datum(target) diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm index a4dff725f7..3851008d86 100644 --- a/code/modules/admin/view_variables/view_variables.dm +++ b/code/modules/admin/view_variables/view_variables.dm @@ -1,4 +1,3 @@ - /client/proc/debug_variables(datum/D in world) set category = "Debug" set name = "View Variables" @@ -6,7 +5,7 @@ var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round. if(!usr.client || !usr.client.holder) //This is usr because admins can call the proc on other clients, even if they're not admins, to show them VVs. - to_chat(usr, "You need to be an administrator to access this.") + to_chat(usr, "You need to be an administrator to access this.", confidential = TRUE) return if(!D) @@ -26,7 +25,6 @@ if(istype(D, /atom)) sprite = getFlatIcon(D) - hash = md5(sprite) if(sprite) hash = md5(sprite) src << browse_rsc(sprite, "vv[hash].png") @@ -97,7 +95,7 @@ [title] - + - \ No newline at end of file + diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index ae48fddfb4..d5e1e91478 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -75,11 +75,12 @@ var/inprefs = FALSE var/list/topiclimiter + + ///Used for limiting the rate of clicks sends by the client to avoid abuse var/list/clicklimiter - var/datum/chatOutput/chatOutput - - var/list/credits //lazy list of all credit object bound to this client + ///lazy list of all credit object bound to this client + var/list/credits var/datum/player_details/player_details //these persist between logins/logouts during the same round. diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index e7aa447840..72250fa8f2 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -20,7 +20,9 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( When somebody clicks a link in game, this Topic is called first. It does the stuff in this proc and then is redirected to the Topic() proc for the src=[0xWhatever] (if specified in the link). ie locate(hsrc).Topic() + Such links can be spoofed. + Because of this certain things MUST be considered whenever adding a Topic() for something: - Can it be fed harmful values which could cause runtimes? - Is the Topic call an admin-only thing? @@ -38,7 +40,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( var/asset_cache_job if(href_list["asset_cache_confirm_arrival"]) asset_cache_job = asset_cache_confirm_arrival(href_list["asset_cache_confirm_arrival"]) - if(!asset_cache_job) + if (!asset_cache_job) return // Rate limiting @@ -100,7 +102,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( return // Tgui Topic middleware - if(!tgui_Topic(href_list)) + if(tgui_Topic(href_list)) return // Admin PM @@ -108,10 +110,9 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( cmd_admin_pm(href_list["priv_msg"],null) return - // CITADEL Start - Mentor PM + // Mentor PM (cit.) if (citadel_client_procs(href_list)) return - // CITADEL End switch(href_list["_src_"]) if("holder") @@ -119,7 +120,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( if("usr") hsrc = mob if("mentor") // CITADEL - hsrc = mentor_datum // CITADEL END + hsrc = mentor_datum if("prefs") if (inprefs) return @@ -129,8 +130,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( return if("vars") return view_var_Topic(href,href_list,hsrc) - if("chat") - return chatOutput.Topic(href, href_list) switch(href_list["action"]) if("openLink") @@ -147,7 +146,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( to_chat(src, "Become a BYOND member to access member-perks and features, as well as support the engine that makes this game possible. Only 10 bucks for 3 months! Click Here to find out more.") return 0 return 1 - /* * Call back proc that should be checked in all paths where a client can send messages * @@ -210,14 +208,10 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( /////////// //CONNECT// /////////// -#if (PRELOAD_RSC == 0) -GLOBAL_LIST_EMPTY(external_rsc_urls) -#endif /client/New(TopicData) - world.SetConfig("APP/admin", ckey, "role=admin") //CITADEL EDIT - Allows admins to reboot in OOM situations + world.SetConfig("APP/admin", ckey, "role=admin") var/tdata = TopicData //save this for later use - chatOutput = new /datum/chatOutput(src) TopicData = null //Prevent calls to client.Topic from connect if(connection != "seeker" && connection != "web")//Invalid connection type. @@ -226,6 +220,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) GLOB.clients += src GLOB.directory[ckey] = src + // Instantiate tgui panel + tgui_panel = new(src) + GLOB.ahelp_tickets.ClientLogin(src) var/connecting_admin = FALSE //because de-admined admins connecting should be treated like admins. //Admin Authorisation @@ -266,7 +263,6 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) new /datum/admins(localhost_rank, ckey, 1, 1) //preferences datum - also holds some persistent data for the client (because we may as well keep these datums to a minimum) prefs = GLOB.preferences_datums[ckey] - if(prefs) prefs.parent = src else @@ -276,7 +272,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) prefs.last_ip = address //these are gonna be used for banning prefs.last_id = computer_id //these are gonna be used for banning - fps = prefs.clientfps + fps = prefs.clientfps //(prefs.clientfps < 0) ? RECOMMENDED_FPS : prefs.clientfps if(fexists(roundend_report_file())) verbs += /client/proc/show_previous_roundend_report @@ -301,22 +297,26 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) alert_mob_dupe_login = TRUE if(matches) if(C) - message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(C)].") - log_access("Notice: [key_name(src)] has the same [matches] as [key_name(C)].") + message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(C)].") + log_admin_private("Notice: [key_name(src)] has the same [matches] as [key_name(C)].") else - message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(C)] (no longer logged in). ") - log_access("Notice: [key_name(src)] has the same [matches] as [key_name(C)] (no longer logged in).") + message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(C)] (no longer logged in). ") + log_admin_private("Notice: [key_name(src)] has the same [matches] as [key_name(C)] (no longer logged in).") if(GLOB.player_details[ckey]) player_details = GLOB.player_details[ckey] player_details.byond_version = full_version else - player_details = new + player_details = new(ckey) player_details.byond_version = full_version GLOB.player_details[ckey] = player_details . = ..() //calls mob.Login() + // if (length(GLOB.stickybanadminexemptions)) + // GLOB.stickybanadminexemptions -= ckey + // if (!length(GLOB.stickybanadminexemptions)) + // restore_stickybans() if (byond_version >= 512) if (!byond_build || byond_build < 1386) @@ -336,7 +336,12 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) qdel(src) return - chatOutput.start() // Starts the chat + // if(SSinput.initialized) placed here on tg. + // set_macros() + // update_movement_keys() + + // Initialize tgui panel + tgui_panel.initialize() if(alert_mob_dupe_login) spawn() @@ -347,12 +352,13 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) connection_timeofday = world.timeofday winset(src, null, "command=\".configure graphics-hwmode on\"") var/cev = CONFIG_GET(number/client_error_version) + var/ceb = CONFIG_GET(number/client_error_build) var/cwv = CONFIG_GET(number/client_warn_version) - if (byond_version < cev) //Out of date client. + if (byond_version < cev || (byond_version == cev && byond_build < ceb)) //Out of date client. to_chat(src, "Your version of BYOND is too old:") to_chat(src, CONFIG_GET(string/client_error_message)) - to_chat(src, "Your version: [byond_version]") - to_chat(src, "Required version: [cev] or later") + to_chat(src, "Your version: [byond_version].[byond_build]") + to_chat(src, "Required version: [cev].[ceb] or later") to_chat(src, "Visit BYOND's website to get the latest version of BYOND.") if (connecting_admin) to_chat(src, "Because you are an admin, you are being allowed to walk past this limitation, But it is still STRONGLY suggested you upgrade") @@ -464,6 +470,10 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) if (menuitem) menuitem.Load_checked(src) + // view_size = new(src, getScreenSize(prefs.widescreenpref)) + // view_size.resetFormat() + // view_size.setZoomMode() + // fit_viewport() Master.UpdateTickRate() /client/proc/ensure_keys_set() @@ -477,13 +487,17 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) /client/Del() if(!gc_destroyed) - Destroy() + Destroy() //Clean up signals and timers. return ..() /client/Destroy() + GLOB.clients -= src + GLOB.directory -= ckey + log_access("Logout: [key_name(src)]") + GLOB.ahelp_tickets.ClientLogout(src) + // SSserver_maint.UpdateHubStatus() if(credits) QDEL_LIST(credits) - log_access("Logout: [key_name(src)]") if(holder) adminGreet(1) holder.owner = null @@ -505,16 +519,13 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) ) send2irc("Server", "[cheesy_message] (No admins online)") - - GLOB.ahelp_tickets.ClientLogout(src) - GLOB.directory -= ckey - GLOB.clients -= src QDEL_LIST_ASSOC_VAL(char_render_holders) if(movingmob != null) movingmob.client_mobs_in_contents -= mob UNSETEMPTY(movingmob.client_mobs_in_contents) + // seen_messages = null Master.UpdateTickRate() - . = ..() + . = ..() //Even though we're going to be hard deleted there are still some things that want to know the destroy is happening return QDEL_HINT_HARDDEL_NOW /client/proc/set_client_age_from_db(connectiontopic) @@ -616,6 +627,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) var/datum/DBQuery/query_log_connection = SSdbcore.NewQuery("INSERT INTO `[format_table_name("connection_log")]` (`id`,`datetime`,`server_ip`,`server_port`,`round_id`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')),'[world.port]','[GLOB.round_id]','[sql_ckey]',INET_ATON('[sql_ip]'),'[sql_computerid]')") query_log_connection.Execute() qdel(query_log_connection) + + // SSserver_maint.UpdateHubStatus() + if(new_player) player_age = -1 . = player_age @@ -857,40 +871,31 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) return inactivity return FALSE -//send resources to the client. It's here in its own proc so we can move it around easiliy if need be +/// Send resources to the client. +/// Sends both game resources and browser assets. /client/proc/send_resources() #if (PRELOAD_RSC == 0) var/static/next_external_rsc = 0 - if(GLOB.external_rsc_urls && GLOB.external_rsc_urls.len) - next_external_rsc = WRAP(next_external_rsc+1, 1, GLOB.external_rsc_urls.len+1) - preload_rsc = GLOB.external_rsc_urls[next_external_rsc] + var/list/external_rsc_urls = CONFIG_GET(keyed_list/external_rsc_urls) + if(length(external_rsc_urls)) + next_external_rsc = WRAP(next_external_rsc+1, 1, external_rsc_urls.len+1) + preload_rsc = external_rsc_urls[next_external_rsc] #endif - //get the common files - getFiles( - 'html/search.js', - 'html/panels.css', - 'html/browser/common.css', - 'html/browser/scannernew.css', - 'html/browser/playeroptions.css', - ) + spawn (10) //removing this spawn causes all clients to not get verbs. //load info on what assets the client has src << browse('code/modules/asset_cache/validate_assets.html', "window=asset_cache_browser") //Precache the client with all other assets slowly, so as to not block other browse() calls - getFilesSlow(src, SSassets.preload, register_asset = FALSE) - addtimer(CALLBACK(GLOBAL_PROC, /proc/getFilesSlow, src, SSassets.preload, FALSE), 5 SECONDS) + if (CONFIG_GET(flag/asset_simple_preload)) + addtimer(CALLBACK(SSassets.transport, /datum/asset_transport.proc/send_assets_slow, src, SSassets.transport.preload), 5 SECONDS) #if (PRELOAD_RSC == 0) for (var/name in GLOB.vox_sounds) var/file = GLOB.vox_sounds[name] Export("##action=load_rsc", file) stoplag() - for (var/name in GLOB.vox_sounds_male) - var/file = GLOB.vox_sounds_male[name] - Export("##action=load_rsc", file) - stoplag() #endif diff --git a/code/modules/client/darkmode.dm b/code/modules/client/darkmode.dm deleted file mode 100644 index f806e5c964..0000000000 --- a/code/modules/client/darkmode.dm +++ /dev/null @@ -1,65 +0,0 @@ -//Darkmode preference by Kmc2000// - -/* -This lets you switch chat themes by using winset and CSS loading, you must relog to see this change (or rebuild your browseroutput datum) -Things to note: -If you change ANYTHING in interface/skin.dmf you need to change it here: -Format: -winset(src, "window as appears in skin.dmf after elem", "var to change = desired value") -How this works: -I've added a function to browseroutput.js which registers a cookie for darkmode and swaps the chat accordingly. You can find the button to do this under the "cog" icon next to the ping button (top right of chat) -This then swaps the window theme automatically -Thanks to spacemaniac and mcdonald for help with the JS side of this. -*/ - -/client/proc/force_white_theme() //There's no way round it. We're essentially changing the skin by hand. It's painful but it works, and is the way Lummox suggested. - //Main windows - winset(src, "infowindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "info", "background-color = [COLOR_WHITEMODE_BACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "browseroutput", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "outputwindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "mainwindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND]") - winset(src, "split", "background-color = [COLOR_WHITEMODE_BACKGROUND]") - //Buttons - winset(src, "changelog", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "rules", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "wiki", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "forum", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "github", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "report-issue", "background-color = [COLOR_WHITEMODE_ISSUE_BUTTON_BG];text-color = [COLOR_WHITEMODE_TEXT]") - //Status and verb tabs - winset(src, "output", "background-color = [COLOR_WHITEMODE_BACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "statwindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "stat", "background-color = [COLOR_WHITEMODE_BACKGROUND];tab-background-color = [COLOR_WHITEMODE_DARKBACKGROUND];\ - text-color = [COLOR_WHITEMODE_TEXT];tab-text-color = [COLOR_WHITEMODE_TEXT];\ - prefix-color = [COLOR_WHITEMODE_TEXT];suffix-color = [COLOR_WHITEMODE_TEXT]") - //Etc. - winset(src, "say", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "asset_cache_browser", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") - winset(src, "tooltip", "background-color = [COLOR_WHITEMODE_BACKGROUND];text-color = [COLOR_WHITEMODE_TEXT]") - -/client/proc/force_dark_theme() //Inversely, if theyre using white theme and want to swap to the superior dark theme, let's get WINSET() ing - //Main windows - winset(src, "infowindow", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "info", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "browseroutput", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "outputwindow", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "mainwindow", "background-color = [COLOR_DARKMODE_DARKBACKGROUND]") - winset(src, "split", "background-color = [COLOR_DARKMODE_BACKGROUND]") - //Buttons - winset(src, "changelog", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "rules", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "wiki", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "forum", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "github", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "report-issue", "background-color = [COLOR_DARKMODE_ISSUE_BUTTON_BG];text-color = [COLOR_DARKMODE_TEXT]") - //Status and verb tabs - winset(src, "output", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "statwindow", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "stat", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];tab-background-color = [COLOR_DARKMODE_BACKGROUND];\ - text-color = [COLOR_DARKMODE_TEXT];tab-text-color = [COLOR_DARKMODE_TEXT];\ - prefix-color = [COLOR_DARKMODE_TEXT];suffix-color = [COLOR_DARKMODE_TEXT]") - //Etc. - winset(src, "say", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "asset_cache_browser", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") - winset(src, "tooltip", "background-color = [COLOR_DARKMODE_BACKGROUND];text-color = [COLOR_DARKMODE_TEXT]") \ No newline at end of file diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 778b5175a7..51e027522c 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -163,6 +163,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) ) var/custom_speech_verb = "default" //if your say_mod is to be something other than your races var/custom_tongue = "default" //if your tongue is to be something other than your races + var/chosen_limb_id //body sprite selected to load for the users limbs, null means default, is sanitized when loaded /// Security record note section var/security_records @@ -246,6 +247,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) /// Which of the 5 persistent scar slots we randomly roll to load for this round, if enabled. Actually rolled in [/datum/preferences/proc/load_character(slot)] var/scars_index = 1 + var/hide_ckey = FALSE //pref for hiding if your ckey shows round-end or not + /datum/preferences/New(client/C) parent = C @@ -370,6 +373,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "[medical_records]" else dat += "[TextPreview(medical_records)]...
" + dat += "
Hide ckey: [hide_ckey ? "Enabled" : "Disabled"]
" dat += "
" //Character Appearance @@ -521,6 +525,12 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "" mutant_category = 0 + if(length(pref_species.allowed_limb_ids)) + if(!chosen_limb_id || !(chosen_limb_id in pref_species.allowed_limb_ids)) + chosen_limb_id = pref_species.id + dat += "

Body sprite

" + dat += "[chosen_limb_id]" + if(mutant_category) dat += "" mutant_category = 0 @@ -849,6 +859,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "
" dat += "

Fetish content prefs

" dat += "Arousal:[arousable == TRUE ? "Enabled" : "Disabled"]
" + dat += "Genital examine text:[(cit_toggles & GENITAL_EXAMINE) ? "Enabled" : "Disabled"]
" + dat += "Vore examine text:[(cit_toggles & VORE_EXAMINE) ? "Enabled" : "Disabled"]
" dat += "Voracious MediHound sleepers: [(cit_toggles & MEDIHOUND_SLEEPER) ? "Yes" : "No"]
" dat += "Hear Vore Sounds: [(cit_toggles & EATING_NOISES) ? "Yes" : "No"]
" dat += "Hear Vore Digestion Sounds: [(cit_toggles & DIGESTION_NOISES) ? "Yes" : "No"]
" @@ -1438,6 +1450,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(!isnull(msg)) features["ooc_notes"] = msg + if("hide_ckey") + hide_ckey = !hide_ckey + if(user) + user.mind?.hide_ckey = hide_ckey + if("hair") var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference","#"+hair_color) as color|null if(new_hair) @@ -2092,8 +2109,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) else features["body_model"] = chosengender gender = chosengender - facial_hair_style = random_facial_hair_style(gender) - hair_style = random_hair_style(gender) if("body_size") var/min = CONFIG_GET(number/body_size_min) @@ -2119,6 +2134,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/selected_custom_speech_verb = input(user, "Choose your desired speech verb (none means your species speech verb)", "Character Preference") as null|anything in GLOB.speech_verbs if(selected_custom_speech_verb) custom_speech_verb = selected_custom_speech_verb + + if("bodysprite") + var/selected_body_sprite = input(user, "Choose your desired body sprite", "Character Preference") as null|anything in pref_species.allowed_limb_ids + if(selected_body_sprite) + chosen_limb_id = selected_body_sprite //this gets sanitized before loading else switch(href_list["preference"]) //CITADEL PREFERENCES EDIT - I can't figure out how to modularize these, so they have to go here. :c -Pooj @@ -2342,6 +2362,13 @@ GLOBAL_LIST_EMPTY(preferences_datums) parent.mob.hud_used.update_parallax_pref(parent.mob) // Citadel edit - Prefs don't work outside of this. :c + + if("genital_examine") + cit_toggles ^= GENITAL_EXAMINE + + if("vore_examine") + cit_toggles ^= VORE_EXAMINE + if("hound_sleeper") cit_toggles ^= MEDIHOUND_SLEEPER @@ -2510,6 +2537,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) character.dna.features = features.Copy() character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE) + if(chosen_limb_id && (chosen_limb_id in character.dna.species.allowed_limb_ids)) + character.dna.species.mutant_bodyparts["limbs_id"] = chosen_limb_id character.dna.real_name = character.real_name character.dna.nameless = character.nameless character.dna.custom_species = character.custom_species diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index a8183e4940..8591d77e50 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -514,7 +514,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["scars3"] >> scars_list["3"] S["scars4"] >> scars_list["4"] S["scars5"] >> scars_list["5"] - + S["chosen_limb_id"] >> chosen_limb_id + S["hide_ckey"] >> hide_ckey //saved per-character //Custom names for(var/custom_name_id in GLOB.preferences_custom_names) @@ -844,6 +845,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["feature_ooc_notes"], features["ooc_notes"]) + WRITE_FILE(S["chosen_limb_id"], chosen_limb_id) + //Custom names for(var/custom_name_id in GLOB.preferences_custom_names) var/savefile_slot_name = custom_name_id + "_name" //TODO remove this @@ -856,6 +859,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["joblessrole"] , joblessrole) //Write prefs WRITE_FILE(S["job_preferences"] , job_preferences) + WRITE_FILE(S["hide_ckey"] , hide_ckey) //Quirks WRITE_FILE(S["all_quirks"] , all_quirks) @@ -871,6 +875,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["scars4"] , scars_list["4"]) WRITE_FILE(S["scars5"] , scars_list["5"]) + //gear loadout if(chosen_gear.len) var/text_to_save = chosen_gear.Join("|") diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm index 951e36f9a6..e16a491c61 100644 --- a/code/modules/client/preferences_toggles.dm +++ b/code/modules/client/preferences_toggles.dm @@ -145,8 +145,7 @@ TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, togglemidis)() to_chat(usr, "You will no longer hear sounds uploaded by admins") usr.stop_sound_channel(CHANNEL_ADMIN) var/client/C = usr.client - if(C && C.chatOutput && !C.chatOutput.broken && C.chatOutput.loaded) - C.chatOutput.stopMusic() + C?.tgui_panel?.stop_music() SSblackbox.record_feedback("nested tally", "preferences_verb", 1, list("Toggle Hearing Midis", "[usr.client.prefs.toggles & SOUND_MIDI ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /datum/verbs/menu/Settings/Sound/togglemidis/Get_checked(client/C) return C.prefs.toggles & SOUND_MIDI @@ -234,8 +233,7 @@ TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, toggleprayersounds)() set desc = "Stop Current Sounds" SEND_SOUND(usr, sound(null)) var/client/C = usr.client - if(C && C.chatOutput && !C.chatOutput.broken && C.chatOutput.loaded) - C.chatOutput.stopMusic() + C?.tgui_panel?.stop_music() SSblackbox.record_feedback("nested tally", "preferences_verb", 1, list("Stop Self Sounds")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm index fa1145ecea..99703482b9 100644 --- a/code/modules/client/verbs/ooc.dm +++ b/code/modules/client/verbs/ooc.dm @@ -158,88 +158,6 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8") else to_chat(src, "There are no admin notices at the moment.") -/client/verb/fix_chat() - set name = "Fix chat" - set category = "OOC" - if (!chatOutput || !istype(chatOutput)) - var/action = alert(src, "Invalid Chat Output data found!\nRecreate data?", "Wot?", "Recreate Chat Output data", "Cancel") - if (action != "Recreate Chat Output data") - return - chatOutput = new /datum/chatOutput(src) - chatOutput.start() - action = alert(src, "Goon chat reloading, wait a bit and tell me if it's fixed", "", "Fixed", "Nope") - if (action == "Fixed") - log_game("GOONCHAT: [key_name(src)] Had to fix their goonchat by re-creating the chatOutput datum") - else - chatOutput.load() - action = alert(src, "How about now? (give it a moment (it may also try to load twice))", "", "Yes", "No") - if (action == "Yes") - log_game("GOONCHAT: [key_name(src)] Had to fix their goonchat by re-creating the chatOutput datum and forcing a load()") - else - action = alert(src, "Welp, I'm all out of ideas. Try closing byond and reconnecting.\nWe could also disable fancy chat and re-enable oldchat", "", "Thanks anyways", "Switch to old chat") - if (action == "Switch to old chat") - winset(src, "output", "is-visible=true;is-disabled=false") - winset(src, "browseroutput", "is-visible=false") - log_game("GOONCHAT: [key_name(src)] Failed to fix their goonchat window after recreating the chatOutput and forcing a load()") - - else if (chatOutput.loaded) - var/action = alert(src, "ChatOutput seems to be loaded\nDo you want me to force a reload, wiping the chat log or just refresh the chat window because it broke/went away?", "Hmmm", "Force Reload", "Refresh", "Cancel") - switch (action) - if ("Force Reload") - chatOutput.loaded = FALSE - chatOutput.start() //this is likely to fail since it asks , but we should try it anyways so we know. - action = alert(src, "Goon chat reloading, wait a bit and tell me if it's fixed", "", "Fixed", "Nope") - if (action == "Fixed") - log_game("GOONCHAT: [key_name(src)] Had to fix their goonchat by forcing a start()") - else - chatOutput.load() - action = alert(src, "How about now? (give it a moment (it may also try to load twice))", "", "Yes", "No") - if (action == "Yes") - log_game("GOONCHAT: [key_name(src)] Had to fix their goonchat by forcing a load()") - else - action = alert(src, "Welp, I'm all out of ideas. Try closing byond and reconnecting.\nWe could also disable fancy chat and re-enable oldchat", "", "Thanks anyways", "Switch to old chat") - if (action == "Switch to old chat") - winset(src, "output", "is-visible=true;is-disabled=false") - winset(src, "browseroutput", "is-visible=false") - log_game("GOONCHAT: [key_name(src)] Failed to fix their goonchat window forcing a start() and forcing a load()") - - if ("Refresh") - chatOutput.showChat() - action = alert(src, "Goon chat refreshing, wait a bit and tell me if it's fixed", "", "Fixed", "Nope, force a reload") - if (action == "Fixed") - log_game("GOONCHAT: [key_name(src)] Had to fix their goonchat by forcing a show()") - else - chatOutput.loaded = FALSE - chatOutput.load() - action = alert(src, "How about now? (give it a moment)", "", "Yes", "No") - if (action == "Yes") - log_game("GOONCHAT: [key_name(src)] Had to fix their goonchat by forcing a load()") - else - action = alert(src, "Welp, I'm all out of ideas. Try closing byond and reconnecting.\nWe could also disable fancy chat and re-enable oldchat", "", "Thanks anyways", "Switch to old chat") - if (action == "Switch to old chat") - winset(src, "output", "is-visible=true;is-disabled=false") - winset(src, "browseroutput", "is-visible=false") - log_game("GOONCHAT: [key_name(src)] Failed to fix their goonchat window forcing a show() and forcing a load()") - return - - else - chatOutput.start() - var/action = alert(src, "Manually loading Chat, wait a bit and tell me if it's fixed", "", "Fixed", "Nope") - if (action == "Fixed") - log_game("GOONCHAT: [key_name(src)] Had to fix their goonchat by manually calling start()") - else - chatOutput.load() - alert(src, "How about now? (give it a moment (it may also try to load twice))", "", "Yes", "No") - if (action == "Yes") - log_game("GOONCHAT: [key_name(src)] Had to fix their goonchat by manually calling start() and forcing a load()") - else - action = alert(src, "Welp, I'm all out of ideas. Try closing byond and reconnecting.\nWe could also disable fancy chat and re-enable oldchat", "", "Thanks anyways", "Switch to old chat") - if (action == "Switch to old chat") - winset(src, "output", list2params(list("on-show" = "", "is-disabled" = "false", "is-visible" = "true"))) - winset(src, "browseroutput", "is-disabled=true;is-visible=false") - log_game("GOONCHAT: [key_name(src)] Failed to fix their goonchat window after manually calling start() and forcing a load()") - - /client/verb/motd() set name = "MOTD" diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index cf7dbc7462..6732f1c86c 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -80,7 +80,9 @@ item_state = "hostrench" flags_inv = 0 strip_delay = 80 - unique_reskin = list("Coat" = "hostrench", "Cloak" = "trenchcloak") + unique_reskin = list("Coat" = "hostrench", + "Cloak" = "trenchcloak" + ) /obj/item/clothing/suit/armor/vest/warden name = "warden's jacket" diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 27fb0cc00d..85c1d0e114 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -118,7 +118,6 @@ icon_state = "plasmaman" item_state = "plasmaman" armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 0, "fire" = 95, "acid" = 95) - slowdown = 1 body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS mutantrace_variation = USE_TAUR_CLIP_MASK can_adjust = FALSE diff --git a/code/modules/emoji/emoji_parse.dm b/code/modules/emoji/emoji_parse.dm index 3fd83899c9..64c07f5a38 100644 --- a/code/modules/emoji/emoji_parse.dm +++ b/code/modules/emoji/emoji_parse.dm @@ -17,7 +17,7 @@ if(search) emoji = lowertext(copytext(text, pos + length(text[pos]), search)) var/isthisapath = (emoji[1] == "/") && text2path(emoji) - var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/goonchat) + var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat) var/tag = sheet.icon_tag("emoji-[emoji]") if(tag) parsed += "[tag]" //evil way of enforcing 16x16 diff --git a/code/modules/events/brain_trauma.dm b/code/modules/events/brain_trauma.dm index 3e8182a827..0a07e2a693 100644 --- a/code/modules/events/brain_trauma.dm +++ b/code/modules/events/brain_trauma.dm @@ -14,7 +14,8 @@ continue if(!H.getorgan(/obj/item/organ/brain)) // If only I had a brain continue - + if(HAS_TRAIT(H,TRAIT_EXEMPT_HEALTH_EVENTS)) + continue traumatize(H) break diff --git a/code/modules/events/fake_virus.dm b/code/modules/events/fake_virus.dm index 77520198e8..cebf1ed14b 100644 --- a/code/modules/events/fake_virus.dm +++ b/code/modules/events/fake_virus.dm @@ -6,7 +6,7 @@ /datum/round_event/fake_virus/start() var/list/fake_virus_victims = list() for(var/mob/living/carbon/human/H in shuffle(GLOB.player_list)) - if(!H.client || H.stat == DEAD || H.InCritical()) + if(!H.client || H.stat == DEAD || H.InCritical() || HAS_TRAIT(H,TRAIT_EXEMPT_HEALTH_EVENTS)) continue fake_virus_victims += H diff --git a/code/modules/food_and_drinks/food/snacks.dm b/code/modules/food_and_drinks/food/snacks.dm index 895699434a..4d5f4e2dd0 100644 --- a/code/modules/food_and_drinks/food/snacks.dm +++ b/code/modules/food_and_drinks/food/snacks.dm @@ -97,9 +97,12 @@ All foods are distributed among various categories. Use common sense. return -/obj/item/reagent_containers/food/snacks/attack(mob/living/M, mob/living/user, def_zone) +/obj/item/reagent_containers/food/snacks/attack(mob/living/M, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1) if(user.a_intent == INTENT_HARM) return ..() + INVOKE_ASYNC(src, .proc/attempt_forcefeed, M, user) + +/obj/item/reagent_containers/food/snacks/proc/attempt_forcefeed(mob/living/M, mob/living/user) if(!eatverb) eatverb = pick("bite","chew","nibble","gnaw","gobble","chomp") if(!reagents.total_volume) //Shouldn't be needed but it checks to see if it has anything left in it. diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm deleted file mode 100644 index ce27dccb74..0000000000 --- a/code/modules/goonchat/browserOutput.dm +++ /dev/null @@ -1,341 +0,0 @@ -/********************************* -For the main html chat area -*********************************/ - -/// Should match the value set in the browser js -#define MAX_COOKIE_LENGTH 5 - -//Precaching a bunch of shit. Someone ship this out of here -GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of icons for the browser output - -//lazy renaming to chat_output, instead renamed to old chatOutput -/** - * The chatOutput datum exists to handle the goonchat browser. - * On client, created on Client/New() - */ -/datum/chatOutput - /// The client that owns us. - var/client/owner - /// How many times client data has been checked - var/total_checks = 0 - /// When to next clear the client data checks counter - var/next_time_to_clear = 0 - /// Has the client loaded the browser output area? - var/loaded = FALSE - /// If they haven't loaded chat, this is where messages will go until they do - var/list/messageQueue - var/cookieSent = FALSE // Has the client sent a cookie for analysis - var/broken = FALSE - var/list/connectionHistory //Contains the connection history passed from chat cookie - var/adminMusicVolume = 25 //This is for the Play Global Sound verb - -/datum/chatOutput/New(client/C) - owner = C - messageQueue = list() - connectionHistory = list() - -/** - * start: Tries to load the chat browser - * Aborts if a problem is encountered. - * Async because this is called from Client/New. - */ -/datum/chatOutput/proc/start() - set waitfor = FALSE - //Check for existing chat - if(!owner) - return FALSE - - if(!winexists(owner, "browseroutput")) // Oh goddamnit. - broken = TRUE - message_admins("Couldn't start chat for [key_name_admin(owner)]!") - . = FALSE - alert(owner.mob, "Updated chat window does not exist. If you are using a custom skin file please allow the game to update.") - return - - if(winget(owner, "browseroutput", "is-visible") == "true") //Already setup - doneLoading() - - else //Not setup - load() - - return TRUE - -/// Loads goonchat and sends assets. -/datum/chatOutput/proc/load() - set waitfor = FALSE - if(!owner) - return - - var/datum/asset/stuff = get_asset_datum(/datum/asset/group/goonchat) - stuff.send(owner) - - owner << browse(file('code/modules/goonchat/browserassets/html/browserOutput.html'), "window=browseroutput") - -/// Interprets input from the client. Will send data back if required. -/datum/chatOutput/Topic(href, list/href_list) - if(usr.client != owner) - return TRUE - - // Build arguments. - // Arguments are in the form "param[paramname]=thing" - var/list/params = list() - for(var/key in href_list) - if(length_char(key) > 7 && findtext(key, "param")) // 7 is the amount of characters in the basic param key template. - var/param_name = copytext_char(key, 7, -1) - var/item = href_list[key] - - params[param_name] = item - - var/data // Data to be sent back to the chat. - switch(href_list["proc"]) - if("doneLoading") - data = doneLoading(arglist(params)) - - if("debug") - data = debug(arglist(params)) - - if("ping") - data = ping(arglist(params)) - - if("analyzeClientData") - data = analyzeClientData(arglist(params)) - - if("setMusicVolume") - data = setMusicVolume(arglist(params)) - if("colorPresetPost") //User just swapped color presets in their goonchat preferences. Do we do anything else? - switch(href_list["preset"]) - if("light") - owner.force_white_theme() - if("dark" || "normal") - owner.force_dark_theme() - // if("swaptodarkmode") - // swaptodarkmode() - // if("swaptolightmode") - // swaptolightmode() - - if(data) - ehjax_send(data = data) - - -/// Called on chat output done-loading by JS. -/datum/chatOutput/proc/doneLoading() - if(loaded) - return - - testing("Chat loaded for [owner.ckey]") - loaded = TRUE - showChat() - - - for(var/message in messageQueue) - // whitespace has already been handled by the original to_chat - to_chat(owner, message, handle_whitespace=FALSE) - - messageQueue = null - sendClientData() - - syncRegex() - - //do not convert to to_chat() - SEND_TEXT(owner, "Failed to load fancy chat, reverting to old chat. Certain features won't work.") - -/// Hides the standard output and makes the browser visible. -/datum/chatOutput/proc/showChat() - winset(owner, "output", "is-visible=false") - winset(owner, "browseroutput", "is-disabled=false;is-visible=true") - -/// Calls syncRegex on all currently owned chatOutput datums -/proc/syncChatRegexes() - for (var/user in GLOB.clients) - var/client/C = user - var/datum/chatOutput/Cchat = C.chatOutput - if (Cchat && !Cchat.broken && Cchat.loaded) - Cchat.syncRegex() - -/// Used to dynamically add regexes to the browser output. Currently only used by the IC filter. -/datum/chatOutput/proc/syncRegex() - var/list/regexes = list() - /* - if (config.ic_filter_regex) - regexes["show_filtered_ic_chat"] = list( - config.ic_filter_regex.name, - "ig", - "$1" - ) - */ - if (regexes.len) - ehjax_send(data = list("syncRegex" = regexes)) - -/// Sends json encoded data to the browser. -/datum/chatOutput/proc/ehjax_send(client/C = owner, window = "browseroutput", data) - if(islist(data)) - data = json_encode(data) - C << output("[data]", "[window]:ehjaxCallback") - -/** - * Sends music data to the browser. If enabled by the browser, it will start playing. - * Arguments: - * music must be a https adress. - * extra_data is a list. The keys "pitch", "start" and "end" are used. - ** "pitch" determines the playback rate - ** "start" determines the start time of the sound - ** "end" determines when the musics stops playing - */ -/datum/chatOutput/proc/sendMusic(music, pitch, list/extra_data) //someone remove pitch - if(!findtext(music, GLOB.is_http_protocol)) - return - var/list/music_data = list("adminMusic" = url_encode(url_encode(music))) - - if(extra_data?.len) - music_data["musicRate"] = extra_data["pitch"] || pitch - music_data["musicSeek"] = extra_data["start"] - music_data["musicHalt"] = extra_data["end"] - - ehjax_send(data = music_data) - -/// Stops music playing throw the browser. -/datum/chatOutput/proc/stopMusic() - ehjax_send(data = "stopMusic") - -/// Setter for adminMusicVolume. Sanitizes the value to between 0 and 100. -/datum/chatOutput/proc/setMusicVolume(volume = "") - if(volume) - adminMusicVolume = clamp(text2num(volume), 0, 100) - -/// Sends client connection details to the chat to handle and save -/datum/chatOutput/proc/sendClientData() - //Get dem deets - var/list/deets = list("clientData" = list()) - deets["clientData"]["ckey"] = owner.ckey - deets["clientData"]["ip"] = owner.address - deets["clientData"]["compid"] = owner.computer_id - var/data = json_encode(deets) - ehjax_send(data = data) - -/// Called by client, sent data to investigate (cookie history so far) -/datum/chatOutput/proc/analyzeClientData(cookie = "") - //Spam check - if(world.time > next_time_to_clear) - next_time_to_clear = world.time + (3 SECONDS) - total_checks = 0 - - total_checks += 1 - - if(total_checks > SPAM_TRIGGER_AUTOMUTE) - message_admins("[key_name(owner)] kicked for goonchat topic spam") - qdel(owner) - return - - if(!cookie) - return - - if(cookie != "none") - var/list/connData = json_decode(cookie) - if (connData && islist(connData) && connData.len > 0 && connData["connData"]) - connectionHistory = connData["connData"] //lol fuck - var/list/found = new() - - if(connectionHistory.len > MAX_COOKIE_LENGTH) - message_admins("[key_name(src.owner)] was kicked for an invalid ban cookie)") - qdel(owner) - return - - for(var/i in connectionHistory.len to 1 step -1) - if(QDELETED(owner)) - //he got cleaned up before we were done - return - var/list/row = src.connectionHistory[i] - if (!row || row.len < 3 || (!row["ckey"] || !row["compid"] || !row["ip"])) //Passed malformed history object - return - if (world.IsBanned(row["ckey"], row["ip"], row["compid"], real_bans_only=TRUE)) - found = row - break - CHECK_TICK - - //Uh oh this fucker has a history of playing on a banned account!! - if (found.len > 0) - message_admins("[key_name(src.owner)] has a cookie from a banned account! (Matched: [found["ckey"]], [found["ip"]], [found["compid"]])") - log_admin_private("[key_name(owner)] has a cookie from a banned account! (Matched: [found["ckey"]], [found["ip"]], [found["compid"]])") - - cookieSent = TRUE - -/// Called by js client every 60 seconds -/datum/chatOutput/proc/ping() - return "pong" - -/// Called by js client on js error -/datum/chatOutput/proc/debug(error) - log_world("\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: [(src.owner.key ? src.owner.key : src.owner)] triggered JS error: [error]") - -/// Global chat proc. to_chat_immediate will circumvent SSchat and send data as soon as possible. -/proc/to_chat_immediate(target, message, handle_whitespace = TRUE, trailing_newline = TRUE, confidential = FALSE) - if(!target || !message) - return - - if(target == world) - target = GLOB.clients - - var/original_message = message - if(handle_whitespace) - message = replacetext(message, "\n", "
") - message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]") //EIGHT SPACES IN TOTAL!! - if(trailing_newline) - message += "
" - - if(islist(target)) - // Do the double-encoding outside the loop to save nanoseconds - var/twiceEncoded = url_encode(url_encode(message)) - for(var/I in target) - var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible - - if (!C) - continue - - //Send it to the old style output window. - SEND_TEXT(C, original_message) - - if(!C.chatOutput || C.chatOutput.broken) // A player who hasn't updated his skin file. - continue - - if(!C.chatOutput.loaded) - //Client still loading, put their messages in a queue - C.chatOutput.messageQueue += message - continue - - C << output(twiceEncoded, "browseroutput:output") - else - var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible - - if (!C) - return - - //Send it to the old style output window. - SEND_TEXT(C, original_message) - - if(!C.chatOutput || C.chatOutput.broken) // A player who hasn't updated his skin file. - return - - if(!C.chatOutput.loaded) - //Client still loading, put their messages in a queue - C.chatOutput.messageQueue += message - return - - // url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript. - C << output(url_encode(url_encode(message)), "browseroutput:output") - -/// Sends a text message to the target. -/proc/to_chat(target, message, handle_whitespace = TRUE, trailing_newline = TRUE, confidential = FALSE) - if(Master.current_runlevel == RUNLEVEL_INIT || !SSchat?.initialized) - to_chat_immediate(target, message, handle_whitespace, trailing_newline, confidential) - return - SSchat.queue(target, message, handle_whitespace, trailing_newline, confidential) - -/// Dark mode light mode stuff. Yell at KMC if this breaks! (See darkmode.dm for documentation) -/datum/chatOutput/proc/swaptolightmode() - owner.force_white_theme() - -/// Light mode stuff. (See darkmode.dm for documentation) -/datum/chatOutput/proc/swaptodarkmode() - owner.force_dark_theme() - -#undef MAX_COOKIE_LENGTH diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css deleted file mode 100644 index 2669a3634a..0000000000 --- a/code/modules/goonchat/browserassets/css/browserOutput.css +++ /dev/null @@ -1,464 +0,0 @@ -/***************************************** -* -* GLOBAL STYLES -* -******************************************/ -html, body { - padding: 0; - margin: 0; - height: 100%; - color: #000000; -} -body { - background: #E0E0E0; /*CIT CHANGE - darkens chatbox a lil*/ - font-family: Verdana, sans-serif; - font-size: 13px; - line-height: 1.2; - overflow-x: hidden; - overflow-y: scroll; - word-wrap: break-word; -} - -em { - font-style: normal; - font-weight: bold; -} - -img { - margin: 0; - padding: 0; - line-height: 1; - -ms-interpolation-mode: nearest-neighbor; - image-rendering: pixelated; -} -img.icon { - height: 1em; - min-height: 16px; - width: auto; - vertical-align: bottom; -} - - -.r:before { /* "repeated" badge class for combined messages */ - content: 'x'; -} -.r { - display: inline-block; - min-width: 0.5em; - font-size: 0.7em; - padding: 0.2em 0.3em; - line-height: 1; - color: white; - text-align: center; - white-space: nowrap; - vertical-align: middle; - background-color: crimson; - border-radius: 10px; -} - -a {color: #0000ff;} -a.visited {color: #ff00ff;} -a:visited {color: #ff00ff;} -a.popt {text-decoration: none;} - -/***************************************** -* -* OUTPUT NOT RELATED TO ACTUAL MESSAGES -* -******************************************/ -#loading { - position: fixed; - width: 300px; - height: 150px; - text-align: center; - left: 50%; - top: 50%; - margin: -75px 0 0 -150px; -} -#loading i {display: block; padding-bottom: 3px;} - -#messages { - font-size: 13px; - padding: 3px; - margin: 0; - word-wrap: break-word; -} -#newMessages { - position: fixed; - display: block; - bottom: 0; - right: 0; - padding: 8px; - background: #d0d0d0; - text-decoration: none; - font-variant: small-caps; - font-size: 1.1em; - font-weight: bold; - color: #333; -} -#newMessages:hover {background: #ccc;} -#newMessages i {vertical-align: middle; padding-left: 3px;} -#ping { - position: fixed; - top: 0; - right: 135px; - width: 45px; - background: #d0d0d0; - height: 30px; - padding: 8px 0 2px 0; -} -#ping i {display: block; text-align: center;} -#ping .ms { - display: block; - text-align: center; - font-size: 8pt; - padding-top: 2px; -} -#userBar { - position: fixed; - top: 0; - right: 0; -} -#userBar .subCell { - background: #d0d0d0; - height: 30px; - padding: 5px 0; - display: block; - color: #333; - text-decoration: none; - line-height: 28px; - border-top: 1px solid #b4b4b4; -} -#userBar .subCell:hover {background: #ccc;} -#userBar .toggle { - width: 45px; - background: #ccc; - border-top: 0; - float: right; - text-align: center; -} -#userBar .sub {clear: both; display: none; width: 180px;} -#userBar .sub.scroll {overflow-y: scroll;} -#userBar .sub.subCell {padding: 3px 0 3px 8px; line-height: 30px; font-size: 0.9em; clear: both;} -#userBar .sub span { - display: block; - line-height: 30px; - float: left; -} -#userBar .sub i { - display: block; - padding: 0 5px; - font-size: 1.1em; - width: 22px; - text-align: center; - line-height: 30px; - float: right; -} -#userBar .sub input { - position: absolute; - padding: 7px 5px; - width: 121px; - line-height: 30px; - float: left; -} -#userBar .topCell {border-top: 0;} - -/* POPUPS */ -.popup { - position: fixed; - top: 50%; - left: 50%; - background: #d0d0d0; -} -.popup .close { - position: absolute; - background: #aaa; - top: 0; - right: 0; - color: #333; - text-decoration: none; - z-index: 2; - padding: 0 10px; - height: 30px; - line-height: 30px; -} -.popup .close:hover {background: #999;} -.popup .head { - background: #999; - color: #d0d0d0; - padding: 0 10px; - height: 30px; - line-height: 30px; - text-transform: uppercase; - font-size: 0.9em; - font-weight: bold; - border-bottom: 2px solid green; -} -.popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;} -.popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;} -.popup input[type=submit] {padding: 5px 10px; background: #999; color: #d0d0d0; text-transform: uppercase; font-size: 0.9em; font-weight: bold;} -.popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;} - -.changeFont {padding: 10px;} -.changeFont a {display: block; text-decoration: none; padding: 3px; color: #333;} -.changeFont a:hover {background: #ccc;} - -.highlightPopup {padding: 10px; text-align: center;} -.highlightPopup input[type=text] {display: block; width: 215px; text-align: left; margin-top: 5px;} -.highlightPopup input.highlightColor {background-color: #FFFF00;} -.highlightPopup input.highlightTermSubmit {margin-top: 5px;} - -/* ADMIN CONTEXT MENU */ -.contextMenu { - background-color: #d0d0d0; - position: fixed; - margin: 2px; - width: 150px; -} -.contextMenu a { - display: block; - padding: 2px 5px; - text-decoration: none; - color: #333; -} - -.contextMenu a:hover { - background-color: #ccc; -} - -/* ADMIN FILTER MESSAGES MENU */ -.filterMessages {padding: 5px;} -.filterMessages div {padding: 2px 0;} -.filterMessages input {} -.filterMessages label {} - -.icon-stack {height: 1em; line-height: 1em; width: 1em; vertical-align: middle; margin-top: -2px;} - - -/***************************************** -* -* OUTPUT ACTUALLY RELATED TO MESSAGES -* -******************************************/ - -/* MOTD */ -.motd {color: #638500; font-family: Verdana, sans-serif;} -.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #638500; text-decoration: underline;} -.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #638500;} - -/* ADD HERE FOR BOLD */ -.bold, .name, .prefix, .ooc, .looc, .adminooc, .admin, .medal, .yell {font-weight: bold;} - -/* ADD HERE FOR ITALIC */ -.italic, .italics, .emote {font-style: italic;} - -/* OUTPUT COLORS */ -.highlight {background: yellow;} - -h1, h2, h3, h4, h5, h6 {color: #0000ff;font-family: Georgia, Verdana, sans-serif;} -h1.alert, h2.alert {color: #000000;} - -em {font-style: normal; font-weight: bold;} - -.ooc {color: #002eb8; font-weight: bold;} -.looc {color: #6699CC; font-weight: bold;} -.antagooc {color: #b8002e; font-weight: bold;} -.adminobserverooc {color: #0099cc; font-weight: bold;} -.adminooc {color: #700038; font-weight: bold;} - -.adminsay {color: #FF4500} -.admin {color: #386aff; font-weight: bold;} - -.name { font-weight: bold;} - -.say {} -.deadsay {color: #5c00e6;} -.binarysay {color: #20c20e; background-color: #000000; display: block;} -.binarysay a {color: #00ff00;} -.binarysay a:active, .binarysay a:visited {color: #88ff88;} -.radio {color: #008000;} -.sciradio {color: #993399;} -.comradio {color: #948f02;} -.secradio {color: #a30000;} -.medradio {color: #337296;} -.engradio {color: #fb5613;} -.suppradio {color: #a8732b;} -.servradio {color: #6eaa2c;} -.syndradio {color: #6d3f40;} -.centcomradio {color: #686868;} -.aiprivradio {color: #ff00ff;} -.redteamradio {color: #ff0000;} -.blueteamradio {color: #0000ff;} - -.yell { font-weight: bold;} - -.alert {color: #ff0000;} -h1.alert, h2.alert {color: #000000;} - -.emote { font-style: italic;} -.selecteddna {color: #ffffff; background-color: #001B1B} - -.attack {color: #ff0000;} -.disarm {color: #990000;} -.passive {color: #660000;} - -.userdanger {color: #ff0000; font-weight: bold; font-size: 185%;} -.bolddanger {color: #c51e1e;font-weight: bold;} -.danger {color: #ff0000;} -.tinydanger {color: #c51e1e; font-size: 85%;} -.smalldanger {color: #c51e1e; font-size: 90%;} -.warning {color: #ff0000; font-style: italic;} -.alertwarning {color: #FF0000; font-weight: bold} -.boldwarning {color: #ff0000; font-style: italic; font-weight: bold} -.announce {color: #228b22; font-weight: bold;} -.boldannounce {color: #ff0000; font-weight: bold;} -.greenannounce {color: #00ff00; font-weight: bold;} -.rose {color: #ff5050;} -.info {color: #0000CC;} -.notice {color: #000099;} -.tinynotice {color: #6685f5; font-style: italic; font-size: 85%;} -.smallnotice {color: #6685f5; font-size: 90%;} -.smallnoticeital {color: #6685f5; font-style: italic; font-size: 90%;} -.boldnotice {color: #000099; font-weight: bold;} -.adminnotice {color: #0000ff;} -.adminhelp {color: #ff0000; font-weight: bold;} -.unconscious {color: #0000ff; font-weight: bold;} -.suicide {color: #ff5050; font-style: italic;} -.green {color: #03ff39;} -.red {color: #FF0000;} -.pink {color: #FF69Bf;} -.blue {color: #0000FF;} -.nicegreen {color: #14a833;} -.userlove {color: #FF1493; font-style: italic; font-weight: bold; text-shadow: 0 0 6px #ff6dbc;} -.love {color: #ff006a; font-style: italic; text-shadow: 0 0 6px #ff6d6d;} -.shadowling {color: #3b2769;} -.cult {color: #960000;} - -.cultitalic {color: #960000; font-style: italic;} -.cultbold {color: #960000; font-style: italic; font-weight: bold;} -.cultboldtalic {color: #960000; font-weight: bold; font-size: 185%;} - -.cultlarge {color: #960000; font-weight: bold; font-size: 185%;} -.narsie {color: #960000; font-weight: bold; font-size: 925%;} -.narsiesmall {color: #960000; font-weight: bold; font-size: 370%;} -.colossus {color: #7F282A; font-size: 310%;} -.hierophant {color: #660099; font-weight: bold; font-style: italic;} -.hierophant_warning {color: #660099; font-style: italic;} -.purple {color: #5e2d79;} -.holoparasite {color: #35333a;} - -.revennotice {color: #1d2953;} -.revenboldnotice {color: #1d2953; font-weight: bold;} -.revenbignotice {color: #1d2953; font-weight: bold; font-size: 185%;} -.revenminor {color: #823abb} -.revenwarning {color: #760fbb; font-style: italic;} -.revendanger {color: #760fbb; font-weight: bold; font-size: 185%;} -.umbra {color: #5000A0;} -.umbra_emphasis {color: #5000A0; font-weight: bold; font-style: italic;} -.umbra_large {color: #5000A0; font-size: 185%; font-weight: bold; font-style: italic;} - -.deconversion_message {color: #5000A0; font-size: 185%; font-style: italic;} - -.brass {color: #BE8700;} -.heavy_brass {color: #BE8700; font-weight: bold; font-style: italic;} -.large_brass {color: #BE8700; font-size: 185%;} -.big_brass {color: #BE8700; font-size: 185%; font-weight: bold; font-style: italic;} -.ratvar {color: #BE8700; font-size: 370%; font-weight: bold; font-style: italic;} -.alloy {color: #42474D;} -.heavy_alloy {color: #42474D; font-weight: bold; font-style: italic;} -.nezbere_large {color: #42474D; font-size: 185%; font-weight: bold; font-style: italic;} -.nezbere {color: #42474D; font-weight: bold; font-style: italic;} -.nezbere_small {color: #42474D;} -.sevtug_large {color: #AF0AAF; font-size: 185%; font-weight: bold; font-style: italic;} -.sevtug {color: #AF0AAF; font-weight: bold; font-style: italic;} -.sevtug_small {color: #AF0AAF;} -.inathneq_large {color: #1E8CE1; font-size: 185%; font-weight: bold; font-style: italic;} -.inathneq {color: #1E8CE1; font-weight: bold; font-style: italic;} -.inathneq_small {color: #1E8CE1;} -.nzcrentr_large {color: #DAAA18; font-size: 185%; font-weight: bold; font-style: italic;} -.nzcrentr {color: #DAAA18; font-weight: bold; font-style: italic;} -.nzcrentr_small {color: #DAAA18;} -.neovgre_large {color: #6E001A; font-size: 185%; font-weight: bold; font-style: italic;} -.neovgre {color: #6E001A; font-weight: bold; font-style: italic;} -.neovgre_small {color: #6E001A;} - -.newscaster {color: #800000;} -.ghostalert {color: #5c00e6; font-style: italic; font-weight: bold;} - -.alien {color: #543354;} -.noticealien {color: #00c000;} -.alertalien {color: #00c000; font-weight: bold;} -.changeling {color: #800080; font-style: italic;} - -.spider {color: #4d004d; font-weight: bold; font-size: 185%;} - -.interface {color: #330033;} - -.sans {font-family: "Comic Sans MS", cursive, sans-serif;} -.papyrus {font-family: "Papyrus", cursive, sans-serif;} -.robot {font-family: "Courier New", cursive, sans-serif;} - -.command_headset {font-weight: bold; font-size: 160%;} -.small {font-size: 60%;} -.big {font-size: 185%;} -.reallybig {font-size: 245%;} -.extremelybig {font-size: 310%;} -.greentext {color: #00FF00; font-size: 185%;} -.redtext {color: #FF0000; font-size: 185%;} -.clown {color: #FF69Bf; font-size: 160%; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} -.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;} -.spooky {color: #FF6100;} -.velvet {color: #660015; font-weight: bold; animation: velvet 5000ms infinite;} - -.lethal {color: #bf3d3d; font-weight: bold;} -.stun {color: #0f81bc; font-weight: bold;} -.ion {color: #d084d6; font-weight: bold;} -.xray {color: #32c025; font-weight: bold;} - -@keyframes velvet { - 0% { color: #400020; } - 40% { color: #FF0000; } - 50% { color: #FF8888; } - 60% { color: #FF0000; } - 100% { color: #400020; } -} - -.hypnophrase {color: #202020; font-weight: bold; animation: hypnocolor 1500ms infinite;} -@keyframes hypnocolor { - 0% { color: #202020; } - 25% { color: #4b02ac; } - 50% { color: #9f41f1; } - 75% { color: #541c9c; } - 100% { color: #7adbf3; } -} - -.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;} -@keyframes phobia { - 0% { color: #f75a5a; } - 50% { color: #dd0000; } - 100% { color: #f75a5a; } -} - - -.icon {height: 1em; width: auto;} - -.memo {color: #638500; text-align: center;} -.memoedit {text-align: center; font-size: 125%;} -.abductor {color: #800080; font-style: italic;} -.mind_control {color: #A00D6F; font-size: 100%; font-weight: bold; font-style: italic;} -.slime {color: #00CED1;} -.drone {color: #848482;} -.monkey {color: #975032;} -.swarmer {color: #2C75FF;} -.resonate {color: #298F85;} - -.monkeyhive {color: #774704;} -.monkeylead {color: #774704; font-size: 125%;} - -.connectionClosed, .fatalError {background: red; color: white; padding: 5px;} -.connectionClosed.restored {background: green;} -.internal.boldnshit {color: #000099; font-weight: bold;} - -/* HELPER CLASSES */ -.text-normal {font-weight: normal; font-style: normal;} -.hidden {display: none; visibility: hidden;} diff --git a/code/modules/goonchat/browserassets/css/browserOutput_dark.css b/code/modules/goonchat/browserassets/css/browserOutput_dark.css deleted file mode 100644 index 3377bcf72c..0000000000 --- a/code/modules/goonchat/browserassets/css/browserOutput_dark.css +++ /dev/null @@ -1,159 +0,0 @@ -html, body {color: #E0E0E0;} -body { - background: #171717; - font-color: #E0E0E0; - scrollbar-face-color:#1A1A1A; - scrollbar-track-color:#171717; - scrollbar-highlight-color:#171717; -} - -a {color: #397ea5;} -a.visited {color: #7c00e6;} -a:visited {color: #7c00e6;} - -#newMessages { - background: #242424; - color: #E0E0E0; -} -#newMessages:hover {background: #272727;} - -#ping {background: #272727;} - -#userBar .subCell { - background: #272727; - color: #E0E0E0; - border-top: 1px solid #171717; -} -#userBar .subCell:hover {background: #272727;} -#userBar .toggle {background: #272727;} - -/* MOTD */ -.motd {color: #E0E0E0;} -.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #E0E0E0;} -.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #E0E0E0;} - -h1, h2, h3, h4, h5, h6 {color: #E0E0E0;} -h1.alert, h2.alert {color: #E0E0E0;} - -.ooc {color: #cca300;} -.looc {color: #d8b555;} -.antagooc {color: #ce254f;} -.adminobserverooc {color: #0099cc;} -.adminooc {color: #3d5bc3;} - -.admin {color: #5975da;} - -.deadsay {color: #e2c1ff;} -.radio {color: #1ecc43;} -.sciradio {color: #c68cfa;} -.comradio {color: #5177ff;} -.secradio {color: #dd3535;} -.medradio {color: #57b8f0;} -.engradio {color: #f37746;} -.suppradio {color: #b88646;} -.servradio {color: #6ca729;} -.syndradio {color: #8f4a4b;} -.centcomradio {color: #2681a5;} -.aiprivradio {color: #d65d95;} -.redteamradio {color: #ff4444;} -.blueteamradio {color: #3434fd;} - -.alert {color: #d82020;} -h1.alert, h2.alert {color: #99aab5;} - -.attack {color: #e01c1c;} -.disarm {color: #b42525;} -.passive {color: #a00f0f;} - -.userdanger {color: #c51e1e;} -.danger {color: #c51e1e;} -.warning {color: #c51e1e;} -.alertwarning {color: #c51e1e;} -.boldwarning {color: #c51e1e;} -.announce {color: #c51e1e;} -.boldannounce {color: #c51e1e;} -.greenannounce {color: #059223;} -.info {color: #6685f5;} -.notice {color: #6685f5;} -.boldnotice {color: #6685f5;} -.adminnotice {color: #6685f5;} -.adminhelp {color: #ff0000;} -.unconscious {color: #E0E0E0;} -.red {color: #FF0000;} -.pink {color: #ff70c1;} -.blue {color: #215cff;} -.green {color: #059223;} -.nicegreen {color: #059223;} -.userlove {color: #ff42a6; text-shadow: 0 0 6px #82365e;} -.love {color: #ff4591; text-shadow: 0 0 6px #994449;} -.shadowling {color: #8e8a99;} -.cult {color: #aa1c1c;} - -.cultitalic {color: #aa1c1c;} -.cultbold {color: #aa1c1c;} -.cultboldtalic {color: #aa1c1c;} - -.cultlarge {color: #aa1c1c;} -.narsie {color: #aa1c1c;} -.narsiesmall {color: #aa1c1c;} -.hierophant {color: #b441ee;} -.hierophant_warning {color: #c56bf1;} -.purple {color: #9956d3;} -.holoparasite {color: #88809c;} - -.revennotice {color: #3645aa;} -.revenboldnotice {color: #3645aa;} -.revenbignotice {color: #3645aa;} -.revenminor {color: #823ddd;} -.revenwarning {color: #8911d9;} -.revendanger {color: #8911d9;} -.umbra {color: #7c00e6;} -.umbra_emphasis {color: #7c00e6;} -.umbra_large {color: #7c00e6;} - -.deconversion_message {color: #a947ff;} - -.alloy {color: #545b64;} -.heavy_alloy {color: #545b64;} -.nezbere_large {color: #545b64;} -.nezbere {color: #545b64;} -.nezbere_small {color: #545b64;} -.inathneq_large {color: #1d7dc7;} -.inathneq {color: #1d7dc7;} -.inathneq_small {color: #1d7dc7;} -.neovgre_large {color: #7c0622;} -.neovgre {color: #7c0622;} -.neovgre_small {color: #7c0622;} - -.newscaster {color: #c05d5d;} -.ghostalert {color: #6600ff;} - -.alien {color: #855d85;} -.noticealien {color: #059223;} -.alertalien {color: #059223;} -.changeling {color: #059223;} - -.spider {color: #8800ff;} - -.interface {color: #750e75;} - -.greentext {color: #059223;} -.redtext {color: #c51e1e;} -.clown {color: #ff70c1;} -.velvet {color: #660015;} -@keyframes velvet { - 0% { color: #890020; } - 40% { color: #c51e1e; } - 50% { color: #FF8888; } - 60% { color: #c51e1e; } - 100% { color: #890020; } -} - -.abductor {color: #c204c2;} -.mind_control {color: #df3da9;} -.drone {color: #979795;} - -.monkeyhive {color: #a56408;} -.monkeylead {color: #af6805;} - -.internal.boldnshit {color: #3d5bc3;} diff --git a/code/modules/goonchat/browserassets/css/browserOutput_light.css b/code/modules/goonchat/browserassets/css/browserOutput_light.css deleted file mode 100644 index b7036c74d8..0000000000 --- a/code/modules/goonchat/browserassets/css/browserOutput_light.css +++ /dev/null @@ -1,14 +0,0 @@ -body {background: #F1F1F1;} - -#newMessages {background: #ddd;} -#ping {background: #ddd;} - -#userBar .subCell {background: #ddd;} - -/* POPUPS */ -.popup {background: #ddd;} -.popup .head {color: #ddd;} -.popup input[type=submit] {color: #ddd;} - -/* ADMIN CONTEXT MENU */ -.contextMenu {background-color: #ddd;} diff --git a/code/modules/goonchat/browserassets/html/browserOutput.html b/code/modules/goonchat/browserassets/html/browserOutput.html deleted file mode 100644 index ce51cd8de8..0000000000 --- a/code/modules/goonchat/browserassets/html/browserOutput.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - Chat - - - - - - - - - - -
- -
- Loading...

- If this takes longer than 30 seconds, it will automatically reload a maximum of 5 times.
- If it still doesn't work, use the bug report button at the top right of the window. -
-
-
- -
- - - - - diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js deleted file mode 100644 index ac30076de4..0000000000 --- a/code/modules/goonchat/browserassets/js/browserOutput.js +++ /dev/null @@ -1,1104 +0,0 @@ - -/***************************************** -* -* FUNCTION AND VAR DECLARATIONS -* -******************************************/ - -//DEBUG STUFF -var escaper = encodeURIComponent || escape; -var decoder = decodeURIComponent || unescape; -window.onerror = function(msg, url, line, col, error) { - if (document.location.href.indexOf("proc=debug") <= 0) { - var extra = !col ? '' : ' | column: ' + col; - extra += !error ? '' : ' | error: ' + error; - extra += !navigator.userAgent ? '' : ' | user agent: ' + navigator.userAgent; - var debugLine = 'Error: ' + msg + ' | url: ' + url + ' | line: ' + line + extra; - window.location = '?_src_=chat&proc=debug¶m[error]='+escaper(debugLine); - } - return true; -}; - -//Globals -window.status = 'Output'; -var $messages, $subOptions, $subAudio, $selectedSub, $contextMenu, $filterMessages, $last_message; -var opts = { - //General - 'messageCount': 0, //A count...of messages... - 'messageLimit': 2053, //A limit...for the messages... - 'scrollSnapTolerance': 10, //If within x pixels of bottom - 'clickTolerance': 10, //Keep focus if outside x pixels of mousedown position on mouseup - 'imageRetryDelay': 50, //how long between attempts to reload images (in ms) - 'imageRetryLimit': 50, //how many attempts should we make? - 'popups': 0, //Amount of popups opened ever - 'wasd': false, //Is the user in wasd mode? - 'priorChatHeight': 0, //Thing for height-resizing detection - 'restarting': false, //Is the round restarting? - 'colorPreset': 0, // index in the color presets list. - //'darkmode':false, //Are we using darkmode? If not WHY ARE YOU LIVING IN 2009??? <- /tg/ take on darktheme - - //Options menu - 'selectedSubLoop': null, //Contains the interval loop for closing the selected sub menu - 'suppressSubClose': false, //Whether or not we should be hiding the selected sub menu - 'highlightTerms': [], - 'highlightLimit': 5, - 'highlightColor': '#FFFF00', //The color of the highlighted message - 'pingDisabled': false, //Has the user disabled the ping counter - - //Ping display - 'lastPang': 0, //Timestamp of the last response from the server. - 'pangLimit': 35000, - 'pingTime': 0, //Timestamp of when ping sent - 'pongTime': 0, //Timestamp of when ping received - 'noResponse': false, //Tracks the state of the previous ping request - 'noResponseCount': 0, //How many failed pings? - - //Clicks - 'mouseDownX': null, - 'mouseDownY': null, - 'preventFocus': false, //Prevents switching focus to the game window - - //Client Connection Data - 'clientDataLimit': 5, - 'clientData': [], - - //Admin music volume update - 'volumeUpdateDelay': 5000, //Time from when the volume updates to data being sent to the server - 'volumeUpdating': false, //True if volume update function set to fire - 'updatedVolume': 0, //The volume level that is sent to the server - 'musicStartAt': 0, //The position the music starts playing - 'musicEndAt': 0, //The position the music... stops playing... if null, doesn't apply (so the music runs through) - - 'defaultMusicVolume': 25, - - 'messageCombining': true, - -}; -var replaceRegexes = {}; - -// Array of names for chat display color presets. CIT SPECIFIC. -// If not set to normal, a CSS file `browserOutput_${name}.css` will be added to the head. -var colorPresets = [ - 'normal', - 'light', - 'dark' -] - -function clamp(val, min, max) { - return Math.max(min, Math.min(val, max)) -} - -//Polyfill for fucking date now because of course IE8 and below don't support it -if (!Date.now) { - Date.now = function now() { - return new Date().getTime(); - }; -} -//Polyfill for trim() (IE8 and below) -if (typeof String.prototype.trim !== 'function') { - String.prototype.trim = function () { - return this.replace(/^\s+|\s+$/g, ''); - }; -} - -// CIT SPECIFIC. -function updateColorPreset() { - var el = $("#colorPresetLink")[0]; - el.href = "browserOutput_"+colorPresets[opts.colorPreset]+".css"; - runByond('?_src_=chat&proc=colorPresetPost&preset='+colorPresets[opts.colorPreset]); -} - -// Linkify the contents of a node, within its parent. -function linkify(parent, insertBefore, text) { - var start = 0; - var match; - var regex = /(?:(?:https?:\/\/)|(?:www\.))(?:[^ ]*?\.[^ ]*?)+[-A-Za-z0-9+&@#\/%?=~_|$!:,.;()]+/ig; - while ((match = regex.exec(text)) !== null) { - // add the unmatched text - parent.insertBefore(document.createTextNode(text.substring(start, match.index)), insertBefore); - - var href = match[0]; - if (!/^https?:\/\//i.test(match[0])) { - href = "http://" + match[0]; - } - - // add the link - var link = document.createElement("a"); - link.href = href; - link.textContent = match[0]; - parent.insertBefore(link, insertBefore); - - start = regex.lastIndex; - } - if (start !== 0) { - // add the remaining text and remove the original text node - parent.insertBefore(document.createTextNode(text.substring(start)), insertBefore); - parent.removeChild(insertBefore); - } -} - -// Recursively linkify the children of a given node. -function linkify_node(node) { - var children = node.childNodes; - // work backwards to avoid the risk of looping forever on our own output - for (var i = children.length - 1; i >= 0; --i) { - var child = children[i]; - if (child.nodeType == Node.TEXT_NODE) { - // text is to be linkified - linkify(node, child, child.textContent); - } else if (child.nodeName != "A" && child.nodeName != "a") { - // do not linkify existing links - linkify_node(child); - } - } -} - -//Shit fucking piece of crap that doesn't work god fuckin damn it -function linkify_fallback(text) { - var rex = /((?:'+$0+''; - } - else { - return $1 ? $0: ''+$0+''; - } - }); -} - -function byondDecode(message) { - // Basically we url_encode twice server side so we can manually read the encoded version and actually do UTF-8. - // The replace for + is because FOR SOME REASON, BYOND replaces spaces with a + instead of %20, and a plus with %2b. - // Marvelous. - message = message.replace(/\+/g, "%20"); - try { - // This is a workaround for the above not always working when BYOND's shitty url encoding breaks. (byond bug id:2399401) - if (decodeURIComponent) { - message = decodeURIComponent(message); - } else { - throw new Error("Easiest way to trigger the fallback") - } - } catch (err) { - message = unescape(message); - } - return message; -} - -function replaceRegex() { - var selectedRegex = replaceRegexes[$(this).attr('replaceRegex')]; - if (selectedRegex) { - var replacedText = $(this).html().replace(selectedRegex[0], selectedRegex[1]); - $(this).html(replacedText); - } - $(this).removeAttr('replaceRegex'); -} - -// Get a highlight markup span -function createHighlightMarkup() { - var extra = ''; - if (opts.highlightColor) { - extra += ' style="background-color: ' + opts.highlightColor + '"'; - } - return ''; -} - -// Get all child text nodes that match a regex pattern -function getTextNodes(elem, pattern) { - var result = $([]); - $(elem).contents().each(function(idx, child) { - if (child.nodeType === 3 && /\S/.test(child.nodeValue) && pattern.test(child.nodeValue)) { - result = result.add(child); - } - else { - result = result.add(getTextNodes(child, pattern)); - } - }); - return result; -} - -// Highlight all text terms matching the registered regex patterns -function highlightTerms(el) { - var pattern = new RegExp("(" + opts.highlightTerms.join('|') + ")", 'gi'); - var nodes = getTextNodes(el, pattern); - - nodes.each(function (idx, node) { - var content = $(node).text(); - var parent = $(node).parent(); - var pre = $(node.previousSibling); - $(node).remove(); - content.split(pattern).forEach(function (chunk) { - // Get our highlighted span/text node - var toInsert = null; - if (pattern.test(chunk)) { - var tmpElem = $(createHighlightMarkup()); - tmpElem.text(chunk); - toInsert = tmpElem; - } - else { - toInsert = document.createTextNode(chunk); - } - - // Insert back into our element - if (pre.length == 0) { - var result = parent.prepend(toInsert); - pre = $(result[0].firstChild); - } - else { - pre.after(toInsert); - pre = $(pre[0].nextSibling); - } - }); - }); -} - -function iconError(E) { - var that = this; - setTimeout(function() { - var attempts = $(that).data('reload_attempts'); - if (typeof attempts === 'undefined' || !attempts) { - attempts = 1; - } - if (attempts > opts.imageRetryLimit) - return; - var src = that.src; - that.src = null; - that.src = src+'#'+attempts; - $(that).data('reload_attempts', ++attempts); - }, opts.imageRetryDelay); -} - -//Send a message to the client -function output(message, flag) { - if (typeof message === 'undefined') { - return; - } - if (typeof flag === 'undefined') { - flag = ''; - } - - if (flag !== 'internal') - opts.lastPang = Date.now(); - - message = byondDecode(message).trim(); - - //The behemoth of filter-code (for Admin message filters) - //Note: This is proooobably hella inefficient - var filteredOut = false; - if (opts.hasOwnProperty('showMessagesFilters') && !opts.showMessagesFilters['All'].show) { - //Get this filter type (defined by class on message) - var messageHtml = $.parseHTML(message), - messageClasses; - if (opts.hasOwnProperty('filterHideAll') && opts.filterHideAll) { - var internal = false; - messageClasses = (!!$(messageHtml).attr('class') ? $(messageHtml).attr('class').split(/\s+/) : false); - if (messageClasses) { - for (var i = 0; i < messageClasses.length; i++) { //Every class - if (messageClasses[i] == 'internal') { - internal = true; - break; - } - } - } - if (!internal) { - filteredOut = 'All'; - } - } else { - //If the element or it's child have any classes - if (!!$(messageHtml).attr('class') || !!$(messageHtml).children().attr('class')) { - messageClasses = $(messageHtml).attr('class').split(/\s+/); - if (!!$(messageHtml).children().attr('class')) { - messageClasses = messageClasses.concat($(messageHtml).children().attr('class').split(/\s+/)); - } - var tempCount = 0; - for (var i = 0; i < messageClasses.length; i++) { //Every class - var thisClass = messageClasses[i]; - $.each(opts.showMessagesFilters, function(key, val) { //Every filter - if (key !== 'All' && val.show === false && typeof val.match != 'undefined') { - for (var i = 0; i < val.match.length; i++) { - var matchClass = val.match[i]; - if (matchClass == thisClass) { - filteredOut = key; - break; - } - } - } - if (filteredOut) return false; - }); - if (filteredOut) break; - tempCount++; - } - } else { - if (!opts.showMessagesFilters['Misc'].show) { - filteredOut = 'Misc'; - } - } - } - } - - //Stuff we do along with appending a message - var atBottom = false; - if (!filteredOut) { - var bodyHeight = $('body').height(); - var messagesHeight = $messages.outerHeight(); - var scrollPos = $('body,html').scrollTop(); - - //Should we snap the output to the bottom? - if (bodyHeight + scrollPos >= messagesHeight - opts.scrollSnapTolerance) { - atBottom = true; - if ($('#newMessages').length) { - $('#newMessages').remove(); - } - //If not, put the new messages box in - } else { - if ($('#newMessages').length) { - var messages = $('#newMessages .number').text(); - messages = parseInt(messages); - messages++; - $('#newMessages .number').text(messages); - if (messages == 2) { - $('#newMessages .messageWord').append('s'); - } - } else { - $messages.after('1 new message '); - } - } - } - - opts.messageCount++; - - //Pop the top message off if history limit reached - if (opts.messageCount >= opts.messageLimit) { - $messages.children('div.entry:first-child').remove(); - opts.messageCount--; //I guess the count should only ever equal the limit - } - - // Create the element - if combining is off, we use it, and if it's on, we - // might discard it bug need to check its text content. Some messages vary - // only in HTML markup, have the same text content, and should combine. - var entry = document.createElement('div'); - entry.innerHTML = message; - var trimmed_message = entry.textContent || entry.innerText || ""; - - var handled = false; - if (opts.messageCombining) { - var lastmessages = $messages.children('div.entry:last-child').last(); - if (lastmessages.length && $last_message && $last_message == trimmed_message) { - var badge = lastmessages.children('.r').last(); - if (badge.length) { - badge = badge.detach(); - badge.text(parseInt(badge.text()) + 1); - } else { - badge = $('', {'class': 'r', 'text': 2}); - } - lastmessages.html(message); - lastmessages.find('[replaceRegex]').each(replaceRegex); - lastmessages.append(badge); - badge.animate({ - "font-size": "0.9em" - }, 100, function() { - badge.animate({ - "font-size": "0.7em" - }, 100); - }); - opts.messageCount--; - handled = true; - } - } - - if (!handled) { - //Actually append the message - entry.className = 'entry'; - - if (filteredOut) { - entry.className += ' hidden'; - entry.setAttribute('data-filter', filteredOut); - } - - $(entry).find('[replaceRegex]').each(replaceRegex); - - $last_message = trimmed_message; - $messages[0].appendChild(entry); - $(entry).find("img.icon").error(iconError); - - var to_linkify = $(entry).find(".linkify"); - if (typeof Node === 'undefined') { - // Linkify fallback for old IE - for(var i = 0; i < to_linkify.length; ++i) { - to_linkify[i].innerHTML = linkify_fallback(to_linkify[i].innerHTML); - } - } else { - // Linkify for modern IE versions - for(var i = 0; i < to_linkify.length; ++i) { - linkify_node(to_linkify[i]); - } - } - - //Actually do the snap - //Stuff we can do after the message shows can go here, in the interests of responsiveness - if (opts.highlightTerms && opts.highlightTerms.length > 0) { - highlightTerms($(entry)); - } - } - - if (!filteredOut && atBottom) { - $('body,html').scrollTop($messages.outerHeight()); - } -} - -function internalOutput(message, flag) -{ - output(escaper(message), flag) -} - -//Runs a route within byond, client or server side. Consider this "ehjax" for byond. -function runByond(uri) { - window.location = uri; -} - -function setCookie(cname, cvalue, exdays) { - cvalue = escaper(cvalue); - var d = new Date(); - d.setTime(d.getTime() + (exdays*24*60*60*1000)); - var expires = 'expires='+d.toUTCString(); - document.cookie = cname + '=' + cvalue + '; ' + expires + "; path=/"; -} - -function getCookie(cname) { - var name = cname + '='; - var ca = document.cookie.split(';'); - for(var i=0; i < ca.length; i++) { - var c = ca[i]; - while (c.charAt(0)==' ') c = c.substring(1); - if (c.indexOf(name) === 0) { - return decoder(c.substring(name.length,c.length)); - } - } - return ''; -} - -function rgbToHex(R,G,B) {return toHex(R)+toHex(G)+toHex(B);} -function toHex(n) { - n = parseInt(n,10); - if (isNaN(n)) return "00"; - n = Math.max(0,Math.min(n,255)); - return "0123456789ABCDEF".charAt((n-n%16)/16) + "0123456789ABCDEF".charAt(n%16); -} - -/* -function swap() { //Swap to darkmode - if (opts.darkmode){ - document.getElementById("sheetofstyles").href = "browserOutput_white.css"; - opts.darkmode = false; - runByond('?_src_=chat&proc=swaptolightmode'); - } else { - document.getElementById("sheetofstyles").href = "browserOutput.css"; - opts.darkmode = true; - runByond('?_src_=chat&proc=swaptodarkmode'); - } - setCookie('darkmode', (opts.darkmode ? 'true' : 'false'), 365); -} -*/ -function handleClientData(ckey, ip, compid) { - //byond sends player info to here - var currentData = {'ckey': ckey, 'ip': ip, 'compid': compid}; - if (opts.clientData && !$.isEmptyObject(opts.clientData)) { - runByond('?_src_=chat&proc=analyzeClientData¶m[cookie]='+JSON.stringify({'connData': opts.clientData})); - - for (var i = 0; i < opts.clientData.length; i++) { - var saved = opts.clientData[i]; - if (currentData.ckey == saved.ckey && currentData.ip == saved.ip && currentData.compid == saved.compid) { - return; //Record already exists - } - } - //Lets make sure we obey our limit (can connect from server with higher limit) - while (opts.clientData.length >= opts.clientDataLimit) { - opts.clientData.shift(); - } - } else { - runByond('?_src_=chat&proc=analyzeClientData¶m[cookie]=none'); - } - - //Update the cookie with current details - opts.clientData.push(currentData); - setCookie('connData', JSON.stringify(opts.clientData), 365); -} - -//Server calls this on ehjax response -//Or, y'know, whenever really -function ehjaxCallback(data) { - opts.lastPang = Date.now(); - if (data == 'softPang') { - return; - } else if (data == 'pang') { - opts.pingCounter = 0; //reset - opts.pingTime = Date.now(); - runByond('?_src_=chat&proc=ping'); - - } else if (data == 'pong') { - if (opts.pingDisabled) {return;} - opts.pongTime = Date.now(); - var pingDuration = Math.ceil((opts.pongTime - opts.pingTime) / 2); - $('#pingMs').text(pingDuration+'ms'); - pingDuration = Math.min(pingDuration, 255); - var red = pingDuration; - var green = 255 - pingDuration; - var blue = 0; - var hex = rgbToHex(red, green, blue); - $('#pingDot').css('color', '#'+hex); - - } else if (data == 'roundrestart') { - opts.restarting = true; - internalOutput('
The connection has been closed because the server is restarting. Please wait while you automatically reconnect.
', 'internal'); - } else if (data == 'stopMusic') { - $('#adminMusic').prop('src', ''); - } else { - //Oh we're actually being sent data instead of an instruction - var dataJ; - try { - dataJ = $.parseJSON(data); - } catch (e) { - //But...incorrect :sadtrombone: - window.onerror('JSON: '+e+'. '+data, 'browserOutput.html', 327); - return; - } - data = dataJ; - - if (data.clientData) { - if (opts.restarting) { - opts.restarting = false; - $('.connectionClosed.restarting:not(.restored)').addClass('restored').text('The round restarted and you successfully reconnected!'); - } - if (!data.clientData.ckey && !data.clientData.ip && !data.clientData.compid) { - //TODO: Call shutdown perhaps - return; - } else { - handleClientData(data.clientData.ckey, data.clientData.ip, data.clientData.compid); - } - sendVolumeUpdate(); - } else if (data.adminMusic) { - if (typeof data.adminMusic === 'string') { - var adminMusic = byondDecode(data.adminMusic); - var bindLoadedData = false; - adminMusic = adminMusic.match(/https?:\/\/\S+/) || ''; - if (data.musicRate) { - var newRate = Number(data.musicRate); - if(newRate) { - $('#adminMusic').prop('defaultPlaybackRate', newRate); - } - } else { - $('#adminMusic').prop('defaultPlaybackRate', 1.0); - } - if (data.musicSeek) { - opts.musicStartAt = Number(data.musicSeek) || 0; - bindLoadedData = true; - } else { - opts.musicStartAt = 0; - } - if (data.musicHalt) { - opts.musicEndAt = Number(data.musicHalt) || null; - bindLoadedData = true; - } - if (bindLoadedData) { - $('#adminMusic').one('loadeddata', adminMusicLoadedData); - } - $('#adminMusic').prop('src', adminMusic); - $('#adminMusic').trigger("play"); - } - } else if (data.syncRegex) { - for (var i in data.syncRegex) { - - var regexData = data.syncRegex[i]; - var regexName = regexData[0]; - var regexFlags = regexData[1]; - var regexReplaced = regexData[2]; - - replaceRegexes[i] = [new RegExp(regexName, regexFlags), regexReplaced]; - } - } - } -} - -function createPopup(contents, width) { - opts.popups++; - $('body').append(''); - - //Attach close popup event - var $popup = $('#popup'+opts.popups); - var height = $popup.outerHeight(); - $popup.css({'height': height+'px', 'margin': '-'+(height/2)+'px 0 0 -'+(width/2)+'px'}); - - $popup.on('click', '.close', function(e) { - e.preventDefault(); - $popup.remove(); - }); -} - -function toggleWasd(state) { - opts.wasd = (state == 'on' ? true : false); -} - -function sendVolumeUpdate() { - opts.volumeUpdating = false; - if(opts.updatedVolume) { - runByond('?_src_=chat&proc=setMusicVolume¶m[volume]='+opts.updatedVolume); - } -} - -function adminMusicEndCheck(event) { - if (opts.musicEndAt) { - if ($('#adminMusic').prop('currentTime') >= opts.musicEndAt) { - $('#adminMusic').off(event); - $('#adminMusic').trigger('pause'); - $('#adminMusic').prop('src', ''); - } - } else { - $('#adminMusic').off(event); - } -} - -function adminMusicLoadedData(event) { - if (opts.musicStartAt && ($('#adminMusic').prop('duration') === Infinity || (opts.musicStartAt <= $('#adminMusic').prop('duration'))) ) { - $('#adminMusic').prop('currentTime', opts.musicStartAt); - } - if (opts.musicEndAt) { - $('#adminMusic').on('timeupdate', adminMusicEndCheck); - } -} - -function subSlideUp() { - $(this).removeClass('scroll'); - $(this).css('height', ''); -} - -function startSubLoop() { - if (opts.selectedSubLoop) { - clearInterval(opts.selectedSubLoop); - } - return setInterval(function() { - if (!opts.suppressSubClose && $selectedSub.is(':visible')) { - $selectedSub.slideUp('fast', subSlideUp); - clearInterval(opts.selectedSubLoop); - } - }, 5000); //every 5 seconds -} - -function handleToggleClick($sub, $toggle) { - if ($selectedSub !== $sub && $selectedSub.is(':visible')) { - $selectedSub.slideUp('fast', subSlideUp); - } - $selectedSub = $sub - if ($selectedSub.is(':visible')) { - $selectedSub.slideUp('fast', subSlideUp); - clearInterval(opts.selectedSubLoop); - } else { - $selectedSub.slideDown('fast', function() { - var windowHeight = $(window).height(); - var toggleHeight = $toggle.outerHeight(); - var priorSubHeight = $selectedSub.outerHeight(); - var newSubHeight = windowHeight - toggleHeight; - $(this).height(newSubHeight); - if (priorSubHeight > (windowHeight - toggleHeight)) { - $(this).addClass('scroll'); - } - }); - opts.selectedSubLoop = startSubLoop(); - } -} - -/***************************************** -* -* DOM READY -* -******************************************/ - -if (typeof $ === 'undefined') { - var div = document.getElementById('loading').childNodes[1]; - div += '

ERROR: Jquery did not load.'; -} - -$(function() { - $messages = $('#messages'); - $subOptions = $('#subOptions'); - $subAudio = $('#subAudio'); - $selectedSub = $subOptions; - - //Hey look it's a controller loop! - setInterval(function() { - if (opts.lastPang + opts.pangLimit < Date.now() && !opts.restarting) { //Every pingLimit - if (!opts.noResponse) { //Only actually append a message if the previous ping didn't also fail (to prevent spam) - opts.noResponse = true; - opts.noResponseCount++; - internalOutput('
You are either AFK, experiencing lag or the connection has closed.
', 'internal'); - } - } else if (opts.noResponse) { //Previous ping attempt failed ohno - $('.connectionClosed[data-count="'+opts.noResponseCount+'"]:not(.restored)').addClass('restored').text('Your connection has been restored (probably)!'); - opts.noResponse = false; - } - }, 2000); //2 seconds - - - /***************************************** - * - * LOAD SAVED CONFIG - * - ******************************************/ - var savedConfig = { - fontsize: getCookie('fontsize'), //no need for compatabiliy, cookie name is the same - lineheight: getCookie('lineheight'), - 'spingDisabled': getCookie('pingdisabled'), - 'shighlightTerms': getCookie('highlightterms'), - 'shighlightColor': getCookie('highlightcolor'), - 'smusicVolume': getCookie('musicVolume'), - 'smessagecombining': getCookie('messagecombining'), - 'sdarkmode': getCookie('darkmode'), - 'scolorPreset': getCookie('colorpreset'), - }; - - if (savedConfig.fontsize) { - $messages.css('font-size', savedConfig.fontsize); - internalOutput('Loaded font size setting of: '+savedConfig.fontsize+'', 'internal'); - } - if (savedConfig.lineheight) { - $("body").css('line-height', savedConfig.lineheight); - internalOutput('Loaded line height setting of: '+savedConfig.lineheight+'', 'internal'); - } - // if(savedConfig.sdarkmode == 'true'){ - // swap(); - // } - if (savedConfig.scolorPreset) { - opts.colorPreset = Number(savedConfig.scolorPreset); - updateColorPreset(); - internalOutput('Loaded color preset of: '+colorPresets[opts.colorPreset]+'', 'internal'); - } - if (savedConfig.spingDisabled) { - if (savedConfig.spingDisabled == 'true') { - opts.pingDisabled = true; - $('#ping').hide(); - } - internalOutput('Loaded ping display of: '+(opts.pingDisabled ? 'hidden' : 'visible')+'', 'internal'); - } - if (savedConfig.shighlightTerms) { - var savedTerms = $.parseJSON(savedConfig.shighlightTerms).filter(function (entry) { - return entry !== null && /\S/.test(entry); - }); - var actualTerms = savedTerms.length != 0 ? savedTerms.join(', ') : null; - if (actualTerms) { - internalOutput('Loaded highlight strings of: ' + actualTerms+'', 'internal'); - opts.highlightTerms = savedTerms; - } - } - if (savedConfig.shighlightColor) { - opts.highlightColor = savedConfig.shighlightColor; - internalOutput('Loaded highlight color of: '+savedConfig.shighlightColor+'', 'internal'); - } - if (savedConfig.smusicVolume) { - var newVolume = clamp(savedConfig.smusicVolume, 0, 100); - $('#adminMusic').prop('volume', newVolume / 100); - $('#musicVolume').val(newVolume); - opts.updatedVolume = newVolume; - sendVolumeUpdate(); - internalOutput('Loaded music volume of: '+savedConfig.smusicVolume+'', 'internal'); - } - else{ - $('#adminMusic').prop('volume', opts.defaultMusicVolume / 100); - } - - if (savedConfig.smessagecombining) { - if (savedConfig.smessagecombining == 'false') { - opts.messageCombining = false; - } else { - opts.messageCombining = true; - } - } - (function() { - var dataCookie = getCookie('connData'); - if (dataCookie) { - var dataJ; - try { - dataJ = $.parseJSON(dataCookie); - } catch (e) { - window.onerror('JSON '+e+'. '+dataCookie, 'browserOutput.html', 434); - return; - } - opts.clientData = dataJ; - } - })(); - - - /***************************************** - * - * BASE CHAT OUTPUT EVENTS - * - ******************************************/ - - $('body').on('click', 'a', function(e) { - e.preventDefault(); - }); - - $('body').on('mousedown', function(e) { - var $target = $(e.target); - - if ($contextMenu && opts.hasOwnProperty('contextMenuTarget') && opts.contextMenuTarget) { - hideContextMenu(); - return false; - } - - if ($target.is('a') || $target.parent('a').length || $target.is('input') || $target.is('textarea')) { - opts.preventFocus = true; - } else { - opts.preventFocus = false; - opts.mouseDownX = e.pageX; - opts.mouseDownY = e.pageY; - } - }); - - $messages.on('mousedown', function(e) { - if ($selectedSub && $selectedSub.is(':visible')) { - $selectedSub.slideUp('fast', subSlideUp); - clearInterval(opts.selectedSubLoop); - } - }); - - $('body').on('mouseup', function(e) { - if (!opts.preventFocus && - (e.pageX >= opts.mouseDownX - opts.clickTolerance && e.pageX <= opts.mouseDownX + opts.clickTolerance) && - (e.pageY >= opts.mouseDownY - opts.clickTolerance && e.pageY <= opts.mouseDownY + opts.clickTolerance) - ) { - opts.mouseDownX = null; - opts.mouseDownY = null; - runByond('byond://winset?mapwindow.map.focus=true'); - } - }); - - $messages.on('click', 'a', function(e) { - var href = $(this).attr('href'); - $(this).addClass('visited'); - if (href[0] == '?' || (href.length >= 8 && href.substring(0,8) == 'byond://')) { - runByond(href); - } else { - href = escaper(href); - runByond('?action=openLink&link='+href); - } - runByond('byond://winset?mapwindow.map.focus=true'); - }); - - $('body').on('keydown', function(e) { - if (e.target.nodeName == 'INPUT' || e.target.nodeName == 'TEXTAREA') { - return; - } - if (e.ctrlKey || e.altKey || e.shiftKey) { //Band-aid "fix" for allowing ctrl+c copy paste etc. Needs a proper fix. - return; - } - runByond('byond://winset?mapwindow.map.focus=true'); - }); - - //Mildly hacky fix for scroll issues on mob change (interface gets resized sometimes, messing up snap-scroll) - $(window).on('resize', function(e) { - if ($(this).height() !== opts.priorChatHeight) { - $('body,html').scrollTop($messages.outerHeight()); - opts.priorChatHeight = $(this).height(); - } - }); - - - /***************************************** - * - * OPTIONS INTERFACE EVENTS - * - ******************************************/ - - $('body').on('click', '#newMessages', function(e) { - var messagesHeight = $messages.outerHeight(); - $('body,html').scrollTop(messagesHeight); - $('#newMessages').remove(); - runByond('byond://winset?mapwindow.map.focus=true'); - }); - - $('#toggleOptions').click(function(e) { - handleToggleClick($subOptions, $(this)); - }); - // $('#darkmodetoggle').click(function(e) { - // swap(); - // }); - $('#toggleAudio').click(function(e) { - handleToggleClick($subAudio, $(this)); - }); - - $('.sub, .toggle').mouseenter(function() { - opts.suppressSubClose = true; - }); - - $('.sub, .toggle').mouseleave(function() { - opts.suppressSubClose = false; - }); - - $('#decreaseFont').click(function(e) { - savedConfig.fontsize = Math.max(parseInt(savedConfig.fontsize || 13) - 1, 1) + 'px'; - $messages.css({'font-size': savedConfig.fontsize}); - setCookie('fontsize', savedConfig.fontsize, 365); - internalOutput('Font size set to '+savedConfig.fontsize+'', 'internal'); - }); - - $('#increaseFont').click(function(e) { - savedConfig.fontsize = (parseInt(savedConfig.fontsize || 13) + 1) + 'px'; - $messages.css({'font-size': savedConfig.fontsize}); - setCookie('fontsize', savedConfig.fontsize, 365); - internalOutput('Font size set to '+savedConfig.fontsize+'', 'internal'); - }); - - $('#decreaseLineHeight').click(function(e) { - savedConfig.lineheight = Math.max(parseFloat(savedConfig.lineheight || 1.2) - 0.1, 0.1).toFixed(1); - $("body").css({'line-height': savedConfig.lineheight}); - setCookie('lineheight', savedConfig.lineheight, 365); - internalOutput('Line height set to '+savedConfig.lineheight+'', 'internal'); - }); - - $('#increaseLineHeight').click(function(e) { - savedConfig.lineheight = (parseFloat(savedConfig.lineheight || 1.2) + 0.1).toFixed(1); - $("body").css({'line-height': savedConfig.lineheight}); - setCookie('lineheight', savedConfig.lineheight, 365); - internalOutput('Line height set to '+savedConfig.lineheight+'', 'internal'); - }); - - $('#togglePing').click(function(e) { - if (opts.pingDisabled) { - $('#ping').slideDown('fast'); - opts.pingDisabled = false; - } else { - $('#ping').slideUp('fast'); - opts.pingDisabled = true; - } - setCookie('pingdisabled', (opts.pingDisabled ? 'true' : 'false'), 365); - }); - - $('#saveLog').click(function(e) { - // Requires IE 10+ to issue download commands. Just opening a popup - // window will cause Ctrl+S to save a blank page, ignoring innerHTML. - if (!window.Blob) { - output('This function is only supported on IE 10 and up. Upgrade if possible.', 'internal'); - return; - } - - $.ajax({ - type: 'GET', - url: 'browserOutput.css', // browserOutput_white.css - success: function(styleData) { - var blob = new Blob(['Chat Log', $messages.html(), '']); - - var fname = 'SS13 Chat Log'; - var date = new Date(), month = date.getMonth(), day = date.getDay(), hours = date.getHours(), mins = date.getMinutes(), secs = date.getSeconds(); - fname += ' ' + date.getFullYear() + '-' + (month < 10 ? '0' : '') + month + '-' + (day < 10 ? '0' : '') + day; - fname += ' ' + (hours < 10 ? '0' : '') + hours + (mins < 10 ? '0' : '') + mins + (secs < 10 ? '0' : '') + secs; - fname += '.html'; - - window.navigator.msSaveBlob(blob, fname); - } - }); - }); - - $('#highlightTerm').click(function(e) { - if ($('.popup .highlightTerm').is(':visible')) {return;} - var termInputs = ''; - for (var i = 0; i < opts.highlightLimit; i++) { - termInputs += '
'; - } - var popupContent = '
String Highlighting
' + - '
' + - '
Choose up to '+opts.highlightLimit+' strings that will highlight the line when they appear in chat.
' + - '
' + - termInputs + - '
' + - '
' + - '
' + - '
'; - createPopup(popupContent, 250); - }); - - $('body').on('keyup', '#highlightColor', function() { - var color = $('#highlightColor').val(); - color = color.trim(); - if (!color || color.charAt(0) != '#') return; - $('#highlightColor').css('background-color', color); - }); - - $('body').on('submit', '#highlightTermForm', function(e) { - e.preventDefault(); - - opts.highlightTerms = []; - for (var count = 0; count < opts.highlightLimit; count++) { - var term = $('#highlightTermInput'+count).val(); - if (term !== null && /\S/.test(term)) { - opts.highlightTerms.push(term.trim().toLowerCase()); - } - } - - var color = $('#highlightColor').val(); - color = color.trim(); - if (color == '' || color.charAt(0) != '#') { - opts.highlightColor = '#FFFF00'; - } else { - opts.highlightColor = color; - } - var $popup = $('#highlightPopup').closest('.popup'); - $popup.remove(); - - setCookie('highlightterms', JSON.stringify(opts.highlightTerms), 365); - setCookie('highlightcolor', opts.highlightColor, 365); - }); - - $('#clearMessages').click(function() { - $messages.empty(); - opts.messageCount = 0; - }); - - $('#changeColorPreset').click(function() { //CIT SPECIFIC - opts.colorPreset = (opts.colorPreset+1) % colorPresets.length; - updateColorPreset(); - setCookie('colorpreset', opts.colorPreset, 365); - internalOutput('Changed color preset to: '+colorPresets[opts.colorPreset]); - }); - - $('#musicVolumeSpan').hover(function() { - $('#musicVolumeText').addClass('hidden'); - $('#musicVolume').removeClass('hidden'); - }, function() { - $('#musicVolume').addClass('hidden'); - $('#musicVolumeText').removeClass('hidden'); - }); - - $('#musicVolume').change(function() { - var newVolume = $('#musicVolume').val(); - newVolume = clamp(newVolume, 0, 100); - $('#adminMusic').prop('volume', newVolume / 100); - setCookie('musicVolume', newVolume, 365); - opts.updatedVolume = newVolume; - if(!opts.volumeUpdating) { - setTimeout(sendVolumeUpdate, opts.volumeUpdateDelay); - opts.volumeUpdating = true; - } - }); - - $('#toggleCombine').click(function(e) { - opts.messageCombining = !opts.messageCombining; - setCookie('messagecombining', (opts.messageCombining ? 'true' : 'false'), 365); - }); - - $('img.icon').error(iconError); - - - - - /***************************************** - * - * KICK EVERYTHING OFF - * - ******************************************/ - - runByond('?_src_=chat&proc=doneLoading'); - if ($('#loading').is(':visible')) { - $('#loading').remove(); - } - $('#userBar').show(); - opts.priorChatHeight = $(window).height(); -}); diff --git a/code/modules/goonchat/browserassets/js/json2.min.js b/code/modules/goonchat/browserassets/js/json2.min.js deleted file mode 100644 index d867407f26..0000000000 --- a/code/modules/goonchat/browserassets/js/json2.min.js +++ /dev/null @@ -1 +0,0 @@ -"object"!=typeof JSON&&(JSON={}),function(){"use strict";function f(t){return 10>t?"0"+t:t}function this_value(){return this.valueOf()}function quote(t){return rx_escapable.lastIndex=0,rx_escapable.test(t)?'"'+t.replace(rx_escapable,function(t){var e=meta[t];return"string"==typeof e?e:"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+t+'"'}function str(t,e){var r,n,o,u,f,a=gap,i=e[t];switch(i&&"object"==typeof i&&"function"==typeof i.toJSON&&(i=i.toJSON(t)),"function"==typeof rep&&(i=rep.call(e,t,i)),typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";if(gap+=indent,f=[],"[object Array]"===Object.prototype.toString.apply(i)){for(u=i.length,r=0;u>r;r+=1)f[r]=str(r,i)||"null";return o=0===f.length?"[]":gap?"[\n"+gap+f.join(",\n"+gap)+"\n"+a+"]":"["+f.join(",")+"]",gap=a,o}if(rep&&"object"==typeof rep)for(u=rep.length,r=0;u>r;r+=1)"string"==typeof rep[r]&&(n=rep[r],o=str(n,i),o&&f.push(quote(n)+(gap?": ":":")+o));else for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(o=str(n,i),o&&f.push(quote(n)+(gap?": ":":")+o));return o=0===f.length?"{}":gap?"{\n"+gap+f.join(",\n"+gap)+"\n"+a+"}":"{"+f.join(",")+"}",gap=a,o}}var rx_one=/^[\],:{}\s]*$/,rx_two=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,rx_three=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,rx_four=/(?:^|:|,)(?:\s*\[)+/g,rx_escapable=/[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,rx_dangerous=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},Boolean.prototype.toJSON=this_value,Number.prototype.toJSON=this_value,String.prototype.toJSON=this_value);var gap,indent,meta,rep;"function"!=typeof JSON.stringify&&(meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},JSON.stringify=function(t,e,r){var n;if(gap="",indent="","number"==typeof r)for(n=0;r>n;n+=1)indent+=" ";else"string"==typeof r&&(indent=r);if(rep=e,e&&"function"!=typeof e&&("object"!=typeof e||"number"!=typeof e.length))throw new Error("JSON.stringify");return str("",{"":t})}),"function"!=typeof JSON.parse&&(JSON.parse=function(text,reviver){function walk(t,e){var r,n,o=t[e];if(o&&"object"==typeof o)for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(n=walk(o,r),void 0!==n?o[r]=n:delete o[r]);return reviver.call(t,e,o)}var j;if(text=String(text),rx_dangerous.lastIndex=0,rx_dangerous.test(text)&&(text=text.replace(rx_dangerous,function(t){return"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})),rx_one.test(text.replace(rx_two,"@").replace(rx_three,"]").replace(rx_four,"")))return j=eval("("+text+")"),"function"==typeof reviver?walk({"":j},""):j;throw new SyntaxError("JSON.parse")})}(); \ No newline at end of file diff --git a/code/modules/holiday/halloween/jacqueen.dm b/code/modules/holiday/halloween/jacqueen.dm index 4561e0ae3e..573b04a296 100644 --- a/code/modules/holiday/halloween/jacqueen.dm +++ b/code/modules/holiday/halloween/jacqueen.dm @@ -334,8 +334,7 @@ to_chat(C, " You feel an overwhelming desire to [message]") if(2) visible_message("[src] waves their arms around, \"If only you had a better upbringing, your ears are now full of my singing!\"") - var/client/C2 = C.client - C2.chatOutput.sendMusic("https://puu.sh/ExBbv.mp4", 1)//I hope this works! + C.client.tgui_panel?.play_music("https://puu.sh/ExBbv.mp4") if(3) visible_message("[src] waves their arms around, \"You're cute little bumpkin, On your head is a pumpkin!\"") if(C.head) diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm index abf6632939..f6be9db9a2 100644 --- a/code/modules/hydroponics/hydroitemdefines.dm +++ b/code/modules/hydroponics/hydroitemdefines.dm @@ -103,6 +103,7 @@ throwforce = 5 throw_speed = 2 throw_range = 3 + attack_speed = CLICK_CD_MELEE w_class = WEIGHT_CLASS_BULKY flags_1 = CONDUCT_1 armour_penetration = 20 @@ -125,9 +126,12 @@ playsound(src,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) return (BRUTELOSS) -/obj/item/scythe/pre_attack(atom/A, mob/living/user, params) +/obj/item/scythe/pre_attack(atom/A, mob/living/user, params, attackchain_flags, damage_multiplier) + . = ..() + if(. & STOP_ATTACK_PROC_CHAIN) + return if(swiping || !istype(A, /obj/structure/spacevine) || get_turf(A) == get_turf(user)) - return ..() + return else var/turf/user_turf = get_turf(user) var/dir_to_target = get_dir(user_turf, get_turf(A)) @@ -138,11 +142,12 @@ var/turf/T = get_step(user_turf, turn(dir_to_target, i)) for(var/obj/structure/spacevine/V in T) if(user.Adjacent(V)) - melee_attack_chain(user, V) + melee_attack_chain(user, V, attackchain_flags = ATTACK_IGNORE_CLICKDELAY) stam_gain += 5 //should be hitcost swiping = FALSE stam_gain += 2 //Initial hitcost user.adjustStaminaLoss(-stam_gain) + user.DelayNextAction() // ************************************* // Nutrient defines for hydroponics @@ -192,4 +197,4 @@ /obj/item/reagent_containers/glass/bottle/killer/pestkiller name = "bottle of pest spray" desc = "Contains a pesticide." - list_reagents = list(/datum/reagent/toxin/pestkiller = 50) \ No newline at end of file + list_reagents = list(/datum/reagent/toxin/pestkiller = 50) diff --git a/code/modules/instruments/songs/_song.dm b/code/modules/instruments/songs/_song.dm index d842dbc003..a0d96658e6 100644 --- a/code/modules/instruments/songs/_song.dm +++ b/code/modules/instruments/songs/_song.dm @@ -2,6 +2,12 @@ #define MUSIC_MAXLINES 1000 #define MUSIC_MAXLINECHARS 300 +/** + * # Song datum + * + * These are the actual backend behind instruments. + * They attach to an atom and provide the editor + playback functionality. + */ /datum/song /// Name of the song var/name = "Untitled" @@ -15,6 +21,9 @@ /// delay between notes in deciseconds var/tempo = 5 + /// How far we can be heard + var/instrument_range = 15 + /// Are we currently playing? var/playing = FALSE @@ -53,17 +62,24 @@ /////////////////// Playing variables //////////////// /** - * Only used in synthesized playback - The chords we compiled. Non assoc list of lists: - * list(list(key1, key2, key3..., tempo_divisor), list(key1, key2..., tempo_divisor), ...) - * tempo_divisor always exists - * if key1 (and so if there's no keys) doesn't exist it's a rest + * Build by compile_chords() + * Must be rebuilt on instrument switch. * Compilation happens when we start playing and is cleared after we finish playing. + * Format: list of chord lists, with chordlists having (key1, key2, key3, tempodiv) */ var/list/compiled_chords + /// Current section of a long chord we're on, so we don't need to make a billion chords, one for every unit ticklag. + var/elapsed_delay + /// Amount of delay to wait before playing the next chord + var/delay_by + /// Current chord we're on. + var/current_chord /// Channel as text = current volume percentage but it's 0 to 100 instead of 0 to 1. var/list/channels_playing = list() /// List of channels that aren't being used, as text. This is to prevent unnecessary freeing and reallocations from SSsounds/SSinstruments. var/list/channels_idle = list() + /// Person playing us + var/mob/user_playing ////////////////////////////////////////////////////// /// Last world.time we checked for who can hear us @@ -72,8 +88,6 @@ var/list/hearing_mobs /// If this is enabled, some things won't be strictly cleared when they usually are (liked compiled_chords on play stop) var/debug_mode = FALSE - /// Last time we processed decay - var/last_process_decay /// Max sound channels to occupy var/max_sound_channels = CHANNELS_PER_INSTRUMENT /// Current channels, so we can save a length() call. @@ -113,7 +127,7 @@ var/cached_exponential_dropoff = 1.045 ///////////////////////////////////////////////////////////////////////// -/datum/song/New(atom/parent, list/instrument_ids) +/datum/song/New(atom/parent, list/instrument_ids, new_range) SSinstruments.on_song_new(src) lines = list() tempo = sanitize_tempo(tempo) @@ -125,6 +139,8 @@ hearing_mobs = list() volume = clamp(volume, min_volume, max_volume) update_sustain() + if(new_range) + instrument_range = new_range /datum/song/Destroy() stop_playing() @@ -135,12 +151,15 @@ parent = null return ..() +/** + * Checks and stores which mobs can hear us. Terminates sounds for mobs that leave our range. + */ /datum/song/proc/do_hearcheck() last_hearcheck = world.time var/list/old = hearing_mobs.Copy() hearing_mobs.len = 0 var/turf/source = get_turf(parent) - for(var/mob/M in get_hearers_in_view(15, source)) + for(var/mob/M in get_hearers_in_view(instrument_range, source)) if(!(M?.client?.prefs?.toggles & SOUND_INSTRUMENTS)) continue hearing_mobs[M] = get_dist(M, source) @@ -148,10 +167,15 @@ for(var/i in exited) terminate_sound_mob(i) -/// I can either be a datum, id, or path (if the instrument has no id). +/** + * Sets our instrument, caching anything necessary for faster accessing. Accepts an ID, typepath, or instantiated instrument datum. + */ /datum/song/proc/set_instrument(datum/instrument/I) + terminate_all_sounds() + var/old_legacy if(using_instrument) using_instrument.songs_using -= src + old_legacy = (using_instrument.instrument_flags & INSTRUMENT_LEGACY) using_instrument = null cached_samples = null cached_legacy_ext = null @@ -162,7 +186,7 @@ if(istype(I)) using_instrument = I I.songs_using += src - var/instrument_legacy = CHECK_BITFIELD(I.instrument_flags, INSTRUMENT_LEGACY) + var/instrument_legacy = (I.instrument_flags & INSTRUMENT_LEGACY) if(instrument_legacy) cached_legacy_ext = I.legacy_instrument_ext cached_legacy_dir = I.legacy_instrument_path @@ -170,23 +194,37 @@ else cached_samples = I.samples legacy = FALSE + if(isnull(old_legacy) || (old_legacy != instrument_legacy)) + if(playing) + compile_chords() -/// THIS IS A BLOCKING CALL. +/** + * Attempts to start playing our song. + */ /datum/song/proc/start_playing(mob/user) if(playing) return if(!using_instrument?.ready()) to_chat(user, "An error has occured with [src]. Please reset the instrument.") return + compile_chords() + if(!length(compiled_chords)) + to_chat(user, "Song is empty.") + return playing = TRUE - updateDialog() + updateDialog(user_playing) //we can not afford to runtime, since we are going to be doing sound channel reservations and if we runtime it means we have a channel allocation leak. //wrap the rest of the stuff to ensure stop_playing() is called. - last_process_decay = world.time + do_hearcheck() + elapsed_delay = 0 + delay_by = 0 + current_chord = 1 + user_playing = user START_PROCESSING(SSinstruments, src) - . = do_play_lines(user) - stop_playing() +/** + * Stops playing, terminating all sounds if in synthesized mode. Clears hearing_mobs. + */ /datum/song/proc/stop_playing() if(!playing) return @@ -196,42 +234,93 @@ STOP_PROCESSING(SSinstruments, src) terminate_all_sounds(TRUE) hearing_mobs.len = 0 - updateDialog() + user_playing = null -/// THIS IS A BLOCKING CALL. -/datum/song/proc/do_play_lines(user) - if(!playing) +/** + * Processes our song. + */ +/datum/song/proc/process_song(wait) + if(!length(compiled_chords) || should_stop_playing(user_playing)) + stop_playing() return - do_hearcheck() - if(legacy) - do_play_lines_legacy(user) - else - do_play_lines_synthesized(user) + var/list/chord = compiled_chords[current_chord] + if(++elapsed_delay >= delay_by) + play_chord(chord) + elapsed_delay = 0 + delay_by = tempodiv_to_delay(chord[length(chord)]) + current_chord++ + if(current_chord > length(compiled_chords)) + if(repeat) + repeat-- + current_chord = 1 + return + else + stop_playing() + return +/** + * Converts a tempodiv to ticks to elapse before playing the next chord, taking into account our tempo. + */ +/datum/song/proc/tempodiv_to_delay(tempodiv) + if(!tempodiv) + tempodiv = 1 // no division by 0. some song converters tend to use 0 for when it wants to have no div, for whatever reason. + return max(1, round((tempo/tempodiv) / world.tick_lag, 1)) + +/** + * Compiles chords. + */ +/datum/song/proc/compile_chords() + legacy? compile_legacy() : compile_synthesized() + +/** + * Plays a chord. + */ +/datum/song/proc/play_chord(list/chord) + // last value is timing information + for(var/i in 1 to (length(chord) - 1)) + legacy? playkey_legacy(chord[i][1], chord[i][2], chord[i][3], user_playing) : playkey_synth(chord[i], user_playing) + +/** + * Checks if we should halt playback. + */ /datum/song/proc/should_stop_playing(mob/user) return QDELETED(parent) || !using_instrument || !playing +/** + * Sanitizes tempo to a value that makes sense and fits the current world.tick_lag. + */ /datum/song/proc/sanitize_tempo(new_tempo) new_tempo = abs(new_tempo) return clamp(round(new_tempo, world.tick_lag), world.tick_lag, 5 SECONDS) +/** + * Gets our beats per minute based on our tempo. + */ /datum/song/proc/get_bpm() return 600 / tempo +/** + * Sets our tempo from a beats-per-minute, sanitizing it to a valid number first. + */ /datum/song/proc/set_bpm(bpm) tempo = sanitize_tempo(600 / bpm) -/// Updates the window for our user. Override in subtypes. -/datum/song/proc/updateDialog(mob/user = usr) +/** + * Updates the window for our users. Override down the line. + */ +/datum/song/proc/updateDialog(mob/user) ui_interact(user) /datum/song/process(wait) if(!playing) return PROCESS_KILL - var/delay = world.time - last_process_decay - process_decay(delay) - last_process_decay = world.time + // it's expected this ticks at every world.tick_lag. if it lags, do not attempt to catch up. + process_song(world.tick_lag) + process_decay(world.tick_lag) +/** + * Updates our cached linear/exponential falloff stuff, saving calculations down the line. + */ /datum/song/proc/update_sustain() // Exponential is easy cached_exponential_dropoff = sustain_exponential_dropoff @@ -241,21 +330,33 @@ var/volume_decrease_per_decisecond = volume_diff / target_duration cached_linear_dropoff = volume_decrease_per_decisecond +/** + * Setter for setting output volume. + */ /datum/song/proc/set_volume(volume) src.volume = clamp(volume, max(0, min_volume), min(100, max_volume)) update_sustain() updateDialog() +/** + * Setter for setting how low the volume has to get before a note is considered "dead" and dropped + */ /datum/song/proc/set_dropoff_volume(volume) sustain_dropoff_volume = clamp(volume, INSTRUMENT_MIN_SUSTAIN_DROPOFF, 100) update_sustain() updateDialog() +/** + * Setter for setting exponential falloff factor. + */ /datum/song/proc/set_exponential_drop_rate(drop) sustain_exponential_dropoff = clamp(drop, INSTRUMENT_EXP_FALLOFF_MIN, INSTRUMENT_EXP_FALLOFF_MAX) update_sustain() updateDialog() +/** + * Setter for setting linear falloff duration. + */ /datum/song/proc/set_linear_falloff_duration(duration) sustain_linear_duration = clamp(duration, 0.1, INSTRUMENT_MAX_TOTAL_SUSTAIN) update_sustain() @@ -277,10 +378,8 @@ // subtype for handheld instruments, like violin /datum/song/handheld -/datum/song/handheld/updateDialog(mob/user = usr) - if(user.machine != src) - return - parent.ui_interact(user) +/datum/song/handheld/updateDialog(mob/user) + parent.ui_interact(user || usr) /datum/song/handheld/should_stop_playing(mob/user) . = ..() @@ -292,10 +391,8 @@ // subtype for stationary structures, like pianos /datum/song/stationary -/datum/song/stationary/updateDialog(mob/user = usr) - if(user.machine != src) - return - parent.ui_interact(user) +/datum/song/stationary/updateDialog(mob/user) + parent.ui_interact(user || usr) /datum/song/stationary/should_stop_playing(mob/user) . = ..() diff --git a/code/modules/instruments/songs/editor.dm b/code/modules/instruments/songs/editor.dm index 8c5171667a..e385eed142 100644 --- a/code/modules/instruments/songs/editor.dm +++ b/code/modules/instruments/songs/editor.dm @@ -82,7 +82,6 @@ var/datum/browser/popup = new(user, "instrument", parent?.name || "instrument", 700, 500) popup.set_content(dat.Join("")) - popup.set_title_image(user.browse_rsc_icon(parent.icon, parent.icon_state)) popup.open() /datum/song/proc/ParseSong(text) diff --git a/code/modules/instruments/songs/play_legacy.dm b/code/modules/instruments/songs/play_legacy.dm index fa64656ebc..eee9be3cc7 100644 --- a/code/modules/instruments/songs/play_legacy.dm +++ b/code/modules/instruments/songs/play_legacy.dm @@ -1,48 +1,52 @@ -/// Playing legacy instruments - None of the "advanced" like sound reservations and decay are invoked. -/datum/song/proc/do_play_lines_legacy(mob/user) - while(repeat >= 0) - var/cur_oct[7] - var/cur_acc[7] - for(var/i = 1 to 7) - cur_oct[i] = 3 - cur_acc[i] = "n" +/** + * Compiles our lines into "chords" with filenames for legacy playback. This makes there have to be a bit of lag at the beginning of the song, but repeats will not have to parse it again, and overall playback won't be impacted by as much lag. + */ +/datum/song/proc/compile_legacy() + if(!length(src.lines)) + return + var/list/lines = src.lines //cache for hyepr speed! + compiled_chords = list() + var/list/octaves = list(3, 3, 3, 3, 3, 3, 3) + var/list/accents = list("n", "n", "n", "n", "n", "n", "n") + for(var/line in lines) + var/list/chords = splittext(lowertext(line), ",") + for(var/chord in chords) + var/list/compiled_chord = list() + var/tempodiv = 1 + var/list/notes_tempodiv = splittext(chord, "/") + var/len = length(notes_tempodiv) + if(len >= 2) + tempodiv = text2num(notes_tempodiv[2]) + if(len) //some dunkass is going to do ,,,, to make 3 rests instead of ,/1 because there's no standardization so let's be prepared for that. + var/list/notes = splittext(notes_tempodiv[1], "-") + for(var/note in notes) + if(length(note) == 0) + continue + // 1-7, A-G + var/key = text2ascii(note) - 96 + if((key < 1) || (key > 7)) + continue + for(var/i in 2 to length(note)) + var/oct_acc = copytext(note, i, i + 1) + var/num = text2num(oct_acc) + if(!num) //it's an accidental + accents[key] = oct_acc //if they misspelled it/fucked up that's on them lmao, no safety checks. + else //octave + octaves[key] = clamp(num, octave_min, octave_max) + compiled_chord[++compiled_chord.len] = list(key, accents[key], octaves[key]) + compiled_chord += tempodiv //this goes last + if(length(compiled_chord)) + compiled_chords[++compiled_chords.len] = compiled_chord - for(var/line in lines) - for(var/beat in splittext(lowertext(line), ",")) - if(should_stop_playing(user)) - return - var/list/notes = splittext(beat, "/") - if(length(notes)) //because some jack-butts are going to do ,,,, to symbolize 3 rests instead of something reasonable like ,/1. - for(var/note in splittext(notes[1], "-")) - if(length(note) == 0) - continue - var/cur_note = text2ascii(note) - 96 - if(cur_note < 1 || cur_note > 7) - continue - for(var/i=2 to length(note)) - var/ni = copytext(note,i,i+1) - if(!text2num(ni)) - if(ni == "#" || ni == "b" || ni == "n") - cur_acc[cur_note] = ni - else if(ni == "s") - cur_acc[cur_note] = "#" // so shift is never required - else - cur_oct[cur_note] = text2num(ni) - playnote_legacy(cur_note, cur_acc[cur_note], cur_oct[cur_note]) - if(notes.len >= 2 && text2num(notes[2])) - sleep(sanitize_tempo(tempo / text2num(notes[2]))) - else - sleep(tempo) - if(should_stop_playing(user)) - return - repeat-- - updateDialog() - repeat = 0 - -// note is a number from 1-7 for A-G -// acc is either "b", "n", or "#" -// oct is 1-8 (or 9 for C) -/datum/song/proc/playnote_legacy(note, acc as text, oct) +/** + * Proc to play a legacy note. Just plays the sound to hearing mobs (and does hearcheck if necessary), no fancy channel/sustain/management. + * + * Arguments: + * * note is a number from 1-7 for A-G + * * acc is either "b", "n", or "#" + * * oct is 1-8 (or 9 for C) + */ +/datum/song/proc/playkey_legacy(note, acc as text, oct, mob/user) // handle accidental -> B<>C of E<>F if(acc == "b" && (note == 3 || note == 6)) // C or F if(note == 3) diff --git a/code/modules/instruments/songs/play_synthesized.dm b/code/modules/instruments/songs/play_synthesized.dm index 5e7c5652a0..4df54f5e6b 100644 --- a/code/modules/instruments/songs/play_synthesized.dm +++ b/code/modules/instruments/songs/play_synthesized.dm @@ -1,27 +1,7 @@ -/datum/song/proc/do_play_lines_synthesized(mob/user) - compile_lines() - while(repeat >= 0) - if(should_stop_playing(user)) - return - var/warned = FALSE - for(var/_chord in compiled_chords) - if(should_stop_playing(user)) - return - var/list/chord = _chord - var/tempodiv = chord[chord.len] - for(var/i in 1 to chord.len - 1) - var/key = chord[i] - if(!playkey_synth(key)) - if(!warned) - warned = TRUE - to_chat(user, "Your instrument has ran out of channels. You might be playing your song too fast or be setting sustain to too high of a value. This warning will be suppressed for the rest of this cycle.") - sleep(sanitize_tempo(tempo / (tempodiv || 1))) - repeat-- - updateDialog() - repeat = 0 - -/// C-Db2-A-A4/2,A-B#4-C/3,/4,A,A-B-C as an example -/datum/song/proc/compile_lines() +/** + * Compiles our lines into "chords" with numbers. This makes there have to be a bit of lag at the beginning of the song, but repeats will not have to parse it again, and overall playback won't be impacted by as much lag. + */ +/datum/song/proc/compile_synthesized() if(!length(src.lines)) return var/list/lines = src.lines //cache for hyepr speed! @@ -57,10 +37,12 @@ compiled_chord += tempodiv //this goes last if(length(compiled_chord)) compiled_chords[++compiled_chords.len] = compiled_chord - CHECK_TICK - return compiled_chords -/datum/song/proc/playkey_synth(key) +/** + * Plays a specific numerical key from our instrument to anyone who can hear us. + * Does a hearing check if enough time has passed. + */ +/datum/song/proc/playkey_synth(key, mob/user) if(can_noteshift) key = clamp(key + note_shift, key_min, key_max) if((world.time - MUSICIAN_HEARCHECK_MINDELAY) > last_hearcheck) @@ -83,6 +65,9 @@ M.playsound_local(get_turf(parent), null, volume, FALSE, K.frequency, INSTRUMENT_DISTANCE_NO_FALLOFF, channel, null, copy, distance_multiplier = INSTRUMENT_DISTANCE_FALLOFF_BUFF) // Could do environment and echo later but not for now +/** + * Stops all sounds we are "responsible" for. Only works in synthesized mode. + */ /datum/song/proc/terminate_all_sounds(clear_channels = TRUE) for(var/i in hearing_mobs) terminate_sound_mob(i) @@ -93,10 +78,16 @@ using_sound_channels = 0 SSsounds.free_datum_channels(src) +/** + * Stops all sounds we are responsible for in a given person. Only works in synthesized mode. + */ /datum/song/proc/terminate_sound_mob(mob/M) for(var/channel in channels_playing) M.stop_sound_channel(text2num(channel)) +/** + * Pops a channel we have reserved so we don't have to release and re-request them from SSsounds every time we play a note. This is faster. + */ /datum/song/proc/pop_channel() if(length(channels_idle)) //just pop one off of here if we have one available . = text2num(channels_idle[1]) @@ -108,6 +99,12 @@ if(!isnull(.)) using_sound_channels++ +/** + * Decays our channels and updates their volumes to mobs who can hear us. + * + * Arguments: + * * wait_ds - the deciseconds we should decay by. This is to compensate for any lag, as otherwise songs would get pretty nasty during high time dilation. + */ /datum/song/proc/process_decay(wait_ds) var/linear_dropoff = cached_linear_dropoff * wait_ds var/exponential_dropoff = cached_exponential_dropoff ** wait_ds diff --git a/code/modules/language/language.dm b/code/modules/language/language.dm index 536bf06e8d..42b439ba03 100644 --- a/code/modules/language/language.dm +++ b/code/modules/language/language.dm @@ -35,7 +35,7 @@ return TRUE /datum/language/proc/get_icon() - var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/goonchat) + var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat) return sheet.icon_tag("language-[icon_state]") /datum/language/proc/get_random_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm index f777246453..3953f5e28c 100644 --- a/code/modules/library/lib_machines.dm +++ b/code/modules/library/lib_machines.dm @@ -66,7 +66,6 @@ dat += "\[Go Back\]
" var/datum/browser/popup = new(user, "publiclibrary", name, 600, 400) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() /obj/machinery/computer/libraryconsole/Topic(href, href_list) @@ -314,7 +313,6 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums var/datum/browser/popup = new(user, "library", name, 600, 400) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() /obj/machinery/computer/libraryconsole/bookmanagement/proc/findscanner(viewrange) @@ -537,7 +535,6 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums dat += "
" var/datum/browser/popup = new(user, "scanner", name, 600, 400) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() /obj/machinery/libraryscanner/Topic(href, href_list) diff --git a/code/modules/mapping/minimaps.dm b/code/modules/mapping/minimaps.dm index 7a62e9ab44..e0eb174cb3 100644 --- a/code/modules/mapping/minimaps.dm +++ b/code/modules/mapping/minimaps.dm @@ -4,7 +4,7 @@ // The map icons var/icon/map_icon var/icon/meta_icon - + var/list/color_area_names = list() var/minx @@ -33,7 +33,7 @@ meta_icon = new('html/blank.png') map_icon.Scale(x2 - x1 + 1, y2 - y1 + 1) // arrays start at 1 meta_icon.Scale(x2 - x1 + 1, y2 - y1 + 1) - + var/list/area_to_color = list() for(var/turf/T in block(locate(x1, y1, z_level), locate(x2, y2, z_level))) var/area/A = T.loc @@ -44,7 +44,7 @@ crop_x2 = max(crop_x2, T.x) crop_y1 = min(crop_y1, T.y) crop_y2 = max(crop_y2, T.y) - + var/meta_color = area_to_color[A] if(!meta_color) meta_color = rgb(rand(0, 255), rand(0, 255), rand(0, 255)) // technically conflicts could happen but it's like very unlikely and it's not that big of a deal if one happens @@ -73,13 +73,15 @@ overlay_icon = new(map_icon) overlay_icon.Scale(16, 16) //we're done baking, now we ship it. - register_asset("minimap-[id].png", map_icon) - register_asset("minimap-[id]-meta.png", meta_icon) + if (!SSassets.cache["minimap-[id].png"]) + SSassets.transport.register_asset("minimap-[id].png", map_icon) + if (!SSassets.cache["minimap-[id]-meta.png"]) + SSassets.transport.register_asset("minimap-[id]-meta.png", meta_icon) /datum/minimap/proc/send(mob/user) if(!id) CRASH("ERROR: send called, but the minimap id is null/missing. ID: [id]") - send_asset_list(user, list("minimap-[id].png" = map_icon, "minimap-[id]-meta.png" = meta_icon)) + SSassets.transport.send_assets(user, list("minimap-[id].png" = map_icon, "minimap-[id]-meta.png" = meta_icon)) /datum/minimap_group var/list/minimaps = list() @@ -100,15 +102,17 @@ var/list/datas = list() var/list/info = list() - + for(var/i in 1 to length(minimaps))// OLD: for(var/i in 1 to length(minimaps)) var/datum/minimap/M = minimaps[i] + var/map_name = "minimap-[M.id].png" + var/meta_name = "minimap-[M.id]-meta.png" M.send(user) info += {"
- - + +
@@ -183,6 +187,4 @@ var/datum/browser/popup = new(user, "minimap_[id]", name, 500, 700) popup.add_head_content(headerJS) //set the head popup.set_content(info) - var/datum/minimap/MICO = minimaps[1] - popup.set_title_image(MICO.overlay_icon) popup.open(FALSE) diff --git a/code/modules/mining/aux_base.dm b/code/modules/mining/aux_base.dm index 006065d048..b10177ebaf 100644 --- a/code/modules/mining/aux_base.dm +++ b/code/modules/mining/aux_base.dm @@ -70,7 +70,6 @@ interface with the mining shuttle at the landing site if a mobile beacon is also var/datum/browser/popup = new(user, "computer", "base management", 550, 300) //width, height popup.set_content("
[dat]
") - popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) popup.open() diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index e03de83e02..819b005b43 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -78,10 +78,7 @@ if(28) new /obj/item/clothing/neck/necklace/memento_mori(src) if(29) - if(prob(50)) - new /obj/item/malf_upgrade(src) - else - new /obj/item/disk/tech_disk/illegal(src) + new /obj/item/disk/tech_disk/illegal(src) //KA modkit design discs /obj/item/disk/design_disk/modkit_disc diff --git a/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm b/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm index 899bf91081..d1f7f15ac9 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm @@ -14,14 +14,14 @@ name = "Standard" icon_state = "standard" -/datum/sprite_accessory/xeno_dorsal/royal - name = "Royal" - icon_state = "royal" - /datum/sprite_accessory/xeno_dorsal/down name = "Dorsal Down" icon_state = "down" +/datum/sprite_accessory/xeno_dorsal/royal + name = "Royal" + icon_state = "royal" + /****************************************** ************* Xeno Tails ****************** *******************************************/ @@ -57,14 +57,14 @@ name = "Standard" icon_state = "standard" -/datum/sprite_accessory/xeno_head/royal - name = "royal" - icon_state = "royal" - /datum/sprite_accessory/xeno_head/hollywood name = "hollywood" icon_state = "hollywood" +/datum/sprite_accessory/xeno_head/royal + name = "royal" + icon_state = "royal" + /datum/sprite_accessory/xeno_head/warrior name = "warrior" icon_state = "warrior" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm b/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm index a04838a360..5286acb33a 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm @@ -16,6 +16,12 @@ icon_state = "dtiger" gender_specific = 1 +/datum/sprite_accessory/body_markings/guilmon + name = "Guilmon" + icon_state = "guilmon" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' + /datum/sprite_accessory/body_markings/ltiger name = "Light Tiger Body" icon_state = "ltiger" @@ -49,11 +55,6 @@ icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' relevant_layers = null -/datum/sprite_accessory/mam_body_markings/plain - name = "Plain" - icon_state = "plain" - icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' - /datum/sprite_accessory/mam_body_markings/redpanda name = "Redpanda" icon_state = "redpanda" @@ -77,14 +78,14 @@ icon_state = "bellyslim" icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' -/datum/sprite_accessory/mam_body_markings/corgi - name = "Corgi" - icon_state = "corgi" - /datum/sprite_accessory/mam_body_markings/cow name = "Bovine" icon_state = "bovine" +/datum/sprite_accessory/mam_body_markings/corgi + name = "Corgi" + icon_state = "corgi" + /datum/sprite_accessory/mam_body_markings/corvid name = "Corvid" icon_state = "corvid" @@ -139,15 +140,19 @@ name = "Hyena" icon_state = "hyena" -/datum/sprite_accessory/mam_body_markings/lab - name = "Lab" - icon_state = "lab" - /datum/sprite_accessory/mam_body_markings/insect name = "Insect" icon_state = "insect" icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' +/datum/sprite_accessory/mam_body_markings/lab + name = "Lab" + icon_state = "lab" + +/datum/sprite_accessory/mam_body_markings/orca + name = "Orca" + icon_state = "orca" + /datum/sprite_accessory/mam_body_markings/otie name = "Otie" icon_state = "otie" @@ -156,14 +161,15 @@ name = "Otter" icon_state = "otter" -/datum/sprite_accessory/mam_body_markings/orca - name = "Orca" - icon_state = "orca" - /datum/sprite_accessory/mam_body_markings/panther name = "Panther" icon_state = "panther" +/datum/sprite_accessory/mam_body_markings/plain + name = "Plain" + icon_state = "plain" + icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' + /datum/sprite_accessory/mam_body_markings/possum name = "Possum" icon_state = "possum" @@ -172,6 +178,10 @@ name = "Raccoon" icon_state = "raccoon" +/datum/sprite_accessory/mam_body_markings/sergal + name = "Sergal" + icon_state = "sergal" + /datum/sprite_accessory/mam_body_markings/pede name = "Scolipede" icon_state = "scolipede" @@ -181,18 +191,14 @@ name = "Shark" icon_state = "shark" -/datum/sprite_accessory/mam_body_markings/skunk - name = "Skunk" - icon_state = "skunk" - -/datum/sprite_accessory/mam_body_markings/sergal - name = "Sergal" - icon_state = "sergal" - /datum/sprite_accessory/mam_body_markings/shepherd name = "Shepherd" icon_state = "shepherd" +/datum/sprite_accessory/mam_body_markings/skunk + name = "Skunk" + icon_state = "skunk" + /datum/sprite_accessory/mam_body_markings/tajaran name = "Tajaran" icon_state = "tajaran" @@ -232,75 +238,10 @@ icon_state = "none" relevant_layers = null -/datum/sprite_accessory/insect_fluff/plain - name = "Plain" - icon_state = "plain" - -/datum/sprite_accessory/insect_fluff/reddish - name = "Reddish" - icon_state = "redish" - -/datum/sprite_accessory/insect_fluff/royal - name = "Royal" - icon_state = "royal" - -/datum/sprite_accessory/insect_fluff/gothic - name = "Gothic" - icon_state = "gothic" - -/datum/sprite_accessory/insect_fluff/lovers - name = "Lovers" - icon_state = "lovers" - -/datum/sprite_accessory/insect_fluff/whitefly - name = "White Fly" - icon_state = "whitefly" - /datum/sprite_accessory/insect_fluff/punished name = "Burnt Off" icon_state = "punished" -/datum/sprite_accessory/insect_fluff/firewatch - name = "Firewatch" - icon_state = "firewatch" - -/datum/sprite_accessory/insect_fluff/deathhead - name = "Deathshead" - icon_state = "deathhead" - -/datum/sprite_accessory/insect_fluff/poison - name = "Poison" - icon_state = "poison" - -/datum/sprite_accessory/insect_fluff/ragged - name = "Ragged" - icon_state = "ragged" - -/datum/sprite_accessory/insect_fluff/moonfly - name = "Moon Fly" - icon_state = "moonfly" - -/datum/sprite_accessory/insect_fluff/snow - name = "Snow" - icon_state = "snow" - -/datum/sprite_accessory/insect_fluff/oakworm - name = "Oak Worm" - icon_state = "oakworm" - -/datum/sprite_accessory/insect_fluff/jungle - name = "Jungle" - icon_state = "jungle" - -/datum/sprite_accessory/insect_fluff/witchwing - name = "Witch Wing" - icon_state = "witchwing" - -/datum/sprite_accessory/insect_fluff/colored - name = "Colored (Hair)" - icon_state = "snow" - color_src = HAIR - /datum/sprite_accessory/insect_fluff/colored1 name = "Colored (Primary)" icon_state = "snow" @@ -314,4 +255,69 @@ /datum/sprite_accessory/insect_fluff/colored3 name = "Colored (Tertiary)" icon_state = "snow" - color_src = MUTCOLORS3 \ No newline at end of file + color_src = MUTCOLORS3 + +/datum/sprite_accessory/insect_fluff/colored + name = "Colored (Hair)" + icon_state = "snow" + color_src = HAIR + +/datum/sprite_accessory/insect_fluff/deathhead + name = "Deathshead" + icon_state = "deathhead" + +/datum/sprite_accessory/insect_fluff/firewatch + name = "Firewatch" + icon_state = "firewatch" + +/datum/sprite_accessory/insect_fluff/gothic + name = "Gothic" + icon_state = "gothic" + +/datum/sprite_accessory/insect_fluff/jungle + name = "Jungle" + icon_state = "jungle" + +/datum/sprite_accessory/insect_fluff/lovers + name = "Lovers" + icon_state = "lovers" + +/datum/sprite_accessory/insect_fluff/moonfly + name = "Moon Fly" + icon_state = "moonfly" + +/datum/sprite_accessory/insect_fluff/oakworm + name = "Oak Worm" + icon_state = "oakworm" + +/datum/sprite_accessory/insect_fluff/plain + name = "Plain" + icon_state = "plain" + +/datum/sprite_accessory/insect_fluff/poison + name = "Poison" + icon_state = "poison" + +/datum/sprite_accessory/insect_fluff/ragged + name = "Ragged" + icon_state = "ragged" + +/datum/sprite_accessory/insect_fluff/reddish + name = "Reddish" + icon_state = "redish" + +/datum/sprite_accessory/insect_fluff/royal + name = "Royal" + icon_state = "royal" + +/datum/sprite_accessory/insect_fluff/snow + name = "Snow" + icon_state = "snow" + +/datum/sprite_accessory/insect_fluff/whitefly + name = "White Fly" + icon_state = "whitefly" + +/datum/sprite_accessory/insect_fluff/witchwing + name = "Witch Wing" + icon_state = "witchwing" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm index 1e6c797364..7515ce560a 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm @@ -41,7 +41,7 @@ extra = TRUE extra_color_src = NONE -/datum/sprite_accessory/ears/human/bigwolfdark +/datum/sprite_accessory/ears/human/bigwolfdark //ignore alphabetical sort here for ease-of-use name = "Dark Big Wolf" icon_state = "bigwolfdark" icon = 'modular_citadel/icons/mob/mam_ears.dmi' @@ -55,6 +55,12 @@ extra = TRUE extra_color_src = NONE +/datum/sprite_accessory/ears/bunny + name = "Bunny" + icon_state = "bunny" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + /datum/sprite_accessory/ears/cat name = "Cat" icon_state = "cat" @@ -74,6 +80,12 @@ icon = 'modular_citadel/icons/mob/mam_ears.dmi' color_src = MUTCOLORS3 +/datum/sprite_accessory/ears/lab + name = "Dog, Floppy" + icon_state = "lab" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + /datum/sprite_accessory/ears/human/eevee name = "Eevee" icon_state = "eevee" @@ -115,12 +127,6 @@ icon_state = "jellyfish" color_src = HAIR -/datum/sprite_accessory/ears/lab - name = "Dog, Floppy" - icon_state = "lab" - color_src = MATRIXED - icon = 'modular_citadel/icons/mob/mam_ears.dmi' - /datum/sprite_accessory/ears/murid name = "Murid" icon_state = "murid" @@ -133,18 +139,18 @@ color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_ears.dmi' -/datum/sprite_accessory/ears/human/pede - name = "Scolipede" - icon_state = "pede" - icon = 'modular_citadel/icons/mob/mam_ears.dmi' - color_src = MATRIXED - /datum/sprite_accessory/ears/human/rabbit name = "Rabbit" icon_state = "rabbit" color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_ears.dmi' +/datum/sprite_accessory/ears/human/pede + name = "Scolipede" + icon_state = "pede" + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED + /datum/sprite_accessory/ears/human/sergal name = "Sergal" icon_state = "sergal" @@ -169,12 +175,6 @@ color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_ears.dmi' -/datum/sprite_accessory/ears/bunny - name = "Bunny" - icon_state = "bunny" - color_src = MATRIXED - icon = 'modular_citadel/icons/mob/mam_ears.dmi' - /****************************************** *************** Furry Ears **************** *******************************************/ @@ -216,7 +216,7 @@ extra = TRUE extra_color_src = NONE -/datum/sprite_accessory/ears/mam_ears/bigwolfdark +/datum/sprite_accessory/ears/mam_ears/bigwolfdark //alphabetical sort ignored here for ease-of-use name = "Dark Big Wolf" icon_state = "bigwolfdark" @@ -226,6 +226,10 @@ extra = TRUE extra_color_src = NONE +/datum/sprite_accessory/ears/mam_ears/bunny + name = "Bunny" + icon_state = "bunny" + /datum/sprite_accessory/ears/mam_ears/cat name = "Cat" icon_state = "cat" @@ -256,13 +260,11 @@ name = "Eevee" icon_state = "eevee" - /datum/sprite_accessory/ears/mam_ears/elf name = "Elf" icon_state = "elf" color_src = MUTCOLORS3 - /datum/sprite_accessory/ears/mam_ears/elephant name = "Elephant" icon_state = "elephant" @@ -283,15 +285,15 @@ name = "Husky" icon_state = "wolf" -/datum/sprite_accessory/ears/mam_ears/kangaroo - name = "kangaroo" - icon_state = "kangaroo" - /datum/sprite_accessory/ears/mam_ears/jellyfish name = "Jellyfish" icon_state = "jellyfish" color_src = HAIR +/datum/sprite_accessory/ears/mam_ears/kangaroo + name = "kangaroo" + icon_state = "kangaroo" + /datum/sprite_accessory/ears/mam_ears/lab name = "Dog, Long" icon_state = "lab" @@ -304,18 +306,14 @@ name = "Otusian" icon_state = "otie" -/datum/sprite_accessory/ears/mam_ears/squirrel - name = "Squirrel" - icon_state = "squirrel" +/datum/sprite_accessory/ears/mam_ears/rabbit + name = "Rabbit" + icon_state = "rabbit" /datum/sprite_accessory/ears/mam_ears/pede name = "Scolipede" icon_state = "pede" -/datum/sprite_accessory/ears/mam_ears/rabbit - name = "Rabbit" - icon_state = "rabbit" - /datum/sprite_accessory/ears/mam_ears/sergal name = "Sergal" icon_state = "sergal" @@ -324,10 +322,10 @@ name = "skunk" icon_state = "skunk" +/datum/sprite_accessory/ears/mam_ears/squirrel + name = "Squirrel" + icon_state = "squirrel" + /datum/sprite_accessory/ears/mam_ears/wolf name = "Wolf" icon_state = "wolf" - -/datum/sprite_accessory/ears/mam_ears/bunny - name = "Bunny" - icon_state = "bunny" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/frills.dm b/code/modules/mob/dead/new_player/sprite_accessories/frills.dm index 18a76df116..49013161a9 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/frills.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/frills.dm @@ -11,6 +11,10 @@ icon_state = "none" relevant_layers = null +/datum/sprite_accessory/frills/aquatic + name = "Aquatic" + icon_state = "aqua" + /datum/sprite_accessory/frills/simple name = "Simple" icon_state = "simple" @@ -18,7 +22,3 @@ /datum/sprite_accessory/frills/short name = "Short" icon_state = "short" - -/datum/sprite_accessory/frills/aquatic - name = "Aquatic" - icon_state = "aqua" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm b/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm index 34988f5656..a07fdaa5d3 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm @@ -6,6 +6,10 @@ gender = MALE // barf (unless you're a dorf, dorfs dig chix w/ beards :P) // please make sure they're sorted alphabetically and categorized +/datum/sprite_accessory/facial_hair/shaved //this is exempt from the alphabetical sort + name = "Shaved" + icon_state = null + gender = NEUTER /datum/sprite_accessory/facial_hair/threeoclock name = "Beard (3 o\'Clock)" @@ -135,11 +139,6 @@ name = "Mutton Chops with Moustache" icon_state = "facial_muttonmus" -/datum/sprite_accessory/facial_hair/shaved - name = "Shaved" - icon_state = null - gender = NEUTER - /datum/sprite_accessory/facial_hair/sideburn name = "Sideburns" icon_state = "facial_sideburns" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm b/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm index 138704067d..8e4e6ad617 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm @@ -9,6 +9,10 @@ // try to spell // you do not need to define _s or _l sub-states, game automatically does this for you +/datum/sprite_accessory/hair/bald //this is exempt from the alphabetical sort + name = "Bald" + icon_state = "bald" + /datum/sprite_accessory/hair/afro name = "Afro" icon_state = "hair_afro" @@ -25,10 +29,6 @@ name = "Ahoge" icon_state = "hair_antenna" -/datum/sprite_accessory/hair/bald - name = "Bald" - icon_state = "bald" - /datum/sprite_accessory/hair/balding name = "Balding Hair" icon_state = "hair_e" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/horns.dm b/code/modules/mob/dead/new_player/sprite_accessories/horns.dm index 3a65eaebfa..aff342c7a6 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/horns.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/horns.dm @@ -12,22 +12,10 @@ icon_state = "none" relevant_layers = null -/datum/sprite_accessory/horns/simple - name = "Simple" - icon_state = "simple" - -/datum/sprite_accessory/horns/short - name = "Short" - icon_state = "short" - /datum/sprite_accessory/horns/curled name = "Curled" icon_state = "curled" -/datum/sprite_accessory/horns/ram - name = "Ram" - icon_state = "ram" - /datum/sprite_accessory/horns/angler name = "Angeler" icon_state = "angler" @@ -40,3 +28,15 @@ /datum/sprite_accessory/horns/guilmon name = "Guilmon" icon_state = "guilmon" + +/datum/sprite_accessory/horns/ram + name = "Ram" + icon_state = "ram" + +/datum/sprite_accessory/horns/simple + name = "Simple" + icon_state = "simple" + +/datum/sprite_accessory/horns/short + name = "Short" + icon_state = "short" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/ipc_synths.dm b/code/modules/mob/dead/new_player/sprite_accessories/ipc_synths.dm index 110ac69201..6019245b80 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/ipc_synths.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/ipc_synths.dm @@ -11,96 +11,90 @@ name = "Blank" icon_state = "blank" -/datum/sprite_accessory/screen/pink - name = "Pink" - icon_state = "pink" - -/datum/sprite_accessory/screen/green - name = "Green" - icon_state = "green" - -/datum/sprite_accessory/screen/red - name = "Red" - icon_state = "red" - /datum/sprite_accessory/screen/blue name = "Blue" icon_state = "blue" -/datum/sprite_accessory/screen/yellow - name = "Yellow" - icon_state = "yellow" - -/datum/sprite_accessory/screen/shower - name = "Shower" - icon_state = "shower" - -/datum/sprite_accessory/screen/nature - name = "Nature" - icon_state = "nature" - -/datum/sprite_accessory/screen/eight - name = "Eight" - icon_state = "eight" - -/datum/sprite_accessory/screen/goggles - name = "Goggles" - icon_state = "goggles" - -/datum/sprite_accessory/screen/heart - name = "Heart" - icon_state = "heart" - -/datum/sprite_accessory/screen/monoeye - name = "Mono eye" - icon_state = "monoeye" - /datum/sprite_accessory/screen/breakout name = "Breakout" icon_state = "breakout" -/datum/sprite_accessory/screen/purple - name = "Purple" - icon_state = "purple" - -/datum/sprite_accessory/screen/scroll - name = "Scroll" - icon_state = "scroll" +/datum/sprite_accessory/screen/bsod + name = "BSOD" + icon_state = "bsod" /datum/sprite_accessory/screen/console name = "Console" icon_state = "console" -/datum/sprite_accessory/screen/rgb - name = "RGB" - icon_state = "rgb" +/datum/sprite_accessory/screen/eight + name = "Eight" + icon_state = "eight" + +/datum/sprite_accessory/screen/eyes + name = "Eyes" + icon_state = "eyes" + +/datum/sprite_accessory/screen/ecgwave + name = "ECG wave" + icon_state = "ecgwave" + +/datum/sprite_accessory/screen/green + name = "Green" + icon_state = "green" + +/datum/sprite_accessory/screen/goggles + name = "Goggles" + icon_state = "goggles" /datum/sprite_accessory/screen/golglider name = "Gol Glider" icon_state = "golglider" +/datum/sprite_accessory/screen/heart + name = "Heart" + icon_state = "heart" + +/datum/sprite_accessory/screen/pink + name = "Pink" + icon_state = "pink" + +/datum/sprite_accessory/screen/red + name = "Red" + icon_state = "red" + +/datum/sprite_accessory/screen/monoeye + name = "Mono eye" + icon_state = "monoeye" + +/datum/sprite_accessory/screen/nature + name = "Nature" + icon_state = "nature" + +/datum/sprite_accessory/screen/purple + name = "Purple" + icon_state = "purple" + /datum/sprite_accessory/screen/rainbow name = "Rainbow" icon_state = "rainbow" -/datum/sprite_accessory/screen/sunburst - name = "Sunburst" - icon_state = "sunburst" - -/datum/sprite_accessory/screen/static - name = "Static" - icon_state = "static" - -//Oracle Station sprites - -/datum/sprite_accessory/screen/bsod - name = "BSOD" - icon_state = "bsod" - /datum/sprite_accessory/screen/redtext name = "Red Text" icon_state = "retext" +/datum/sprite_accessory/screen/rgb + name = "RGB" + icon_state = "rgb" + +/datum/sprite_accessory/screen/scroll + name = "Scroll" + icon_state = "scroll" + +/datum/sprite_accessory/screen/shower + name = "Shower" + icon_state = "shower" + /datum/sprite_accessory/screen/sinewave name = "Sine wave" icon_state = "sinewave" @@ -109,22 +103,25 @@ name = "Square wave" icon_state = "squarwave" -/datum/sprite_accessory/screen/ecgwave - name = "ECG wave" - icon_state = "ecgwave" +/datum/sprite_accessory/screen/stars + name = "Stars" + icon_state = "stars" -/datum/sprite_accessory/screen/eyes - name = "Eyes" - icon_state = "eyes" +/datum/sprite_accessory/screen/static + name = "Static" + icon_state = "static" + +/datum/sprite_accessory/screen/sunburst + name = "Sunburst" + icon_state = "sunburst" /datum/sprite_accessory/screen/textdrop name = "Text drop" icon_state = "textdrop" -/datum/sprite_accessory/screen/stars - name = "Stars" - icon_state = "stars" - +/datum/sprite_accessory/screen/yellow + name = "Yellow" + icon_state = "yellow" /****************************************** ************** IPC Antennas *************** @@ -145,14 +142,6 @@ name = "Angled Antennae" icon_state = "antennae" -/datum/sprite_accessory/antenna/tvantennae - name = "TV Antennae" - icon_state = "tvantennae" - -/datum/sprite_accessory/antenna/cyberhead - name = "Cyberhead" - icon_state = "cyberhead" - /datum/sprite_accessory/antenna/antlers name = "Antlers" icon_state = "antlers" @@ -160,3 +149,11 @@ /datum/sprite_accessory/antenna/crowned name = "Crowned" icon_state = "crowned" + +/datum/sprite_accessory/antenna/cyberhead + name = "Cyberhead" + icon_state = "cyberhead" + +/datum/sprite_accessory/antenna/tvantennae + name = "TV Antennae" + icon_state = "tvantennae" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm b/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm index d41f5ace22..6f7b955d8f 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm @@ -49,6 +49,13 @@ relevant_layers = null hide_legs = FALSE +/datum/sprite_accessory/taur/canine + name = "Canine" + icon_state = "canine" + taur_mode = STYLE_PAW_TAURIC + color_src = MUTCOLORS + extra = TRUE + /datum/sprite_accessory/taur/cow name = "Cow" icon_state = "cow" @@ -95,6 +102,13 @@ color_src = MUTCOLORS extra = TRUE +/datum/sprite_accessory/taur/feline + name = "Feline" + icon_state = "feline" + taur_mode = STYLE_PAW_TAURIC + color_src = MUTCOLORS + extra = TRUE + /datum/sprite_accessory/taur/horse name = "Horse" icon_state = "horse" @@ -126,17 +140,3 @@ taur_mode = STYLE_SNEK_TAURIC color_src = MUTCOLORS hide_legs = USE_SNEK_CLIP_MASK - -/datum/sprite_accessory/taur/canine - name = "Canine" - icon_state = "canine" - taur_mode = STYLE_PAW_TAURIC - color_src = MUTCOLORS - extra = TRUE - -/datum/sprite_accessory/taur/feline - name = "Feline" - icon_state = "feline" - taur_mode = STYLE_PAW_TAURIC - color_src = MUTCOLORS - extra = TRUE diff --git a/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm b/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm index f514ef54db..99d2c67cc9 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm @@ -7,14 +7,19 @@ var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) return ((H.wear_mask && (H.wear_mask.flags_inv & HIDESNOUT)) || (H.head && (H.head.flags_inv & HIDESNOUT)) || !HD || HD.status == BODYPART_ROBOTIC) -/datum/sprite_accessory/snouts/sharp - name = "Sharp" - icon_state = "sharp" +/datum/sprite_accessory/snout/guilmon + name = "Guilmon" + icon_state = "guilmon" + color_src = MATRIXED /datum/sprite_accessory/snouts/round name = "Round" icon_state = "round" +/datum/sprite_accessory/snouts/sharp + name = "Sharp" + icon_state = "sharp" + /datum/sprite_accessory/snouts/sharplight name = "Sharp + Light" icon_state = "sharplight" @@ -23,11 +28,6 @@ name = "Round + Light" icon_state = "roundlight" -/datum/sprite_accessory/snout/guilmon - name = "Guilmon" - icon_state = "guilmon" - color_src = MATRIXED - //christ this was a mistake, but it's here just in case someone wants to selectively fix -- Pooj /************* Lizard compatable snoots *********** /datum/sprite_accessory/snouts/bird @@ -192,11 +192,19 @@ extra = TRUE extra_color_src = MUTCOLORS3 -/datum/sprite_accessory/snouts/mam_snouts/skulldog - name = "Skulldog" - icon_state = "skulldog" +/datum/sprite_accessory/snouts/mam_snouts/husky + name = "Husky" + icon_state = "husky" + +/datum/sprite_accessory/snouts/mam_snouts/rhino + name = "Horn" + icon_state = "rhino" extra = TRUE - extra_color_src = MATRIXED + extra = MUTCOLORS3 + +/datum/sprite_accessory/snouts/mam_snouts/rodent + name = "Rodent" + icon_state = "rodent" /datum/sprite_accessory/snouts/mam_snouts/lcanid name = "Mammal, Long" @@ -226,32 +234,20 @@ name = "Mammal, Thick ALT" icon_state = "wolfalt" -/datum/sprite_accessory/snouts/mam_snouts/redpanda - name = "WahCoon" - icon_state = "wah" - -/datum/sprite_accessory/snouts/mam_snouts/redpandaalt - name = "WahCoon ALT" - icon_state = "wahalt" - -/datum/sprite_accessory/snouts/mam_snouts/rhino - name = "Horn" - icon_state = "rhino" - extra = TRUE - extra = MUTCOLORS3 - -/datum/sprite_accessory/snouts/mam_snouts/rodent - name = "Rodent" - icon_state = "rodent" - -/datum/sprite_accessory/snouts/mam_snouts/husky - name = "Husky" - icon_state = "husky" - /datum/sprite_accessory/snouts/mam_snouts/otie name = "Otie" icon_state = "otie" +/datum/sprite_accessory/snouts/mam_snouts/round + name = "Round" + icon_state = "round" + color_src = MUTCOLORS + +/datum/sprite_accessory/snouts/mam_snouts/roundlight + name = "Round + Light" + icon_state = "roundlight" + color_src = MUTCOLORS + /datum/sprite_accessory/snouts/mam_snouts/pede name = "Scolipede" icon_state = "pede" @@ -268,30 +264,33 @@ name = "hShark" icon_state = "hshark" -/datum/sprite_accessory/snouts/mam_snouts/toucan - name = "Toucan" - icon_state = "toucan" - /datum/sprite_accessory/snouts/mam_snouts/sharp name = "Sharp" icon_state = "sharp" color_src = MUTCOLORS -/datum/sprite_accessory/snouts/mam_snouts/round - name = "Round" - icon_state = "round" - color_src = MUTCOLORS - /datum/sprite_accessory/snouts/mam_snouts/sharplight name = "Sharp + Light" icon_state = "sharplight" color_src = MUTCOLORS -/datum/sprite_accessory/snouts/mam_snouts/roundlight - name = "Round + Light" - icon_state = "roundlight" - color_src = MUTCOLORS +/datum/sprite_accessory/snouts/mam_snouts/skulldog + name = "Skulldog" + icon_state = "skulldog" + extra = TRUE + extra_color_src = MATRIXED +/datum/sprite_accessory/snouts/mam_snouts/toucan + name = "Toucan" + icon_state = "toucan" + +/datum/sprite_accessory/snouts/mam_snouts/redpanda + name = "WahCoon" + icon_state = "wah" + +/datum/sprite_accessory/snouts/mam_snouts/redpandaalt + name = "WahCoon ALT" + icon_state = "wahalt" /****************************************** **************** Snouts ******************* @@ -318,6 +317,16 @@ extra = TRUE extra_color_src = MUTCOLORS3 +/datum/sprite_accessory/snouts/mam_snouts/frhino + name = "Horn (Top)" + icon_state = "frhino" + extra = TRUE + extra = MUTCOLORS3 + +/datum/sprite_accessory/snouts/mam_snouts/fhusky + name = "Husky (Top)" + icon_state = "fhusky" + /datum/sprite_accessory/snouts/mam_snouts/flcanid name = "Mammal, Long (Top)" icon_state = "flcanid" @@ -346,27 +355,23 @@ name = "Mammal, Thick ALT (Top)" icon_state = "fwolfalt" -/datum/sprite_accessory/snouts/mam_snouts/fredpanda - name = "WahCoon (Top)" - icon_state = "fwah" - -/datum/sprite_accessory/snouts/mam_snouts/frhino - name = "Horn (Top)" - icon_state = "frhino" - extra = TRUE - extra = MUTCOLORS3 +/datum/sprite_accessory/snouts/mam_snouts/fotie + name = "Otie (Top)" + icon_state = "fotie" /datum/sprite_accessory/snouts/mam_snouts/frodent name = "Rodent (Top)" icon_state = "frodent" -/datum/sprite_accessory/snouts/mam_snouts/fhusky - name = "Husky (Top)" - icon_state = "fhusky" +/datum/sprite_accessory/snouts/mam_snouts/fround + name = "Round (Top)" + icon_state = "fround" + color_src = MUTCOLORS -/datum/sprite_accessory/snouts/mam_snouts/fotie - name = "Otie (Top)" - icon_state = "fotie" +/datum/sprite_accessory/snouts/mam_snouts/froundlight + name = "Round + Light (Top)" + icon_state = "froundlight" + color_src = MUTCOLORS /datum/sprite_accessory/snouts/mam_snouts/fpede name = "Scolipede (Top)" @@ -380,26 +385,20 @@ name = "Shark (Top)" icon_state = "fshark" -/datum/sprite_accessory/snouts/mam_snouts/ftoucan - name = "Toucan (Top)" - icon_state = "ftoucan" - /datum/sprite_accessory/snouts/mam_snouts/fsharp name = "Sharp (Top)" icon_state = "fsharp" color_src = MUTCOLORS -/datum/sprite_accessory/snouts/mam_snouts/fround - name = "Round (Top)" - icon_state = "fround" - color_src = MUTCOLORS - /datum/sprite_accessory/snouts/mam_snouts/fsharplight name = "Sharp + Light (Top)" icon_state = "fsharplight" color_src = MUTCOLORS -/datum/sprite_accessory/snouts/mam_snouts/froundlight - name = "Round + Light (Top)" - icon_state = "froundlight" - color_src = MUTCOLORS +/datum/sprite_accessory/snouts/mam_snouts/ftoucan + name = "Toucan (Top)" + icon_state = "ftoucan" + +/datum/sprite_accessory/snouts/mam_snouts/fredpanda + name = "WahCoon (Top)" + icon_state = "fwah" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/socks.dm b/code/modules/mob/dead/new_player/sprite_accessories/socks.dm index 19ec677a72..ffb808eede 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/socks.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/socks.dm @@ -20,6 +20,10 @@ name = "Knee-high - Bee" icon_state = "bee_knee" +/datum/sprite_accessory/underwear/socks/christmas_knee + name = "Knee-High - Christmas" + icon_state = "christmas_knee" + /datum/sprite_accessory/underwear/socks/commie_knee name = "Knee-High - Commie" icon_state = "commie_knee" @@ -32,6 +36,14 @@ name = "Knee-high - Rainbow" icon_state = "rainbow_knee" +/datum/sprite_accessory/underwear/socks/candycaner_knee + name = "Knee-High - Red Candy Cane" + icon_state = "candycaner_knee" + +/datum/sprite_accessory/underwear/socks/candycaneg_knee //ignore alphabetisation for ease of use in scenarios like this + name = "Knee-High - Green Candy Cane" + icon_state = "candycaneg_knee" + /datum/sprite_accessory/underwear/socks/striped_knee name = "Knee-high - Striped" icon_state = "striped_knee" @@ -46,18 +58,6 @@ name = "Knee-High - UK" icon_state = "uk_knee" -/datum/sprite_accessory/underwear/socks/christmas_knee - name = "Knee-High - Christmas" - icon_state = "christmas_knee" - -/datum/sprite_accessory/underwear/socks/candycaner_knee - name = "Knee-High - Red Candy Cane" - icon_state = "candycaner_knee" - -/datum/sprite_accessory/underwear/socks/candycaneg_knee - name = "Knee-High - Green Candy Cane" - icon_state = "candycaneg_knee" - /datum/sprite_accessory/underwear/socks/socks_norm name = "Normal" icon_state = "socks_norm" @@ -129,22 +129,34 @@ name = "Thigh-high - Bee" icon_state = "bee_thigh" +/datum/sprite_accessory/underwear/socks/christmas_thigh + name = "Thigh-high - Christmas" + icon_state = "christmas_thigh" + /datum/sprite_accessory/underwear/socks/commie_thigh name = "Thigh-high - Commie" icon_state = "commie_thigh" -/datum/sprite_accessory/underwear/socks/usa_thigh - name = "Thigh-high - Freedom" - icon_state = "assblastusa_thigh" - /datum/sprite_accessory/underwear/socks/fishnet name = "Thigh-high - Fishnet" icon_state = "fishnet" +/datum/sprite_accessory/underwear/socks/usa_thigh + name = "Thigh-high - Freedom" + icon_state = "assblastusa_thigh" + /datum/sprite_accessory/underwear/socks/rainbow_thigh name = "Thigh-high - Rainbow" icon_state = "rainbow_thigh" +/datum/sprite_accessory/underwear/socks/candycaner_thigh + name = "Thigh-high - Red Candy Cane" + icon_state = "candycaner_thigh" + +/datum/sprite_accessory/underwear/socks/candycaneg_thigh + name = "Thigh-high - Green Candy Cane" + icon_state = "candycaneg_thigh" + /datum/sprite_accessory/underwear/socks/striped_thigh name = "Thigh-high - Striped" icon_state = "striped_thigh" @@ -157,16 +169,4 @@ /datum/sprite_accessory/underwear/socks/uk_thigh name = "Thigh-high - UK" - icon_state = "uk_thigh" - -/datum/sprite_accessory/underwear/socks/christmas_thigh - name = "Thigh-high - Christmas" - icon_state = "christmas_thigh" - -/datum/sprite_accessory/underwear/socks/candycaner_thigh - name = "Thigh-high - Red Candy Cane" - icon_state = "candycaner_thigh" - -/datum/sprite_accessory/underwear/socks/candycaneg_thigh - name = "Thigh-high - Green Candy Cane" - icon_state = "candycaneg_thigh" \ No newline at end of file + icon_state = "uk_thigh" \ No newline at end of file diff --git a/code/modules/mob/dead/new_player/sprite_accessories/spines.dm b/code/modules/mob/dead/new_player/sprite_accessories/spines.dm index 83415ed375..5d7207c934 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/spines.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/spines.dm @@ -21,21 +21,13 @@ name = "None" icon_state = "none" -/datum/sprite_accessory/spines/short - name = "Short" - icon_state = "short" +/datum/sprite_accessory/spines/aqautic + name = "Aquatic" + icon_state = "aqua" -/datum/sprite_accessory/spines_animated/short - name = "Short" - icon_state = "short" - -/datum/sprite_accessory/spines/shortmeme - name = "Short + Membrane" - icon_state = "shortmeme" - -/datum/sprite_accessory/spines_animated/shortmeme - name = "Short + Membrane" - icon_state = "shortmeme" +/datum/sprite_accessory/spines_animated/aqautic + name = "Aquatic" + icon_state = "aqua" /datum/sprite_accessory/spines/long name = "Long" @@ -53,10 +45,18 @@ name = "Long + Membrane" icon_state = "longmeme" -/datum/sprite_accessory/spines/aqautic - name = "Aquatic" - icon_state = "aqua" +/datum/sprite_accessory/spines/short + name = "Short" + icon_state = "short" -/datum/sprite_accessory/spines_animated/aqautic - name = "Aquatic" - icon_state = "aqua" +/datum/sprite_accessory/spines_animated/short + name = "Short" + icon_state = "short" + +/datum/sprite_accessory/spines/shortmeme + name = "Short + Membrane" + icon_state = "shortmeme" + +/datum/sprite_accessory/spines_animated/shortmeme + name = "Short + Membrane" + icon_state = "shortmeme" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm b/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm index 16531d8f06..9addd15dca 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm @@ -25,12 +25,6 @@ icon_state = "synthliz_tertunder" //Synth body markings -/datum/sprite_accessory/mam_body_markings/synthliz - recommended_species = list("synthliz") - icon = 'modular_citadel/icons/mob/synthliz_body_markings.dmi' - name = "Synthetic Lizard - Plates" - icon_state = "synthlizscutes" - /datum/sprite_accessory/mam_body_markings/synthliz/synthliz_pecs icon = 'modular_citadel/icons/mob/synthliz_body_markings.dmi' name = "Synthetic Lizard - Pecs" @@ -41,6 +35,12 @@ name = "Synthetic Lizard - Pecs Light" icon_state = "synthlizpecslight" +/datum/sprite_accessory/mam_body_markings/synthliz + recommended_species = list("synthliz") + icon = 'modular_citadel/icons/mob/synthliz_body_markings.dmi' + name = "Synthetic Lizard - Plates" + icon_state = "synthlizscutes" + //Synth tails /datum/sprite_accessory/tails/mam_tails/synthliz recommended_species = list("synthliz") @@ -70,17 +70,17 @@ name = "Synthetic Lizard - Curled" icon_state = "synth_curled" -/datum/sprite_accessory/antenna/synthliz/synthliz_thick +/datum/sprite_accessory/antenna/synthliz/synth_horns icon = 'modular_citadel/icons/mob/synthliz_antennas.dmi' color_src = MUTCOLORS - name = "Synthetic Lizard - Thick" - icon_state = "synth_thick" + name = "Synthetic Lizard - Horns" + icon_state = "synth_horns" -/datum/sprite_accessory/antenna/synthliz/synth_thicklight +/datum/sprite_accessory/antenna/synthliz/synth_hornslight icon = 'modular_citadel/icons/mob/synthliz_antennas.dmi' color_src = MATRIXED - name = "Synthetic Lizard - Thick Light" - icon_state = "synth_thicklight" + name = "Synthetic Lizard - Horns Light" + icon_state = "synth_hornslight" /datum/sprite_accessory/antenna/synthliz/synth_short icon = 'modular_citadel/icons/mob/synthliz_antennas.dmi' @@ -100,17 +100,17 @@ name = "Synthetic Lizard - Sharp Light" icon_state = "synth_sharplight" -/datum/sprite_accessory/antenna/synthliz/synth_horns +/datum/sprite_accessory/antenna/synthliz/synthliz_thick icon = 'modular_citadel/icons/mob/synthliz_antennas.dmi' color_src = MUTCOLORS - name = "Synthetic Lizard - Horns" - icon_state = "synth_horns" + name = "Synthetic Lizard - Thick" + icon_state = "synth_thick" -/datum/sprite_accessory/antenna/synthliz/synth_hornslight +/datum/sprite_accessory/antenna/synthliz/synth_thicklight icon = 'modular_citadel/icons/mob/synthliz_antennas.dmi' color_src = MATRIXED - name = "Synthetic Lizard - Horns Light" - icon_state = "synth_hornslight" + name = "Synthetic Lizard - Thick Light" + icon_state = "synth_thicklight" //Synth Taurs (Ported from Virgo) /datum/sprite_accessory/taur/synthliz diff --git a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm index 812e0c052c..d9e2de1525 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm @@ -18,38 +18,7 @@ /datum/sprite_accessory/tails_animated/lizard/is_not_visible(var/mob/living/carbon/human/H, var/tauric) return (((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric) || H.dna.species.mutant_bodyparts["tail_lizard"]) -/datum/sprite_accessory/tails/lizard/smooth - name = "Smooth" - icon_state = "smooth" - -/datum/sprite_accessory/tails_animated/lizard/smooth - name = "Smooth" - icon_state = "smooth" - -/datum/sprite_accessory/tails/lizard/dtiger - name = "Dark Tiger" - icon_state = "dtiger" - -/datum/sprite_accessory/tails_animated/lizard/dtiger - name = "Dark Tiger" - icon_state = "dtiger" - -/datum/sprite_accessory/tails/lizard/ltiger - name = "Light Tiger" - icon_state = "ltiger" - -/datum/sprite_accessory/tails_animated/lizard/ltiger - name = "Light Tiger" - icon_state = "ltiger" - -/datum/sprite_accessory/tails/lizard/spikes - name = "Spikes" - icon_state = "spikes" - -/datum/sprite_accessory/tails_animated/lizard/spikes - name = "Spikes" - icon_state = "spikes" - +//this goes first regardless of alphabetical order /datum/sprite_accessory/tails/lizard/none name = "None" icon_state = "None" @@ -72,11 +41,13 @@ color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' -/datum/sprite_accessory/body_markings/guilmon - name = "Guilmon" - icon_state = "guilmon" - color_src = MATRIXED - icon = 'modular_citadel/icons/mob/markings_notmammals.dmi' +/datum/sprite_accessory/tails/lizard/dtiger + name = "Dark Tiger" + icon_state = "dtiger" + +/datum/sprite_accessory/tails_animated/lizard/dtiger + name = "Dark Tiger" + icon_state = "dtiger" /datum/sprite_accessory/tails/lizard/guilmon name = "Guilmon" @@ -90,6 +61,30 @@ color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' +/datum/sprite_accessory/tails/lizard/ltiger + name = "Light Tiger" + icon_state = "ltiger" + +/datum/sprite_accessory/tails_animated/lizard/ltiger + name = "Light Tiger" + icon_state = "ltiger" + +/datum/sprite_accessory/tails/lizard/smooth + name = "Smooth" + icon_state = "smooth" + +/datum/sprite_accessory/tails_animated/lizard/smooth + name = "Smooth" + icon_state = "smooth" + +/datum/sprite_accessory/tails/lizard/spikes + name = "Spikes" + icon_state = "spikes" + +/datum/sprite_accessory/tails_animated/lizard/spikes + name = "Spikes" + icon_state = "spikes" + /****************************************** ************** Human Tails **************** *******************************************/ @@ -107,18 +102,6 @@ /datum/sprite_accessory/tails_animated/human/is_not_visible(var/mob/living/carbon/human/H, var/tauric) return (((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)|| H.dna.species.mutant_bodyparts["tail_human"]) -/datum/sprite_accessory/tails/human/ailurus - name = "Red Panda" - icon_state = "wah" - icon = 'modular_citadel/icons/mob/mam_tails.dmi' - color_src = MATRIXED - -/datum/sprite_accessory/tails_animated/human/ailurus - name = "Red Panda" - icon_state = "wah" - icon = 'modular_citadel/icons/mob/mam_tails.dmi' - color_src = MATRIXED - /datum/sprite_accessory/tails/human/axolotl name = "Axolotl" icon_state = "axolotl" @@ -199,6 +182,14 @@ icon = 'modular_citadel/icons/mob/mam_tails.dmi' color_src = MATRIXED +/datum/sprite_accessory/tails/human/corvid + name = "Corvid" + icon_state = "crow" + +/datum/sprite_accessory/tails_animated/human/corvid + name = "Corvid" + icon_state = "crow" + /datum/sprite_accessory/tails/human/cow name = "Cow" icon_state = "cow" @@ -211,13 +202,25 @@ icon = 'modular_citadel/icons/mob/mam_tails.dmi' color_src = MATRIXED -/datum/sprite_accessory/tails/human/corvid - name = "Corvid" - icon_state = "crow" +/datum/sprite_accessory/tails/human/dtiger + name = "Dark Tiger" + icon_state = "dtiger" -/datum/sprite_accessory/tails_animated/human/corvid - name = "Corvid" - icon_state = "crow" +/datum/sprite_accessory/tails_animated/human/dtiger + name = "Dark Tiger" + icon_state = "dtiger" + +/datum/sprite_accessory/tails/human/datashark + name = "datashark" + icon_state = "datashark" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/datashark + name = "datashark" + icon_state = "datashark" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails/human/eevee name = "Eevee" @@ -298,7 +301,7 @@ color_src = MATRIXED /datum/sprite_accessory/tails_animated/human/insect - name = "insect" + name = "Insect" icon_state = "insect" icon = 'modular_citadel/icons/mob/mam_tails.dmi' color_src = MATRIXED @@ -315,6 +318,14 @@ color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' +/datum/sprite_accessory/tails/human/ltiger + name = "Light Tiger" + icon_state = "ltiger" + +/datum/sprite_accessory/tails_animated/human/ltiger + name = "Light Tiger" + icon_state = "ltiger" + /datum/sprite_accessory/tails/human/murid name = "Murid" icon_state = "murid" @@ -327,18 +338,6 @@ color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' -/datum/sprite_accessory/tails/human/otie - name = "Otusian" - icon_state = "otie" - color_src = MATRIXED - icon = 'modular_citadel/icons/mob/mam_tails.dmi' - -/datum/sprite_accessory/tails_animated/human/otie - name = "Otusian" - icon_state = "otie" - color_src = MATRIXED - icon = 'modular_citadel/icons/mob/mam_tails.dmi' - /datum/sprite_accessory/tails/orca name = "Orca" icon_state = "orca" @@ -351,15 +350,15 @@ color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' -/datum/sprite_accessory/tails/human/pede - name = "Scolipede" - icon_state = "pede" +/datum/sprite_accessory/tails/human/otie + name = "Otusian" + icon_state = "otie" color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' -/datum/sprite_accessory/tails_animated/human/pede - name = "Scolipede" - icon_state = "pede" +/datum/sprite_accessory/tails_animated/human/otie + name = "Otusian" + icon_state = "otie" color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' @@ -375,6 +374,30 @@ color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' +/datum/sprite_accessory/tails/human/ailurus + name = "Red Panda" + icon_state = "wah" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails_animated/human/ailurus + name = "Red Panda" + icon_state = "wah" + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/tails/human/pede + name = "Scolipede" + icon_state = "pede" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/pede + name = "Scolipede" + icon_state = "pede" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + /datum/sprite_accessory/tails/human/sergal name = "Sergal" icon_state = "sergal" @@ -387,6 +410,18 @@ color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' +/datum/sprite_accessory/tails/human/shark + name = "Shark" + icon_state = "shark" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/human/shark + name = "Shark" + icon_state = "shark" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + /datum/sprite_accessory/tails/human/skunk name = "skunk" icon_state = "skunk" @@ -415,30 +450,6 @@ name = "Spikes" icon_state = "spikes" -/datum/sprite_accessory/tails/human/shark - name = "Shark" - icon_state = "shark" - color_src = MATRIXED - icon = 'modular_citadel/icons/mob/mam_tails.dmi' - -/datum/sprite_accessory/tails_animated/human/shark - name = "Shark" - icon_state = "shark" - color_src = MATRIXED - icon = 'modular_citadel/icons/mob/mam_tails.dmi' - -/datum/sprite_accessory/tails/human/datashark - name = "datashark" - icon_state = "datashark" - color_src = MATRIXED - icon = 'modular_citadel/icons/mob/mam_tails.dmi' - -/datum/sprite_accessory/tails_animated/human/datashark - name = "datashark" - icon_state = "datashark" - color_src = MATRIXED - icon = 'modular_citadel/icons/mob/mam_tails.dmi' - /datum/sprite_accessory/tails/human/straighttail name = "Straight Tail" icon_state = "straighttail" @@ -495,22 +506,6 @@ color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' -/datum/sprite_accessory/tails/human/dtiger - name = "Dark Tiger" - icon_state = "dtiger" - -/datum/sprite_accessory/tails_animated/human/dtiger - name = "Dark Tiger" - icon_state = "dtiger" - -/datum/sprite_accessory/tails/human/ltiger - name = "Light Tiger" - icon_state = "ltiger" - -/datum/sprite_accessory/tails_animated/human/ltiger - name = "Light Tiger" - icon_state = "ltiger" - /datum/sprite_accessory/tails/human/wolf name = "Wolf" icon_state = "wolf" @@ -554,16 +549,6 @@ icon_state = "none" relevant_layers = null -/datum/sprite_accessory/tails/mam_tails/ailurus - name = "Red Panda" - icon_state = "wah" - extra = TRUE - -/datum/sprite_accessory/tails_animated/mam_tails_animated/ailurus - name = "Red Panda" - icon_state = "wah" - extra = TRUE - /datum/sprite_accessory/tails/mam_tails/axolotl name = "Axolotl" icon_state = "axolotl" @@ -638,6 +623,18 @@ name = "Cow" icon_state = "cow" +/datum/sprite_accessory/tails/mam_tails/dtiger + name = "Dark Tiger" + icon_state = "dtiger" + color_src = MUTCOLORS + icon = 'icons/mob/mutant_bodyparts.dmi' + +/datum/sprite_accessory/tails_animated/mam_tails_animated/dtiger + name = "Dark Tiger" + icon_state = "dtiger" + color_src = MUTCOLORS + icon = 'icons/mob/mutant_bodyparts.dmi' + /datum/sprite_accessory/tails/mam_tails/eevee name = "Eevee" icon_state = "eevee" @@ -728,6 +725,18 @@ datum/sprite_accessory/tails/mam_tails/insect name = "Lab" icon_state = "lab" +/datum/sprite_accessory/tails/mam_tails/ltiger + name = "Light Tiger" + icon_state = "ltiger" + color_src = MUTCOLORS + icon = 'icons/mob/mutant_bodyparts.dmi' + +/datum/sprite_accessory/tails_animated/mam_tails_animated/ltiger + name = "Light Tiger" + icon_state = "ltiger" + color_src = MUTCOLORS + icon = 'icons/mob/mutant_bodyparts.dmi' + /datum/sprite_accessory/tails/mam_tails/murid name = "Murid" icon_state = "murid" @@ -736,14 +745,6 @@ datum/sprite_accessory/tails/mam_tails/insect name = "Murid" icon_state = "murid" -/datum/sprite_accessory/tails/mam_tails/otie - name = "Otusian" - icon_state = "otie" - -/datum/sprite_accessory/tails_animated/mam_tails_animated/otie - name = "Otusian" - icon_state = "otie" - /datum/sprite_accessory/tails/mam_tails/orca name = "Orca" icon_state = "orca" @@ -752,13 +753,13 @@ datum/sprite_accessory/tails/mam_tails/insect name = "Orca" icon_state = "orca" -/datum/sprite_accessory/tails/mam_tails/pede - name = "Scolipede" - icon_state = "pede" +/datum/sprite_accessory/tails/mam_tails/otie + name = "Otusian" + icon_state = "otie" -/datum/sprite_accessory/tails_animated/mam_tails_animated/pede - name = "Scolipede" - icon_state = "pede" +/datum/sprite_accessory/tails_animated/mam_tails_animated/otie + name = "Otusian" + icon_state = "otie" /datum/sprite_accessory/tails/mam_tails/rabbit name = "Rabbit" @@ -768,6 +769,24 @@ datum/sprite_accessory/tails/mam_tails/insect name = "Rabbit" icon_state = "rabbit" +/datum/sprite_accessory/tails/mam_tails/ailurus + name = "Red Panda" + icon_state = "wah" + extra = TRUE + +/datum/sprite_accessory/tails_animated/mam_tails_animated/ailurus + name = "Red Panda" + icon_state = "wah" + extra = TRUE + +/datum/sprite_accessory/tails/mam_tails/pede + name = "Scolipede" + icon_state = "pede" + +/datum/sprite_accessory/tails_animated/mam_tails_animated/pede + name = "Scolipede" + icon_state = "pede" + /datum/sprite_accessory/tails/mam_tails/sergal name = "Sergal" icon_state = "sergal" @@ -776,6 +795,22 @@ datum/sprite_accessory/tails/mam_tails/insect name = "Sergal" icon_state = "sergal" +/datum/sprite_accessory/tails/mam_tails/shark + name = "Shark" + icon_state = "shark" + +/datum/sprite_accessory/tails_animated/mam_tails_animated/shark + name = "Shark" + icon_state = "shark" + +/datum/sprite_accessory/tails/mam_tails/shepherd + name = "Shepherd" + icon_state = "shepherd" + +/datum/sprite_accessory/tails_animated/mam_tails_animated/shepherd + name = "Shepherd" + icon_state = "shepherd" + /datum/sprite_accessory/tails/mam_tails/skunk name = "Skunk" icon_state = "skunk" @@ -808,22 +843,6 @@ datum/sprite_accessory/tails/mam_tails/insect color_src = MUTCOLORS icon = 'icons/mob/mutant_bodyparts.dmi' -/datum/sprite_accessory/tails/mam_tails/shark - name = "Shark" - icon_state = "shark" - -/datum/sprite_accessory/tails_animated/mam_tails_animated/shark - name = "Shark" - icon_state = "shark" - -/datum/sprite_accessory/tails/mam_tails/shepherd - name = "Shepherd" - icon_state = "shepherd" - -/datum/sprite_accessory/tails_animated/mam_tails_animated/shepherd - name = "Shepherd" - icon_state = "shepherd" - /datum/sprite_accessory/tails/mam_tails/straighttail name = "Straight Tail" icon_state = "straighttail" @@ -864,30 +883,6 @@ datum/sprite_accessory/tails/mam_tails/insect name = "Tiger" icon_state = "tiger" -/datum/sprite_accessory/tails/mam_tails/dtiger - name = "Dark Tiger" - icon_state = "dtiger" - color_src = MUTCOLORS - icon = 'icons/mob/mutant_bodyparts.dmi' - -/datum/sprite_accessory/tails_animated/mam_tails_animated/dtiger - name = "Dark Tiger" - icon_state = "dtiger" - color_src = MUTCOLORS - icon = 'icons/mob/mutant_bodyparts.dmi' - -/datum/sprite_accessory/tails/mam_tails/ltiger - name = "Light Tiger" - icon_state = "ltiger" - color_src = MUTCOLORS - icon = 'icons/mob/mutant_bodyparts.dmi' - -/datum/sprite_accessory/tails_animated/mam_tails_animated/ltiger - name = "Light Tiger" - icon_state = "ltiger" - color_src = MUTCOLORS - icon = 'icons/mob/mutant_bodyparts.dmi' - /datum/sprite_accessory/tails/mam_tails/wolf name = "Wolf" icon_state = "wolf" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm b/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm index b8282931d2..1be02c207e 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm @@ -12,6 +12,38 @@ // please make sure they're sorted alphabetically and categorized +/datum/sprite_accessory/underwear/top/cowboyshirt + name = "Cowboy Shirt Black" + icon_state = "cowboyshirt" + +/datum/sprite_accessory/underwear/top/cowboyshirt/red + name = "Cowboy Shirt Red" + icon_state = "cowboyshirt_red" + +/datum/sprite_accessory/underwear/top/cowboyshirt/navy + name = "Cowboy Shirt Navy" + icon_state = "cowboyshirt_navy" + +/datum/sprite_accessory/underwear/top/cowboyshirt/white + name = "Cowboy Shirt White" + icon_state = "cowboyshirt_white" + +/datum/sprite_accessory/underwear/top/cowboyshirt/s + name = "Cowboy Shirt Shortsleeved Black" + icon_state = "cowboyshirt_s" + +/datum/sprite_accessory/underwear/top/cowboyshirt/red/s + name = "Cowboy Shirt Shortsleeved Red" + icon_state = "cowboyshirt_reds" + +/datum/sprite_accessory/underwear/top/cowboyshirt/navy/s + name = "Cowboy Shirt Shortsleeved Navy" + icon_state = "cowboyshirt_navys" + +/datum/sprite_accessory/underwear/top/cowboyshirt/white/s + name = "Cowboy Shirt Shortsleeved White" + icon_state = "cowboyshirt_whites" + /datum/sprite_accessory/underwear/top/longjon name = "Long John Shirt" icon_state = "ljont" @@ -30,36 +62,6 @@ icon_state = "undershirt" has_color = TRUE -/datum/sprite_accessory/underwear/top/bowlingw - name = "Shirt - Bowling" - icon_state = "bowlingw" - has_color = TRUE - -/datum/sprite_accessory/underwear/top/bowling - name = "Shirt, Bowling - Red" - icon_state = "bowling" - -/datum/sprite_accessory/underwear/top/bowlingp - name = "Shirt, Bowling - Pink" - icon_state = "bowlingp" - -/datum/sprite_accessory/underwear/top/bowlinga - name = "Shirt, Bowling - Aqua" - icon_state = "bowlinga" - -/datum/sprite_accessory/underwear/top/bluejersey - name = "Shirt, Jersey - Blue" - icon_state = "shirt_bluejersey" - -/datum/sprite_accessory/underwear/top/redjersey - name = "Shirt, Jersey - Red" - icon_state = "shirt_redjersey" - -/datum/sprite_accessory/underwear/top/polo - name = "Shirt - Polo" - icon_state = "polo" - has_color = TRUE - /datum/sprite_accessory/underwear/top/alienshirt name = "Shirt - Alien" icon_state = "shirt_alien" @@ -72,6 +74,23 @@ name = "Shirt - Bee" icon_state = "bee_shirt" +/datum/sprite_accessory/underwear/top/bowlingw + name = "Shirt - Bowling" + icon_state = "bowlingw" + has_color = TRUE + +/datum/sprite_accessory/underwear/top/bowlinga + name = "Shirt, Bowling - Aqua" + icon_state = "bowlinga" + +/datum/sprite_accessory/underwear/top/bowling + name = "Shirt, Bowling - Red" + icon_state = "bowling" + +/datum/sprite_accessory/underwear/top/bowlingp + name = "Shirt, Bowling - Pink" + icon_state = "bowlingp" + /datum/sprite_accessory/underwear/top/clownshirt name = "Shirt - Clown" icon_state = "shirt_clown" @@ -88,6 +107,14 @@ name = "Shirt - I Love NT" icon_state = "ilovent" +/datum/sprite_accessory/underwear/top/bluejersey + name = "Shirt, Jersey - Blue" + icon_state = "shirt_bluejersey" + +/datum/sprite_accessory/underwear/top/redjersey + name = "Shirt, Jersey - Red" + icon_state = "shirt_redjersey" + /datum/sprite_accessory/underwear/top/lover name = "Shirt - Lover" icon_state = "lover" @@ -112,6 +139,11 @@ name = "Shirt - Pogoman" icon_state = "pogoman" +/datum/sprite_accessory/underwear/top/polo + name = "Shirt - Polo" + icon_state = "polo" + has_color = TRUE + /datum/sprite_accessory/underwear/top/question name = "Shirt - Question" icon_state = "shirt_question" @@ -120,6 +152,23 @@ name = "Shirt - Skull" icon_state = "shirt_skull" +/datum/sprite_accessory/underwear/top/shortsleeve + name = "Shirt - Short Sleeved" + icon_state = "shortsleeve" + has_color = TRUE + +/datum/sprite_accessory/underwear/top/blueshirtsport + name = "Shirt, Sports - Blue" + icon_state = "blueshirtsport" + +/datum/sprite_accessory/underwear/top/greenshirtsport + name = "Shirt, Sports - Green" + icon_state = "greenshirtsport" + +/datum/sprite_accessory/underwear/top/redshirtsport + name = "Shirt, Sports - Red" + icon_state = "redshirtsport" + /datum/sprite_accessory/underwear/top/ss13 name = "Shirt - SS13" icon_state = "shirt_ss13" @@ -141,27 +190,6 @@ name = "Shirt - USA" icon_state = "shirt_assblastusa" -/datum/sprite_accessory/underwear/top/shortsleeve - name = "Shirt - Short Sleeved" - icon_state = "shortsleeve" - has_color = TRUE - -/datum/sprite_accessory/underwear/top/blueshirtsport - name = "Shirt, Sports - Blue" - icon_state = "blueshirtsport" - -/datum/sprite_accessory/underwear/top/greenshirtsport - name = "Shirt, Sports - Green" - icon_state = "greenshirtsport" - -/datum/sprite_accessory/underwear/top/redshirtsport - name = "Shirt, Sports - Red" - icon_state = "redshirtsport" - -/datum/sprite_accessory/underwear/top/tankfire - name = "Tank Top - Fire" - icon_state = "tank_fire" - /datum/sprite_accessory/underwear/top/tanktop name = "Tank Top" icon_state = "tanktop" @@ -172,6 +200,10 @@ icon_state = "tanktop_alt" has_color = TRUE +/datum/sprite_accessory/underwear/top/tankfire + name = "Tank Top - Fire" + icon_state = "tank_fire" + /datum/sprite_accessory/underwear/top/tanktop_midriff name = "Tank Top - Midriff" icon_state = "tank_midriff" @@ -192,6 +224,8 @@ name = "Tank top - Sun" icon_state = "tank_sun" +//feminine accessories from here on + /datum/sprite_accessory/underwear/top/babydoll name = "Baby-Doll" icon_state = "babydoll" @@ -210,15 +244,25 @@ has_color = TRUE gender = FEMALE -/datum/sprite_accessory/underwear/top/bra_thin - name = "Bra - Thin" - icon_state = "bra_thin" - has_color = TRUE +/datum/sprite_accessory/underwear/top/bra_beekini + name = "Bra - Bee-kini" + icon_state = "bra_bee-kini" gender = FEMALE -/datum/sprite_accessory/underwear/top/bra_kinky - name = "Bra - Kinky Black" - icon_state = "bra_kinky" +/datum/sprite_accessory/underwear/top/bra_binder + name = "Bra (binder)" + icon_state = "bra_binder" + has_color = TRUE + +/datum/sprite_accessory/underwear/top/bra_binder_strapless + name = "Bra (binder, strapless)" + icon_state = "bra_binder_strapless" + has_color = TRUE + + +/datum/sprite_accessory/underwear/top/bra_commie + name = "Bra - Commie" + icon_state = "bra_commie" gender = FEMALE /datum/sprite_accessory/underwear/top/bra_freedom @@ -226,33 +270,17 @@ icon_state = "bra_assblastusa" gender = FEMALE -/datum/sprite_accessory/underwear/top/bra_commie - name = "Bra - Commie" - icon_state = "bra_commie" - gender = FEMALE - -/datum/sprite_accessory/underwear/top/bra_beekini - name = "Bra - Bee-kini" - icon_state = "bra_bee-kini" - gender = FEMALE - -/datum/sprite_accessory/underwear/top/bra_uk - name = "Bra - UK" - icon_state = "bra_uk" - gender = FEMALE - -/datum/sprite_accessory/underwear/top/bra_neko - name = "Bra - Neko" - icon_state = "bra_neko" - has_color = TRUE - gender = FEMALE - /datum/sprite_accessory/underwear/top/halterneck_bra name = "Bra - Halterneck" icon_state = "halterneck_bra" has_color = TRUE gender = FEMALE +/datum/sprite_accessory/underwear/top/bra_kinky + name = "Bra - Kinky Black" + icon_state = "bra_kinky" + gender = FEMALE + /datum/sprite_accessory/underwear/top/sports_bra name = "Bra, Sports" icon_state = "sports_bra" @@ -283,9 +311,21 @@ has_color = TRUE gender = FEMALE -/datum/sprite_accessory/underwear/top/fishnet_sleeves - name = "Fishnet - sleeves" - icon_state = "fishnet_sleeves" +/datum/sprite_accessory/underwear/top/bra_thin + name = "Bra - Thin" + icon_state = "bra_thin" + has_color = TRUE + gender = FEMALE + +/datum/sprite_accessory/underwear/top/bra_neko + name = "Bra - Neko" + icon_state = "bra_neko" + has_color = TRUE + gender = FEMALE + +/datum/sprite_accessory/underwear/top/bra_uk + name = "Bra - UK" + icon_state = "bra_uk" gender = FEMALE /datum/sprite_accessory/underwear/top/fishnet_gloves @@ -293,6 +333,11 @@ icon_state = "fishnet_gloves" gender = FEMALE +/datum/sprite_accessory/underwear/top/fishnet_sleeves + name = "Fishnet - sleeves" + icon_state = "fishnet_sleeves" + gender = FEMALE + /datum/sprite_accessory/underwear/top/fishnet_base name = "Fishnet - top" icon_state = "fishnet_body" @@ -315,45 +360,3 @@ icon_state = "tubetop" has_color = TRUE gender = FEMALE - -/datum/sprite_accessory/underwear/top/cowboyshirt - name = "Cowboy Shirt Black" - icon_state = "cowboyshirt" - -/datum/sprite_accessory/underwear/top/cowboyshirt/s - name = "Cowboy Shirt Shortsleeved Black" - icon_state = "cowboyshirt_s" - -/datum/sprite_accessory/underwear/top/cowboyshirt/white - name = "Cowboy Shirt White" - icon_state = "cowboyshirt_white" - -/datum/sprite_accessory/underwear/top/cowboyshirt/white/s - name = "Cowboy Shirt Shortsleeved White" - icon_state = "cowboyshirt_whites" - -/datum/sprite_accessory/underwear/top/cowboyshirt/navy - name = "Cowboy Shirt Navy" - icon_state = "cowboyshirt_navy" - -/datum/sprite_accessory/underwear/top/cowboyshirt/navy/s - name = "Cowboy Shirt Shortsleeved Navy" - icon_state = "cowboyshirt_navys" - -/datum/sprite_accessory/underwear/top/cowboyshirt/red - name = "Cowboy Shirt Red" - icon_state = "cowboyshirt_red" - -/datum/sprite_accessory/underwear/top/cowboyshirt/red/s - name = "Cowboy Shirt Shortsleeved Red" - icon_state = "cowboyshirt_reds" - -/datum/sprite_accessory/underwear/top/bra_binder - name = "Bra (binder)" - icon_state = "bra_binder" - has_color = TRUE - -/datum/sprite_accessory/underwear/top/bra_binder_strapless - name = "Bra (binder, strapless)" - icon_state = "bra_binder_strapless" - has_color = TRUE diff --git a/code/modules/mob/dead/new_player/sprite_accessories/underwear.dm b/code/modules/mob/dead/new_player/sprite_accessories/underwear.dm index 58d5e1ba88..edfeba79f1 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/underwear.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/underwear.dm @@ -10,18 +10,6 @@ icon_state = null covers_groin = FALSE -/datum/sprite_accessory/underwear/bottom/mankini - name = "Mankini" - icon_state = "mankini" - has_color = TRUE - gender = MALE - -/datum/sprite_accessory/underwear/bottom/male_kinky - name = "Jockstrap" - icon_state = "jockstrap" - has_color = TRUE - gender = MALE - /datum/sprite_accessory/underwear/bottom/briefs name = "Briefs" icon_state = "briefs" @@ -77,6 +65,26 @@ has_digitigrade = TRUE has_color = TRUE +/datum/sprite_accessory/underwear/bottom/male_kinky + name = "Jockstrap" + icon_state = "jockstrap" + has_color = TRUE + gender = MALE + +/datum/sprite_accessory/underwear/bottom/longjon + name = "Long John Bottoms" + icon_state = "ljonb" + has_digitigrade = TRUE + has_color = TRUE + +/datum/sprite_accessory/underwear/bottom/mankini + name = "Mankini" + icon_state = "mankini" + has_color = TRUE + gender = MALE + +//feminine underwear from here on + /datum/sprite_accessory/underwear/bottom/panties name = "Panties" icon_state = "panties" @@ -89,11 +97,6 @@ has_color = TRUE gender = FEMALE -/datum/sprite_accessory/underwear/bottom/fishnet_lower - name = "Panties - Fishnet" - icon_state = "fishnet_lower" - gender = FEMALE - /datum/sprite_accessory/underwear/bottom/female_beekini name = "Panties - Bee-kini" icon_state = "panties_bee-kini" @@ -104,6 +107,11 @@ icon_state = "panties_commie" gender = FEMALE +/datum/sprite_accessory/underwear/bottom/fishnet_lower + name = "Panties - Fishnet" + icon_state = "fishnet_lower" + gender = FEMALE + /datum/sprite_accessory/underwear/bottom/female_usastripe name = "Panties - Freedom" icon_state = "panties_assblastusa" @@ -114,11 +122,6 @@ icon_state = "panties_kinky" gender = FEMALE -/datum/sprite_accessory/underwear/bottom/panties_uk - name = "Panties - UK" - icon_state = "panties_uk" - gender = FEMALE - /datum/sprite_accessory/underwear/bottom/panties_neko name = "Panties - Neko" icon_state = "panties_neko" @@ -149,17 +152,10 @@ has_color = TRUE gender = FEMALE -/datum/sprite_accessory/underwear/bottom/longjon - name = "Long John Bottoms" - icon_state = "ljonb" - has_digitigrade = TRUE - has_color = TRUE - -/datum/sprite_accessory/underwear/bottom/swimsuit_red - name = "Swimsuit, One Piece - Red" - icon_state = "swimming_red" +/datum/sprite_accessory/underwear/bottom/panties_uk + name = "Panties - UK" + icon_state = "panties_uk" gender = FEMALE - covers_chest = TRUE /datum/sprite_accessory/underwear/bottom/swimsuit name = "Swimsuit, One Piece - Black" @@ -173,6 +169,12 @@ gender = FEMALE covers_chest = TRUE +/datum/sprite_accessory/underwear/bottom/swimsuit_red + name = "Swimsuit, One Piece - Red" + icon_state = "swimming_red" + gender = FEMALE + covers_chest = TRUE + /datum/sprite_accessory/underwear/bottom/thong name = "Thong" icon_state = "thong" @@ -184,5 +186,3 @@ icon_state = "thong_babydoll" has_color = TRUE gender = FEMALE - - diff --git a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm index fb03df88a1..fb71bb483d 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm @@ -58,6 +58,10 @@ dimension_y = 34 relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER) +/datum/sprite_accessory/deco_wings/atlas + name = "Atlas" + icon_state = "atlas" + /datum/sprite_accessory/deco_wings/bat name = "Bat" icon_state = "bat" @@ -66,6 +70,10 @@ name = "Bee" icon_state = "bee" +/datum/sprite_accessory/deco_wings/deathhead + name = "Deathshead" + icon_state = "deathhead" + /datum/sprite_accessory/deco_wings/fairy name = "Fairy" icon_state = "fairy" @@ -74,14 +82,6 @@ name = "Feathery" icon_state = "feathery" -/datum/sprite_accessory/deco_wings/atlas - name = "Atlas" - icon_state = "atlas" - -/datum/sprite_accessory/deco_wings/deathhead - name = "Deathshead" - icon_state = "deathhead" - /datum/sprite_accessory/deco_wings/firewatch name = "Firewatch" icon_state = "firewatch" @@ -150,6 +150,10 @@ icon_state = "none" relevant_layers = null +/datum/sprite_accessory/insect_wings/atlas + name = "Atlas" + icon_state = "atlas" + /datum/sprite_accessory/insect_wings/bat name = "Bat" icon_state = "bat" @@ -158,6 +162,10 @@ name = "Bee" icon_state = "bee" +/datum/sprite_accessory/insect_wings/deathhead + name = "Deathshead" + icon_state = "deathhead" + /datum/sprite_accessory/insect_wings/fairy name = "Fairy" icon_state = "fairy" @@ -166,14 +174,6 @@ name = "Feathery" icon_state = "feathery" -/datum/sprite_accessory/insect_wings/atlas - name = "Atlas" - icon_state = "atlas" - -/datum/sprite_accessory/insect_wings/deathhead - name = "Deathshead" - icon_state = "deathhead" - /datum/sprite_accessory/insect_wings/firewatch name = "Firewatch" icon_state = "firewatch" @@ -182,6 +182,10 @@ name = "Gothic" icon_state = "gothic" +/datum/sprite_accessory/insect_wings/jungle + name = "Jungle" + icon_state = "jungle" + /datum/sprite_accessory/insect_wings/lovers name = "Lovers" icon_state = "lovers" @@ -198,6 +202,10 @@ name = "Moon Fly" icon_state = "moonfly" +/datum/sprite_accessory/insect_wings/oakworm + name = "Oak Worm" + icon_state = "oakworm" + /datum/sprite_accessory/insect_wings/plain name = "Plain" icon_state = "plain" @@ -230,14 +238,6 @@ name = "White Fly" icon_state = "whitefly" -/datum/sprite_accessory/insect_wings/oakworm - name = "Oak Worm" - icon_state = "oakworm" - -/datum/sprite_accessory/insect_wings/jungle - name = "Jungle" - icon_state = "jungle" - /datum/sprite_accessory/insect_wings/witchwing name = "Witch Wing" icon_state = "witchwing" diff --git a/code/modules/mob/dead/observer/orbit.dm b/code/modules/mob/dead/observer/orbit.dm index b81172afad..3aa5f8e302 100644 --- a/code/modules/mob/dead/observer/orbit.dm +++ b/code/modules/mob/dead/observer/orbit.dm @@ -80,3 +80,8 @@ data["npcs"] = npcs return data + +/datum/orbit_menu/ui_assets() + . = ..() || list() + . += get_asset_datum(/datum/asset/simple/orbit) + diff --git a/code/modules/mob/living/brain/emote.dm b/code/modules/mob/living/brain/emote.dm index 540c7b3949..e1cb1a29cc 100644 --- a/code/modules/mob/living/brain/emote.dm +++ b/code/modules/mob/living/brain/emote.dm @@ -1,13 +1,3 @@ -/datum/emote/brain - mob_type_allowed_typecache = list(/mob/living/brain) - mob_type_blacklist_typecache = list() - -/datum/emote/brain/can_run_emote(mob/user, status_check = TRUE) - . = ..() - var/mob/living/brain/B = user - if(!istype(B) || (!(B.container && istype(B.container, /obj/item/mmi)))) - return FALSE - /datum/emote/brain/alarm key = "alarm" message = "sounds an alarm." diff --git a/code/modules/mob/living/carbon/alien/emote.dm b/code/modules/mob/living/carbon/alien/emote.dm index 0ab448d2c5..963981b51e 100644 --- a/code/modules/mob/living/carbon/alien/emote.dm +++ b/code/modules/mob/living/carbon/alien/emote.dm @@ -1,6 +1,3 @@ -/datum/emote/living/alien - mob_type_allowed_typecache = list(/mob/living/carbon/alien) - /datum/emote/living/alien/gnarl key = "gnarl" key_third_person = "gnarls" diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index edb681e60f..b7d67e49a6 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -87,7 +87,7 @@ if(user != src && (user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM)) for(var/datum/surgery/S in surgeries) if(S.next_step(user,user.a_intent)) - return 1 + return STOP_ATTACK_PROC_CHAIN if(!all_wounds || !(user.a_intent == INTENT_HELP || user == src)) return ..() @@ -95,7 +95,7 @@ for(var/i in shuffle(all_wounds)) var/datum/wound/W = i if(W.try_treating(I, user)) - return 1 + return STOP_ATTACK_PROC_CHAIN return ..() diff --git a/code/modules/mob/living/carbon/emote.dm b/code/modules/mob/living/carbon/emote.dm index e3512e3929..49501e0315 100644 --- a/code/modules/mob/living/carbon/emote.dm +++ b/code/modules/mob/living/carbon/emote.dm @@ -1,6 +1,3 @@ -/datum/emote/living/carbon - mob_type_allowed_typecache = list(/mob/living/carbon) - /datum/emote/living/carbon/airguitar key = "airguitar" message = "is strumming the air and headbanging like a safari chimp." @@ -22,7 +19,6 @@ muzzle_ignore = TRUE restraint_check = TRUE emote_type = EMOTE_AUDIBLE - mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/carbon/clap/run_emote(mob/living/user, params) . = ..() @@ -41,7 +37,6 @@ key = "gnarl" key_third_person = "gnarls" message = "gnarls and shows its teeth..." - mob_type_allowed_typecache = list(/mob/living/carbon/monkey, /mob/living/carbon/alien) /datum/emote/living/carbon/moan key = "moan" @@ -55,27 +50,23 @@ key = "roll" key_third_person = "rolls" message = "rolls." - mob_type_allowed_typecache = list(/mob/living/carbon/monkey, /mob/living/carbon/alien) restraint_check = TRUE /datum/emote/living/carbon/scratch key = "scratch" key_third_person = "scratches" message = "scratches." - mob_type_allowed_typecache = list(/mob/living/carbon/monkey, /mob/living/carbon/alien) restraint_check = TRUE /datum/emote/living/carbon/screech key = "screech" key_third_person = "screeches" message = "screeches." - mob_type_allowed_typecache = list(/mob/living/carbon/monkey, /mob/living/carbon/alien) /datum/emote/living/carbon/sign key = "sign" key_third_person = "signs" message_param = "signs the number %t." - mob_type_allowed_typecache = list(/mob/living/carbon/monkey, /mob/living/carbon/alien) restraint_check = TRUE /datum/emote/living/carbon/sign/select_param(mob/user, params) @@ -87,13 +78,11 @@ key = "signal" key_third_person = "signals" message_param = "raises %t fingers." - mob_type_allowed_typecache = list(/mob/living/carbon/human) restraint_check = TRUE /datum/emote/living/carbon/tail key = "tail" message = "waves their tail." - mob_type_allowed_typecache = list(/mob/living/carbon/monkey, /mob/living/carbon/alien) /datum/emote/living/carbon/wink key = "wink" diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 1bfb72a415..837b4f73cf 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -1,6 +1,3 @@ -/datum/emote/living/carbon/human - mob_type_allowed_typecache = list(/mob/living/carbon/human) - /datum/emote/living/carbon/human/cry key = "cry" key_third_person = "cries" @@ -192,3 +189,71 @@ key_third_person = "chimes" message = "chimes." sound = 'sound/machines/chime.ogg' + +//rock paper scissors emote handling +/mob/living/carbon/human/proc/beginRockPaperScissors(var/chosen_move) + GLOB.rockpaperscissors_players[src] = list(chosen_move, ROCKPAPERSCISSORS_NOT_DECIDED) + do_after_advanced(src, ROCKPAPERSCISSORS_TIME_LIMIT, src, DO_AFTER_REQUIRES_USER_ON_TURF|DO_AFTER_NO_COEFFICIENT|DO_AFTER_NO_PROGRESSBAR|DO_AFTER_DISALLOW_MOVING_ABSOLUTE_USER, CALLBACK(src, .proc/rockpaperscissors_tick)) + var/new_entry = GLOB.rockpaperscissors_players[src] + if(new_entry[2] == ROCKPAPERSCISSORS_NOT_DECIDED) + to_chat(src, "You put your hand back down.") + GLOB.rockpaperscissors_players -= src + +/mob/living/carbon/human/proc/rockpaperscissors_tick() //called every cycle of the progress bar for rock paper scissors while waiting for an opponent + var/mob/living/carbon/human/opponent + for(var/mob/living/carbon/human/potential_opponent in (GLOB.rockpaperscissors_players - src)) //dont play against yourself + if(get_dist(src, potential_opponent) <= ROCKPAPERSCISSORS_RANGE) + opponent = potential_opponent + break + if(opponent) + //we found an opponent before they found us + var/move_to_number = list("rock" = 0, "paper" = 1, "scissors" = 2) + var/our_move = move_to_number[GLOB.rockpaperscissors_players[src][1]] + var/their_move = move_to_number[GLOB.rockpaperscissors_players[opponent][1]] + var/result_us = ROCKPAPERSCISSORS_WIN + var/result_them = ROCKPAPERSCISSORS_LOSE + if(our_move == their_move) + result_us = ROCKPAPERSCISSORS_TIE + result_them = ROCKPAPERSCISSORS_TIE + else + if(((our_move + 1) % 3) == their_move) + result_us = ROCKPAPERSCISSORS_LOSE + result_them = ROCKPAPERSCISSORS_WIN + //we decided our results so set them in the list + GLOB.rockpaperscissors_players[src][2] = result_us + GLOB.rockpaperscissors_players[opponent][2] = result_them + + //show what happened + src.visible_message("[src] makes [GLOB.rockpaperscissors_players[src][1]] with their hand!") + opponent.visible_message("[opponent] makes [GLOB.rockpaperscissors_players[opponent][1]] with their hands!") + switch(result_us) + if(ROCKPAPERSCISSORS_TIE) + src.visible_message("It was a tie!") + if(ROCKPAPERSCISSORS_WIN) + src.visible_message("[src] wins!") + if(ROCKPAPERSCISSORS_LOSE) + src.visible_message("[opponent] wins!") + + //make the progress bar end so that each player can handle the result + return DO_AFTER_STOP + + //no opponent was found, so keep searching + return DO_AFTER_PROCEED + +//the actual emotes +/datum/emote/living/carbon/human/rockpaperscissors + message = "is attempting to play rock paper scissors!" + +/datum/emote/living/carbon/human/rockpaperscissors/rock + key = "rock" + +/datum/emote/living/carbon/human/rockpaperscissors/paper + key = "paper" + +/datum/emote/living/carbon/human/rockpaperscissors/scissors + key = "scissors" + +/datum/emote/living/carbon/human/rockpaperscissors/run_emote(mob/living/carbon/human/user, params) + if(!(user in GLOB.rockpaperscissors_players)) //no using the emote again while already playing! + . = ..() + user.beginRockPaperScissors(key) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 65b2931e08..16470d81ce 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -113,14 +113,14 @@ . += effects_exam //CIT CHANGES START HERE - adds genital details to examine text - if(LAZYLEN(internal_organs)) + if(LAZYLEN(internal_organs) && CHECK_BITFIELD(user.client?.prefs.cit_toggles, GENITAL_EXAMINE)) for(var/obj/item/organ/genital/dicc in internal_organs) if(istype(dicc) && dicc.is_exposed()) . += "[dicc.desc]" - - var/cursed_stuff = attempt_vr(src,"examine_bellies",args) //vore Code - if(cursed_stuff) - . += cursed_stuff + if(CHECK_BITFIELD(user.client?.prefs.cit_toggles, VORE_EXAMINE)) + var/cursed_stuff = attempt_vr(src,"examine_bellies",args) //vore Code + if(cursed_stuff) + . += cursed_stuff //END OF CIT CHANGES //Jitters diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index af95b9e1b7..5f30d902b1 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -75,12 +75,8 @@ . = pda.owner else if(istype(tablet)) var/obj/item/computer_hardware/card_slot/card_slot = tablet.all_components[MC_CARD] - if(card_slot && (card_slot.stored_card2 || card_slot.stored_card)) - if(card_slot.stored_card2) //The second card is the one used for authorization in the ID changing program, so we prioritize it here for consistency - . = card_slot.stored_card2.registered_name - else - if(card_slot.stored_card) - . = card_slot.stored_card.registered_name + if(card_slot?.stored_card) + . = card_slot.stored_card.registered_name if(!.) . = if_no_id //to prevent null-names making the mob unclickable return diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 230a634e0e..ed509f900a 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -114,6 +114,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) /// Our default override for typing indicator state var/typing_indicator_state + //the ids you can use for your species, if empty, it means default only and not changeable + var/list/allowed_limb_ids + /////////// // PROCS // /////////// @@ -121,7 +124,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) /datum/species/New() if(!limbs_id) //if we havent set a limbs id to use, just use our own id - limbs_id = id + mutant_bodyparts["limbs_id"] = id //done this way to be non-intrusive to the existing system + else + mutant_bodyparts["limbs_id"] = limbs_id ..() //update our mutant bodyparts to include unlocked ones diff --git a/code/modules/mob/living/carbon/human/species_types/bugmen.dm b/code/modules/mob/living/carbon/human/species_types/bugmen.dm index 2a955e28a4..16b371c772 100644 --- a/code/modules/mob/living/carbon/human/species_types/bugmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/bugmen.dm @@ -13,10 +13,11 @@ meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/insect liked_food = MEAT | FRUIT disliked_food = TOXIC - icon_limbs = DEFAULT_BODYPART_ICON_CITADEL exotic_bloodtype = "BUG" exotic_blood_color = BLOOD_COLOR_BUG tail_type = "mam_tail" wagging_type = "mam_waggingtail" - species_type = "insect" \ No newline at end of file + species_type = "insect" + + allowed_limb_ids = list("insect","apid","moth","moth_not_greyscale") diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm index d8dfe63b35..f3b499093b 100644 --- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm +++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm @@ -83,17 +83,7 @@ /obj/item/organ/tongue/dullahan zone = "abstract" - modifies_speech = TRUE - -/obj/item/organ/tongue/dullahan/handle_speech(datum/source, list/speech_args) - if(ishuman(owner)) - var/mob/living/carbon/human/H = owner - if(isdullahan(H)) - var/datum/species/dullahan/D = H.dna.species - if(isobj(D.myhead.loc)) - var/obj/O = D.myhead.loc - O.say(speech_args[SPEECH_MESSAGE]) - speech_args[SPEECH_MESSAGE] = "" + accents = list(/datum/accent/dullahan) /obj/item/organ/ears/dullahan zone = "abstract" diff --git a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm index 7706d4a9d5..534536d6e7 100644 --- a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm @@ -2,7 +2,6 @@ name = "Anthromorph" id = "mammal" default_color = "4B4B4B" - icon_limbs = DEFAULT_BODYPART_ICON_CITADEL species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BEAST mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "deco_wings" = "None", @@ -17,3 +16,5 @@ tail_type = "mam_tail" wagging_type = "mam_waggingtail" species_type = "furry" + + allowed_limb_ids = list("mammal","aquatic","avian") \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species_types/ipc.dm b/code/modules/mob/living/carbon/human/species_types/ipc.dm index 3aef14c256..806782a8b2 100644 --- a/code/modules/mob/living/carbon/human/species_types/ipc.dm +++ b/code/modules/mob/living/carbon/human/species_types/ipc.dm @@ -3,7 +3,6 @@ id = "ipc" say_mod = "beeps" default_color = "00FF00" - icon_limbs = DEFAULT_BODYPART_ICON_CITADEL blacklisted = 0 sexes = 0 species_traits = list(MUTCOLORS,NOEYES,NOTRANSSTING,HAS_FLESH,HAS_BONE) diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm index f5a2f807e4..0f62953e6c 100644 --- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm @@ -21,6 +21,8 @@ species_type = "plant" + allowed_limb_ids = list("pod","mush") + /datum/species/pod/on_species_gain(mob/living/carbon/C, datum/species/old_species) . = ..() C.faction |= "plants" diff --git a/code/modules/mob/living/carbon/human/species_types/synthliz.dm b/code/modules/mob/living/carbon/human/species_types/synthliz.dm index 173411eaa1..70afa2f476 100644 --- a/code/modules/mob/living/carbon/human/species_types/synthliz.dm +++ b/code/modules/mob/living/carbon/human/species_types/synthliz.dm @@ -1,7 +1,6 @@ /datum/species/synthliz name = "Synthetic Lizardperson" id = "synthliz" - icon_limbs = DEFAULT_BODYPART_ICON_CITADEL say_mod = "beeps" default_color = "00FF00" species_traits = list(MUTCOLORS,NOTRANSSTING,EYECOLOR,LIPS,HAIR,HAS_FLESH,HAS_BONE) diff --git a/code/modules/mob/living/carbon/human/species_types/synths.dm b/code/modules/mob/living/carbon/human/species_types/synths.dm index c10521dfd9..3d55ce1027 100644 --- a/code/modules/mob/living/carbon/human/species_types/synths.dm +++ b/code/modules/mob/living/carbon/human/species_types/synths.dm @@ -61,7 +61,7 @@ mutant_organs = S.mutant_organs.Copy() nojumpsuit = S.nojumpsuit no_equip = S.no_equip.Copy() - limbs_id = S.limbs_id + limbs_id = S.mutant_bodyparts["limbs_id"] use_skintones = S.use_skintones fixed_mut_color = S.fixed_mut_color hair_color = S.hair_color diff --git a/code/modules/mob/living/carbon/human/species_types/xeno.dm b/code/modules/mob/living/carbon/human/species_types/xeno.dm index db34d1ae45..ddd1c86f0a 100644 --- a/code/modules/mob/living/carbon/human/species_types/xeno.dm +++ b/code/modules/mob/living/carbon/human/species_types/xeno.dm @@ -4,7 +4,6 @@ id = "xeno" say_mod = "hisses" default_color = "00FF00" - icon_limbs = DEFAULT_BODYPART_ICON_CITADEL species_traits = list(MUTCOLORS,EYECOLOR,LIPS,CAN_SCAR) mutant_bodyparts = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard", "mam_body_markings" = "Xeno","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None", "legs" = "Digitigrade") attack_verb = "slash" diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index e399ddf872..9b39438563 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -660,7 +660,7 @@ use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if //produces a key based on the human's limbs /mob/living/carbon/human/generate_icon_render_key() - . = "[dna.species.limbs_id]" + . = "[dna.species.mutant_bodyparts["limbs_id"]]" if(dna.check_mutation(HULK)) . += "-coloured-hulk" diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index a735baceae..55764d8d50 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -1,9 +1,3 @@ - -/* EMOTE DATUMS */ -/datum/emote/living - mob_type_allowed_typecache = /mob/living - mob_type_blacklist_typecache = list(/mob/living/simple_animal/slime, /mob/living/brain) - /datum/emote/living/blush key = "blush" key_third_person = "blushes" diff --git a/code/modules/mob/living/silicon/robot/emote.dm b/code/modules/mob/living/silicon/robot/emote.dm index c0fca997f5..c532e44ff5 100644 --- a/code/modules/mob/living/silicon/robot/emote.dm +++ b/code/modules/mob/living/silicon/robot/emote.dm @@ -5,7 +5,7 @@ /datum/emote/sound/silicon mob_type_allowed_typecache = list(/mob/living/silicon, /mob/living/carbon/human) emote_type = EMOTE_AUDIBLE - var/unrestricted = FALSE + var/unrestricted = TRUE /datum/emote/sound/silicon/run_emote(mob/user, params) if(!unrestricted && !(issilicon(user) || isipcperson(user))) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 9018c49b2c..d8299d42ad 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -289,50 +289,57 @@ return FALSE return ISINRANGE(T1.x, T0.x - interaction_range, T0.x + interaction_range) && ISINRANGE(T1.y, T0.y - interaction_range, T0.y + interaction_range) -/mob/living/silicon/robot/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/weldingtool) && (user.a_intent != INTENT_HARM || user == src)) +/mob/living/silicon/robot/proc/attempt_welder_repair(obj/item/weldingtool/W, mob/user) + if (!getBruteLoss()) + to_chat(user, "[src] is already in good condition!") + return + if (!W.tool_start_check(user, amount=0)) //The welder has 1u of fuel consumed by it's afterattack, so we don't need to worry about taking any away. + return + user.DelayNextAction(CLICK_CD_MELEE) + if(src == user) + to_chat(user, "You start fixing yourself...") + if(!W.use_tool(src, user, 50)) + return + adjustBruteLoss(-10) + else + to_chat(user, "You start fixing [src]...") + if(!do_after(user, 30, target = src)) + return + adjustBruteLoss(-30) + updatehealth() + add_fingerprint(user) + visible_message("[user] has fixed some of the dents on [src].") + +/mob/living/silicon/robot/proc/attempt_cable_repair(obj/item/stack/cable_coil/W, mob/user) + if (getFireLoss() > 0 || getToxLoss() > 0) user.DelayNextAction(CLICK_CD_MELEE) - if (!getBruteLoss()) - to_chat(user, "[src] is already in good condition!") - return - if (!W.tool_start_check(user, amount=0)) //The welder has 1u of fuel consumed by it's afterattack, so we don't need to worry about taking any away. - return if(src == user) to_chat(user, "You start fixing yourself...") - if(!W.use_tool(src, user, 50)) + if(!W.use_tool(src, user, 50, 1, skill_gain_mult = TRIVIAL_USE_TOOL_MULT)) + to_chat(user, "You need more cable to repair [src]!") return - adjustBruteLoss(-10) + adjustFireLoss(-10) + adjustToxLoss(-10) else to_chat(user, "You start fixing [src]...") - if(!do_after(user, 30, target = src)) + if(!W.use_tool(src, user, 30, 1)) + to_chat(user, "You need more cable to repair [src]!") return - adjustBruteLoss(-30) - updatehealth() - add_fingerprint(user) - visible_message("[user] has fixed some of the dents on [src].") + adjustFireLoss(-30) + adjustToxLoss(-30) + updatehealth() + user.visible_message("[user] has fixed some of the burnt wires on [src].", "You fix some of the burnt wires on [src].") + else + to_chat(user, "The wires seem fine, there's no need to fix them.") + +/mob/living/silicon/robot/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/weldingtool) && (user.a_intent != INTENT_HARM || user == src)) + INVOKE_ASYNC(src, .proc/attempt_welder_repair, W, user) return else if(istype(W, /obj/item/stack/cable_coil) && wiresexposed) - user.DelayNextAction(CLICK_CD_MELEE) - if (getFireLoss() > 0 || getToxLoss() > 0) - if(src == user) - to_chat(user, "You start fixing yourself...") - if(!W.use_tool(src, user, 50, 1, skill_gain_mult = TRIVIAL_USE_TOOL_MULT)) - to_chat(user, "You need more cable to repair [src]!") - return - adjustFireLoss(-10) - adjustToxLoss(-10) - else - to_chat(user, "You start fixing [src]...") - if(!W.use_tool(src, user, 30, 1)) - to_chat(user, "You need more cable to repair [src]!") - return - adjustFireLoss(-30) - adjustToxLoss(-30) - updatehealth() - user.visible_message("[user] has fixed some of the burnt wires on [src].", "You fix some of the burnt wires on [src].") - else - to_chat(user, "The wires seem fine, there's no need to fix them.") + INVOKE_ASYNC(src, .proc/attempt_cable_repair, W, user) + return else if(istype(W, /obj/item/crowbar)) // crowbar means open or close the cover if(opened) diff --git a/code/modules/mob/living/simple_animal/hostile/gorilla/emotes.dm b/code/modules/mob/living/simple_animal/hostile/gorilla/emotes.dm index 100db06174..8fb531f1fb 100644 --- a/code/modules/mob/living/simple_animal/hostile/gorilla/emotes.dm +++ b/code/modules/mob/living/simple_animal/hostile/gorilla/emotes.dm @@ -1,6 +1,5 @@ /datum/emote/sound/gorilla mob_type_allowed_typecache = /mob/living/simple_animal/hostile/gorilla - mob_type_blacklist_typecache = list() /datum/emote/sound/gorilla/ooga key = "ooga" @@ -8,4 +7,3 @@ message = "oogas." message_param = "oogas at %t." sound = 'sound/creatures/gorilla.ogg' - diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm index 525388fa61..bd3a6e8232 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -661,7 +661,7 @@ Difficulty: Normal continue to_chat(M.occupant, "Your [M.name] is struck by a [name]!") playsound(M,'sound/weapons/sear.ogg', 50, 1, -4) - M.take_damage(damage, BURN, 0, 0) + M.take_damage(damage, BURN, 0, 0, null, 50) /obj/effect/hierophant name = "hierophant beacon" diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm index 12f0b41d4e..fa67fd8e3b 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm @@ -200,6 +200,8 @@ L.Stun(75) L.adjustBruteLoss(rand(15,20)) // Less stun more harm latched = TRUE + for(var/obj/mecha/M in loc) + M.take_damage(20, BRUTE, null, null, null, 25) if(!latched) retract() else diff --git a/code/modules/mob/living/simple_animal/slime/emote.dm b/code/modules/mob/living/simple_animal/slime/emote.dm index 070cd48a70..9440caf3fc 100644 --- a/code/modules/mob/living/simple_animal/slime/emote.dm +++ b/code/modules/mob/living/simple_animal/slime/emote.dm @@ -1,6 +1,5 @@ /datum/emote/slime mob_type_allowed_typecache = /mob/living/simple_animal/slime - mob_type_blacklist_typecache = list() /datum/emote/slime/bounce key = "bounce" diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index 1bdd988694..b74dd6fa20 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -106,6 +106,7 @@ set_colour(new_colour) . = ..() AddComponent(/datum/component/footstep, FOOTSTEP_MOB_SLIME, 7.5) + set_nutrition(rand(650, 800)) /mob/living/simple_animal/slime/Destroy() for (var/A in actions) diff --git a/code/modules/mob/living/ventcrawling.dm b/code/modules/mob/living/ventcrawling.dm index 36a596f42e..6661d0ccea 100644 --- a/code/modules/mob/living/ventcrawling.dm +++ b/code/modules/mob/living/ventcrawling.dm @@ -19,8 +19,11 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, typecacheof(list( to_chat(src, "You can't vent crawl while you're restrained!") return if(has_buckled_mobs()) - to_chat(src, "You can't vent crawl with other creatures on you!") - return + // attempt once + unbuckle_all_mobs() + if(has_buckled_mobs()) + to_chat(src, "You can't vent crawl with other creatures on you!") + return if(buckled) to_chat(src, "You can't vent crawl while buckled!") return diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index 31bfb5621f..0d4afd0915 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -50,6 +50,8 @@ var/datum/callback/CB = foo CB.Invoke() + mind?.hide_ckey = client?.prefs?.hide_ckey + log_message("Client [key_name(src)] has taken ownership of mob [src]([src.type])", LOG_OWNERSHIP) SEND_SIGNAL(src, COMSIG_MOB_CLIENT_LOGIN, client) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 52b755d926..aa6635f73d 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -431,7 +431,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp /mob/living/getImplant(type) return locate(type) in implants -/proc/offer_control(mob/M) +/proc/offer_control(mob/M,ignore_category=null) to_chat(M, "Control of your mob has been offered to dead players.") if(usr) log_admin("[key_name(usr)] has offered control of ([key_name(M)]) to ghosts.") @@ -445,7 +445,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp var/datum/antagonist/A = M.mind.has_antag_datum(/datum/antagonist/) if(A) poll_message = "[poll_message] Status:[A.name]." - var/list/mob/candidates = pollCandidatesForMob(poll_message, ROLE_PAI, null, FALSE, 100, M) + var/list/mob/candidates = pollCandidatesForMob(poll_message, ROLE_PAI, null, FALSE, 100, M, ignore_category) if(LAZYLEN(candidates)) var/mob/C = pick(candidates) diff --git a/code/modules/modular_computers/computers/_modular_computer_shared.dm b/code/modules/modular_computers/computers/_modular_computer_shared.dm index 8ca93e8347..9dde9a0c49 100644 --- a/code/modules/modular_computers/computers/_modular_computer_shared.dm +++ b/code/modules/modular_computers/computers/_modular_computer_shared.dm @@ -44,18 +44,20 @@ . += "It has a slot installed for an intelliCard." var/obj/item/computer_hardware/card_slot/card_slot = get_modular_computer_part(MC_CARD) + var/obj/item/computer_hardware/card_slot/card_slot2 = get_modular_computer_part(MC_CARD2) + var/multiple_slots = istype(card_slot) && istype(card_slot2) if(card_slot) - if(card_slot.stored_card || card_slot.stored_card2) + if(card_slot?.stored_card || card_slot2?.stored_card) var/obj/item/card/id/first_ID = card_slot.stored_card - var/obj/item/card/id/second_ID = card_slot.stored_card2 + var/obj/item/card/id/second_ID = card_slot2.stored_card var/multiple_cards = istype(first_ID) && istype(second_ID) if(user_is_adjacent) - . += "It has two slots for identification cards installed[multiple_cards ? " which contain [first_ID] and [second_ID]" : ", one of which contains [first_ID ? first_ID : second_ID]"]." + . += "It has [multiple_slots ? "two slots" : "a slot"] for identification cards installed[multiple_cards ? " which contain [first_ID] and [second_ID]" : ", one of which contains [first_ID ? first_ID : second_ID]"]." else - . += "It has two slots for identification cards installed, [multiple_cards ? "both of which appear" : "and one of them appears"] to be occupied." + . += "It has [multiple_slots ? "two slots" : "a slot"] for identification cards installed, [multiple_cards ? "both of which appear" : "and one of them appears"] to be occupied." . += "Alt-click [src] to eject the identification card[multiple_cards ? "s":""]." else - . += "It has two slots installed for identification cards." + . += "It has [multiple_slots ? "two slots" : "a slot"] installed for identification cards." var/obj/item/computer_hardware/printer/printer_slot = get_modular_computer_part(MC_PRINT) if(printer_slot) diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index 67c04de13f..63cb1cc5fa 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -4,6 +4,12 @@ /obj/item/modular_computer name = "modular microcomputer" desc = "A small portable microcomputer." + icon = 'icons/obj/computer.dmi' + icon_state = "laptop-open" + var/light_on = FALSE + integrity_failure = 0.5 + max_integrity = 100 + armor = list("melee" = 0, "bullet" = 20, "laser" = 20, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 0, "acid" = 0) var/enabled = 0 // Whether the computer is turned on. var/screen_on = 1 // Whether the computer is active/opened/it's screen is on. @@ -22,8 +28,6 @@ // must have it's own DMI file. Icon states must be called exactly the same in all files, but may look differently // If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example. - icon = 'icons/obj/computer.dmi' - icon_state = "laptop-open" var/icon_state_unpowered = null // Icon state when the computer is turned off. var/icon_state_powered = null // Icon state when the computer is turned on. var/icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen. @@ -31,20 +35,16 @@ var/max_hardware_size = 0 // Maximal hardware w_class. Tablets/PDAs have 1, laptops 2, consoles 4. var/steel_sheet_cost = 5 // Amount of steel sheets refunded when disassembling an empty frame of this computer. - integrity_failure = 0.5 - max_integrity = 100 - armor = list("melee" = 0, "bullet" = 20, "laser" = 20, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 0, "acid" = 0) - - // Important hardware (must be installed for computer to work) - - // Optional hardware (improves functionality, but is not critical for computer to work) - - var/list/all_components = list() // List of "connection ports" in this computer and the components with which they are plugged + /// List of "connection ports" in this computer and the components with which they are plugged + var/list/all_components = list() + /// Lazy List of extra hardware slots that can be used modularly. + var/list/expansion_bays + /// Number of total expansion bays this computer has available. + var/max_bays = 0 var/list/idle_threads // Idle programs on background. They still receive process calls but can't be interacted with. var/obj/physical = null // Object that represents our computer. It's used for Adjacent() and UI visibility checks. var/has_light = FALSE //If the computer has a flashlight/LED light/what-have-you installed - var/light_on = FALSE //If that light is enabled var/comp_light_luminosity = 3 //The brightness of that light var/comp_light_color //The color of that light @@ -71,80 +71,15 @@ physical = null return ..() - -/obj/item/modular_computer/proc/add_verb(var/path) - switch(path) - if(MC_CARD) - verbs += /obj/item/modular_computer/proc/eject_id - if(MC_SDD) - verbs += /obj/item/modular_computer/proc/eject_disk - if(MC_AI) - verbs += /obj/item/modular_computer/proc/eject_card - -/obj/item/modular_computer/proc/remove_verb(path) - switch(path) - if(MC_CARD) - verbs -= /obj/item/modular_computer/proc/eject_id - if(MC_SDD) - verbs -= /obj/item/modular_computer/proc/eject_disk - if(MC_AI) - verbs -= /obj/item/modular_computer/proc/eject_card - -// Eject ID card from computer, if it has ID slot with card inside. -/obj/item/modular_computer/proc/eject_id() - set name = "Eject ID" - set category = "Object" - set src in view(1) - - if(issilicon(usr)) - return - var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD] - if(usr.canUseTopic(src, BE_CLOSE)) - card_slot.try_eject(null, usr) - -// Eject ID card from computer, if it has ID slot with card inside. -/obj/item/modular_computer/proc/eject_card() - set name = "Eject Intellicard" - set category = "Object" - - if(issilicon(usr)) - return - var/obj/item/computer_hardware/ai_slot/ai_slot = all_components[MC_AI] - if(usr.canUseTopic(src, BE_CLOSE)) - ai_slot.try_eject(null, usr,1) - - -// Eject ID card from computer, if it has ID slot with card inside. -/obj/item/modular_computer/proc/eject_disk() - set name = "Eject Data Disk" - set category = "Object" - - if(issilicon(usr)) - return - - if(usr.canUseTopic(src, BE_CLOSE)) - var/obj/item/computer_hardware/hard_drive/portable/portable_drive = all_components[MC_SDD] - if(uninstall_component(portable_drive, usr)) - portable_drive.verb_pickup() - /obj/item/modular_computer/AltClick(mob/user) ..() if(issilicon(user)) return 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] - var/obj/item/computer_hardware/ai_slot/ai_slot = all_components[MC_AI] - var/obj/item/computer_hardware/hard_drive/portable/portable_drive = all_components[MC_SDD] - if(portable_drive) - if(uninstall_component(portable_drive, user)) - portable_drive.verb_pickup() - else - if(card_slot && card_slot.try_eject(null, user)) - return - if(ai_slot) - ai_slot.try_eject(null, user) - + return (card_slot2?.try_eject(user) || card_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. /obj/item/modular_computer/GetAccess() @@ -160,19 +95,25 @@ return ..() /obj/item/modular_computer/RemoveID() + 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] - if(!card_slot) - return - return card_slot.RemoveID() + return (card_slot2?.try_eject() || card_slot?.try_eject()) //Try the secondary one first. /obj/item/modular_computer/InsertID(obj/item/inserting_item) var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD] - if(!card_slot) + var/obj/item/computer_hardware/card_slot/card_slot2 = all_components[MC_CARD2] + if(!(card_slot || card_slot2)) + //to_chat(user, "There isn't anywhere you can fit a card into on this computer.") return FALSE + var/obj/item/card/inserting_id = inserting_item.RemoveID() if(!inserting_id) return FALSE - return card_slot.try_insert(inserting_id) + + if((card_slot?.try_insert(inserting_id)) || (card_slot2?.try_insert(inserting_id))) + return TRUE + //to_chat(user, "This computer doesn't have an open card slot.") + return FALSE /obj/item/modular_computer/MouseDrop(obj/over_object, src_location, over_location) var/mob/M = usr diff --git a/code/modules/modular_computers/computers/item/computer_components.dm b/code/modules/modular_computers/computers/item/computer_components.dm index 3c94a66384..8668b279cf 100644 --- a/code/modules/modular_computers/computers/item/computer_components.dm +++ b/code/modules/modular_computers/computers/item/computer_components.dm @@ -6,6 +6,14 @@ to_chat(user, "This component is too large for \the [src]!") return FALSE + if(H.expansion_hw) + if(LAZYLEN(expansion_bays) >= max_bays) + to_chat(user, "All of the computer's expansion bays are filled.") + return FALSE + if(LAZYACCESS(expansion_bays, H.device_type)) + to_chat(user, "The computer immediately ejects /the [H] and flashes an error: \"Hardware Address Conflict\".") + return FALSE + if(all_components[H.device_type]) to_chat(user, "This computer's hardware slot is already occupied by \the [all_components[H.device_type]].") return FALSE @@ -20,6 +28,8 @@ if(user && !user.transferItemToLoc(H, src)) return FALSE + if(H.expansion_hw) + LAZYSET(expansion_bays, H.device_type, H) all_components[H.device_type] = H to_chat(user, "You install \the [H] into \the [src].") @@ -32,7 +42,9 @@ /obj/item/modular_computer/proc/uninstall_component(obj/item/computer_hardware/H, mob/living/user = null) if(H.holder != src) // Not our component at all. return FALSE + if(H.expansion_hw) + LAZYREMOVE(expansion_bays, H.device_type) all_components.Remove(H.device_type) to_chat(user, "You remove \the [H] from \the [src].") @@ -43,6 +55,7 @@ if(enabled && !use_power()) shutdown_computer() update_icon() + return TRUE // Checks all hardware pieces to determine if name matches, if yes, returns the hardware piece, otherwise returns null diff --git a/code/modules/modular_computers/computers/item/computer_ui.dm b/code/modules/modular_computers/computers/item/computer_ui.dm index fd017e2b0f..4a985b93c1 100644 --- a/code/modules/modular_computers/computers/item/computer_ui.dm +++ b/code/modules/modular_computers/computers/item/computer_ui.dm @@ -44,6 +44,33 @@ /obj/item/modular_computer/ui_data(mob/user) var/list/data = get_header_data() data["device_theme"] = device_theme + + data["login"] = list() + var/obj/item/computer_hardware/card_slot/cardholder = all_components[MC_CARD] + if(cardholder) + var/obj/item/card/id/stored_card = cardholder.GetID() + if(stored_card) + var/stored_name = stored_card.registered_name + var/stored_title = stored_card.assignment + if(!stored_name) + stored_name = "Unknown" + if(!stored_title) + stored_title = "Unknown" + data["login"] = list( + IDName = stored_name, + IDJob = stored_title, + ) + + data["removable_media"] = list() + if(all_components[MC_SDD]) + data["removable_media"] += "removable storage disk" + var/obj/item/computer_hardware/ai_slot/intelliholder = all_components[MC_AI] + if(intelliholder?.stored_card) + data["removable_media"] += "intelliCard" + var/obj/item/computer_hardware/card_slot/secondarycardholder = all_components[MC_CARD2] + if(secondarycardholder?.stored_card) + data["removable_media"] += "secondary RFID card" + data["programs"] = list() var/obj/item/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD] for(var/datum/computer_file/program/P in hard_drive.stored_files) @@ -157,6 +184,36 @@ light_color = new_color update_light() return TRUE + + if("PC_Eject_Disk") + var/param = params["name"] + var/mob/user = usr + switch(param) + if("removable storage disk") + var/obj/item/computer_hardware/hard_drive/portable/portable_drive = all_components[MC_SDD] + if(!portable_drive) + return + if(uninstall_component(portable_drive, usr)) + user.put_in_hands(portable_drive) + playsound(src, 'sound/machines/card_slide.ogg', 50) + if("intelliCard") + var/obj/item/computer_hardware/ai_slot/intelliholder = all_components[MC_AI] + if(!intelliholder) + return + if(intelliholder.try_eject(user)) + playsound(src, 'sound/machines/card_slide.ogg', 50) + if("ID") + var/obj/item/computer_hardware/card_slot/cardholder = all_components[MC_CARD] + if(!cardholder) + return + cardholder.try_eject(user) + if("secondary RFID card") + var/obj/item/computer_hardware/card_slot/cardholder = all_components[MC_CARD2] + if(!cardholder) + return + cardholder.try_eject(user) + + else return diff --git a/code/modules/modular_computers/computers/item/laptop.dm b/code/modules/modular_computers/computers/item/laptop.dm index 5927d57a0b..ef83140a8f 100644 --- a/code/modules/modular_computers/computers/item/laptop.dm +++ b/code/modules/modular_computers/computers/item/laptop.dm @@ -12,6 +12,7 @@ hardware_flag = PROGRAM_LAPTOP max_hardware_size = 2 w_class = WEIGHT_CLASS_NORMAL + max_bays = 4 // No running around with open laptops in hands. item_flags = SLOWS_WHILE_IN_HAND diff --git a/code/modules/modular_computers/computers/item/processor.dm b/code/modules/modular_computers/computers/item/processor.dm index c79d7a9361..0d7b567877 100644 --- a/code/modules/modular_computers/computers/item/processor.dm +++ b/code/modules/modular_computers/computers/item/processor.dm @@ -8,6 +8,7 @@ icon_state_unpowered = null icon_state_menu = null hardware_flag = 0 + max_bays = 4 var/obj/machinery/modular_computer/machinery_computer = null @@ -18,7 +19,7 @@ machinery_computer = null . = ..() -/obj/item/modular_computer/processor/New(comp) //intentional new probably +/obj/item/modular_computer/processor/New(comp) ..() STOP_PROCESSING(SSobj, src) // Processed by its machine @@ -56,23 +57,5 @@ machinery_computer.update_icon() return -/obj/item/modular_computer/processor/add_verb(path) - switch(path) - if(MC_CARD) - machinery_computer.verbs += /obj/machinery/modular_computer/proc/eject_id - if(MC_SDD) - machinery_computer.verbs += /obj/machinery/modular_computer/proc/eject_disk - if(MC_AI) - machinery_computer.verbs += /obj/machinery/modular_computer/proc/eject_card - -/obj/item/modular_computer/processor/remove_verb(path) - switch(path) - if(MC_CARD) - machinery_computer.verbs -= /obj/machinery/modular_computer/proc/eject_id - if(MC_SDD) - machinery_computer.verbs -= /obj/machinery/modular_computer/proc/eject_disk - if(MC_AI) - machinery_computer.verbs -= /obj/machinery/modular_computer/proc/eject_card - /obj/item/modular_computer/processor/attack_ghost(mob/user) ui_interact(user) diff --git a/code/modules/modular_computers/computers/item/tablet.dm b/code/modules/modular_computers/computers/item/tablet.dm index 41a256467f..67e8118c7a 100644 --- a/code/modules/modular_computers/computers/item/tablet.dm +++ b/code/modules/modular_computers/computers/item/tablet.dm @@ -5,10 +5,11 @@ icon_state_unpowered = "tablet" icon_state_powered = "tablet" icon_state_menu = "menu" - //worn_icon_state = "tablet" + // worn_icon_state = "tablet" hardware_flag = PROGRAM_TABLET max_hardware_size = 1 w_class = WEIGHT_CLASS_SMALL + max_bays = 3 steel_sheet_cost = 1 slot_flags = ITEM_SLOT_ID | ITEM_SLOT_BELT has_light = TRUE //LED flashlight! diff --git a/code/modules/modular_computers/computers/item/tablet_presets.dm b/code/modules/modular_computers/computers/item/tablet_presets.dm index 7cca8ea5b4..8ac669d2bf 100644 --- a/code/modules/modular_computers/computers/item/tablet_presets.dm +++ b/code/modules/modular_computers/computers/item/tablet_presets.dm @@ -26,11 +26,21 @@ install_component(new /obj/item/computer_hardware/processor_unit/small) install_component(new /obj/item/computer_hardware/battery(src, /obj/item/stock_parts/cell/computer)) install_component(hard_drive) + install_component(new /obj/item/computer_hardware/card_slot) install_component(new /obj/item/computer_hardware/network_card) install_component(new /obj/item/computer_hardware/printer/mini) hard_drive.store_file(new /datum/computer_file/program/bounty) //hard_drive.store_file(new /datum/computer_file/program/shipping) +/obj/item/modular_computer/tablet/preset/advanced/atmos/Initialize() //This will be defunct and will be replaced when NtOS PDAs are done + . = ..() + install_component(new /obj/item/computer_hardware/sensorpackage) + +/obj/item/modular_computer/tablet/preset/advanced/command/Initialize() + . = ..() + install_component(new /obj/item/computer_hardware/sensorpackage) + install_component(new /obj/item/computer_hardware/card_slot/secondary) + /// Given by the syndicate as part of the contract uplink bundle - loads in the Contractor Uplink. /obj/item/modular_computer/tablet/syndicate_contract_uplink/preset/uplink/Initialize() . = ..() diff --git a/code/modules/modular_computers/computers/machinery/console_presets.dm b/code/modules/modular_computers/computers/machinery/console_presets.dm index 9d29b23e76..12b2f6d25a 100644 --- a/code/modules/modular_computers/computers/machinery/console_presets.dm +++ b/code/modules/modular_computers/computers/machinery/console_presets.dm @@ -1,6 +1,6 @@ /obj/machinery/modular_computer/console/preset // Can be changed to give devices specific hardware - var/_has_id_slot = FALSE + var/_has_second_id_slot = FALSE var/_has_printer = FALSE var/_has_battery = FALSE var/_has_ai = FALSE @@ -11,8 +11,9 @@ return cpu.install_component(new /obj/item/computer_hardware/processor_unit) - if(_has_id_slot) - cpu.install_component(new /obj/item/computer_hardware/card_slot) + cpu.install_component(new /obj/item/computer_hardware/card_slot) + if(_has_second_id_slot) + cpu.install_component(new /obj/item/computer_hardware/card_slot/secondary) if(_has_printer) cpu.install_component(new /obj/item/computer_hardware/printer) if(_has_battery) @@ -59,7 +60,7 @@ console_department = "Command" name = "command console" desc = "A stationary computer. This one comes preloaded with command programs." - _has_id_slot = TRUE + _has_second_id_slot = TRUE _has_printer = TRUE /obj/machinery/modular_computer/console/preset/command/install_programs() @@ -73,7 +74,7 @@ console_department = "Identification" name = "identification console" desc = "A stationary computer. This one comes preloaded with identification modification programs." - _has_id_slot = TRUE + _has_second_id_slot = TRUE _has_printer = TRUE /obj/machinery/modular_computer/console/preset/id/install_programs() diff --git a/code/modules/modular_computers/computers/machinery/modular_computer.dm b/code/modules/modular_computers/computers/machinery/modular_computer.dm index 6f016ad147..0e6f4d161a 100644 --- a/code/modules/modular_computers/computers/machinery/modular_computer.dm +++ b/code/modules/modular_computers/computers/machinery/modular_computer.dm @@ -75,30 +75,6 @@ add_overlay("bsod") add_overlay("broken") -// Eject ID card from computer, if it has ID slot with card inside. -/obj/machinery/modular_computer/proc/eject_id() - set name = "Eject ID" - set category = "Object" - - if(cpu) - cpu.eject_id() - -// Eject ID card from computer, if it has ID slot with card inside. -/obj/machinery/modular_computer/proc/eject_disk() - set name = "Eject Data Disk" - set category = "Object" - - if(cpu) - cpu.eject_disk() - -/obj/machinery/modular_computer/proc/eject_card() - set name = "Eject Intellicard" - set category = "Object" - set src in view(1) - - if(cpu) - cpu.eject_card() - /obj/machinery/modular_computer/AltClick(mob/user) if(cpu) cpu.AltClick(user) @@ -136,7 +112,7 @@ return . = ..() -/obj/machinery/modular_computer/attackby(var/obj/item/W as obj, mob/user) +/obj/machinery/modular_computer/attackby(obj/item/W as obj, mob/user) if(cpu && !(flags_1 & NODECONSTRUCT_1)) return cpu.attackby(W, user) return ..() @@ -169,5 +145,4 @@ // "Brute" damage mostly damages the casing. /obj/machinery/modular_computer/bullet_act(obj/item/projectile/Proj) if(cpu) - return cpu.bullet_act(Proj) - return ..() + cpu.bullet_act(Proj) diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm index 12e5ef6e95..6d6a48d567 100644 --- a/code/modules/modular_computers/file_system/program.dm +++ b/code/modules/modular_computers/file_system/program.dm @@ -25,8 +25,6 @@ var/ntnet_status = 1 /// Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET combination) or PROGRAM_ALL var/usage_flags = PROGRAM_ALL - /// Optional string that describes what NTNet server/system this program connects to. Used in default logging. - var/network_destination = null /// Whether the program can be downloaded from NTNet. Set to 0 to disable. var/available_on_ntnet = 1 /// Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable. @@ -82,10 +80,18 @@ /datum/computer_file/program/proc/process_tick() return 1 -// Check if the user can run program. Only humans can operate computer. Automatically called in run_program() -// User has to wear their ID for ID Scan to work. -// Can also be called manually, with optional parameter being access_to_check to scan the user's ID -/datum/computer_file/program/proc/can_run(mob/user, loud = FALSE, access_to_check, transfer = FALSE) +/** + *Check if the user can run program. Only humans can operate computer. Automatically called in run_program() + *ID must be inserted into a card slot to be read. If the program is not currently installed (as is the case when + *NT Software Hub is checking available software), a list can be given to be used instead. + *Arguments: + *user is a ref of the mob using the device. + *loud is a bool deciding if this proc should use to_chats + *access_to_check is an access level that will be checked against the ID + *transfer, if TRUE and access_to_check is null, will tell this proc to use the program's transfer_access in place of access_to_check + *access can contain a list of access numbers to check against. If access is not empty, it will be used istead of checking any inserted ID. +*/ +/datum/computer_file/program/proc/can_run(mob/user, loud = FALSE, access_to_check, transfer = FALSE, var/list/access) // Defaults to required_access if(!access_to_check) if(transfer && transfer_access) @@ -104,29 +110,24 @@ if(issilicon(user)) return TRUE - if(ishuman(user)) + if(!length(access)) var/obj/item/card/id/D var/obj/item/computer_hardware/card_slot/card_slot - if(computer && card_slot) + if(computer) card_slot = computer.all_components[MC_CARD] - D = card_slot.GetID() - var/mob/living/carbon/human/h = user - var/obj/item/card/id/I = h.get_idcard(TRUE) + D = card_slot?.GetID() - if(!I && !D) + if(!D) if(loud) to_chat(user, "\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning.") return FALSE + access = D.GetAccess() - if(I) - if(access_to_check in I.GetAccess()) - return TRUE - else if(D) - if(access_to_check in D.GetAccess()) - return TRUE - if(loud) - to_chat(user, "\The [computer] flashes an \"Access Denied\" warning.") - return 0 + if(access_to_check in access) + return TRUE + if(loud) + to_chat(user, "\The [computer] flashes an \"Access Denied\" warning.") + return FALSE // This attempts to retrieve header data for UIs. If implementing completely new device of different type than existing ones // always include the device here in this proc. This proc basically relays the request to whatever is running the program. @@ -139,8 +140,12 @@ // When implementing new program based device, use this to run the program. /datum/computer_file/program/proc/run_program(mob/living/user) if(can_run(user, 1)) - if(requires_ntnet && network_destination) - generate_network_log("Connection opened to [network_destination].") + if(requires_ntnet) + var/obj/item/card/id/ID + var/obj/item/computer_hardware/card_slot/card_holder = computer.all_components[MC_CARD] + if(card_holder) + ID = card_holder.GetID() + generate_network_log("Connection opened -- Program ID: [filename] User:[ID?"[ID.registered_name]":"None"]") program_state = PROGRAM_STATE_ACTIVE return 1 return 0 @@ -162,8 +167,12 @@ // Use this proc to kill the program. Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client. /datum/computer_file/program/proc/kill_program(forced = FALSE) program_state = PROGRAM_STATE_KILLED - if(network_destination) - generate_network_log("Connection to [network_destination] closed.") + if(requires_ntnet) + var/obj/item/card/id/ID + var/obj/item/computer_hardware/card_slot/card_holder = computer.all_components[MC_CARD] + if(card_holder) + ID = card_holder.GetID() + generate_network_log("Connection closed -- Program ID: [filename] User:[ID?"[ID.registered_name]":"None"]") return 1 /datum/computer_file/program/ui_interact(mob/user, datum/tgui/ui) diff --git a/code/modules/modular_computers/file_system/program_events.dm b/code/modules/modular_computers/file_system/program_events.dm index 3c1daa5af3..1cb74a227b 100644 --- a/code/modules/modular_computers/file_system/program_events.dm +++ b/code/modules/modular_computers/file_system/program_events.dm @@ -2,7 +2,7 @@ // Always include a parent call when overriding an event. // Called when the ID card is removed from computer. ID is removed AFTER this proc. -/datum/computer_file/program/proc/event_idremoved(background, slot) +/datum/computer_file/program/proc/event_idremoved(background) return // Called when the computer fails due to power loss. Override when program wants to specifically react to power loss. diff --git a/code/modules/modular_computers/file_system/programs/airestorer.dm b/code/modules/modular_computers/file_system/programs/airestorer.dm index 364ad79737..7ae6dd203a 100644 --- a/code/modules/modular_computers/file_system/programs/airestorer.dm +++ b/code/modules/modular_computers/file_system/programs/airestorer.dm @@ -1,8 +1,8 @@ /datum/computer_file/program/aidiag filename = "aidiag" - filedesc = "AI Integrity Restorer" + filedesc = "NT FRK" program_icon_state = "generic" - extended_desc = "This program is capable of reconstructing damaged AI systems. Requires direct AI connection via intellicard slot." + extended_desc = "Firmware Restoration Kit, capable of reconstructing damaged AI systems. Requires direct AI connection via intellicard slot." size = 12 requires_ntnet = FALSE usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP @@ -48,7 +48,7 @@ if(computer.all_components[MC_AI]) var/obj/item/computer_hardware/ai_slot/ai_slot = computer.all_components[MC_AI] if(ai_slot && ai_slot.stored_card) - ai_slot.try_eject(0,usr) + ai_slot.try_eject(usr) return TRUE /datum/computer_file/program/aidiag/process_tick() @@ -71,14 +71,19 @@ ai_slot.locked = FALSE restoring = FALSE return - ai_slot.locked =TRUE + ai_slot.locked = TRUE A.adjustOxyLoss(-5, 0)//, FALSE) A.adjustFireLoss(-5, 0)//, FALSE) A.adjustToxLoss(-5, 0) A.adjustBruteLoss(-5, 0) + + // Please don't forget to update health, otherwise the below if statements will probably always fail. A.updatehealth() + if(A.health >= 0 && A.stat == DEAD) A.revive(full_heal = FALSE, admin_revive = FALSE) + cardhold.update_icon() + // Finished restoring if(A.health >= 100) ai_slot.locked = FALSE diff --git a/code/modules/modular_computers/file_system/programs/alarm.dm b/code/modules/modular_computers/file_system/programs/alarm.dm index 577fad83d0..55dea600e3 100644 --- a/code/modules/modular_computers/file_system/programs/alarm.dm +++ b/code/modules/modular_computers/file_system/programs/alarm.dm @@ -1,11 +1,10 @@ /datum/computer_file/program/alarm_monitor filename = "alarmmonitor" - filedesc = "Alarm Monitor" + filedesc = "Canary" ui_header = "alarm_green.gif" program_icon_state = "alert-green" - extended_desc = "This program provides visual interface for station's alarm system." + extended_desc = "This program provides visual interface for a station's alarm system." requires_ntnet = 1 - network_destination = "alarm monitoring network" size = 5 tgui_id = "NtosStationAlertConsole" var/has_alert = 0 diff --git a/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm b/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm index 3accb8e02d..aa361d4544 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm @@ -14,7 +14,7 @@ var/assigned = FALSE var/first_load = TRUE -/datum/computer_file/program/contract_uplink/run_program(var/mob/living/user) +/datum/computer_file/program/contract_uplink/run_program(mob/living/user) . = ..(user) /datum/computer_file/program/contract_uplink/ui_act(action, params) diff --git a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm index 2ba3d69fe6..4f1c488b9e 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm @@ -10,7 +10,7 @@ tgui_id = "NtosRevelation" var/armed = 0 -/datum/computer_file/program/revelation/run_program(var/mob/living/user) +/datum/computer_file/program/revelation/run_program(mob/living/user) . = ..(user) if(armed) activate() diff --git a/code/modules/modular_computers/file_system/programs/arcade.dm b/code/modules/modular_computers/file_system/programs/arcade.dm index 2503073f9a..87a3f1ec94 100644 --- a/code/modules/modular_computers/file_system/programs/arcade.dm +++ b/code/modules/modular_computers/file_system/programs/arcade.dm @@ -1,10 +1,9 @@ /datum/computer_file/program/arcade - filename = "arcade" - filedesc = "Nanotrasen Micro Arcade" + filename = "dsarcade" + filedesc = "Donksoft Micro Arcade" program_icon_state = "arcade" extended_desc = "This port of the classic game 'Outbomb Cuban Pete', redesigned to run on tablets, with thrilling graphics and chilling storytelling." requires_ntnet = FALSE - network_destination = "arcade network" size = 6 tgui_id = "NtosArcade" @@ -25,7 +24,7 @@ /datum/computer_file/program/arcade/proc/game_check(mob/user) sleep(5) - //user?.mind?.adjust_experience(/datum/skill/gaming, 1) No gaming(TM) Yet + // user?.mind?.adjust_experience(/datum/skill/gaming, 1) if(boss_hp <= 0) heads_up = "You have crushed [boss_name]! Rejoice!" playsound(computer.loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3, falloff = 10) @@ -34,7 +33,7 @@ if(istype(computer)) computer.update_icon() ticket_count += 1 - //user?.mind?.adjust_experience(/datum/skill/gaming, 50) + // user?.mind?.adjust_experience(/datum/skill/gaming, 50) sleep(10) else if(player_hp <= 0 || player_mp <= 0) heads_up = "You have been defeated... how will the station survive?" @@ -43,7 +42,7 @@ program_icon_state = "arcade_off" if(istype(computer)) computer.update_icon() - //user?.mind?.adjust_experience(/datum/skill/gaming, 10) + // user?.mind?.adjust_experience(/datum/skill/gaming, 10) sleep(10) /datum/computer_file/program/arcade/proc/enemy_check(mob/user) @@ -98,8 +97,8 @@ if(computer) printer = computer.all_components[MC_PRINT] - //var/gamerSkillLevel = usr.mind?.get_skill_level(/datum/skill/gaming) - //var/gamerSkill = usr.mind?.get_skill_modifier(/datum/skill/gaming, SKILL_RANDS_MODIFIER) + // var/gamerSkillLevel = usr.mind?.get_skill_level(/datum/skill/gaming) + // var/gamerSkill = usr.mind?.get_skill_modifier(/datum/skill/gaming, SKILL_RANDS_MODIFIER) switch(action) if("Attack") var/attackamt = 0 //Spam prevention. @@ -119,8 +118,8 @@ if(pause_state == FALSE) healamt = rand(6,8)// + rand(0, gamerSkill) var/maxPointCost = 3 - //if(gamerSkillLevel >= SKILL_LEVEL_JOURNEYMAN) - // maxPointCost = 2 + // if(gamerSkillLevel >= SKILL_LEVEL_JOURNEYMAN) + // maxPointCost = 2 healcost = rand(1, maxPointCost) pause_state = TRUE heads_up = "You heal for [healamt] damage." diff --git a/code/modules/modular_computers/file_system/programs/atmosscan.dm b/code/modules/modular_computers/file_system/programs/atmosscan.dm index 2df751bebd..c4b9951838 100644 --- a/code/modules/modular_computers/file_system/programs/atmosscan.dm +++ b/code/modules/modular_computers/file_system/programs/atmosscan.dm @@ -1,17 +1,25 @@ /datum/computer_file/program/atmosscan filename = "atmosscan" - filedesc = "Atmospheric Scanner" + filedesc = "AtmoZphere" program_icon_state = "air" extended_desc = "A small built-in sensor reads out the atmospheric conditions around the device." - network_destination = "atmos scan" size = 4 tgui_id = "NtosAtmos" +/datum/computer_file/program/atmosscan/run_program(mob/living/user) + . = ..() + if (!.) + return + if(!computer?.get_modular_computer_part(MC_SENSORS)) //Giving a clue to users why the program is spitting out zeros. + to_chat(user, "\The [computer] flashes an error: \"hardware\\sensorpackage\\startup.bin -- file not found\".") + + /datum/computer_file/program/atmosscan/ui_data(mob/user) var/list/data = get_header_data() var/list/airlist = list() var/turf/T = get_turf(ui_host()) - if(T) + var/obj/item/computer_hardware/sensorpackage/sensors = computer?.get_modular_computer_part(MC_SENSORS) + if(T && sensors?.check_functionality()) var/datum/gas_mixture/environment = T.return_air() var/list/env_gases = environment.get_gases() var/pressure = environment.return_pressure() @@ -24,6 +32,10 @@ if(gas_level > 0) airlist += list(list("name" = "[GLOB.meta_gas_names[id]]", "percentage" = round(gas_level*100, 0.01))) data["AirData"] = airlist + else + data["AirPressure"] = 0 + data["AirTemp"] = 0 + data["AirData"] = list(list()) return data /datum/computer_file/program/atmosscan/ui_act(action, list/params) diff --git a/code/modules/modular_computers/file_system/programs/borg_monitor.dm b/code/modules/modular_computers/file_system/programs/borg_monitor.dm index c2160a0e92..13caab27ef 100644 --- a/code/modules/modular_computers/file_system/programs/borg_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/borg_monitor.dm @@ -1,12 +1,11 @@ /datum/computer_file/program/borg_monitor - filename = "cyborgmonitor" - filedesc = "Cyborg Remote Monitoring" + filename = "siliconnect" + filedesc = "SiliConnect" ui_header = "borg_mon.gif" program_icon_state = "generic" extended_desc = "This program allows for remote monitoring of station cyborgs." requires_ntnet = TRUE transfer_access = ACCESS_ROBOTICS - network_destination = "cyborg remote monitoring" size = 5 tgui_id = "NtosCyborgRemoteMonitor" @@ -32,7 +31,7 @@ var/list/cyborg_data = list( name = R.name, - locked_down = R.lockcharge, + locked_down = R.locked_down, status = R.stat, shell_discon = shell, charge = R.cell ? round(R.cell.percent()) : null, @@ -81,8 +80,8 @@ return ID.registered_name /datum/computer_file/program/borg_monitor/syndicate - filename = "scyborgmonitor" - filedesc = "Mission-Specific Cyborg Remote Monitoring" + filename = "roboverlord" + filedesc = "Roboverlord" ui_header = "borg_mon.gif" program_icon_state = "generic" extended_desc = "This program allows for remote monitoring of mission-assigned cyborgs." @@ -90,7 +89,6 @@ available_on_ntnet = FALSE available_on_syndinet = TRUE transfer_access = null - network_destination = "cyborg remote monitoring" tgui_id = "NtosCyborgRemoteMonitorSyndicate" /datum/computer_file/program/borg_monitor/syndicate/evaluate_borg(mob/living/silicon/robot/R) diff --git a/code/modules/modular_computers/file_system/programs/bounty_board.dm b/code/modules/modular_computers/file_system/programs/bounty_board.dm index 46fde84f65..2e7d3cc87f 100644 --- a/code/modules/modular_computers/file_system/programs/bounty_board.dm +++ b/code/modules/modular_computers/file_system/programs/bounty_board.dm @@ -4,7 +4,6 @@ program_icon_state = "bountyboard" extended_desc = "A multi-platform network for placing requests across the station, with payment across the network being possible.." requires_ntnet = TRUE - network_destination = "bounty board interface" size = 10 tgui_id = "NtosRequestKiosk" ///Reference to the currently logged in user. diff --git a/code/modules/modular_computers/file_system/programs/card.dm b/code/modules/modular_computers/file_system/programs/card.dm index 842d6e2588..6d45914add 100644 --- a/code/modules/modular_computers/file_system/programs/card.dm +++ b/code/modules/modular_computers/file_system/programs/card.dm @@ -7,8 +7,8 @@ #define CARDCON_DEPARTMENT_COMMAND "Command" /datum/computer_file/program/card_mod - filename = "cardmod" - filedesc = "ID Card Modification" + filename = "plexagonidwriter" + filedesc = "Plexagon Access Management" program_icon_state = "id" extended_desc = "Program for programming employee ID cards to access parts of the station." transfer_access = ACCESS_HEADS @@ -98,17 +98,19 @@ return TRUE var/obj/item/computer_hardware/card_slot/card_slot + var/obj/item/computer_hardware/card_slot/card_slot2 var/obj/item/computer_hardware/printer/printer if(computer) card_slot = computer.all_components[MC_CARD] + card_slot2 = computer.all_components[MC_CARD2] printer = computer.all_components[MC_PRINT] - if(!card_slot) + if(!card_slot || !card_slot2) return var/mob/user = usr - var/obj/item/card/id/user_id_card = user.get_idcard(FALSE) + var/obj/item/card/id/user_id_card = card_slot.stored_card - var/obj/item/card/id/id_card = card_slot.stored_card + var/obj/item/card/id/target_id_card = card_slot2.stored_card switch(action) if("PRG_authenticate") @@ -129,14 +131,14 @@ return var/contents = {"

Access Report

Prepared By: [user_id_card && user_id_card.registered_name ? user_id_card.registered_name : "Unknown"]
- For: [id_card.registered_name ? id_card.registered_name : "Unregistered"]
+ For: [target_id_card.registered_name ? target_id_card.registered_name : "Unregistered"]

- Assignment: [id_card.assignment]
+ Assignment: [target_id_card.assignment]
Access:
"} var/known_access_rights = get_all_accesses() - for(var/A in id_card.access) + for(var/A in target_id_card.access) if(A in known_access_rights) contents += " [get_access_desc(A)]" @@ -148,43 +150,40 @@ computer.visible_message("\The [computer] prints out a paper.") return TRUE if("PRG_eject") - if(!computer || !card_slot) + if(!computer || !card_slot2) return - if(id_card) - GLOB.data_core.manifest_modify(id_card.registered_name, id_card.assignment) - card_slot.try_eject(TRUE, user) + if(target_id_card) + GLOB.data_core.manifest_modify(target_id_card.registered_name, target_id_card.assignment) + return card_slot2.try_eject(user) else var/obj/item/I = user.get_active_held_item() if(istype(I, /obj/item/card/id)) - if(!user.transferItemToLoc(I, computer)) - return - card_slot.stored_card = I - playsound(computer, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) - return TRUE + return card_slot2.try_insert(I) + return FALSE if("PRG_terminate") if(!computer || !authenticated) return if(minor) - if(!(id_card.assignment in head_subordinates) && id_card.assignment != "Assistant") + if(!(target_id_card.assignment in head_subordinates) && target_id_card.assignment != "Assistant") return - id_card.access -= get_all_centcom_access() + get_all_accesses() - id_card.assignment = "Unassigned" - id_card.update_label() + target_id_card.access -= get_all_centcom_access() + get_all_accesses() + target_id_card.assignment = "Unassigned" + target_id_card.update_label() playsound(computer, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) return TRUE if("PRG_edit") - if(!computer || !authenticated || !id_card) + if(!computer || !authenticated || !target_id_card) return var/new_name = params["name"] if(!new_name) return - id_card.registered_name = new_name - id_card.update_label() + target_id_card.registered_name = new_name + target_id_card.update_label() playsound(computer, "terminal_type", 50, FALSE) return TRUE if("PRG_assign") - if(!computer || !authenticated || !id_card) + if(!computer || !authenticated || !target_id_card) return var/target = params["assign_target"] if(!target) @@ -193,8 +192,8 @@ if(target == "Custom") var/custom_name = params["custom_name"] if(custom_name) - id_card.assignment = custom_name - id_card.update_label() + target_id_card.assignment = custom_name + target_id_card.update_label() else if(minor && !(target in head_subordinates)) return @@ -212,10 +211,10 @@ to_chat(user, "No class exists for this job: [target]") return new_access = job.get_access() - id_card.access -= get_all_centcom_access() + get_all_accesses() - id_card.access |= new_access - id_card.assignment = target - id_card.update_label() + target_id_card.access -= get_all_centcom_access() + get_all_accesses() + target_id_card.access |= new_access + target_id_card.assignment = target + target_id_card.update_label() playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) return TRUE if("PRG_access") @@ -223,22 +222,22 @@ return var/access_type = text2num(params["access_target"]) if(access_type in (is_centcom ? get_all_centcom_access() : get_all_accesses())) - if(access_type in id_card.access) - id_card.access -= access_type + if(access_type in target_id_card.access) + target_id_card.access -= access_type else - id_card.access |= access_type + target_id_card.access |= access_type playsound(computer, "terminal_type", 50, FALSE) return TRUE if("PRG_grantall") if(!computer || !authenticated || minor) return - id_card.access |= (is_centcom ? get_all_centcom_access() : get_all_accesses()) + target_id_card.access |= (is_centcom ? get_all_centcom_access() : get_all_accesses()) playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) return TRUE if("PRG_denyall") if(!computer || !authenticated || minor) return - id_card.access.Cut() + target_id_card.access.Cut() playsound(computer, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) return TRUE if("PRG_grantregion") @@ -247,7 +246,7 @@ var/region = text2num(params["region"]) if(isnull(region)) return - id_card.access |= get_region_accesses(region) + target_id_card.access |= get_region_accesses(region) playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) return TRUE if("PRG_denyregion") @@ -256,7 +255,7 @@ var/region = text2num(params["region"]) if(isnull(region)) return - id_card.access -= get_region_accesses(region) + target_id_card.access -= get_region_accesses(region) playsound(computer, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) return TRUE @@ -321,17 +320,17 @@ /datum/computer_file/program/card_mod/ui_data(mob/user) var/list/data = get_header_data() - var/obj/item/computer_hardware/card_slot/card_slot + var/obj/item/computer_hardware/card_slot/card_slot2 var/obj/item/computer_hardware/printer/printer if(computer) - card_slot = computer.all_components[MC_CARD] + card_slot2 = computer.all_components[MC_CARD2] printer = computer.all_components[MC_PRINT] data["station_name"] = station_name() if(computer) - data["have_id_slot"] = !!card_slot + data["have_id_slot"] = !!(card_slot2) data["have_printer"] = !!printer else data["have_id_slot"] = FALSE @@ -340,7 +339,7 @@ data["authenticated"] = authenticated if(computer) - var/obj/item/card/id/id_card = card_slot.stored_card + var/obj/item/card/id/id_card = card_slot2.stored_card data["has_id"] = !!id_card data["id_name"] = id_card ? id_card.name : "-----" if(id_card) diff --git a/code/modules/modular_computers/file_system/programs/cargobounty.dm b/code/modules/modular_computers/file_system/programs/cargobounty.dm index d9bc65c98d..74ac44ade3 100644 --- a/code/modules/modular_computers/file_system/programs/cargobounty.dm +++ b/code/modules/modular_computers/file_system/programs/cargobounty.dm @@ -5,7 +5,6 @@ extended_desc = "A basic interface for supply personnel to check and claim bounties." requires_ntnet = TRUE transfer_access = ACCESS_CARGO - network_destination = "cargo claims interface" size = 10 tgui_id = "NtosBountyConsole" ///cooldown var for printing paper sheets. diff --git a/code/modules/modular_computers/file_system/programs/cargoship.dm b/code/modules/modular_computers/file_system/programs/cargoship.dm index 3ba08a3719..db8d6d9f82 100644 --- a/code/modules/modular_computers/file_system/programs/cargoship.dm +++ b/code/modules/modular_computers/file_system/programs/cargoship.dm @@ -1,9 +1,8 @@ /datum/computer_file/program/shipping filename = "shipping" - filedesc = "Nanotrasen Shipping Scanner" + filedesc = "GrandArk Exporter" program_icon_state = "shipping" extended_desc = "A combination printer/scanner app that enables modular computers to print barcodes for easy scanning and shipping." - network_destination = "ship scanner" size = 6 tgui_id = "NtosShipping" ///Account used for creating barcodes. diff --git a/code/modules/modular_computers/file_system/programs/crewmanifest.dm b/code/modules/modular_computers/file_system/programs/crewmanifest.dm index a1503ce3a8..4f2688d8f1 100644 --- a/code/modules/modular_computers/file_system/programs/crewmanifest.dm +++ b/code/modules/modular_computers/file_system/programs/crewmanifest.dm @@ -1,10 +1,10 @@ /datum/computer_file/program/crew_manifest - filename = "crewmani" - filedesc = "Crew Manifest" + filename = "plexagoncrew" + filedesc = "Plexagon Crew List" program_icon_state = "id" extended_desc = "Program for viewing and printing the current crew manifest" transfer_access = ACCESS_HEADS - requires_ntnet = FALSE + requires_ntnet = TRUE size = 4 tgui_id = "NtosCrewManifest" diff --git a/code/modules/modular_computers/file_system/programs/jobmanagement.dm b/code/modules/modular_computers/file_system/programs/jobmanagement.dm index bccc6e4dbe..b88b793b66 100644 --- a/code/modules/modular_computers/file_system/programs/jobmanagement.dm +++ b/code/modules/modular_computers/file_system/programs/jobmanagement.dm @@ -1,10 +1,10 @@ /datum/computer_file/program/job_management - filename = "job_manage" - filedesc = "Job Manager" + filename = "plexagoncore" + filedesc = "Plexagon HR Core" program_icon_state = "id" extended_desc = "Program for viewing and changing job slot avalibility." transfer_access = ACCESS_HEADS - requires_ntnet = 0 + requires_ntnet = TRUE size = 4 tgui_id = "NtosJobManager" diff --git a/code/modules/modular_computers/file_system/programs/ntdownloader.dm b/code/modules/modular_computers/file_system/programs/ntdownloader.dm index 6401d6207f..8fbcfd0b01 100644 --- a/code/modules/modular_computers/file_system/programs/ntdownloader.dm +++ b/code/modules/modular_computers/file_system/programs/ntdownloader.dm @@ -1,14 +1,14 @@ /datum/computer_file/program/ntnetdownload - filename = "ntndownloader" - filedesc = "Software Download Tool" + filename = "ntsoftwarehub" + filedesc = "NT Software Hub" program_icon_state = "generic" extended_desc = "This program allows downloads of software from official NT repositories" - unsendable = 1 - undeletable = 1 + unsendable = TRUE + undeletable = TRUE size = 4 - requires_ntnet = 1 + requires_ntnet = TRUE requires_ntnet_feature = NTNET_SOFTWAREDOWNLOAD - available_on_ntnet = 0 + available_on_ntnet = FALSE ui_header = "downloader_finished.gif" tgui_id = "NtosNetDownloader" @@ -125,6 +125,8 @@ if(!istype(my_computer)) return + var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD] + var/list/access = card_slot?.GetAccess() var/list/data = get_header_data() @@ -146,7 +148,7 @@ for(var/A in main_repo) var/datum/computer_file/program/P = A // Only those programs our user can run will show in the list - if(!P.can_run(user,transfer = 1) || hard_drive.find_file_by_name(P.filename)) + if(!P.can_run(user,transfer = 1, access = access) || hard_drive.find_file_by_name(P.filename)) continue all_entries.Add(list(list( "filename" = P.filename, diff --git a/code/modules/modular_computers/file_system/programs/ntmonitor.dm b/code/modules/modular_computers/file_system/programs/ntmonitor.dm index 7d6d89f32c..bbbde14780 100644 --- a/code/modules/modular_computers/file_system/programs/ntmonitor.dm +++ b/code/modules/modular_computers/file_system/programs/ntmonitor.dm @@ -1,6 +1,6 @@ /datum/computer_file/program/ntnetmonitor - filename = "ntmonitor" - filedesc = "NTNet Diagnostics and Monitoring" + filename = "wirecarp" + filedesc = "WireCarp" //wireshark. program_icon_state = "comm_monitor" extended_desc = "This program monitors stationwide NTNet network, provides access to logging systems, and allows for configuration changes" size = 12 diff --git a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm index df9b02d8ec..f03ff3f8fd 100644 --- a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm +++ b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm @@ -6,7 +6,6 @@ size = 8 requires_ntnet = 1 requires_ntnet_feature = NTNET_COMMUNICATION - network_destination = "NTNRC server" ui_header = "ntnrc_idle.gif" available_on_ntnet = 1 tgui_id = "NtosNetChat" diff --git a/code/modules/modular_computers/file_system/programs/powermonitor.dm b/code/modules/modular_computers/file_system/programs/powermonitor.dm index bd11474858..e87a731a40 100644 --- a/code/modules/modular_computers/file_system/programs/powermonitor.dm +++ b/code/modules/modular_computers/file_system/programs/powermonitor.dm @@ -1,15 +1,14 @@ //normal computer version is located in code\modules\power\monitor.dm, /obj/machinery/computer/monitor /datum/computer_file/program/power_monitor - filename = "powermonitor" - filedesc = "Power Monitor" + filename = "ampcheck" + filedesc = "AmpCheck" program_icon_state = "power_monitor" extended_desc = "This program connects to sensors around the station to provide information about electrical systems" ui_header = "power_norm.gif" transfer_access = ACCESS_ENGINE usage_flags = PROGRAM_CONSOLE requires_ntnet = 0 - network_destination = "power monitoring system" size = 9 tgui_id = "NtosPowerMonitor" diff --git a/code/modules/modular_computers/file_system/programs/radar.dm b/code/modules/modular_computers/file_system/programs/radar.dm index 9b0e09ef99..216365d6ea 100644 --- a/code/modules/modular_computers/file_system/programs/radar.dm +++ b/code/modules/modular_computers/file_system/programs/radar.dm @@ -7,7 +7,6 @@ transfer_access = null available_on_ntnet = FALSE usage_flags = PROGRAM_LAPTOP | PROGRAM_TABLET - network_destination = "tracking program" size = 5 tgui_id = "NtosRadar" ///List of trackable entities. Updated by the scan() proc. @@ -207,7 +206,7 @@ ///A program that tracks crew members via suit sensors /datum/computer_file/program/radar/lifeline - filename = "Lifeline" + filename = "lifeline" filedesc = "Lifeline" extended_desc = "This program allows for tracking of crew members via their suit sensors." requires_ntnet = TRUE @@ -252,9 +251,9 @@ //Nuke Disk Finder App// //////////////////////// -///A program that tracks crew members via suit sensors +///A program that tracks nukes and nuclear accessories /datum/computer_file/program/radar/fission360 - filename = "Fission360" + filename = "fission360" filedesc = "Fission360" program_icon_state = "radarsyndicate" extended_desc = "This program allows for tracking of nuclear authorization disks and warheads." @@ -276,8 +275,6 @@ objects = list() for(var/i in GLOB.nuke_list) var/obj/machinery/nuclearbomb/nuke = i - if(!trackable(nuke)) - continue var/list/nukeinfo = list( ref = REF(nuke), @@ -285,9 +282,8 @@ ) objects += list(nukeinfo) var/obj/item/disk/nuclear/disk = locate() in GLOB.poi_list - if(trackable(disk)) - var/list/nukeinfo = list( - ref = REF(disk), - name = disk.name, - ) - objects += list(nukeinfo) + var/list/nukeinfo = list( + ref = REF(disk), + name = "Nuke Auth. Disk", + ) + objects += list(nukeinfo) diff --git a/code/modules/modular_computers/file_system/programs/robocontrol.dm b/code/modules/modular_computers/file_system/programs/robocontrol.dm index 8644ce09b4..c0b82b9c95 100644 --- a/code/modules/modular_computers/file_system/programs/robocontrol.dm +++ b/code/modules/modular_computers/file_system/programs/robocontrol.dm @@ -1,12 +1,11 @@ /datum/computer_file/program/robocontrol - filename = "robocontrol" - filedesc = "Bot Remote Controller" + filename = "botkeeper" + filedesc = "Botkeeper" program_icon_state = "robot" extended_desc = "A remote controller used for giving basic commands to non-sentient robots." transfer_access = ACCESS_ROBOTICS requires_ntnet = TRUE - network_destination = "robotics control network" size = 12 tgui_id = "NtosRoboControl" ///Number of simple robots on-station. @@ -78,7 +77,7 @@ return if(id_card) GLOB.data_core.manifest_modify(id_card.registered_name, id_card.assignment) - card_slot.try_eject(TRUE, current_user) + card_slot.try_eject(current_user) else playsound(get_turf(ui_host()) , 'sound/machines/buzz-sigh.ogg', 25, FALSE) return diff --git a/code/modules/modular_computers/file_system/programs/sm_monitor.dm b/code/modules/modular_computers/file_system/programs/sm_monitor.dm index 32ad102871..e4cf590930 100644 --- a/code/modules/modular_computers/file_system/programs/sm_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/sm_monitor.dm @@ -1,12 +1,11 @@ /datum/computer_file/program/supermatter_monitor - filename = "smmonitor" - filedesc = "Supermatter Monitoring" + filename = "ntcims" + filedesc = "NT CIMS" ui_header = "smmon_0.gif" program_icon_state = "smmon_0" - extended_desc = "This program connects to specially calibrated supermatter sensors to provide information on the status of supermatter-based engines." + extended_desc = "Crystal Integrity Monitoring System, connects to specially calibrated supermatter sensors to provide information on the status of supermatter-based engines." requires_ntnet = TRUE transfer_access = ACCESS_CONSTRUCTION - network_destination = "supermatter monitoring system" size = 5 tgui_id = "NtosSupermatterMonitor" var/last_status = SUPERMATTER_INACTIVE diff --git a/code/modules/modular_computers/hardware/_hardware.dm b/code/modules/modular_computers/hardware/_hardware.dm index b33442f99b..81555340b2 100644 --- a/code/modules/modular_computers/hardware/_hardware.dm +++ b/code/modules/modular_computers/hardware/_hardware.dm @@ -10,9 +10,11 @@ // Computer that holds this hardware, if any. var/power_usage = 0 // If the hardware uses extra power, change this. - var/enabled = 1 // If the hardware is turned off set this to 0. - var/critical = 0 // Prevent disabling for important component, like the CPU. - var/can_install = 1 // Prevents direct installation of removable media. + var/enabled = TRUE // If the hardware is turned off set this to 0. + var/critical = FALSE // Prevent disabling for important component, like the CPU. + var/can_install = TRUE // Prevents direct installation of removable media. + var/expansion_hw = FALSE // Hardware that fits into expansion bays. + var/removable = TRUE // Whether the hardware is removable or not. var/damage = 0 // Current damage level var/max_damage = 100 // Maximal damage level. var/damage_malfunction = 20 // "Malfunction" threshold. When damage exceeds this value the hardware piece will semi-randomly fail and do !!FUN!! things @@ -20,7 +22,7 @@ var/malfunction_probability = 10// Chance of malfunction when the component is damaged var/device_type -/obj/item/computer_hardware/New(var/obj/L) +/obj/item/computer_hardware/New(obj/L) ..() pixel_x = rand(-8, 8) pixel_y = rand(-8, 8) @@ -56,7 +58,7 @@ return TRUE // Called on multitool click, prints diagnostic information to the user. -/obj/item/computer_hardware/proc/diagnostics(var/mob/user) +/obj/item/computer_hardware/proc/diagnostics(mob/user) to_chat(user, "Hardware Integrity Test... (Corruption: [damage]/[max_damage]) [damage > damage_failure ? "FAIL" : damage > damage_malfunction ? "WARN" : "PASS"]") // Handles damage checks @@ -73,7 +75,7 @@ return TRUE // Good to go. -/obj/item/computer_hardware/examine(var/mob/user) +/obj/item/computer_hardware/examine(mob/user) . = ..() if(damage > damage_failure) . += "It seems to be severely damaged!" diff --git a/code/modules/modular_computers/hardware/ai_slot.dm b/code/modules/modular_computers/hardware/ai_slot.dm index 0ad157afcb..c874d786a0 100644 --- a/code/modules/modular_computers/hardware/ai_slot.dm +++ b/code/modules/modular_computers/hardware/ai_slot.dm @@ -5,6 +5,7 @@ icon_state = "card_mini" w_class = WEIGHT_CLASS_SMALL device_type = MC_AI + expansion_hw = TRUE var/obj/item/aicard/stored_card = null var/locked = FALSE @@ -19,12 +20,6 @@ if(stored_card) . += "There appears to be an intelliCard loaded. There appears to be a pinhole protecting a manual eject button. A screwdriver could probably press it." -/obj/item/computer_hardware/ai_slot/on_install(obj/item/modular_computer/M, mob/living/user = null) - M.add_verb(device_type) - -/obj/item/computer_hardware/ai_slot/on_remove(obj/item/modular_computer/M, mob/living/user = null) - M.remove_verb(device_type) - /obj/item/computer_hardware/ai_slot/try_insert(obj/item/I, mob/living/user = null) if(!holder) return FALSE @@ -44,7 +39,7 @@ return TRUE -/obj/item/computer_hardware/ai_slot/try_eject(slot=0,mob/living/user = null,forced = 0) +/obj/item/computer_hardware/ai_slot/try_eject(mob/living/user = null,forced = FALSE) if(!stored_card) to_chat(user, "There is no card in \the [src].") return FALSE diff --git a/code/modules/modular_computers/hardware/battery_module.dm b/code/modules/modular_computers/hardware/battery_module.dm index 6e3193abfd..0668248315 100644 --- a/code/modules/modular_computers/hardware/battery_module.dm +++ b/code/modules/modular_computers/hardware/battery_module.dm @@ -21,7 +21,7 @@ /obj/item/computer_hardware/battery/handle_atom_del(atom/A) if(A == battery) - try_eject(0, null, TRUE) + try_eject(forced = TRUE) . = ..() /obj/item/computer_hardware/battery/try_insert(obj/item/I, mob/living/user = null) @@ -48,7 +48,7 @@ return TRUE -/obj/item/computer_hardware/battery/try_eject(slot=0, mob/living/user = null, forced = 0) +/obj/item/computer_hardware/battery/try_eject(mob/living/user = null, forced = FALSE) if(!battery) to_chat(user, "There is no power cell connected to \the [src].") return FALSE diff --git a/code/modules/modular_computers/hardware/card_slot.dm b/code/modules/modular_computers/hardware/card_slot.dm index 18b423a42e..c243bf7db1 100644 --- a/code/modules/modular_computers/hardware/card_slot.dm +++ b/code/modules/modular_computers/hardware/card_slot.dm @@ -7,13 +7,10 @@ device_type = MC_CARD var/obj/item/card/id/stored_card = null - var/obj/item/card/id/stored_card2 = null /obj/item/computer_hardware/card_slot/handle_atom_del(atom/A) if(A == stored_card) - try_eject(1, null, TRUE) - if(A == stored_card2) - try_eject(2, null, TRUE) + try_eject(null, TRUE) . = ..() /obj/item/computer_hardware/card_slot/Destroy() @@ -21,37 +18,25 @@ return ..() /obj/item/computer_hardware/card_slot/GetAccess() - if(stored_card && stored_card2) // Best of both worlds - return (stored_card.GetAccess() | stored_card2.GetAccess()) - else if(stored_card) - return stored_card.GetAccess() - else if(stored_card2) - return stored_card2.GetAccess() - return ..() + var/list/total_access + if(stored_card) + total_access = stored_card.GetAccess() + var/obj/item/computer_hardware/card_slot/card_slot2 = holder?.all_components[MC_CARD2] //Best of both worlds + if(card_slot2?.stored_card) + total_access |= card_slot2.stored_card.GetAccess() + return total_access /obj/item/computer_hardware/card_slot/GetID() if(stored_card) return stored_card - else if(stored_card2) - return stored_card2 return ..() /obj/item/computer_hardware/card_slot/RemoveID() if(stored_card) . = stored_card - if(!try_eject(1)) + if(!try_eject()) return null return - if(stored_card2) - . = stored_card2 - if(!try_eject(2)) - return null - -/obj/item/computer_hardware/card_slot/on_install(obj/item/modular_computer/M, mob/living/user = null) - M.add_verb(device_type) - -/obj/item/computer_hardware/card_slot/on_remove(obj/item/modular_computer/M, mob/living/user = null) - M.remove_verb(device_type) /obj/item/computer_hardware/card_slot/try_insert(obj/item/I, mob/living/user = null) if(!holder) @@ -60,8 +45,7 @@ if(!istype(I, /obj/item/card/id)) return FALSE - if(stored_card && stored_card2) - to_chat(user, "You try to insert \the [I] into \the [src], but its slots are occupied.") + if(stored_card) return FALSE if(user) if(!user.transferItemToLoc(I, src)) @@ -69,11 +53,8 @@ else I.forceMove(src) - if(!stored_card) - stored_card = I - else - stored_card2 = I - to_chat(user, "You insert \the [I] into \the [src].") + stored_card = I + to_chat(user, "You insert \the [I] into \the [expansion_hw ? "secondary":"primary"] [src].") playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) if(ishuman(user)) var/mob/living/carbon/human/H = user @@ -82,53 +63,58 @@ return TRUE -/obj/item/computer_hardware/card_slot/try_eject(slot=0, mob/living/user = null, forced = 0) - if(!stored_card && !stored_card2) +/obj/item/computer_hardware/card_slot/try_eject(mob/living/user = null, forced = FALSE) + if(!stored_card) to_chat(user, "There are no cards in \the [src].") return FALSE - var/ejected = 0 - if(stored_card && (!slot || slot == 1)) - if(user) - user.put_in_hands(stored_card) - else - stored_card.forceMove(drop_location()) - stored_card = null - ejected++ + if(user) + user.put_in_hands(stored_card) + else + stored_card.forceMove(drop_location()) + stored_card = null - if(stored_card2 && (!slot || slot == 2)) - if(user) - user.put_in_hands(stored_card2) - else - stored_card2.forceMove(drop_location()) - stored_card2 = null - ejected++ + if(holder) + if(holder.active_program) + holder.active_program.event_idremoved(0) - if(ejected) - if(holder) - if(holder.active_program) - holder.active_program.event_idremoved(0, slot) - - for(var/I in holder.idle_threads) - var/datum/computer_file/program/P = I - P.event_idremoved(1, slot) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - H.sec_hud_set_ID() - to_chat(user, "You remove the card[ejected>1 ? "s" : ""] from \the [src].") - playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) - return TRUE - return FALSE + for(var/p in holder.idle_threads) + var/datum/computer_file/program/computer_program = p + computer_program.event_idremoved(1) + if(ishuman(user)) + var/mob/living/carbon/human/human_user = user + human_user.sec_hud_set_ID() + to_chat(user, "You remove the card from \the [src].") + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + return TRUE /obj/item/computer_hardware/card_slot/attackby(obj/item/I, mob/living/user) if(..()) return if(I.tool_behaviour == TOOL_SCREWDRIVER) - to_chat(user, "You press down on the manual eject button with \the [I].") - try_eject(0,user) - return + if(stored_card) + to_chat(user, "You press down on the manual eject button with \the [I].") + try_eject(user) + return + swap_slot() + to_chat(user, "You adjust the connecter to fit into [expansion_hw ? "an expansion bay" : "the primary ID bay"].") + +/** + *Swaps the card_slot hardware between using the dedicated card slot bay on a computer, and using an expansion bay. +*/ +/obj/item/computer_hardware/card_slot/proc/swap_slot() + expansion_hw = !expansion_hw + if(expansion_hw) + device_type = MC_CARD2 + else + device_type = MC_CARD /obj/item/computer_hardware/card_slot/examine(mob/user) . = ..() - if(stored_card || stored_card2) + . += "The connector is set to fit into [expansion_hw ? "an expansion bay" : "a computer's primary ID bay"], but can be adjusted with a screwdriver." + if(stored_card) . += "There appears to be something loaded in the card slots." + +/obj/item/computer_hardware/card_slot/secondary + device_type = MC_CARD2 + expansion_hw = TRUE diff --git a/code/modules/modular_computers/hardware/hard_drive.dm b/code/modules/modular_computers/hardware/hard_drive.dm index b8b9624388..e5c133de20 100644 --- a/code/modules/modular_computers/hardware/hard_drive.dm +++ b/code/modules/modular_computers/hardware/hard_drive.dm @@ -22,14 +22,14 @@ . = ..() . += "It has [max_capacity] GQ of storage capacity." -/obj/item/computer_hardware/hard_drive/diagnostics(var/mob/user) +/obj/item/computer_hardware/hard_drive/diagnostics(mob/user) ..() // 999 is a byond limit that is in place. It's unlikely someone will reach that many files anyway, since you would sooner run out of space. to_chat(user, "NT-NFS File Table Status: [stored_files.len]/999") to_chat(user, "Storage capacity: [used_capacity]/[max_capacity]GQ") // Use this proc to add file to the drive. Returns 1 on success and 0 on failure. Contains necessary sanity checks. -/obj/item/computer_hardware/hard_drive/proc/store_file(var/datum/computer_file/F) +/obj/item/computer_hardware/hard_drive/proc/store_file(datum/computer_file/F) if(!F || !istype(F)) return 0 @@ -52,7 +52,7 @@ return 1 // Use this proc to remove file from the drive. Returns 1 on success and 0 on failure. Contains necessary sanity checks. -/obj/item/computer_hardware/hard_drive/proc/remove_file(var/datum/computer_file/F) +/obj/item/computer_hardware/hard_drive/proc/remove_file(datum/computer_file/F) if(!F || !istype(F)) return 0 @@ -78,7 +78,7 @@ used_capacity = total_size // Checks whether file can be stored on the hard drive. We can only store unique files, so this checks whether we wouldn't get a duplicity by adding a file. -/obj/item/computer_hardware/hard_drive/proc/can_store_file(var/datum/computer_file/F) +/obj/item/computer_hardware/hard_drive/proc/can_store_file(datum/computer_file/F) if(!F || !istype(F)) return 0 @@ -101,7 +101,7 @@ // Tries to find the file by filename. Returns null on failure -/obj/item/computer_hardware/hard_drive/proc/find_file_by_name(var/filename) +/obj/item/computer_hardware/hard_drive/proc/find_file_by_name(filename) if(!check_functionality()) return null diff --git a/code/modules/modular_computers/hardware/network_card.dm b/code/modules/modular_computers/hardware/network_card.dm index fe1b1879cb..04bf494fe4 100644 --- a/code/modules/modular_computers/hardware/network_card.dm +++ b/code/modules/modular_computers/hardware/network_card.dm @@ -11,7 +11,7 @@ device_type = MC_NET var/static/ntnet_card_uid = 1 -/obj/item/computer_hardware/network_card/diagnostics(var/mob/user) +/obj/item/computer_hardware/network_card/diagnostics(mob/user) ..() to_chat(user, "NIX Unique ID: [identification_id]") to_chat(user, "NIX User Tag: [identification_string]") @@ -22,7 +22,7 @@ if(ethernet) to_chat(user, "OpenEth (Physical Connection) - Physical network connection port") -/obj/item/computer_hardware/network_card/New(var/l) +/obj/item/computer_hardware/network_card/New(l) ..() identification_id = ntnet_card_uid++ @@ -31,7 +31,7 @@ return "[identification_string] (NID [identification_id])" // 0 - No signal, 1 - Low signal, 2 - High signal. 3 - Wired Connection -/obj/item/computer_hardware/network_card/proc/get_signal(var/specific_action = 0) +/obj/item/computer_hardware/network_card/proc/get_signal(specific_action = 0) if(!holder) // Hardware is not installed in anything. No signal. How did this even get called? return 0 diff --git a/code/modules/modular_computers/hardware/portable_disk.dm b/code/modules/modular_computers/hardware/portable_disk.dm index b5a957be04..89b0382e86 100644 --- a/code/modules/modular_computers/hardware/portable_disk.dm +++ b/code/modules/modular_computers/hardware/portable_disk.dm @@ -8,12 +8,8 @@ max_capacity = 16 device_type = MC_SDD -/obj/item/computer_hardware/hard_drive/portable/on_install(obj/item/modular_computer/M, mob/living/user = null) - M.add_verb(device_type) - -/obj/item/computer_hardware/hard_drive/portable/on_remove(obj/item/modular_computer/M, mob/living/user = null) - ..() - M.remove_verb(device_type) +/obj/item/computer_hardware/hard_drive/portable/on_remove(obj/item/modular_computer/MC, mob/user) + return //this is a floppy disk, let's not shut the computer down when it gets pulled out. /obj/item/computer_hardware/hard_drive/portable/install_default_programs() return // Empty by default diff --git a/code/modules/modular_computers/hardware/printer.dm b/code/modules/modular_computers/hardware/printer.dm index ebe40c1922..3bd5946435 100644 --- a/code/modules/modular_computers/hardware/printer.dm +++ b/code/modules/modular_computers/hardware/printer.dm @@ -5,6 +5,7 @@ icon_state = "printer" w_class = WEIGHT_CLASS_NORMAL device_type = MC_PRINT + expansion_hw = TRUE var/stored_paper = 20 var/max_paper = 30 diff --git a/code/modules/modular_computers/hardware/sensor_package.dm b/code/modules/modular_computers/hardware/sensor_package.dm new file mode 100644 index 0000000000..c0363bc809 --- /dev/null +++ b/code/modules/modular_computers/hardware/sensor_package.dm @@ -0,0 +1,8 @@ +//This item doesn't do much on its own, but is required by apps such as AtmoZphere. +/obj/item/computer_hardware/sensorpackage + name = "sensor package" + desc = "An integrated sensor package allowing a computer to take readings from the environment. Required by certain programs." + icon_state = "servo" + w_class = WEIGHT_CLASS_TINY + device_type = MC_SENSORS + expansion_hw = TRUE diff --git a/code/modules/modular_computers/laptop_vendor.dm b/code/modules/modular_computers/laptop_vendor.dm index a8d30bad21..83bb057d66 100644 --- a/code/modules/modular_computers/laptop_vendor.dm +++ b/code/modules/modular_computers/laptop_vendor.dm @@ -52,6 +52,7 @@ var/obj/item/computer_hardware/battery/battery_module = null if(fabricate) fabricated_laptop = new /obj/item/modular_computer/laptop/buildable(src) + fabricated_laptop.install_component(new /obj/item/computer_hardware/card_slot) fabricated_laptop.install_component(new /obj/item/computer_hardware/battery) battery_module = fabricated_laptop.all_components[MC_CELL] total_price = 99 @@ -107,7 +108,7 @@ if(dev_card) total_price += 199 if(fabricate) - fabricated_laptop.install_component(new /obj/item/computer_hardware/card_slot) + fabricated_laptop.install_component(new /obj/item/computer_hardware/card_slot/secondary) return total_price else if(devtype == 2) // Tablet, more expensive, not everyone could probably afford this. @@ -116,6 +117,7 @@ fabricated_tablet = new(src) fabricated_tablet.install_component(new /obj/item/computer_hardware/battery) fabricated_tablet.install_component(new /obj/item/computer_hardware/processor_unit/small) + fabricated_tablet.install_component(new/obj/item/computer_hardware/card_slot) battery_module = fabricated_tablet.all_components[MC_CELL] total_price = 199 switch(dev_battery) @@ -154,11 +156,11 @@ if(dev_printer) total_price += 99 if(fabricate) - fabricated_tablet.install_component(new/obj/item/computer_hardware/printer) + fabricated_tablet.install_component(new/obj/item/computer_hardware/printer/mini) if(dev_card) total_price += 199 if(fabricate) - fabricated_tablet.install_component(new/obj/item/computer_hardware/card_slot) + fabricated_tablet.install_component(new/obj/item/computer_hardware/card_slot/secondary) return total_price return FALSE @@ -257,7 +259,7 @@ say("Insufficient credits on card to purchase!") return credits += target_credits - say("[target_credits] cr has been deposited from your account.") + say("[target_credits] cr have been withdrawn from your account.") return return ..() diff --git a/code/modules/newscaster/newscaster_machine.dm b/code/modules/newscaster/newscaster_machine.dm index cb2d49fc64..7e515bf0f5 100644 --- a/code/modules/newscaster/newscaster_machine.dm +++ b/code/modules/newscaster/newscaster_machine.dm @@ -95,6 +95,10 @@ GLOBAL_LIST_EMPTY(allCasters) . = ..() update_icon() +/obj/machinery/newscaster/attack_ghost(mob/dead/observer/user) + if(istype(user)) + user.read_news() + /obj/machinery/newscaster/ui_interact(mob/user) . = ..() if(ishuman(user) || issilicon(user)) @@ -336,7 +340,6 @@ GLOBAL_LIST_EMPTY(allCasters) dat+="Return" var/datum/browser/popup = new(human_or_robot_user, "newscaster_main", "Newscaster Unit #[unit_no]", 400, 600) popup.set_content(dat) - popup.set_title_image(human_or_robot_user.browse_rsc_icon(icon, icon_state)) popup.open() /obj/machinery/newscaster/Topic(href, href_list) diff --git a/code/modules/paperwork/carbonpaper.dm b/code/modules/paperwork/carbonpaper.dm new file mode 100644 index 0000000000..dc8f172069 --- /dev/null +++ b/code/modules/paperwork/carbonpaper.dm @@ -0,0 +1,45 @@ +/obj/item/paper/carbon + name = "sheet of carbon" + icon_state = "paper_stack" + item_state = "paper" + // inhand_icon_state = "paper" + show_written_words = FALSE + var/copied = FALSE + var/iscopy = FALSE + +/obj/item/paper/carbon/update_icon_state() + if(iscopy) + icon_state = "cpaper" + else if(copied) + icon_state = "paper" + else + icon_state = "paper_stack" + if(info) + icon_state = "[icon_state]_words" + +/obj/item/paper/carbon/proc/removecopy(mob/living/user) + if(!copied) + var/obj/item/paper/carbon/C = src + var/copycontents = C.info + var/obj/item/paper/carbon/Copy = new /obj/item/paper/carbon(user.loc) + + if(info) + copycontents = replacetext(copycontents, "" + Copy.name = "Copy - [C.name]" + to_chat(user, "You tear off the carbon-copy!") + C.copied = TRUE + Copy.iscopy = TRUE + Copy.update_icon_state() + C.update_icon_state() + user.put_in_hands(Copy) + else + to_chat(user, "There are no more carbon copies attached to this paper!") + +/obj/item/paper/carbon/on_attack_hand(mob/living/user) + if(loc == user && user.is_holding(src)) + removecopy(user) + return + return ..() diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm index 1a93661c76..5b576a2438 100644 --- a/code/modules/paperwork/clipboard.dm +++ b/code/modules/paperwork/clipboard.dm @@ -3,6 +3,8 @@ icon = 'icons/obj/bureaucracy.dmi' icon_state = "clipboard" item_state = "clipboard" + // inhand_icon_state = "clipboard" + // worn_icon_state = "clipboard" throwforce = 0 w_class = WEIGHT_CLASS_SMALL throw_speed = 3 @@ -34,7 +36,6 @@ . += "clipboard_pen" . += "clipboard_over" - /obj/item/clipboard/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/paper)) if(!user.transferItemToLoc(W, src)) @@ -92,14 +93,14 @@ to_chat(usr, "You slot [W] into [src].") if(href_list["write"]) - var/obj/item/P = locate(href_list["write"]) - if(istype(P) && P.loc == src) + var/obj/item/P = locate(href_list["write"]) in src + if(istype(P)) if(usr.get_active_held_item()) P.attackby(usr.get_active_held_item(), usr) if(href_list["remove"]) - var/obj/item/P = locate(href_list["remove"]) - if(istype(P) && P.loc == src) + var/obj/item/P = locate(href_list["remove"]) in src + if(istype(P)) P.forceMove(usr.loc) usr.put_in_hands(P) if(P == toppaper) @@ -111,13 +112,13 @@ toppaper = null if(href_list["read"]) - var/obj/item/paper/P = locate(href_list["read"]) - if(istype(P) && P.loc == src) + var/obj/item/paper/P = locate(href_list["read"]) in src + if(istype(P)) usr.examinate(P) if(href_list["top"]) - var/obj/item/P = locate(href_list["top"]) - if(istype(P) && P.loc == src) + var/obj/item/P = locate(href_list["top"]) in src + if(istype(P)) toppaper = P to_chat(usr, "You move [P.name] to the top.") diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index b8f2c95762..390cd0cf83 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -35,7 +35,7 @@ . = ..() if(mapload) for(var/obj/item/I in loc) - if(istype(I, /obj/item/paper) || istype(I, /obj/item/folder) || istype(I, /obj/item/photo)) + if(I.w_class < WEIGHT_CLASS_NORMAL) //there probably shouldn't be anything placed ontop of filing cabinets in a map that isn't meant to go in them I.forceMove(src) /obj/structure/filingcabinet/deconstruct(disassembled = TRUE) @@ -46,7 +46,12 @@ qdel(src) /obj/structure/filingcabinet/attackby(obj/item/P, mob/user, params) - if(istype(P, /obj/item/paper) || istype(P, /obj/item/folder) || istype(P, /obj/item/photo) || istype(P, /obj/item/documents)) + if(P.tool_behaviour == TOOL_WRENCH && user.a_intent != INTENT_HELP) + to_chat(user, "You begin to [anchored ? "unwrench" : "wrench"] [src].") + if(P.use_tool(src, user, 20, volume=50)) + to_chat(user, "You successfully [anchored ? "unwrench" : "wrench"] [src].") + anchored = !anchored + else if(P.w_class < WEIGHT_CLASS_NORMAL) if(!user.transferItemToLoc(P, src)) return to_chat(user, "You put [P] in [src].") @@ -54,11 +59,6 @@ sleep(5) icon_state = initial(icon_state) updateUsrDialog() - else if(istype(P, /obj/item/wrench)) - to_chat(user, "You begin to [anchored ? "unwrench" : "wrench"] [src].") - if(P.use_tool(src, user, 20, volume=50)) - to_chat(user, "You successfully [anchored ? "unwrench" : "wrench"] [src].") - anchored = !anchored else if(user.a_intent != INTENT_HARM) to_chat(user, "You can't put [P] in [src]!") else @@ -67,9 +67,6 @@ /obj/structure/filingcabinet/ui_interact(mob/user) . = ..() - if(isobserver(user)) - return - if(contents.len <= 0) to_chat(user, "[src] is empty.") return @@ -100,16 +97,17 @@ to_chat(user, "You find nothing in [src].") /obj/structure/filingcabinet/Topic(href, href_list) + if(!usr.canUseTopic(src, BE_CLOSE, ismonkey(usr))) + return if(href_list["retrieve"]) usr << browse("", "window=filingcabinet") // Close the menu - var/obj/item/P = locate(href_list["retrieve"])//contents[retrieveindex] - if(istype(P) && P.loc == src && in_range(src, usr)) + var/obj/item/P = locate(href_list["retrieve"]) in src //contents[retrieveindex] + if(istype(P) && in_range(src, usr)) usr.put_in_hands(P) updateUsrDialog() icon_state = "[initial(icon_state)]-open" - sleep(5) - icon_state = initial(icon_state) + addtimer(VARSET_CALLBACK(src, icon_state, initial(icon_state)), 5) /* @@ -170,6 +168,7 @@ virgin = 0 //tabbing here is correct- it's possible for people to try and use it //before the records have been generated, so we do this inside the loop. +//ATTACK HAND IGNORING PARENT RETURN VALUE /obj/structure/filingcabinet/medical/on_attack_hand() populate() . = ..() diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm index c32afab342..305099d115 100644 --- a/code/modules/paperwork/folders.dm +++ b/code/modules/paperwork/folders.dm @@ -33,7 +33,10 @@ if(contents.len) . += "folder_paper" + /obj/item/folder/attackby(obj/item/W, mob/user, params) + if(burn_paper_product_attackby_check(W, user)) + return if(istype(W, /obj/item/paper) || istype(W, /obj/item/photo) || istype(W, /obj/item/documents)) if(!user.transferItemToLoc(W, src)) return @@ -43,11 +46,14 @@ if(!user.is_literate()) to_chat(user, "You scribble illegibly on the cover of [src]!") return + var/inputvalue = stripped_input(user, "What would you like to label the folder?", "Folder Labelling", "", MAX_NAME_LEN) + if(!inputvalue) return + if(user.canUseTopic(src, BE_CLOSE)) - name = "folder - '[inputvalue]'" + name = "folder[(inputvalue ? " - '[inputvalue]'" : null)]" /obj/item/folder/Destroy() @@ -76,14 +82,14 @@ if(usr.contents.Find(src)) if(href_list["remove"]) - var/obj/item/I = locate(href_list["remove"]) - if(istype(I) && I.loc == src) + var/obj/item/I = locate(href_list["remove"]) in src + if(istype(I)) I.forceMove(usr.loc) usr.put_in_hands(I) if(href_list["read"]) - var/obj/item/I = locate(href_list["read"]) - if(istype(I) && I.loc == src) + var/obj/item/I = locate(href_list["read"]) in src + if(istype(I)) usr.examinate(I) //Update everything diff --git a/code/modules/paperwork/handlabeler.dm b/code/modules/paperwork/handlabeler.dm index d054e5ff12..da9fdc4ca4 100644 --- a/code/modules/paperwork/handlabeler.dm +++ b/code/modules/paperwork/handlabeler.dm @@ -1,9 +1,10 @@ /obj/item/hand_labeler name = "hand labeler" - desc = "A combined label printer and applicator in a portable device, designed to be easy to operate and use." + desc = "A combined label printer, applicator, and remover, all in a single portable device. Designed to be easy to operate and use." icon = 'icons/obj/bureaucracy.dmi' icon_state = "labeler0" item_state = "flight" + // inhand_icon_state = "flight" var/label = null var/labels_left = 30 var/mode = 0 @@ -55,9 +56,10 @@ to_chat(user, "You can't label creatures!") // use a collar return - user.visible_message("[user] labels [A] as [label].", \ - "You label [A] as [label].") - A.name = "[A.name] ([label])" + user.visible_message("[user] labels [A] with \"[label]\".", \ + "You label [A] with \"[label]\".") + A.AddComponent(/datum/component/label, label) + // playsound(A, 'sound/items/handling/component_pickup.ogg', 20, TRUE) labels_left-- @@ -90,7 +92,9 @@ name = "cyborg-hand labeler" /obj/item/hand_labeler/borg/afterattack(atom/A, mob/user, proximity) - . = ..(A, user, proximity) + . = ..() + if(!proximity) + return if(!iscyborg(user)) return @@ -114,6 +118,7 @@ desc = "A roll of paper. Use it on a hand labeler to refill it." icon_state = "labeler_refill" item_state = "electropack" + // inhand_icon_state = "electropack" lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' w_class = WEIGHT_CLASS_TINY diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 5d842ef11a..20ec678e45 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -11,41 +11,6 @@ #define MODE_WRITING 1 #define MODE_STAMPING 2 -/** - * This is a custom ui state. All it really does is keep track of pen - * being used and if they are editing it or not. This way we can keep - * the data with the ui rather than on the paper - */ -/datum/ui_state/default/paper_state - /// What edit mode we are in and who is - /// writing on it right now - var/edit_mode = MODE_READING - /// Setup for writing to a sheet - var/pen_color = "black" - var/pen_font = "" - var/is_crayon = FALSE - /// Setup for stamping a sheet - // Why not the stamp obj? I have no idea - // what happens to states out of scope so - // don't want to put instances in this - var/stamp_icon_state = "" - var/stamp_name = "" - var/stamp_class = "" - -/datum/ui_state/default/paper_state/proc/copy_from(datum/ui_state/default/paper_state/from) - switch(from.edit_mode) - if(MODE_READING) - edit_mode = MODE_READING - if(MODE_WRITING) - edit_mode = MODE_WRITING - pen_color = from.pen_color - pen_font = from.pen_font - is_crayon = from.is_crayon - if(MODE_STAMPING) - edit_mode = MODE_STAMPING - stamp_icon_state = from.stamp_icon_state - stamp_class = from.stamp_class - stamp_name = from.stamp_name /** * Paper is now using markdown (like in github pull notes) for ALL rendering @@ -58,6 +23,9 @@ icon = 'icons/obj/bureaucracy.dmi' icon_state = "paper" item_state = "paper" + // inhand_icon_state = "paper" + // worn_icon_state = "paper" + // custom_fire_overlay = "paper_onfire_overlay" throwforce = 0 w_class = WEIGHT_CLASS_TINY throw_range = 1 @@ -80,34 +48,19 @@ var/list/stamps /// Positioning for the stamp in tgui var/list/stamped /// Overlay info - /// This REALLY should be a componenet. Basicly used during, april fools - /// to honk at you - var/rigged = 0 - var/spam_flag = 0 - var/contact_poison // Reagent ID to transfer on contact var/contact_poison_volume = 0 - // Ok, so WHY are we caching the ui's? - // Since we are not using autoupdate we - // need some way to update the ui's of - // other people looking at it and if - // its been updated. Yes yes, lame - // but canot be helped. However by - // doing it this way, we can see - // live updates and have multipule - // people look at it - var/list/viewing_ui = list() - /// When the sheet can be "filled out" /// This is an associated list var/list/form_fields = list() var/field_counter = 1 /obj/item/paper/Destroy() - close_all_ui() stamps = null stamped = null + form_fields = null + stamped = null . = ..() /** @@ -162,7 +115,7 @@ set category = "Object" set src in usr - if(usr.incapacitated() || !usr.is_literate()) + if(!usr.can_read(src) || usr.incapacitated(TRUE, TRUE) || (isobserver(usr) && !IsAdminGhost(usr))) return if(ishuman(usr)) var/mob/living/carbon/human/H = usr @@ -180,18 +133,6 @@ user.visible_message("[user] scratches a grid on [user.p_their()] wrist with the paper! It looks like [user.p_theyre()] trying to commit sudoku...") return (BRUTELOSS) -/// ONLY USED FOR APRIL FOOLS -/obj/item/paper/proc/reset_spamflag() - spam_flag = FALSE - -/obj/item/paper/attack_self(mob/user) - if(rigged && (SSevents.holidays && SSevents.holidays[APRIL_FOOLS])) - if(!spam_flag) - spam_flag = TRUE - playsound(loc, 'sound/items/bikehorn.ogg', 50, TRUE) - addtimer(CALLBACK(src, .proc/reset_spamflag), 20) - . = ..() - /obj/item/paper/proc/clearpaper() info = "" stamps = null @@ -199,28 +140,39 @@ cut_overlays() update_icon_state() -/obj/item/paper/examine_more(mob/user) - ui_interact(user) - return list("You try to read [src]...") +/obj/item/paper/examine(mob/user) + . = ..() + if(!in_range(user, src) && !isobserver(user)) + . += "You're too far away to read it!" + return + if(user.can_read(src)) + ui_interact(user) + return + . += "You cannot read it!" + +/obj/item/paper/ui_status(mob/user,/datum/ui_state/state) + // Are we on fire? Hard ot read if so + if(resistance_flags & ON_FIRE) + return UI_CLOSE + if(!in_range(user,src)) + return UI_CLOSE + if(user.incapacitated(TRUE, TRUE) || (isobserver(user) && !IsAdminGhost(user))) + return UI_UPDATE + // Even harder to read if your blind...braile? humm + // .. or if you cannot read + if(!user.can_read(src)) + return UI_CLOSE + if(in_contents_of(/obj/machinery/door/airlock)) + return UI_INTERACTIVE + return ..() + + /obj/item/paper/can_interact(mob/user) - if(!..()) - return FALSE - // Are we on fire? Hard ot read if so - if(resistance_flags & ON_FIRE) - return FALSE - // Even harder to read if your blind...braile? humm - if(user.is_blind()) - return FALSE - // checks if the user can read. - return user.can_read(src) + if(in_contents_of(/obj/machinery/door/airlock)) + return TRUE + return ..() -/** - * This creates the ui, since we are using a custom state but not much else - * just makes it easyer to make it. - */ -/obj/item/paper/proc/create_ui(mob/user, datum/ui_state/default/paper_state/state) - ui_interact(user, state = state) /obj/item/proc/burn_paper_product_attackby_check(obj/item/I, mob/living/user, bypass_clumsy) var/ignition_message = I.ignition_effect(src, user) @@ -244,49 +196,22 @@ /obj/item/paper/attackby(obj/item/P, mob/living/user, params) if(burn_paper_product_attackby_check(P, user)) - close_all_ui() + SStgui.close_uis(src) return if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon)) if(length(info) >= MAX_PAPER_LENGTH) // Sheet must have less than 1000 charaters to_chat(user, "This sheet of paper is full!") return - - var/datum/ui_state/default/paper_state/state = new - state.edit_mode = MODE_WRITING - // should a crayon be in the same subtype as a pen? How about a brush or charcoal? - // TODO: Convert all writing stuff to one type, /obj/item/art_tool maybe? - state.is_crayon = istype(P, /obj/item/toy/crayon); - if(state.is_crayon) - var/obj/item/toy/crayon/PEN = P - state.pen_font = CRAYON_FONT - state.pen_color = PEN.paint_color - else - var/obj/item/pen/PEN = P - state.pen_font = PEN.font - state.pen_color = PEN.colour - - create_ui(user, state) + ui_interact(user) return else if(istype(P, /obj/item/stamp)) - - var/datum/ui_state/default/paper_state/state = new - state.edit_mode = MODE_STAMPING // we are read only becausse the sheet is full - state.stamp_icon_state = P.icon_state - state.stamp_name = P.name - - var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/simple/paper) - state.stamp_class = sheet.icon_class_name(P.icon_state) - to_chat(user, "You ready your stamp over the paper! ") - - create_ui(user, state) + ui_interact(user) return /// Normaly you just stamp, you don't need to read the thing else // cut paper? the sky is the limit! - var/datum/ui_state/default/paper_state/state = new - state.edit_mode = MODE_READING - create_ui(user, state) // The other ui will be created with just read mode outside of this + ui_interact(user) // The other ui will be created with just read mode outside of this return ..() @@ -301,68 +226,64 @@ get_asset_datum(/datum/asset/spritesheet/simple/paper), ) -/obj/item/paper/ui_interact(mob/user, datum/tgui/ui, - datum/ui_state/default/paper_state/state) - // Update the state - ui = ui || SStgui.get_open_ui(user, src) - if(ui && state) - var/datum/ui_state/default/paper_state/current_state = ui.state - current_state.copy_from(state) +/obj/item/paper/ui_interact(mob/user, datum/tgui/ui) // Update the UI ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "PaperSheet", name) - state = new - ui.set_state(state) - ui.set_autoupdate(FALSE) - viewing_ui[user] = ui ui.open() -/obj/item/paper/ui_close(mob/user) - /// close the editing window and change the mode - viewing_ui[user] = null - . = ..() -// Again, we have to do this as autoupdate is off -/obj/item/paper/proc/update_all_ui() - for(var/datum/tgui/ui in viewing_ui) - ui.process(force = TRUE) +/obj/item/paper/ui_static_data(mob/user) + . = list() + .["text"] = info + .["max_length"] = MAX_PAPER_LENGTH + .["paper_color"] = !color || color == "white" ? "#FFFFFF" : color // color might not be set + .["paper_state"] = icon_state /// TODO: show the sheet will bloodied or crinkling? + .["stamps"] = stamps + -// Again, we have to do this as autoupdate is off -/obj/item/paper/proc/close_all_ui() - for(var/datum/tgui/ui in viewing_ui) - ui.close() - viewing_ui = list() /obj/item/paper/ui_data(mob/user) var/list/data = list() - - var/datum/tgui/ui = viewing_ui[user] - var/datum/ui_state/default/paper_state/state = ui.state - - // Should all this go in static data and just do a forced update? - data["text"] = info - data["max_length"] = MAX_PAPER_LENGTH - data["paper_state"] = icon_state /// TODO: show the sheet will bloodied or crinkling? - data["paper_color"] = !color || color == "white" ? "#FFFFFF" : color // color might not be set - data["stamps"] = stamps - - data["edit_mode"] = state.edit_mode - data["edit_usr"] = "[ui.user]"; - - // pen info for editing - data["is_crayon"] = state.is_crayon - data["pen_font"] = state.pen_font - data["pen_color"] = state.pen_color - // stamping info for..stamping - data["stamp_class"] = state.stamp_class - + var/obj/O = user.get_active_held_item() + if(istype(O, /obj/item/toy/crayon)) + var/obj/item/toy/crayon/PEN = O + data["pen_font"] = CRAYON_FONT + data["pen_color"] = PEN.paint_color + data["edit_mode"] = MODE_WRITING + data["is_crayon"] = TRUE + data["stamp_class"] = "FAKE" + data["stamp_icon_state"] = "FAKE" + else if(istype(O, /obj/item/pen)) + var/obj/item/pen/PEN = O + data["pen_font"] = PEN.font + data["pen_color"] = PEN.colour + data["edit_mode"] = MODE_WRITING + data["is_crayon"] = FALSE + data["stamp_class"] = "FAKE" + data["stamp_icon_state"] = "FAKE" + else if(istype(O, /obj/item/stamp)) + var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/simple/paper) + data["stamp_icon_state"] = O.icon_state + data["stamp_class"] = sheet.icon_class_name(O.icon_state) + data["edit_mode"] = MODE_STAMPING + data["pen_font"] = "FAKE" + data["pen_color"] = "FAKE" + data["is_crayon"] = FALSE + else + data["edit_mode"] = MODE_READING + data["pen_font"] = "FAKE" + data["pen_color"] = "FAKE" + data["is_crayon"] = FALSE + data["stamp_icon_state"] = "FAKE" + data["stamp_class"] = "FAKE" data["field_counter"] = field_counter data["form_fields"] = form_fields return data -/obj/item/paper/ui_act(action, params, datum/tgui/ui, datum/ui_state/default/paper_state/state) +/obj/item/paper/ui_act(action, params,datum/tgui/ui) if(..()) return switch(action) @@ -370,34 +291,33 @@ var/stamp_x = text2num(params["x"]) var/stamp_y = text2num(params["y"]) var/stamp_r = text2num(params["r"]) // rotation in degrees - + var/stamp_icon_state = params["stamp_icon_state"] + var/stamp_class = params["stamp_class"] if (isnull(stamps)) - stamps = new/list() + stamps = list() if(stamps.len < MAX_PAPER_STAMPS) // I hate byond when dealing with freaking lists - stamps += list(list(state.stamp_class, stamp_x, stamp_y,stamp_r)) /// WHHHHY + stamps[++stamps.len] = list(stamp_class, stamp_x, stamp_y, stamp_r) /// WHHHHY /// This does the overlay stuff if (isnull(stamped)) - stamped = new/list() + stamped = list() if(stamped.len < MAX_PAPER_STAMPS_OVERLAYS) - var/mutable_appearance/stampoverlay = mutable_appearance('icons/obj/bureaucracy.dmi', "paper_[state.stamp_icon_state]") + var/mutable_appearance/stampoverlay = mutable_appearance('icons/obj/bureaucracy.dmi', "paper_[stamp_icon_state]") stampoverlay.pixel_x = rand(-2, 2) stampoverlay.pixel_y = rand(-3, 2) add_overlay(stampoverlay) - LAZYADD(stamped, state.stamp_icon_state) + LAZYADD(stamped, stamp_icon_state) - ui.user.visible_message("[ui.user] stamps [src] with [state.stamp_name]!", "You stamp [src] with [state.stamp_name]!") + update_static_data(usr,ui) + ui.user.visible_message("[ui.user] stamps [src] with [stamp_class]!", "You stamp [src] with [stamp_class]!") else to_chat(usr, pick("You try to stamp but you miss!", "There is no where else you can stamp!")) - - update_all_ui() . = TRUE if("save") var/in_paper = params["text"] var/paper_len = length(in_paper) - var/list/fields = params["form_fields"] field_counter = params["field_counter"] ? text2num(params["field_counter"]) : field_counter if(paper_len > MAX_PAPER_LENGTH) @@ -413,14 +333,10 @@ if(info != in_paper) to_chat(ui.user, "You have added to your paper masterpiece!"); info = in_paper - - for(var/key in fields) - form_fields[key] = fields[key]; + update_static_data(usr,ui) - update_all_ui() update_icon() - . = TRUE /** diff --git a/code/modules/paperwork/paper_cutter.dm b/code/modules/paperwork/paper_cutter.dm index 3937720f74..a3b9b23141 100644 --- a/code/modules/paperwork/paper_cutter.dm +++ b/code/modules/paperwork/paper_cutter.dm @@ -26,11 +26,11 @@ var/obj/item/bodypart/BP = C.get_bodypart(BODY_ZONE_HEAD) if(BP) BP.drop_limb() - playsound(loc,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) + playsound(loc, pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg'),50, TRUE, -1) return (BRUTELOSS) else user.visible_message("[user] repeatedly bashes [src.name] against [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1) + playsound(loc, 'sound/items/gavel.ogg', 50, TRUE, -1) return (BRUTELOSS) @@ -42,11 +42,12 @@ if(storedpaper) . += "paper" + /obj/item/papercutter/attackby(obj/item/P, mob/user, params) if(istype(P, /obj/item/paper) && !storedpaper) if(!user.transferItemToLoc(P, src)) return - playsound(loc, "pageturn", 60, 1) + playsound(loc, "pageturn", 60, TRUE) to_chat(user, "You place [P] in [src].") storedpaper = P update_icon() @@ -59,17 +60,17 @@ storedcutter = P update_icon() return - if(istype(P, /obj/item/screwdriver) && storedcutter) + if(P.tool_behaviour == TOOL_SCREWDRIVER && storedcutter) P.play_tool_sound(src) to_chat(user, "[storedcutter] has been [cuttersecured ? "unsecured" : "secured"].") cuttersecured = !cuttersecured return ..() -/obj/item/papercutter/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) +/obj/item/papercutter/on_attack_hand(mob/user) add_fingerprint(user) if(!storedcutter) - to_chat(user, "The cutting blade is gone! You can't use [src] now.") + to_chat(user, "The cutting blade is gone! You can't use [src] now.") return if(!cuttersecured) @@ -79,7 +80,7 @@ update_icon() if(storedpaper) - playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1) + playsound(src.loc, 'sound/weapons/slash.ogg', 50, TRUE) to_chat(user, "You neatly cut [storedpaper].") storedpaper = null qdel(storedpaper) @@ -88,6 +89,7 @@ update_icon() /obj/item/papercutter/MouseDrop(atom/over_object) + . = ..() var/mob/M = usr if(M.incapacitated() || !Adjacent(M)) return @@ -98,10 +100,6 @@ else if(istype(over_object, /obj/screen/inventory/hand)) var/obj/screen/inventory/hand/H = over_object M.putItemFromInventoryInHandIfPossible(src, H.held_index) - - else - . = ..() - add_fingerprint(M) /obj/item/paperslip @@ -112,6 +110,12 @@ resistance_flags = FLAMMABLE max_integrity = 50 +/obj/item/paperslip/attackby(obj/item/I, mob/living/user, params) + if(burn_paper_product_attackby_check(I, user)) + return + return ..() + + /obj/item/paperslip/Initialize() . = ..() pixel_x = rand(-5, 5) @@ -124,5 +128,6 @@ icon = 'icons/obj/bureaucracy.dmi' icon_state = "cutterblade" item_state = "knife" + // inhand_icon_state = "knife" lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi' diff --git a/code/modules/paperwork/paper_premade.dm b/code/modules/paperwork/paper_premade.dm index 414026924a..5d6d3d45e8 100644 --- a/code/modules/paperwork/paper_premade.dm +++ b/code/modules/paperwork/paper_premade.dm @@ -4,53 +4,22 @@ /obj/item/paper/fluff/sop name = "paper- 'Standard Operating Procedure'" - info = {" -Alert Levels: -* Blue - Emergency - * Caused by fire - * Caused by manual interaction - * Action: Close all fire doors. These can only be opened by resetting the alarm -* Red- Ejection/Self Destruct - * Caused by module operating computer. - * Action: After the specified time the module will eject completely. -Engine Maintenance Instructions: -1. Shut off ignition systems: -2. Activate internal power -3. Activate orbital balance matrix -4. Remove volatile liquids from area -5. Wear a fire suit -6. After Decontaminate Visit medical examiner -Toxin Laboratory Procedure: -1. Wear a gas mask regardless -2. Get an oxygen tank. -3. Activate internal atmosphere -4. After Decontaminate Visit medical examiner -Disaster Procedure: -Fire: -1. Activate sector fire alarm. -2. Move to a safe area. -3. Get a fire suit -* After: - 1. Assess Damage - 2. Repair damages - 3. If needed, Evacuate -Meteor Shower: -1. Activate fire alarm -2. Move to the back of ship -* After - 1. Repair damage - 2. If needed, Evacuate -Accidental Reentry: -1. Activate fire alarms in front of ship. -2. Move volatile matter to a fire proof area! -3. Get a fire suit. -4. Stay secure until an emergency ship arrives. -5. If ship does not arrive-Evacuate to a nearby safe area! -"}; + info = "Alert Levels:
\nBlue- Emergency
\n\t1. Caused by fire
\n\t2. Caused by manual interaction
\n\tAction:
\n\t\tClose all fire doors. These can only be opened by resetting the alarm
\nRed- Ejection/Self-Destruct
\n\t1. Caused by module operating computer.
\n\tAction:
\n\t\tAfter the specified time the module will eject completely.
\n
\nEngine Maintenance Instructions:
\n\tShut off ignition systems:
\n\tActivate internal power
\n\tActivate orbital balance matrix
\n\tRemove volatile liquids from area
\n\tWear a fire suit
\n
\n\tAfter
\n\t\tDecontaminate
\n\t\tVisit medical examiner
\n
\nToxin Laboratory Procedure:
\n\tWear a gas mask regardless
\n\tGet an oxygen tank.
\n\tActivate internal atmosphere
\n
\n\tAfter
\n\t\tDecontaminate
\n\t\tVisit medical examiner
\n
\nDisaster Procedure:
\n\tFire:
\n\t\tActivate sector fire alarm.
\n\t\tMove to a safe area.
\n\t\tGet a fire suit
\n\t\tAfter:
\n\t\t\tAssess Damage
\n\t\t\tRepair damages
\n\t\t\tIf needed, Evacuate
\n\tMeteor Shower:
\n\t\tActivate fire alarm
\n\t\tMove to the back of ship
\n\t\tAfter
\n\t\t\tRepair damage
\n\t\t\tIf needed, Evacuate
\n\tAccidental Reentry:
\n\t\tActivate fire alarms in front of ship.
\n\t\tMove volatile matter to a fire proof area!
\n\t\tGet a fire suit.
\n\t\tStay secure until an emergency ship arrives.
\n
\n\t\tIf ship does not arrive-
\n\t\t\tEvacuate to a nearby safe area!" /obj/item/paper/fluff/shuttles/daniel info = "i love daniel
daniel is my best friend

you are tearing me apart elise" +/obj/item/paper/fluff/jobs/prisoner/letter + name = "letter from home" + info = {"Dearest sweetheart, +
It is truly saddening you must spend your time locked up in an awful prison on that dangerous station. I have spoken to your lawyer who will attempt to appeal to the judge so your sentence may hopefully be reduced. +
Regardless, I just want you to understand that all of us out here still love you, and want to see you released safely some day! I know that prison can be a very vicious place, so please promise us you'll avoid getting into any fights or trouble, okay? +
We all care for your safety deeply, and could not live with ourselves if you ended up getting hurt. We've scheduled a visit to see you, and with any luck, hopefully our request will be granted soon. +
Anyways, please do your best to make it by in that place, and never forget we'll be always here for you, no matter if we're separated. +
+
Please stay safe, +
-Love, Your Dearest"} + //////////// Job guides n' fluff @@ -90,13 +59,46 @@ Accidental Reentry: name = "paper- 'Chemical Information'" info = "Known Onboard Toxins:
\n\tGrade A Semi-Liquid Plasma:
\n\t\tHighly poisonous. You cannot sustain concentrations above 15 units.
\n\t\tA gas mask fails to filter plasma after 50 units.
\n\t\tWill attempt to diffuse like a gas.
\n\t\tFiltered by scrubbers.
\n\t\tThere is a bottled version which is very different
\n\t\t\tfrom the version found in canisters!
\n
\n\t\tWARNING: Highly Flammable. Keep away from heat sources
\n\t\texcept in an enclosed fire area!
\n\t\tWARNING: It is a crime to use this without authorization.
\nKnown Onboard Anti-Toxin:
\n\tAnti-Toxin Type 01P: Works against Grade A Plasma.
\n\t\tBest if injected directly into bloodstream.
\n\t\tA full injection is in every regular Med-Kit.
\n\t\tSpecial toxin Kits hold around 7.
\n
\nKnown Onboard Chemicals (other):
\n\tRejuvenation T#001:
\n\t\tEven 1 unit injected directly into the bloodstream
\n\t\t\twill cure unconscious and sleep toxins.
\n\t\tIf administered to a dying patient it will prevent
\n\t\t\tfurther damage for about units*3 seconds.
\n\t\t\tit will not cure them or allow them to be cured.
\n\t\tIt can be administered to a non-dying patient
\n\t\t\tbut the chemicals disappear just as fast.
\n\tMorphine T#054:
\n\t\t5 units will induce precisely 1 minute of sleep.
\n\t\t\tThe effect are cumulative.
\n\t\tWARNING: It is a crime to use this without authorization" +/obj/item/paper/fluff/jobs/medical/hippocratic + name = "paper- 'Hippocratic Oath'" + info = {"I swear to fulfill, to the best of my ability and judgment, this covenant: +
+ I will respect the hard-won scientific gains of those physicians in whose steps I walk, + and gladly share such knowledge as is mine with those who are to follow. +
+ I will apply, for the benefit of the sick, all measures that are required, + avoiding those twin traps of overtreatment and therapeutic nihilism. +
+ I will remember that there is art to medicine as well as science, + and that warmth, sympathy, and understanding may outweigh the surgeon's knife or the chemist's drug. +
+ I will not be ashamed to say "I know not," + nor will I fail to call in my colleagues when the skills of another are needed for a patient's recovery. +
+ I will respect the privacy of my patients, for their problems are not disclosed to me that the world may know. Most especially must I tread with care in matters of life and death. + If it is given me to save a life, all thanks. But it may also be within my power to take a life; + this awesome responsibility must be faced with great humbleness and awareness of my own frailty. Above all, I must not play at God. +
+ I will remember that I do not treat a fever chart, a cancerous growth, but a sick human being, whose illness may affect the person's family and economic stability. + My responsibility includes these related problems, if I am to care adequately for the sick. +
+ I will prevent disease whenever I can, for prevention is preferable to cure. +
+ I will remember that I remain a member of society, with special obligations to all my fellow human beings, + those sound of mind and body as well as the infirm. +
+ If I do not violate this oath, may I enjoy life and art, respected while I live and remembered with affection thereafter. + May I always act so as to preserve the finest traditions of my calling and may I long experience the joy of healing those who seek my help. +
"} + /* * Stations */ +////////// cogstation. /obj/item/paper/guides/cogstation/job_changes name = "MEMO: Job Changes" - info = "To ensure minimal employee downtime, please take note of the following changes to select professions that CogStation specifically requires:
\n
\n- Scientists are to have access to chemistry in order to reach the MedSci router.
\n
\n- Chemists should at the very least be provided with an encryption key for the Science channel, if not basic access to the Research department at large.
\n- Roboticists are to have basic Medical and Morgue access.
\n- Engineers and Atmospheric Technicians are to have Warehouse and Mining access.
\n- The Cook should not have Morgue access
\n- The Clown and Mime are to have Maintenance access. This is necessary due to the location of their offices.
\n
\nGenerated by Organic Resources Bot #2053" + info = "To ensure minimal employee downtime, please take note of the following changes to select professions that CogStation specifically requires:
\n
\n- Engineers and Atmospheric Technicians are to have Warehouse and Mining access.
\n- The Cook should not have Morgue access.
\n- The Clown and Mime are to have Maintenance access. This is necessary due to the location of their offices.
\n
\nGenerated by Organic Resources Bot #2053" /obj/item/paper/guides/cogstation/letter_sec name = "To future Security personnel" @@ -104,7 +106,7 @@ Accidental Reentry: /obj/item/paper/guides/cogstation/disposals name = "Regarding the disposal system:" - info = "As you might have noticed, this station has far more disposal pipes than you may expect from your average Nanotrasen research facility. Part of the reason for this is specialization - mail, trash, even corpses have their own disposal systems. Unfortunately, the convenient color-coding was lost in translocation and we've had to compensate by marking the area around each bin.
\n
\n- WHITE/GRAY STRIPES is for DELIVERIES.
\n- RED STRIPES is for CORPSES.
\n- EVERYTHING ELSE is for TRASH,
barring a few exceptions that should be labeled as such.
\n
\nIdeally the station won't sustain any heavy structural damage during your time here but if it does, or someone decides to tamper with/sabotage this system, you'll be forgiven if you can't put it back together perfectly.
\n
\n-C. Donnelly
Architectural Analyst" + info = "As you might have noticed, this station has far more disposal pipes than you may expect from your average Nanotrasen research facility. Part of the reason for this is specialization - mail, trash, even corpses have their own disposal systems. Unfortunately, the convenient color-coding was lost in translocation and we've had to compensate by marking the area around each bin.
\n
\n- WHITE/GRAY STRIPES are for DELIVERIES.
\n- RED STRIPES are for CORPSES.
\n- EVERYTHING ELSE is for TRASH,
barring a few exceptions that should be labeled as such.
\n
\nIdeally the station won't sustain any heavy structural damage during your time here but if it does, or someone decides to tamper with/sabotage this system, you'll be forgiven if you can't put it back together perfectly.
\n
\n-C. Donnelly
Architectural Analyst" /obj/item/paper/guides/cogstation/janitor name = "a quick tip" @@ -128,7 +130,7 @@ Accidental Reentry: /obj/item/paper/guides/cogstation/letter_eng name = "To future Engineering staff:" - info = "I'm not gonna sugarcoat this. Compared to other departments, you might have your work cut out for you. CogStation is an entirely different beast than your standard Box, but everyone's still gonna expect you to keep the place running.
\n
\n If there's any good news, it's your time to shine if you know how to run a thermo-electric generator. That's what this station runs on, and that isn't likely to change anytime soon. If it's absolutely critical you might be able to run a singularity or tesla engine east of mining, but it won't have any sort of shielding out there.
\n
\nYou still have three solar arrays to work with, two of them being on each end of the starboard side. The port side array will need you to either get access from a head of staff or security, unless you want to spacewalk around the whole station. Don't be afraid to ask the latter - they're there for you, after all. As for other utilities the air system is a bit different than you'd expect, but fortunately you should have the atmos techs this station needed a long time ago. The disposal network is significantly more complicated, yet more capable. I've already elaborated on it, so I'll let you find and read my write-up for that. As for the routing system, it's just begging to get hit by a stray meteor so consider other utilities a higher priority.
\n
\nGood luck. You're gonna need it.
\n
\n-C. Donnelly
Architectural Analyst" + info = "I'm not gonna sugarcoat this. Compared to other departments, you might have your work cut out for you. CogStation is an entirely different beast than your standard Box, but everyone's still gonna expect you to keep the place running.
\n
\n If there's any good news, it's your time to shine if you know how to run a thermo-electric generator. That's what this station runs on, and that isn't likely to change anytime soon. If it's absolutely critical you might be able to run a singularity or tesla engine east of mining, but it won't have any sort of protection out there.
\n
\nYou still have three solar arrays to work with, two of them being on each end of the starboard side. The port side array will need you to either get access from a head of staff or security, unless you want to spacewalk around the whole station. Don't be afraid to ask the latter - they're there for you, after all. As for other utilities the air system is a bit different than you'd expect, but fortunately you should have the atmos techs this station needed a long time ago. The disposal network is significantly more complicated, yet more capable. I've already elaborated on it, so I'll let you find and read my write-up for that. As for the routing system, it's just begging to get hit by a stray meteor so consider other utilities a higher priority.
\n
\nGood luck. You're gonna need it.
\n
\n-C. Donnelly
Architectural Analyst" /obj/item/paper/guides/cogstation/letter_atmos name = "To future Atmospheric Technicians:" @@ -140,15 +142,15 @@ Accidental Reentry: /obj/item/paper/guides/cogstation/letter_hos name = "To the future HoS" - info = "I'm gonna be rather disappointed if CentCom doesn't brief you about this station, but if they don't I wrote up another letter for your department that should cover it pretty well. Make sure your officers read it if they aren't up to speed.
\n
\nSomething you in particular should know is that if someone's getting to be too much to handle, the boys and I have constructed a 'discount transfer centre' just behind the router. Use it only as a last resort - the walls may be reinforced but they're still thin, and you'll have big trouble on your hands if the AI or any cyborgs find out about it.
\n
-LC" + info = "I'm gonna be rather disappointed if Central Command doesn't brief you about this station, but if they don't I wrote up another letter for your department that should cover it pretty well. Make sure your officers read it if they aren't up to speed.
\n
\nSomething you in particular should know is that if someone's getting to be too much to handle, the boys and I have constructed a 'discount transfer centre' just behind the router. Use it only as a last resort - the walls may be reinforced but they're still thin, and you'll have big trouble on your hands if the AI or any cyborgs find out about it.
\n
-LC" /obj/item/paper/guides/cogstation/letter_supp name = "To future Supply Staff:" - info = "Cargo, move freight. Miners, don't die. Your jobs are pretty straightforward, which is likely why they originally fell under Engineering on this station as opposed to their own department. Although we've considerably readjusted this part of the station to accommodate you, there are potential differences you should be aware of.
\n
\nEngineeringwill have access to some of your department, namely the warehouse and mining dock. Mining operations on this station were originally asteroid-based, hence the catwalk into the great beyond. Although you won't need to worry about being space-worthy due to a newly installed shuttle dock, they might need to get out there.
\n
\nYou'll have all your usual means of shipping out goods, but the disposal network is more complex with a separate line for mail and trash. I've left another note that explains this in detail, but know trash is the janitor's responsibility, not yours.
\n
\nThe biggest difference has to be this station's router system, which allows departments to ship goods between themselves. Even if the belts aren't working properly they'll still have their own request consoles, so you'll want to check for orders regularly.
\n
\n-C. Donnelly
\nArchitectural Analyst" + info = "Cargo, move freight. Miners, don't die. Your jobs are pretty straightforward, which is likely why they originally fell under Engineering on this station as opposed to their own department. Although we've considerably readjusted this part of the station to accommodate you, there are potential differences you should be aware of.
\n
\nEngineeringwill have access to some of your department, namely the warehouse and mining dock. Mining operations on this station were originally asteroid-based, hence the catwalk into the great beyond. Although you won't need to worry about being space-worthy due to a newly installed shuttle dock, they might need to get out there.
\n
\nYou'll have all your usual means of shipping out goods, but the disposal network is more complex with a separate line for mail and trash. It also isn't fully space-proofed, meanin it may not be the best choice for livestock, monkey cubes, or clowns. I've left another note that explains this in detail, but know trash is the janitor's responsibility, not yours.
\n
\nThe biggest difference has to be this station's router system, which allows departments to ship goods between themselves. Even if the belts aren't working properly they'll still have their own request consoles, so you'll want to check for orders regularly.
\n
\n-C. Donnelly
\nArchitectural Analyst" -/obj/item/paper/fluff/cogstation/sleepers - name = "Re: Sleepers?" - info = "Yes, the sleepers are meant to be publicly accessible. Policies in this station's original location encouraged crew to visit the clinic or treat themselves when it came to minor injuries.
\n
\nThis is no excuse for you not to do your jobs. You may wish to keep an eye on the sleepers as to ensure they're being used responsibly. Remember, allowing an overdose to happen under your watch isn't much different from administering that overdose yourself.
\n
\n- Dr. Halley" +/obj/item/paper/guides/cogstation/letter_med + name = "Re: Future Medical Staff" + info = "With this station nearing approval for regular use, I've been told to consolidate anything noteworthy about its general medical department into a single document. As you may be able to guess, this is that document.
\n
\n- First, you should know a medical clinic is present in the civilian (starboard bow) wing. If you have personnel to spare, it's recommended you have someone staff it - that way people with minor injuries can report there instead of clogging up the research wing.
\n
\n- Despite recent renovations to bring this station in line with regional policy, you'll still find the robotics lab directly adjacent to your department. I advise you take full advantage of this, whether it's requesting prosthetics in advance or harvesting organs from those who have undergone more...permanent procedures.
\n
\n- Lastly, please make a habit of checking the morgue on a regular basis. Thanks to the Corpse Disposal Network (or CDN for short), you may find the station's deceased delivered directly to you. Some may be employees capable of being revived - more information can be found in the morgue itself.
\n
\n- Dr. Halley" /obj/item/paper/fluff/cogstation/cloner name = "Re: Issue with the cloner?" @@ -172,7 +174,7 @@ Accidental Reentry: /obj/item/paper/fluff/cogstation/letter_chap name = "A message from the DHDA" - info = "Regardless of what the name leads you to believe, CogStation is neither Ratvarian in origin nor designed by members of this so-called 'clock cult'. Despite a potential common enemy and instances of exhibiting peaceful behavior, their beliefs have been labeled 'Heretical' by the Department of Higher-Dimensional Affairs and following them is grounds for immediate termination.
\nAs the station's designated Chaplain, it is advised you correct anyone who claims this station and/or its designers are Ratvarian. While they are most likely misinformed or 'joking around', untruths gain credibility the more they are repeated.
\n
\nSoulstone Obelisk
\n
\nDepartment of Higher-Dimensional Affairs" + info = "Regardless of what the name leads you to believe, CogStation is neither Ratvarian in origin nor designed by members of this so-called 'clock cult'. Despite a potential common enemy and instances of exhibiting peaceful behavior, their beliefs have been labeled 'Heretical' by the Department of Higher-Dimensional Affairs and following them is grounds for immediate termination.
\nAs the station's designated Chaplain, it is advised you correct anyone who claims this station and/or its designers are Ratvarian. While they are most likely misinformed or 'joking around', untruths gain credibility the more they are repeated.
\n
\nSoulstone Obelisk
\n
\nDepartment of Higher-Dimensional Affairs" /obj/item/paper/fluff/cogstation/cluwne name = "Mysterious Note" @@ -184,7 +186,7 @@ Accidental Reentry: /obj/item/paper/fluff/cogstation/eva name = "MEMO: Spacesuits" - info = "As a Head of Personnel, you may be familiar with crew members requesting EVA access, particularly when there is an absence of credible threats on the station. While it is your decision to grant or deny access unless overriden by your superior(s), you should be aware of an abundance of spacesuits on this station. While intended for emergencies, these suits are cheaper to replace. You may find it beneficial to direct aspiring 'space explorers' towards finding one of these suits instead, although it is advised you order replacement suits in advance through the cargo department.
\n
\n-Generated by Organic Resources Bot #2053" + info = "As a Head of Personnel, you may be familiar with crew members requesting EVA access, particularly when there is an absence of credible threats on the station. While it is your decision to grant or deny access unless overriden by your superior(s), you should be aware of an abundance of spacesuits on this station. While intended for emergencies, these suits are cheaper to replace. You may find it beneficial to direct aspiring 'space explorers' towards finding one of these suits instead, although it is advised you order replacement suits in advance through the cargo department.
\n
\nGenerated by Organic Resources Bot #2053" /obj/item/paper/fluff/cogstation/chemists name = "Re: Scientists?!" @@ -214,9 +216,9 @@ Accidental Reentry: name = "ROUTER STATUS: LIMITED" info = "Currently, this router cannot receive deliveries from the Airbridge, MedSci, Security, or Service Routers. Cargo and the recycler are the only points currently accepting deliveries from here, although manual input from the routing depot is currently required.
\n
\n-C. Donnelly
\n
\nArchitectural Analyst" -/obj/item/paper/fluff/cogstation/router_cargo - name = "ROUTER STATUS: VERY LIMITED" - info = "Currently, this router cannot receive deliveries from the Airbridge, MedSci, Security, or Service Routers. It is not yet capable of making deliveries, beyond sending items to the recycler.
\n
\n-C. Donnelly
\n
\nArchitectural Analyst" +/obj/item/paper/fluff/cogstation/mulebot + name = "MEMO: MULEbots" + info = "As you may know, MULEbots have been coded to minimize travel distance for maximum efficiency. In the case of this station, that may include travelling through depressurized areas exposed to space. Please bear this in mind before using them to transport living tissue.
\n
\nGenerated by Organic Resources Bot #2053" /////////// CentCom diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm index 28cb5ffae9..b8bbd0a30e 100644 --- a/code/modules/paperwork/paperbin.dm +++ b/code/modules/paperwork/paperbin.dm @@ -4,6 +4,7 @@ icon = 'icons/obj/bureaucracy.dmi' icon_state = "paper_bin1" item_state = "sheet-metal" + // inhand_icon_state = "sheet-metal" lefthand_file = 'icons/mob/inhands/misc/sheets_lefthand.dmi' righthand_file = 'icons/mob/inhands/misc/sheets_righthand.dmi' throwforce = 0 @@ -43,6 +44,7 @@ ..() /obj/item/paper_bin/MouseDrop(atom/over_object) + . = ..() var/mob/living/M = usr if(!istype(M) || M.incapacitated() || !Adjacent(M)) return @@ -54,17 +56,18 @@ var/obj/screen/inventory/hand/H = over_object M.putItemFromInventoryInHandIfPossible(src, H.held_index) - else - . = ..() - add_fingerprint(M) /obj/item/paper_bin/attack_paw(mob/user) return attack_hand(user) -/obj/item/paper_bin/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) - if(user.lying) - return +//ATTACK HAND IGNORING PARENT RETURN VALUE +/obj/item/paper_bin/on_attack_hand(mob/user) + if(isliving(user)) + var/mob/living/L = user + if(!(L.mobility_flags & MOBILITY_PICKUP)) + return + // user.changeNext_move(CLICK_CD_MELEE) if(bin_pen) var/obj/item/pen/P = bin_pen P.add_fingerprint(user) @@ -85,8 +88,8 @@ P = new papertype(src) if(SSevents.holidays && SSevents.holidays[APRIL_FOOLS]) if(prob(30)) - P.info = "*HONK HONK HONK HONK HONK HONK HONK
HOOOOOOOOOOOOOOOOOOOOOONK*\n*APRIL FOOLS*\n" - P.rigged = 1 + P.info = "HONK HONK HONK HONK HONK HONK HONK
HOOOOOOOOOOOOOOOOOOOOOONK
APRIL FOOLS
" + P.AddComponent(/datum/component/honkspam) P.add_fingerprint(user) P.forceMove(user.loc) @@ -148,8 +151,7 @@ papertype = /obj/item/paper/natural resistance_flags = FLAMMABLE -/obj/item/paper_bin/bundlenatural/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) - ..() +/obj/item/paper_bin/bundlenatural/on_attack_hand(mob/user) if(total_paper < 1) qdel(src) @@ -173,3 +175,9 @@ qdel(src) else ..() + +/obj/item/paper_bin/carbon + name = "carbon paper bin" + desc = "Contains all the paper you'll ever need, in duplicate!" + icon_state = "paper_bin_carbon" + papertype = /obj/item/paper/carbon diff --git a/code/modules/paperwork/paperplane.dm b/code/modules/paperwork/paperplane.dm index c6a1ee1389..53fe886d65 100644 --- a/code/modules/paperwork/paperplane.dm +++ b/code/modules/paperwork/paperplane.dm @@ -1,9 +1,9 @@ - /obj/item/paperplane name = "paper plane" desc = "Paper, folded in the shape of a plane." icon = 'icons/obj/bureaucracy.dmi' icon_state = "paperplane" + // custom_fire_overlay = "paperplane_onfire" throw_range = 7 throw_speed = 1 throwforce = 0 @@ -11,7 +11,7 @@ resistance_flags = FLAMMABLE max_integrity = 50 - var/hit_probability = 2//% + var/hit_probability = 2 //% var/obj/item/paper/internalPaper /obj/item/paperplane/origami @@ -41,6 +41,13 @@ qdel(src) return ..() +/obj/item/paperplane/Exited(atom/movable/AM, atom/newLoc) + . = ..() + if (AM == internalPaper) + internalPaper = null + if(!QDELETED(src)) + qdel(src) + /obj/item/paperplane/Destroy() QDEL_NULL(internalPaper) return ..() @@ -71,31 +78,19 @@ user.put_in_hands(internal_paper_tmp) /obj/item/paperplane/attackby(obj/item/P, mob/living/carbon/human/user, params) - ..() + if(burn_paper_product_attackby_check(P, user)) + return if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon)) - to_chat(user, "You should unfold [src] before changing it.") + to_chat(user, "You should unfold [src] before changing it!") return else if(istype(P, /obj/item/stamp)) //we don't randomize stamps on a paperplane internalPaper.attackby(P, user) //spoofed attack to update internal paper. update_icon() + add_fingerprint(user) + return - else if(P.get_temperature()) - if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(10)) - user.visible_message("[user] accidentally ignites [user.p_them()]self!", \ - "You miss [src] and accidentally light yourself on fire!") - user.dropItemToGround(P) - user.adjust_fire_stacks(1) - user.IgniteMob() - return - - if(!(in_range(user, src))) //to prevent issues as a result of telepathically lighting a paper - return - user.dropItemToGround(src) - user.visible_message("[user] lights [src] ablaze with [P]!", "You light [src] on fire!") - fire_act() - - add_fingerprint(user) + return ..() /obj/item/paperplane/throw_at(atom/target, range, speed, mob/thrower, spin=FALSE, diagonals_first = FALSE, datum/callback/callback) @@ -112,26 +107,28 @@ if(..() || !ishuman(hit_atom))//if the plane is caught or it hits a nonhuman return var/mob/living/carbon/human/H = hit_atom + var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES) if(prob(hit_probability)) if(H.is_eyes_covered()) return - var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES) - visible_message("\The [src] hits [H] in the eye!") + visible_message("\The [src] hits [H] in the eye[eyes ? "" : " socket"]!") H.adjust_blurriness(6) - if(eyes) - eyes.applyOrganDamage(rand(6,8)) + eyes?.applyOrganDamage(rand(6,8)) H.DefaultCombatKnockdown(40) H.emote("scream") - /obj/item/paper/examine(mob/user) . = ..() . += "Alt-click [src] to fold it into a paper plane." /obj/item/paper/AltClick(mob/living/carbon/user, obj/item/I) - . = ..() - if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user), NO_TK)) + if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user))) return + if(istype(src, /obj/item/paper/carbon)) + var/obj/item/paper/carbon/Carbon = src + if(!Carbon.iscopy && !Carbon.copied) + to_chat(user, "Take off the carbon copy first.") + return to_chat(user, "You fold [src] into the shape of a plane!") user.temporarilyRemoveItemFromInventory(src) var/obj/item/paperplane/plane_type = /obj/item/paperplane @@ -142,4 +139,3 @@ I = new plane_type(user, src) user.put_in_hands(I) - return TRUE diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 91b8a6719b..13890ae69e 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -16,6 +16,8 @@ icon = 'icons/obj/bureaucracy.dmi' icon_state = "pen" item_state = "pen" + // inhand_icon_state = "pen" + // worn_icon_state = "pen" slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_EARS throwforce = 0 w_class = WEIGHT_CLASS_TINY @@ -76,6 +78,22 @@ icon_state = "pen-fountain" font = FOUNTAIN_PEN_FONT +/obj/item/pen/charcoal + name = "charcoal stylus" + desc = "It's just a wooden stick with some compressed ash on the end. At least it can write." + icon_state = "pen-charcoal" + colour = "dimgray" + font = CHARCOAL_FONT + custom_materials = null + grind_results = list(/datum/reagent/ash = 5, /datum/reagent/cellulose = 10) + +/datum/crafting_recipe/charcoal_stylus + name = "Charcoal Stylus" + result = /obj/item/pen/charcoal + reqs = list(/obj/item/stack/sheet/mineral/wood = 1, /datum/reagent/ash = 30) + time = 30 + category = CAT_PRIMAL + /obj/item/pen/fountain/captain name = "captain's fountain pen" desc = "It's an expensive Oak fountain pen. The nib is quite sharp." @@ -93,6 +111,7 @@ "Black and Silver" = "pen-fountain-b", "Command Blue" = "pen-fountain-cb" ) + embedding = list("embed_chance" = 75) /obj/item/pen/fountain/captain/Initialize() . = ..() @@ -139,20 +158,18 @@ if(QDELETED(O) || !user.canUseTopic(O, BE_CLOSE)) return if(oldname == input) - to_chat(user, "You changed \the [O.name] to... well... \the [O.name].") + to_chat(user, "You changed \the [O.name] to... well... \the [O.name].") else O.name = input - to_chat(user, "\The [oldname] has been successfully been renamed to \the [input].") + to_chat(user, "\The [oldname] has been successfully been renamed to \the [input].") O.renamedByPlayer = TRUE - log_game("[user] [key_name(user)] has renamed [O] to [input]") if(penchoice == "Change description") - var/input = stripped_input(user,"Describe \the [O.name] here", ,"", 2048) + var/input = stripped_input(user,"Describe \the [O.name] here", ,"", 100) if(QDELETED(O) || !user.canUseTopic(O, BE_CLOSE)) return O.desc = input - to_chat(user, "You have successfully changed \the [O.name]'s description.") - log_game("[user] [key_name(user)] has changed [O]'s description to to [input]") + to_chat(user, "You have successfully changed \the [O.name]'s description.") /* * Sleepypens @@ -181,9 +198,10 @@ */ /obj/item/pen/edagger attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") //these wont show up if the pen is off + // attack_verb_continuous = list("slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") //these won't show up if the pen is off + // attack_verb_simple = list("slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") sharpness = SHARP_EDGED var/on = FALSE - embedding = list(embed_chance = EMBED_CHANCE) /obj/item/pen/edagger/ComponentInitialize() . = ..() @@ -193,29 +211,38 @@ /obj/item/pen/edagger/get_sharpness() return on * sharpness +/obj/item/pen/edagger/suicide_act(mob/user) + . = BRUTELOSS + if(on) + user.visible_message("[user] forcefully rams the pen into their mouth!") + else + user.visible_message("[user] is holding a pen up to their mouth! It looks like [user.p_theyre()] trying to commit suicide!") + attack_self(user) + /obj/item/pen/edagger/attack_self(mob/living/user) if(on) on = FALSE force = initial(force) + throw_speed = initial(throw_speed) w_class = initial(w_class) name = initial(name) hitsound = initial(hitsound) - embedding = null + embedding = list(embed_chance = EMBED_CHANCE) throwforce = initial(throwforce) - playsound(user, 'sound/weapons/saberoff.ogg', 5, 1) + playsound(user, 'sound/weapons/saberoff.ogg', 5, TRUE) to_chat(user, "[src] can now be concealed.") - updateEmbedding() else on = TRUE force = 18 + throw_speed = 4 w_class = WEIGHT_CLASS_NORMAL name = "energy dagger" hitsound = 'sound/weapons/blade1.ogg' - embedding = list(embed_chance = 100, fall_chance = 0) //rule of cool + embedding = list(embed_chance = 100) //rule of cool throwforce = 35 - playsound(user, 'sound/weapons/saberon.ogg', 5, 1) + playsound(user, 'sound/weapons/saberon.ogg', 5, TRUE) to_chat(user, "[src] is now active.") - updateEmbedding() + updateEmbedding() update_icon() /obj/item/pen/edagger/update_icon_state() @@ -235,6 +262,8 @@ icon = 'icons/obj/bureaucracy.dmi' icon_state = "digging_pen" item_state = "pen" + // inhand_icon_state = "pen" + // worn_icon_state = "pen" force = 3 w_class = WEIGHT_CLASS_TINY custom_materials = list(/datum/material/iron=10, /datum/material/diamond=100, /datum/material/titanium = 10) diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index 0b1f3bb01d..38029b5d4c 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -1,12 +1,20 @@ -/* Photocopiers! - * Contains: - * Photocopier - * Toner Cartridge - */ -/* - * Photocopier - */ +/// For use with the `color_mode` var. Photos will be printed in greyscale while the var has this value. +#define PHOTO_GREYSCALE "Greyscale" +/// For use with the `color_mode` var. Photos will be printed in full color while the var has this value. +#define PHOTO_COLOR "Color" + +/// How much toner is used for making a copy of a paper. +#define PAPER_TONER_USE 0.125 +/// How much toner is used for making a copy of a photo. +#define PHOTO_TONER_USE 0.625 +/// How much toner is used for making a copy of a document. +#define DOCUMENT_TONER_USE 0.75 +/// How much toner is used for making a copy of an ass. +#define ASS_TONER_USE 0.625 +/// The maximum amount of copies you can make with one press of the copy button. +#define MAX_COPIES_AT_ONCE 10 + /obj/machinery/photocopier name = "photocopier" desc = "Used to copy important documents and anatomy studies." @@ -19,183 +27,316 @@ power_channel = EQUIP max_integrity = 300 integrity_failure = 0.33 - var/obj/item/paper/copy = null //what's in the copier! - var/obj/item/photo/photocopy = null - var/obj/item/documents/doccopy = null - var/copies = 1 //how many copies to print! - var/toner = 40 //how much toner is left! woooooo~ - var/maxcopies = 10 //how many copies can be copied at once- idea shamelessly stolen from bs12's copier! - var/greytoggle = "Greyscale" - var/mob/living/ass //i can't believe i didn't write a stupid-ass comment about this var when i first coded asscopy. + /// A reference to an `/obj/item/paper` inside the copier, if one is inserted. Otherwise null. + var/obj/item/paper/paper_copy + /// A reference to an `/obj/item/photo` inside the copier, if one is inserted. Otherwise null. + var/obj/item/photo/photo_copy + /// A reference to an `/obj/item/documents` inside the copier, if one is inserted. Otherwise null. + var/obj/item/documents/document_copy + /// A reference to a mob on top of the photocopier trying to copy their ass. Null if there is no mob. + var/mob/living/ass + /// A reference to the toner cartridge that's inserted into the copier. Null if there is no cartridge. + var/obj/item/toner/toner_cartridge + /// How many copies will be printed with one click of the "copy" button. + var/num_copies = 1 + /// Used with photos. Determines if the copied photo will be in greyscale or color. + var/color_mode = PHOTO_COLOR + /// Indicates whether the printer is currently busy copying or not. var/busy = FALSE -/obj/machinery/photocopier/ui_interact(mob/user) +/obj/machinery/photocopier/Initialize() . = ..() - var/list/dat = list("Photocopier

") - if(copy || photocopy || doccopy || (ass && (ass.loc == src.loc))) - dat += "Remove Paper
" - if(toner) - dat += "Copy
" - dat += "Printing: [copies] copies." - dat += "- " - dat += "+

" - if(photocopy) - dat += "Printing in [greytoggle]

" - else if(toner) - dat += "Please insert paper to copy.

" - if(isAI(user)) - dat += "Print photo from database

" - dat += "Current toner level: [toner]" - if(!toner) - dat +="
Please insert a new toner cartridge!" - user << browse(dat.Join(""), "window=copier") - onclose(user, "copier") + //AddComponent(/datum/component/payment, 5, SSeconomy.get_dep_account(ACCOUNT_CIV), PAYMENT_CLINICAL) + toner_cartridge = new(src) -/obj/machinery/photocopier/Topic(href, href_list) +/obj/machinery/photocopier/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Photocopier") + ui.open() + +/obj/machinery/photocopier/ui_data(mob/user) + var/list/data = list() + data["has_item"] = !copier_empty() + data["num_copies"] = num_copies + + if(photo_copy) + data["is_photo"] = TRUE + data["color_mode"] = color_mode + + if(isAI(user)) + data["isAI"] = TRUE + data["can_AI_print"] = toner_cartridge ? toner_cartridge.charges >= PHOTO_TONER_USE : FALSE + else + data["isAI"] = FALSE + + if(toner_cartridge) + data["has_toner"] = TRUE + data["current_toner"] = toner_cartridge.charges + data["max_toner"] = toner_cartridge.max_charges + data["has_enough_toner"] = has_enough_toner() + else + data["has_toner"] = FALSE + data["has_enough_toner"] = FALSE + + return data + +/obj/machinery/photocopier/ui_act(action, list/params) if(..()) return - if(href_list["copy"]) - if(copy) - for(var/i = 0, i < copies, i++) - if(toner > 0 && !busy && copy) - var/copy_as_paper = 1 - if(istype(copy, /obj/item/paper/contract/employment)) - var/obj/item/paper/contract/employment/E = copy - var/obj/item/paper/contract/employment/C = new /obj/item/paper/contract/employment (loc, E.target.current) - if(C) - copy_as_paper = 0 - if(copy_as_paper) - var/obj/item/paper/c = new /obj/item/paper (loc) - if(length(copy.info) > 0) //Only print and add content if the copied doc has words on it - if(toner > 10) //lots of toner, make it dark - c.info = "" - else //no toner? shitty copies for you! - c.info = "" - var/copied = copy.info - copied = replacetext(copied, "" - c.name = copy.name - c.update_icon() - c.stamps = copy.stamps - if(copy.stamped) - c.stamped = copy.stamped.Copy() - c.copy_overlays(copy, TRUE) - toner-- - busy = TRUE - addtimer(CALLBACK(src, .proc/reset_busy), 1.5 SECONDS) - else - break - updateUsrDialog() - else if(photocopy) - for(var/i = 0, i < copies, i++) - if(toner >= 5 && !busy && photocopy) //Was set to = 0, but if there was say 3 toner left and this ran, you would get -2 which would be weird for ink - new /obj/item/photo (loc, photocopy.picture.Copy(greytoggle == "Greyscale"? TRUE : FALSE)) - busy = TRUE - addtimer(CALLBACK(src, .proc/reset_busy), 1.5 SECONDS) - else - break - else if(doccopy) - for(var/i = 0, i < copies, i++) - if(toner > 5 && !busy && doccopy) - new /obj/item/documents/photocopy(loc, doccopy) - toner-= 6 // the sprite shows 6 papers, yes I checked - busy = TRUE - addtimer(CALLBACK(src, .proc/reset_busy), 1.5 SECONDS) - else - break - updateUsrDialog() - else if(ass) //ASS COPY. By Miauw - for(var/i = 0, i < copies, i++) - var/icon/temp_img - if(ishuman(ass) && (ass.get_item_by_slot(ITEM_SLOT_ICLOTHING) || ass.get_item_by_slot(ITEM_SLOT_OCLOTHING))) - to_chat(usr, "You feel kind of silly, copying [ass == usr ? "your" : ass][ass == usr ? "" : "\'s"] ass with [ass == usr ? "your" : "[ass.p_their()]"] clothes on." ) - break - else if(toner >= 5 && !busy && check_ass()) //You have to be sitting on the copier and either be a xeno or a human without clothes on. - if(isalienadult(ass) || istype(ass, /mob/living/simple_animal/hostile/alien)) //Xenos have their own asses, thanks to Pybro. - temp_img = icon('icons/ass/assalien.png') - else if(ishuman(ass)) //Suit checks are in check_ass - temp_img = icon(ass.gender == FEMALE ? 'icons/ass/assfemale.png' : 'icons/ass/assmale.png') - else if(isdrone(ass)) //Drones are hot - temp_img = icon('icons/ass/assdrone.png') - else - break - busy = TRUE - sleep(15) - var/obj/item/photo/p = new /obj/item/photo (loc) - var/datum/picture/toEmbed = new(name = "[ass]'s Ass", desc = "You see [ass]'s ass on the photo.", image = temp_img) - p.pixel_x = rand(-10, 10) - p.pixel_y = rand(-10, 10) - toEmbed.psize_x = 128 - toEmbed.psize_y = 128 - p.set_picture(toEmbed, TRUE, TRUE) - toner -= 5 - busy = FALSE - else - break - updateUsrDialog() - else if(href_list["remove"]) - if(copy) - remove_photocopy(copy, usr) - copy = null - else if(photocopy) - remove_photocopy(photocopy, usr) - photocopy = null - else if(doccopy) - remove_photocopy(doccopy, usr) - doccopy = null - else if(check_ass()) - to_chat(ass, "You feel a slight pressure on your ass.") - updateUsrDialog() - else if(href_list["min"]) - if(copies > 1) - copies-- - updateUsrDialog() - else if(href_list["add"]) - if(copies < maxcopies) - copies++ - updateUsrDialog() - else if(href_list["aipic"]) - if(!isAI(usr)) - return - if(toner >= 5 && !busy) + + switch(action) + // Copying paper, photos, documents and asses. + if("make_copy") + if(busy) + to_chat(usr, "[src] is currently busy copying something. Please wait until it is finished.") + return FALSE + if(paper_copy) + if(!length(paper_copy.info)) + to_chat(usr, "An error message flashes across [src]'s screen: \"The supplied paper is blank. Aborting.\"") + return FALSE + // Basic paper + if(istype(paper_copy, /obj/item/paper)) + do_copy_loop(CALLBACK(src, .proc/make_paper_copy), usr) + return TRUE + // Devil contract paper. + if(istype(paper_copy, /obj/item/paper/contract/employment)) + do_copy_loop(CALLBACK(src, .proc/make_devil_paper_copy), usr) + return TRUE + // Copying photo. + if(photo_copy) + do_copy_loop(CALLBACK(src, .proc/make_photo_copy), usr) + return TRUE + // Copying Documents. + if(document_copy) + do_copy_loop(CALLBACK(src, .proc/make_document_copy), usr) + return TRUE + // ASS COPY. By Miauw + if(ass) + do_copy_loop(CALLBACK(src, .proc/make_ass_copy), usr) + return TRUE + + // Remove the paper/photo/document from the photocopier. + if("remove") + if(paper_copy) + remove_photocopy(paper_copy, usr) + paper_copy = null + else if(photo_copy) + remove_photocopy(photo_copy, usr) + photo_copy = null + else if(document_copy) + remove_photocopy(document_copy, usr) + document_copy = null + else if(check_ass()) + to_chat(ass, "You feel a slight pressure on your ass.") + return TRUE + + // AI printing photos from their saved images. + if("ai_photo") + if(busy) + to_chat(usr, "[src] is currently busy copying something. Please wait until it is finished.") + return FALSE var/mob/living/silicon/ai/tempAI = usr - if(tempAI.aicamera.stored.len == 0) - to_chat(usr, "No images saved") + if(!length(tempAI.aicamera.stored)) + to_chat(usr, "No images saved.") return var/datum/picture/selection = tempAI.aicamera.selectpicture(usr) - var/obj/item/photo/photo = new(loc, selection) - photo.pixel_x = rand(-10, 10) - photo.pixel_y = rand(-10, 10) - toner -= 5 //AI prints color pictures only, thus they can do it more efficiently - busy = TRUE - addtimer(CALLBACK(src, .proc/reset_busy), 1.5 SECONDS) - updateUsrDialog() - else if(href_list["colortoggle"]) - if(greytoggle == "Greyscale") - greytoggle = "Color" - else - greytoggle = "Greyscale" - updateUsrDialog() + var/obj/item/photo/photo = new(loc, selection) // AI prints color photos only. + give_pixel_offset(photo) + toner_cartridge.charges -= PHOTO_TONER_USE + return TRUE + // Switch between greyscale and color photos + if("color_mode") + if(params["mode"] in list(PHOTO_GREYSCALE, PHOTO_COLOR)) + color_mode = params["mode"] + return TRUE + + // Remove the toner cartridge from the copier. + if("remove_toner") + if(issilicon(usr) || (ishuman(usr) && !usr.put_in_hands(toner_cartridge))) + toner_cartridge.forceMove(drop_location()) + toner_cartridge = null + return TRUE + + // Set the number of copies to be printed with 1 click of the "copy" button. + if("set_copies") + num_copies = clamp(text2num(params["num_copies"]), 1, MAX_COPIES_AT_ONCE) + return TRUE + +/** + * Determines if the photocopier has enough toner to create `num_copies` amount of copies of the currently inserted item. + */ +/obj/machinery/photocopier/proc/has_enough_toner() + if(paper_copy) + return toner_cartridge.charges >= (PAPER_TONER_USE * num_copies) + else if(document_copy) + return toner_cartridge.charges >= (DOCUMENT_TONER_USE * num_copies) + else if(photo_copy) + return toner_cartridge.charges >= (PHOTO_TONER_USE * num_copies) + else if(ass) + return toner_cartridge.charges >= (ASS_TONER_USE * num_copies) + return FALSE + +/** + * Will invoke the passed in `copy_cb` callback in 1 second intervals, and charge the user 5 credits for each copy made. + * + * Arguments: + * * copy_cb - a callback for which proc to call. Should only be one of the `make_x_copy()` procs, such as `make_paper_copy()`. + * * user - the mob who clicked copy. + */ +/obj/machinery/photocopier/proc/do_copy_loop(datum/callback/copy_cb, mob/user) + busy = TRUE + var/i + for(i in 1 to num_copies) + //if(attempt_charge(src, user) & COMPONENT_OBJ_CANCEL_CHARGE) + // break + addtimer(copy_cb, i SECONDS) + addtimer(CALLBACK(src, .proc/reset_busy), i SECONDS) + +/** + * Sets busy to `FALSE`. Created as a proc so it can be used in callbacks. + */ /obj/machinery/photocopier/proc/reset_busy() busy = FALSE - updateUsrDialog() -/obj/machinery/photocopier/proc/do_insertion(obj/item/O, mob/user) - O.forceMove(src) - to_chat(user, "You insert [O] into [src].") +/** + * Gives items a random x and y pixel offset, between -10 and 10 for each. + * + * This is done that when someone prints multiple papers, we dont have them all appear to be stacked in the same exact location. + * + * Arguments: + * * copied_item - The paper, document, or photo that was just spawned on top of the printer. + */ +/obj/machinery/photocopier/proc/give_pixel_offset(obj/item/copied_item) + copied_item.pixel_x = rand(-10, 10) + copied_item.pixel_y = rand(-10, 10) + +/** + * Handles the copying of devil contract paper. Transfers all the text, stamps and so on from the old paper, to the copy. + * + * Checks first if `paper_copy` exists. Since this proc is called from a timer, it's possible that it was removed. + * Does not check if it has enough toner because devil contracts cost no toner to print. + */ +/obj/machinery/photocopier/proc/make_devil_paper_copy() + if(!paper_copy) + return + var/obj/item/paper/contract/employment/E = paper_copy + var/obj/item/paper/contract/employment/C = new(loc, E.target.current) + give_pixel_offset(C) + +/** + * Handles the copying of paper. Transfers all the text, stamps and so on from the old paper, to the copy. + * + * Checks first if `paper_copy` exists. Since this proc is called from a timer, it's possible that it was removed. + */ +/obj/machinery/photocopier/proc/make_paper_copy() + if(!paper_copy) + return + var/obj/item/paper/copied_paper = new(loc) + give_pixel_offset(copied_paper) + if(toner_cartridge.charges > 10) // Lots of toner, make it dark. + copied_paper.info = "" + else // No toner? shitty copies for you! + copied_paper.info = "" + + var/copied_info = paper_copy.info + copied_info = replacetext(copied_info, "" + copied_paper.name = paper_copy.name + copied_paper.update_icon() + copied_paper.stamps = paper_copy.stamps + if(paper_copy.stamped) + copied_paper.stamped = paper_copy.stamped.Copy() + copied_paper.copy_overlays(paper_copy, TRUE) + toner_cartridge.charges -= PAPER_TONER_USE + +/** + * Handles the copying of photos, which can be printed in either color or greyscale. + * + * Checks first if `photo_copy` exists. Since this proc is called from a timer, it's possible that it was removed. + */ +/obj/machinery/photocopier/proc/make_photo_copy() + if(!photo_copy) + return + var/obj/item/photo/copied_pic = new(loc, photo_copy.picture.Copy(color_mode == PHOTO_GREYSCALE ? TRUE : FALSE)) + give_pixel_offset(copied_pic) + toner_cartridge.charges -= PHOTO_TONER_USE + +/** + * Handles the copying of documents. + * + * Checks first if `document_copy` exists. Since this proc is called from a timer, it's possible that it was removed. + */ +/obj/machinery/photocopier/proc/make_document_copy() + if(!document_copy) + return + var/obj/item/documents/photocopy/copied_doc = new(loc, document_copy) + give_pixel_offset(copied_doc) + toner_cartridge.charges -= DOCUMENT_TONER_USE + +/** + * Handles the copying of an ass photo. + * + * Calls `check_ass()` first to make sure that `ass` exists, among other conditions. Since this proc is called from a timer, it's possible that it was removed. + * Additionally checks that the mob has their clothes off. + */ +/obj/machinery/photocopier/proc/make_ass_copy() + if(!check_ass()) + return + if(ishuman(ass)) //(ass.get_item_by_slot(ITEM_SLOT_ICLOTHING) || ass.get_item_by_slot(ITEM_SLOT_OCLOTHING))) + var/mob/living/carbon/C = ass //have to typecast to this, is_groin_exposed is carbon level + if(C.is_groin_exposed()) + to_chat(usr, "You feel kind of silly, copying [ass == usr ? "your" : ass][ass == usr ? "" : "\'s"] ass with [ass == usr ? "your" : "[ass.p_their()]"] clothes on." ) + return + + var/icon/temp_img + if(isalienadult(ass) || istype(ass, /mob/living/simple_animal/hostile/alien)) //Xenos have their own asses, thanks to Pybro. + temp_img = icon('icons/ass/assalien.png') + else if(ishuman(ass)) //Suit checks are after check_ass + temp_img = icon(ass.gender == FEMALE ? 'icons/ass/assfemale.png' : 'icons/ass/assmale.png') + else if(isdrone(ass)) //Drones are hot + temp_img = icon('icons/ass/assdrone.png') + + var/obj/item/photo/copied_ass = new /obj/item/photo(loc) + var/datum/picture/toEmbed = new(name = "[ass]'s Ass", desc = "You see [ass]'s ass on the photo.", image = temp_img) + give_pixel_offset(copied_ass) + toEmbed.psize_x = 128 + toEmbed.psize_y = 128 + copied_ass.set_picture(toEmbed, TRUE, TRUE) + toner_cartridge.charges -= ASS_TONER_USE + +/** + * Inserts the item into the copier. Called in `attackby()` after a human mob clicked on the copier with a paper, photo, or document. + * + * Arugments: + * * object - the object that got inserted. + * * user - the mob that inserted the object. + */ +/obj/machinery/photocopier/proc/do_insertion(obj/item/object, mob/user) + object.forceMove(src) + to_chat(user, "You insert [object] into [src].") flick("photocopier1", src) - updateUsrDialog() -/obj/machinery/photocopier/proc/remove_photocopy(obj/item/O, mob/user) +/** + * Called when someone hits the "remove item" button on the copier UI. + * + * If the user is a silicon, it drops the object at the location of the copier. If the user is not a silicon, it tries to put the object in their hands first. + * Sets `busy` to `FALSE` because if the inserted item is removed, the copier should halt copying. + * + * Arguments: + * * object - the item we're trying to remove. + * * user - the user removing the item. + */ +/obj/machinery/photocopier/proc/remove_photocopy(obj/item/object, mob/user) if(!issilicon(user)) //surprised this check didn't exist before, putting stuff in AI's hand is bad - O.forceMove(user.loc) - user.put_in_hands(O) + object.forceMove(user.loc) + user.put_in_hands(object) else - O.forceMove(drop_location()) - to_chat(user, "You take [O] out of [src].") + object.forceMove(drop_location()) + to_chat(user, "You take [object] out of [src]. [busy ? "The [src] comes to a halt." : ""]") /obj/machinery/photocopier/attackby(obj/item/O, mob/user, params) if(default_unfasten_wrench(user, O)) @@ -210,7 +351,7 @@ else if(!user.temporarilyRemoveItemFromInventory(O)) return - copy = O + paper_copy = O do_insertion(O, user) else to_chat(user, "There is already something in [src]!") @@ -219,7 +360,7 @@ if(copier_empty()) if(!user.temporarilyRemoveItemFromInventory(O)) return - photocopy = O + photo_copy = O do_insertion(O, user) else to_chat(user, "There is already something in [src]!") @@ -228,38 +369,35 @@ if(copier_empty()) if(!user.temporarilyRemoveItemFromInventory(O)) return - doccopy = O + document_copy = O do_insertion(O, user) else to_chat(user, "There is already something in [src]!") else if(istype(O, /obj/item/toner)) - if(toner <= 0) - if(!user.temporarilyRemoveItemFromInventory(O)) - return - qdel(O) - toner = 40 - to_chat(user, "You insert [O] into [src].") - updateUsrDialog() - else - to_chat(user, "This cartridge is not yet ready for replacement! Use up the rest of the toner.") + if(toner_cartridge) + to_chat(user, "[src] already has a toner cartridge inserted. Remove that one first.") + return + O.forceMove(src) + toner_cartridge = O + to_chat(user, "You insert [O] into [src].") else if(istype(O, /obj/item/areaeditor/blueprints)) - to_chat(user, "The Blueprint is too large to put into the copier. You need to find something else to record the document") + to_chat(user, "The Blueprint is too large to put into the copier. You need to find something else to record the document.") else return ..() /obj/machinery/photocopier/obj_break(damage_flag) . = ..() - if(. && toner > 0) + if(. && toner_cartridge.charges) new /obj/effect/decal/cleanable/oil(get_turf(src)) - toner = 0 + toner_cartridge.charges = 0 /obj/machinery/photocopier/MouseDrop_T(mob/target, mob/user) check_ass() //Just to make sure that you can re-drag somebody onto it after they moved off. - if (!istype(target) || target.anchored || target.buckled || !Adjacent(target) || !user.canUseTopic(src, BE_CLOSE) || target == ass || copier_blocked()) + if(!istype(target) || target.anchored || target.buckled || !Adjacent(target) || !user.canUseTopic(src, BE_CLOSE) || target == ass || copier_blocked()) return - src.add_fingerprint(user) + add_fingerprint(user) if(target == user) user.visible_message("[user] starts climbing onto the photocopier!", "You start climbing onto the photocopier...") else @@ -277,49 +415,63 @@ target.forceMove(drop_location()) ass = target - if(photocopy) - photocopy.forceMove(drop_location()) - visible_message("[photocopy] is shoved out of the way by [ass]!") - photocopy = null + if(photo_copy) + photo_copy.forceMove(drop_location()) + visible_message("[photo_copy] is shoved out of the way by [ass]!") + photo_copy = null - else if(copy) - copy.forceMove(drop_location()) - visible_message("[copy] is shoved out of the way by [ass]!") - copy = null - updateUsrDialog() + else if(paper_copy) + paper_copy.forceMove(drop_location()) + visible_message("[paper_copy] is shoved out of the way by [ass]!") + paper_copy = null + else if(document_copy) + document_copy.forceMove(drop_location()) + visible_message("[document_copy] is shoved out of the way by [ass]!") + document_copy = null + +/obj/machinery/photocopier/Exited(atom/movable/AM, atom/newloc) + check_ass() // There was potentially a person sitting on the copier, check if they're still there. + return ..() + +/** + * Checks the living mob `ass` exists and its location is the same as the photocopier. + * + * Returns FALSE if `ass` doesn't exist or is not at the copier's location. Returns TRUE otherwise. + */ /obj/machinery/photocopier/proc/check_ass() //I'm not sure wether I made this proc because it's good form or because of the name. if(!ass) - return 0 - if(ass.loc != src.loc) + return FALSE + if(ass.loc != loc) ass = null - updateUsrDialog() - return 0 - else if(ishuman(ass)) - if(!ass.get_item_by_slot(ITEM_SLOT_ICLOTHING) && !ass.get_item_by_slot(ITEM_SLOT_OCLOTHING)) - return 1 - else - return 0 - else - return 1 + return FALSE + return TRUE +/** + * Checks if the copier is deleted, or has something dense at its location. Called in `MouseDrop_T()` + */ /obj/machinery/photocopier/proc/copier_blocked() if(QDELETED(src)) return if(loc.density) - return 1 + return TRUE for(var/atom/movable/AM in loc) if(AM == src) continue if(AM.density) - return 1 - return 0 + return TRUE + return FALSE +/** + * Checks if there is an item inserted into the copier or a mob sitting on top of it. + * + * Return `FALSE` is the copier has something inside of it. Returns `TRUE` if it doesn't. + */ /obj/machinery/photocopier/proc/copier_empty() - if(copy || photocopy || check_ass()) - return 0 + if(paper_copy || photo_copy || document_copy || check_ass()) + return FALSE else - return 1 + return TRUE /* * Toner cartridge @@ -343,3 +495,11 @@ desc = "Why would ANYONE need THIS MUCH TONER?" charges = 200 max_charges = 200 + +#undef PHOTO_GREYSCALE +#undef PHOTO_COLOR +#undef PAPER_TONER_USE +#undef PHOTO_TONER_USE +#undef DOCUMENT_TONER_USE +#undef ASS_TONER_USE +#undef MAX_COPIES_AT_ONCE diff --git a/code/modules/paperwork/stamps.dm b/code/modules/paperwork/stamps.dm index 241dde13a8..104f70bfdf 100644 --- a/code/modules/paperwork/stamps.dm +++ b/code/modules/paperwork/stamps.dm @@ -4,6 +4,7 @@ icon = 'icons/obj/bureaucracy.dmi' icon_state = "stamp-ok" item_state = "stamp" + // inhand_icon_state = "stamp" throwforce = 0 w_class = WEIGHT_CLASS_TINY throw_speed = 3 @@ -11,6 +12,8 @@ custom_materials = list(/datum/material/iron=60) pressure_resistance = 2 attack_verb = list("stamped") + // attack_verb_continuous = list("stamps") + // attack_verb_simple = list("stamp") /obj/item/stamp/suicide_act(mob/user) user.visible_message("[user] stamps 'VOID' on [user.p_their()] forehead, then promptly falls over, dead.") @@ -66,5 +69,25 @@ icon_state = "stamp-clown" dye_color = DYE_CLOWN +/obj/item/stamp/mime + name = "mime's rubber stamp" + icon_state = "stamp-mime" + dye_color = DYE_MIME + +/obj/item/stamp/chap + name = "chaplain's rubber stamp" + icon_state = "stamp-chap" + dye_color = DYE_CHAP + +/obj/item/stamp/centcom + name = "CentCom rubber stamp" + icon_state = "stamp-centcom" + dye_color = DYE_CENTCOM + +/obj/item/stamp/syndicate + name = "Syndicate rubber stamp" + icon_state = "stamp-syndicate" + dye_color = DYE_SYNDICATE + /obj/item/stamp/attack_paw(mob/user) return attack_hand(user) diff --git a/code/modules/paperwork/ticketmachine.dm b/code/modules/paperwork/ticketmachine.dm new file mode 100644 index 0000000000..e46ed64971 --- /dev/null +++ b/code/modules/paperwork/ticketmachine.dm @@ -0,0 +1,231 @@ +//Bureaucracy machine! +//Simply set this up in the hopline and you can serve people based on ticket numbers + +/obj/machinery/ticket_machine + name = "ticket machine" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "ticketmachine" + desc = "A marvel of bureaucratic engineering encased in an efficient plastic shell. It can be refilled with a hand labeler refill roll and linked to buttons with a multitool." + density = FALSE + maptext_height = 26 + maptext_width = 32 + maptext_x = 7 + maptext_y = 10 + layer = HIGH_OBJ_LAYER + var/ticket_number = 0 //Increment the ticket number whenever the HOP presses his button + var/current_number = 0 //What ticket number are we currently serving? + var/max_number = 100 //At this point, you need to refill it. + var/cooldown = 50 + var/ready = TRUE + var/id = "ticket_machine_default" //For buttons + var/list/ticket_holders = list() + var/list/obj/item/ticket_machine_ticket/tickets = list() + +/obj/machinery/ticket_machine/multitool_act(mob/living/user, obj/item/I) + if(!multitool_check_buffer(user, I)) //make sure it has a data buffer + return + var/obj/item/multitool/M = I + M.buffer = src + to_chat(user, "You store linkage information in [I]'s buffer.") + return TRUE + +/obj/machinery/ticket_machine/emag_act(mob/user) //Emag the ticket machine to dispense burning tickets, as well as randomize its number to destroy the HoP's mind. + if(obj_flags & EMAGGED) + return + to_chat(user, "You overload [src]'s bureaucratic logic circuitry to its MAXIMUM setting.") + ticket_number = rand(0,max_number) + current_number = ticket_number + obj_flags |= EMAGGED + if(tickets.len) + for(var/obj/item/ticket_machine_ticket/ticket in tickets) + ticket.audible_message("\the [ticket] disperses!") + qdel(ticket) + tickets.Cut() + update_icon() + +/obj/machinery/ticket_machine/Initialize() + . = ..() + update_icon() + +/obj/machinery/ticket_machine/proc/increment() + if(current_number > ticket_number) + return + if(current_number && !(obj_flags & EMAGGED) && tickets[current_number]) + tickets[current_number].audible_message("\the [tickets[current_number]] disperses!") + qdel(tickets[current_number]) + if(current_number < ticket_number) + current_number ++ //Increment the one we're serving. + playsound(src, 'sound/misc/announce_dig.ogg', 50, FALSE) + say("Now serving ticket #[current_number]!") + if(!(obj_flags & EMAGGED) && tickets[current_number]) + tickets[current_number].audible_message("\the [tickets[current_number]] vibrates!") + update_icon() //Update our icon here rather than when they take a ticket to show the current ticket number being served + +/obj/machinery/button/ticket_machine + name = "increment ticket counter" + desc = "Use this button after you've served someone to tell the next person to come forward." + device_type = /obj/item/assembly/control/ticket_machine + req_access = list() + id = "ticket_machine_default" + +/obj/machinery/button/ticket_machine/Initialize() + . = ..() + if(device) + var/obj/item/assembly/control/ticket_machine/ours = device + ours.id = id + +/obj/machinery/button/ticket_machine/multitool_act(mob/living/user, obj/item/I) + . = ..() + if(I.tool_behaviour == TOOL_MULTITOOL) + var/obj/item/multitool/M = I + if(M.buffer && !istype(M.buffer, /obj/machinery/ticket_machine)) + return + var/obj/item/assembly/control/ticket_machine/controller = device + controller.linked = M.buffer + id = null + controller.id = null + to_chat(user, "You've linked [src] to [controller.linked].") + +/obj/item/assembly/control/ticket_machine + name = "ticket machine controller" + desc = "A remote controller for the HoP's ticket machine." + var/obj/machinery/ticket_machine/linked //To whom are we linked? + +/obj/item/assembly/control/ticket_machine/Initialize() + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/item/assembly/control/ticket_machine/LateInitialize() + find_machine() + +/obj/item/assembly/control/ticket_machine/proc/find_machine() //Locate the one to which we're linked + for(var/obj/machinery/ticket_machine/ticketsplease in GLOB.machines) + if(ticketsplease.id == id) + linked = ticketsplease + if(linked) + return TRUE + else + return FALSE + +/obj/item/assembly/control/ticket_machine/activate() + if(cooldown) + return + if(!linked) + return + cooldown = TRUE + linked.increment() + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10) + +/obj/machinery/ticket_machine/update_icon() + switch(ticket_number) //Gives you an idea of how many tickets are left + if(0 to 49) + icon_state = "ticketmachine_100" + if(50 to 99) + icon_state = "ticketmachine_50" + if(100) + icon_state = "ticketmachine_0" + handle_maptext() + +/obj/machinery/ticket_machine/proc/handle_maptext() + switch(ticket_number) //This is here to handle maptext offsets so that the numbers align. + if(0 to 9) + maptext_x = 13 + if(10 to 99) + maptext_x = 10 + if(100) + maptext_x = 8 + maptext = "[current_number]" //Finally, apply the maptext + +/obj/machinery/ticket_machine/attackby(obj/item/I, mob/user, params) + ..() + if(istype(I, /obj/item/hand_labeler_refill)) + if(!(ticket_number >= max_number)) + to_chat(user, "[src] refuses [I]! There [max_number-ticket_number==1 ? "is" : "are"] still [max_number-ticket_number] ticket\s left!") + return + to_chat(user, "You start to refill [src]'s ticket holder (doing this will reset its ticket count!).") + if(do_after(user, 30, target = src)) + to_chat(user, "You insert [I] into [src] as it whirs nondescriptly.") + qdel(I) + ticket_number = 0 + current_number = 0 + if(tickets.len) + for(var/obj/item/ticket_machine_ticket/ticket in tickets) + ticket.audible_message("\the [ticket] disperses!") + qdel(ticket) + tickets.Cut() + max_number = initial(max_number) + update_icon() + return + +/obj/machinery/ticket_machine/proc/reset_cooldown() + ready = TRUE + +/obj/machinery/ticket_machine/attack_hand(mob/living/carbon/user) + . = ..() + if(!ready) + to_chat(user,"You press the button, but nothing happens...") + return + if(ticket_number >= max_number) + to_chat(user,"Ticket supply depleted, please refill this unit with a hand labeller refill cartridge!") + return + if((user in ticket_holders) && !(obj_flags & EMAGGED)) + to_chat(user, "You already have a ticket!") + return + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 100, FALSE) + ticket_number ++ + to_chat(user, "You take a ticket from [src], looks like you're ticket number #[ticket_number]...") + var/obj/item/ticket_machine_ticket/theirticket = new /obj/item/ticket_machine_ticket(get_turf(src)) + theirticket.name = "Ticket #[ticket_number]" + theirticket.maptext = "[ticket_number]" + theirticket.saved_maptext = "[ticket_number]" + theirticket.ticket_number = ticket_number + theirticket.source = src + theirticket.owner = user + user.put_in_hands(theirticket) + ticket_holders += user + tickets += theirticket + if(obj_flags & EMAGGED) //Emag the machine to destroy the HOP's life. + ready = FALSE + addtimer(CALLBACK(src, .proc/reset_cooldown), cooldown)//Small cooldown to prevent piles of flaming tickets + theirticket.fire_act() + user.dropItemToGround(theirticket) + user.adjust_fire_stacks(1) + user.IgniteMob() + return + +/obj/item/ticket_machine_ticket + name = "Ticket" + desc = "A ticket which shows your place in the Head of Personnel's line. Made from Nanotrasen patented NanoPaper®. Though solid, its form seems to shimmer slightly. Feels (and burns) just like the real thing." + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "ticket" + maptext_x = 7 + maptext_y = 10 + w_class = WEIGHT_CLASS_TINY + resistance_flags = FLAMMABLE + max_integrity = 50 + var/saved_maptext = null + var/mob/living/carbon/owner + var/obj/machinery/ticket_machine/source + var/ticket_number + +/obj/item/ticket_machine_ticket/attack_hand(mob/user) + . = ..() + maptext = saved_maptext //For some reason, storage code removes all maptext off objs, this stops its number from being wiped off when taken out of storage. + +/obj/item/ticket_machine_ticket/attackby(obj/item/P, mob/living/carbon/human/user, params) //Stolen from papercode + if(burn_paper_product_attackby_check(P, user)) + return + + return ..() + +/obj/item/paper/extinguish() + ..() + update_icon() + +/obj/item/ticket_machine_ticket/Destroy() + if(owner && source) + source.ticket_holders -= owner + source.tickets[ticket_number] = null + owner = null + source = null + return ..() diff --git a/code/modules/photography/_pictures.dm b/code/modules/photography/_pictures.dm index f667e18f47..6f85cdb3a6 100644 --- a/code/modules/photography/_pictures.dm +++ b/code/modules/photography/_pictures.dm @@ -30,16 +30,16 @@ if(autogenerate_icon && !picture_icon && picture_image) regenerate_small_icon() -/datum/picture/proc/get_small_icon() +/datum/picture/proc/get_small_icon(iconstate) if(!picture_icon) - regenerate_small_icon() + regenerate_small_icon(iconstate) return picture_icon -/datum/picture/proc/regenerate_small_icon() +/datum/picture/proc/regenerate_small_icon(iconstate) if(!picture_image) return var/icon/small_img = icon(picture_image) - var/icon/ic = icon('icons/obj/items_and_weapons.dmi', "photo") + var/icon/ic = icon('icons/obj/items_and_weapons.dmi', iconstate ? iconstate :"photo") small_img.Scale(8, 8) ic.Blend(small_img,ICON_OVERLAY, 13, 13) picture_icon = ic diff --git a/code/modules/photography/photos/photo.dm b/code/modules/photography/photos/photo.dm index 5c78709e9b..c363c549de 100644 --- a/code/modules/photography/photos/photo.dm +++ b/code/modules/photography/photos/photo.dm @@ -35,23 +35,23 @@ /obj/item/photo/update_icon_state() if(!istype(picture) || !picture.picture_image) return - var/icon/I = picture.get_small_icon() + var/icon/I = picture.get_small_icon(initial(icon_state)) if(I) icon = I /obj/item/photo/suicide_act(mob/living/carbon/user) user.visible_message("[user] is taking one last look at \the [src]! It looks like [user.p_theyre()] giving in to death!")//when you wanna look at photo of waifu one last time before you die... if (user.gender == MALE) - playsound(user, 'sound/voice/human/manlaugh1.ogg', 50, 1)//EVERY TIME I DO IT MAKES ME LAUGH + playsound(user, 'sound/voice/human/manlaugh1.ogg', 50, TRUE)//EVERY TIME I DO IT MAKES ME LAUGH else if (user.gender == FEMALE) - playsound(user, 'sound/voice/human/womanlaugh.ogg', 50, 1) + playsound(user, 'sound/voice/human/womanlaugh.ogg', 50, TRUE) return OXYLOSS /obj/item/photo/attack_self(mob/user) user.examinate(src) /obj/item/photo/attackby(obj/item/P, mob/user, params) - if(try_burn(P, user)) + if(burn_paper_product_attackby_check(P, user)) return if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon)) if(!user.is_literate()) @@ -60,31 +60,13 @@ var/txt = stripped_input(user, "What would you like to write on the back?", "Photo Writing", "", 128) if(txt && user.canUseTopic(src, BE_CLOSE)) scribble = txt - ..() - -/obj/item/photo/proc/try_burn(obj/item/I, mob/living/user) - var/ignition_message = I.ignition_effect(src, user) - if(!ignition_message) - return - . = TRUE - if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(10) && Adjacent(user)) - user.visible_message("[user] accidentally ignites [user.p_them()]self!", \ - "You miss [src] and accidentally light yourself on fire!") - if(user.is_holding(I)) //checking if they're holding it in case TK is involved - user.dropItemToGround(I) - user.adjust_fire_stacks(1) - user.IgniteMob() - return - - if(user.is_holding(src)) //no TK shit here. - user.dropItemToGround(src) - user.visible_message(ignition_message) - add_fingerprint(user) - fire_act(I.get_temperature()) + else + return ..() /obj/item/photo/examine(mob/user) . = ..() - if(in_range(src, user)) + + if(in_range(src, user) || isobserver(user)) show(user) else . += "You need to get closer to get a good look at this photo!" diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm index 54b1362518..93fd9fe3d9 100644 --- a/code/modules/power/generator.dm +++ b/code/modules/power/generator.dm @@ -66,7 +66,7 @@ var/energy_transfer = delta_temperature*hot_air_heat_capacity*cold_air_heat_capacity/(hot_air_heat_capacity+cold_air_heat_capacity) var/heat = energy_transfer*(1-efficiency) - lastgen += LOGISTIC_FUNCTION(1000000,0.0034,delta_temperature,2000) + lastgen += LOGISTIC_FUNCTION(1250000,0.0001,delta_temperature,50000) hot_air.set_temperature(hot_air.return_temperature() - energy_transfer/hot_air_heat_capacity) cold_air.set_temperature(cold_air.return_temperature() + heat/cold_air_heat_capacity) @@ -139,7 +139,6 @@ . = ..() var/datum/browser/popup = new(user, "teg", "Thermo-Electric Generator", 460, 300) popup.set_content(get_menu()) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() /obj/machinery/power/generator/Topic(href, href_list) diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm index eb80548441..be24ea0fef 100644 --- a/code/modules/power/tesla/coil.dm +++ b/code/modules/power/tesla/coil.dm @@ -160,6 +160,14 @@ buckle_lying = FALSE buckle_requires_restraints = TRUE +/obj/machinery/power/grounding_rod/Initialize() + GLOB.grounding_rods |= src + return ..() + +/obj/machinery/power/grounding_rod/Destroy() + GLOB.grounding_rods.Remove(src) + return ..() + /obj/machinery/power/grounding_rod/default_unfasten_wrench(mob/user, obj/item/I, time = 20) . = ..() if(. == SUCCESSFUL_UNFASTEN) diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm index 06e5d27f6d..89c5aa3316 100644 --- a/code/modules/power/tesla/energy_ball.dm +++ b/code/modules/power/tesla/energy_ball.dm @@ -31,6 +31,7 @@ var/produced_power var/energy_to_raise = 32 var/energy_to_lower = -20 + var/obj/machinery/power/grounding_rod/rodtarget /obj/singularity/energy_ball/Initialize(mapload, starting_energy = 50, is_miniball = FALSE) miniball = is_miniball @@ -60,11 +61,12 @@ return //don't annnounce miniballs ..() - /obj/singularity/energy_ball/process() if(!orbiting) handle_energy() + determine_containment() + move_the_basket_ball(4 + orbiting_balls.len * 1.5) playsound(src.loc, 'sound/magic/lightningbolt.ogg', 100, TRUE, extrarange = 30) @@ -87,12 +89,19 @@ if(orbiting_balls.len) . += "There are [orbiting_balls.len] mini-balls orbiting it." - /obj/singularity/energy_ball/proc/move_the_basket_ball(var/move_amount) //we face the last thing we zapped, so this lets us favor that direction a bit var/move_bias = pick(GLOB.alldirs) + var/move_dir + for(var/rod in GLOB.grounding_rods) // grounding rods pull the tesla ball, picks the nearest one + if(!rodtarget || get_dist(src,rod)= energy_to_raise) @@ -121,6 +144,10 @@ else if(orbiting_balls.len) dissipate() //sing code has a much better system. + if(energy<=0) + investigate_log("fizzled.", INVESTIGATE_SINGULO) + qdel(src) + /obj/singularity/energy_ball/proc/new_mini_ball() if(!loc) return @@ -134,7 +161,6 @@ EB.orbit(src, orbitsize, pick(FALSE, TRUE), rand(10, 25), pick(3, 4, 5, 6, 36)) - /obj/singularity/energy_ball/Bump(atom/A) dust_mobs(A) @@ -166,7 +192,6 @@ if (!QDELETED(src)) qdel(src) - /obj/singularity/energy_ball/proc/dust_mobs(atom/A) if(isliving(A)) var/mob/living/L = A @@ -329,6 +354,12 @@ else power = closest_atom.zap_act(power, zap_flags, shocked_targets) + + var/obj/singularity/energy_ball/tesla = source + if(istype(tesla)) + if(istype(closest_atom,/obj/machinery/power/grounding_rod) && tesla.energy>13 && !tesla.contained) + qdel(closest_atom) // each rod deletes two miniballs, + tesla.energy = round(tesla.energy/1.5625) // if there are no miniballs the rod stays and continues to pull the ball in if(prob(20))//I know I know tesla_zap(closest_atom, next_range, power * 0.5, zap_flags, shocked_targets) tesla_zap(closest_atom, next_range, power * 0.5, zap_flags, shocked_targets) diff --git a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm index 0b00c89c02..8cd49bdf16 100644 --- a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm +++ b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm @@ -149,6 +149,9 @@ icon = 'icons/obj/ammo.dmi' icon_state = "shotgunclip" caliber = "shotgun" // slapped in to allow shell mix n match + slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_POCKET + w_class = WEIGHT_CLASS_NORMAL + w_volume = ITEM_VOLUME_STRIPPER_CLIP ammo_type = /obj/item/ammo_casing/shotgun max_ammo = 4 var/pixeloffsetx = 4 diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 17dcfa96e6..0a587e8eba 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -268,7 +268,7 @@ for(var/i = ratio, i >= 1, i--) charge_overlay.pixel_x = ammo_x_offset * (i - 1) charge_overlay.pixel_y = ammo_y_offset * (i - 1) - . += charge_overlay + . += new /mutable_appearance(charge_overlay) else . += "[icon_state]_charge[ratio]" diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm index e1433eb64e..3675efa283 100644 --- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm @@ -329,7 +329,7 @@ color = "#101000" // rgb: 16, 16, 0 nutriment_factor = 0 taste_description = "sweet red tea" - glass_icon_state = "teaglass" + glass_icon_state = "tea_red" glass_name = "glass of red tea" glass_desc = "A piping hot tea that helps with the digestion of food." @@ -340,6 +340,7 @@ M.drowsyness = max(0,M.drowsyness-1) M.jitteriness = max(0,M.jitteriness-3) M.adjust_bodytemperature(23 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, BODYTEMP_NORMAL) + ..() . = 1 /datum/reagent/consumable/tea/green @@ -348,7 +349,7 @@ color = "#101000" // rgb: 16, 16, 0 nutriment_factor = 0 taste_description = "tart green tea" - glass_icon_state = "teaglass" + glass_icon_state = "tea_green" glass_name = "glass of tea" glass_desc = "A calming glass of green tea to help get you through the day." @@ -358,6 +359,7 @@ M.drowsyness = max(0,M.drowsyness-1) M.jitteriness = max(0,M.jitteriness-3) M.adjust_bodytemperature(15 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, BODYTEMP_NORMAL) + ..() . = 1 /datum/reagent/consumable/tea/forest @@ -367,7 +369,7 @@ nutriment_factor = 0 quality = DRINK_NICE taste_description = "sweet tea" - glass_icon_state = "teaglass" + glass_icon_state = "tea_forest" glass_name = "glass of forest tea" glass_desc = "A lovely glass of tea and honey." @@ -379,6 +381,7 @@ M.drowsyness = max(0,M.drowsyness-1) M.jitteriness = max(0,M.jitteriness-3) M.adjust_bodytemperature(15 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, BODYTEMP_NORMAL) + ..() . = 1 /datum/reagent/consumable/tea/mush @@ -388,7 +391,7 @@ nutriment_factor = 0 quality = DRINK_NICE taste_description = "fungal infections" - glass_icon_state = "teaglass" + glass_icon_state = "tea_mush" glass_name = "glass of mush tea" glass_desc = "A cold merky brown tea." @@ -398,6 +401,7 @@ M.Dizzy(10) if(prob(10)) M.disgust = 0 + ..() . = 1 /datum/reagent/consumable/lemonade diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 9b25a80680..926ed27854 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -19,6 +19,10 @@ var/stream_range = 1 //the range of tiles the sprayer will reach when in stream mode. var/stream_amount = 10 //the amount of reagents transfered when in stream mode. var/spray_delay = 3 //The amount of sleep() delay between each chempuff step. + /// Last world.time of spray + var/last_spray = 0 + /// Spray cooldown + var/spray_cooldown = CLICK_CD_MELEE var/can_fill_from_container = TRUE amount_per_transfer_from_this = 5 volume = 250 @@ -27,8 +31,6 @@ /obj/item/reagent_containers/spray/afterattack(atom/A, mob/user) . = ..() - if(!user.CheckActionCooldown(CLICK_CD_MELEE)) - return if(istype(A, /obj/structure/sink) || istype(A, /obj/structure/janitorialcart) || istype(A, /obj/machinery/hydroponics)) return @@ -49,7 +51,8 @@ to_chat(user, "[src] is empty!") return - spray(A) + if(!spray(A)) + return playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6) user.last_action = world.time @@ -64,10 +67,10 @@ if(reagents.has_reagent(/datum/reagent/lube)) message_admins("[ADMIN_LOOKUPFLW(user)] fired Space lube from \a [src] at [ADMIN_VERBOSEJMP(T)].") log_game("[key_name(user)] fired Space lube from \a [src] at [AREACOORD(T)].") - return - /obj/item/reagent_containers/spray/proc/spray(atom/A) + if((last_spray + spray_cooldown) > world.time) + return var/range = clamp(get_dist(src, A), 1, current_range) var/obj/effect/decal/chempuff/D = new /obj/effect/decal/chempuff(get_turf(src)) D.create_reagents(amount_per_transfer_from_this, NONE, NO_REAGENTS_VALUE) @@ -79,10 +82,11 @@ reagents.trans_to(D, amount_per_transfer_from_this, 1/range) D.color = mix_color_from_reagents(D.reagents.reagent_list) var/wait_step = max(round(2+ spray_delay * INVERSE(range)), 2) - do_spray(A, wait_step, D, range, puff_reagent_left) + last_spray = world.time + INVOKE_ASYNC(src, .proc/do_spray, A, wait_step, D, range, puff_reagent_left) + return TRUE /obj/item/reagent_containers/spray/proc/do_spray(atom/A, wait_step, obj/effect/decal/chempuff/D, range, puff_reagent_left) - set waitfor = FALSE var/range_left = range for(var/i=0, i[dat]") - popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) popup.open() /obj/machinery/computer/shuttle/Topic(href, href_list) diff --git a/code/modules/shuttle/custom_shuttle.dm b/code/modules/shuttle/custom_shuttle.dm index c71b6ba9a8..8047e972db 100644 --- a/code/modules/shuttle/custom_shuttle.dm +++ b/code/modules/shuttle/custom_shuttle.dm @@ -68,7 +68,6 @@ popup = new(user, "computer", M ? M.name : "shuttle", 350, 450) popup.set_content("
[dat]
") - popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) popup.open() /obj/machinery/computer/custom_shuttle/Topic(href, href_list) diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm index 472734b74b..9ebcfe91d6 100644 --- a/code/modules/station_goals/bsa.dm +++ b/code/modules/station_goals/bsa.dm @@ -31,6 +31,7 @@ anchored = TRUE /obj/machinery/bsa/wrench_act(mob/living/user, obj/item/I) + ..() default_unfasten_wrench(user, I, 10) return TRUE @@ -142,17 +143,17 @@ /obj/machinery/bsa/full/proc/get_front_turf() switch(dir) if(WEST) - return locate(x - 6,y,z) + return locate(x - 7,y,z) if(EAST) - return locate(x + 4,y,z) + return locate(x + 7,y,z) return get_turf(src) /obj/machinery/bsa/full/proc/get_back_turf() switch(dir) if(WEST) - return locate(x + 4,y,z) + return locate(x + 5,y,z) if(EAST) - return locate(x - 6,y,z) + return locate(x - 5,y,z) return get_turf(src) /obj/machinery/bsa/full/proc/get_target_turf() @@ -169,11 +170,12 @@ switch(cannon_direction) if(WEST) setDir(WEST) - pixel_x = -192 top_layer.icon_state = "top_west" icon_state = "cannon_west" if(EAST) setDir(EAST) + pixel_x = -128 + bound_x = -128 top_layer.icon_state = "top_east" icon_state = "cannon_east" add_overlay(top_layer) @@ -211,6 +213,7 @@ message_admins("[ADMIN_LOOKUPFLW(user)] has launched an artillery strike targeting [ADMIN_VERBOSEJMP(bullseye)] but it was blocked by [blocker] at [ADMIN_VERBOSEJMP(target)].") log_game("[key_name(user)] has launched an artillery strike targeting [AREACOORD(bullseye)] but it was blocked by [blocker] at [AREACOORD(target)].") + /obj/machinery/bsa/full/proc/reload() ready = FALSE use_power(power_used_per_shot) @@ -293,15 +296,16 @@ /obj/machinery/computer/bsa_control/proc/get_target_name() if(istype(target, /area)) return get_area_name(target, TRUE) - else if(istype(target, /obj/item/gps)) - var/obj/item/gps/G = target + else if(istype(target, /datum/component/gps)) + var/datum/component/gps/G = target return G.gpstag /obj/machinery/computer/bsa_control/proc/get_impact_turf() if(istype(target, /area)) return pick(get_area_turfs(target)) - else if(istype(target, /obj/item/gps)) - return get_turf(target) + else if(istype(target, /datum/component/gps)) + var/datum/component/gps/G = target + return get_turf(G.parent) /obj/machinery/computer/bsa_control/proc/fire(mob/user) if(cannon.stat) diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 3d88282937..e90f86bf1c 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -598,7 +598,7 @@ var/datum/species/S = H.dna.species base_bp_icon = S?.icon_limbs || DEFAULT_BODYPART_ICON - species_id = S.limbs_id + species_id = S.mutant_bodyparts["limbs_id"] species_flags_list = H.dna.species.species_traits //body marking memes @@ -613,7 +613,6 @@ if(S.use_skintones) skin_tone = H.skin_tone - base_bp_icon = (base_bp_icon == DEFAULT_BODYPART_ICON) ? DEFAULT_BODYPART_ICON_ORGANIC : base_bp_icon else skin_tone = "" @@ -626,13 +625,9 @@ species_color = S.fixed_mut_color else species_color = H.dna.features["mcolor"] - base_bp_icon = (base_bp_icon == DEFAULT_BODYPART_ICON) ? DEFAULT_BODYPART_ICON_ORGANIC : base_bp_icon else species_color = "" - if(base_bp_icon != DEFAULT_BODYPART_ICON) - color_src = mut_colors ? MUTCOLORS : ((H.dna.skin_tone_override && S.use_skintones == USE_SKINTONES_GRAYSCALE_CUSTOM) ? CUSTOM_SKINTONE : SKINTONE) - if(S.mutant_bodyparts["legs"]) if(body_zone == BODY_ZONE_L_LEG || body_zone == BODY_ZONE_R_LEG) if(DIGITIGRADE in S.species_traits) @@ -652,11 +647,16 @@ body_markings = "plain" aux_marking = "plain" markings_color = list(colorlist) - else body_markings = null aux_marking = null + if(species_id in GLOB.greyscale_limb_types) //should they have greyscales? + base_bp_icon = DEFAULT_BODYPART_ICON_ORGANIC + + if(base_bp_icon != DEFAULT_BODYPART_ICON) + color_src = mut_colors ? MUTCOLORS : ((H.dna.skin_tone_override && S.use_skintones == USE_SKINTONES_GRAYSCALE_CUSTOM) ? CUSTOM_SKINTONE : SKINTONE) + if(!dropping_limb && H.dna.check_mutation(HULK)) mutation_color = "00aa00" else diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm index 049fc5b5d4..9172ce00bc 100644 --- a/code/modules/surgery/organs/eyes.dm +++ b/code/modules/surgery/organs/eyes.dm @@ -265,6 +265,10 @@ var/C = input(owner, "Select Color", "Select color", "#ffffff") as color|null if(!C || QDELETED(src) || QDELETED(user) || QDELETED(owner) || owner != user) return + var/list/hsv = ReadHSV(RGBtoHSV(C)) + if(hsv[2] > 125) + to_chat(user, "A color that saturated? Surely not!") + return var/range = input(user, "Enter range (0 - [max_light_beam_distance])", "Range Select", 0) as null|num if(!isnum(range)) return @@ -396,4 +400,4 @@ #undef BLURRY_VISION_ONE #undef BLURRY_VISION_TWO -#undef BLIND_VISION_THREE \ No newline at end of file +#undef BLIND_VISION_THREE diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm index 7090ab62e2..33d143d400 100644 --- a/code/modules/surgery/organs/tongue.dm +++ b/code/modules/surgery/organs/tongue.dm @@ -11,7 +11,8 @@ var/say_mod = null var/taste_sensitivity = 15 // lower is more sensitive. maxHealth = TONGUE_MAX_HEALTH - var/modifies_speech = FALSE + var/list/initial_accents //the ones the tongue starts with, not what it currently has + var/list/accents //done in order of priority (please always apply abductor accent and stuttering last) var/static/list/languages_possible_base = typecacheof(list( /datum/language/common, /datum/language/draconic, @@ -37,9 +38,12 @@ now_failing = "Your [name] feels like it's about to fall out!." now_fixed = "The excruciating pain of your [name] has subsided." languages_possible = languages_possible_base + for(var/accent in initial_accents) + initial_accents += new accent -/obj/item/organ/tongue/proc/handle_speech(datum/source, list/speech_args) - return +/obj/item/organ/tongue/proc/handle_speech(datum/source, list/speech_args) //this wont proc unless there's initial_accents + for(var/datum/accent/speech_modifier in initial_accents) + speech_args = speech_modifier.modify_speech(speech_args, source, owner) /obj/item/organ/tongue/applyOrganDamage(d, maximum = maxHealth) . = ..() @@ -52,7 +56,7 @@ ..() if(say_mod && M.dna && M.dna.species) M.dna.species.say_mod = say_mod - if (modifies_speech) + if(initial_accents) RegisterSignal(M, COMSIG_MOB_SAY, .proc/handle_speech) M.UnregisterSignal(M, COMSIG_MOB_SAY) @@ -74,16 +78,7 @@ say_mod = "hisses" taste_sensitivity = 10 // combined nose + tongue, extra sensitive maxHealth = 40 //extra sensitivity means tongue is more susceptible to damage - modifies_speech = TRUE - -/obj/item/organ/tongue/lizard/handle_speech(datum/source, list/speech_args) - var/static/regex/lizard_hiss = new("s+", "g") - var/static/regex/lizard_hiSS = new("S+", "g") - var/message = speech_args[SPEECH_MESSAGE] - if(message[1] != "*") - message = lizard_hiss.Replace(message, "sss") - message = lizard_hiSS.Replace(message, "SSS") - speech_args[SPEECH_MESSAGE] = message + initial_accents = list(/datum/accent/lizard) /obj/item/organ/tongue/fly name = "proboscis" @@ -92,16 +87,7 @@ say_mod = "buzzes" taste_sensitivity = 25 // you eat vomit, this is a mercy maxHealth = 80 //years of eatting trash has made your tongue strong - modifies_speech = TRUE - -/obj/item/organ/tongue/fly/handle_speech(datum/source, list/speech_args) - var/static/regex/fly_buzz = new("z+", "g") - var/static/regex/fly_buZZ = new("Z+", "g") - var/message = speech_args[SPEECH_MESSAGE] - if(message[1] != "*") - message = fly_buzz.Replace(message, "zzz") - message = fly_buZZ.Replace(message, "ZZZ") - speech_args[SPEECH_MESSAGE] = message + initial_accents = list(/datum/accent/fly) /obj/item/organ/tongue/abductor name = "superlingual matrix" @@ -110,7 +96,7 @@ say_mod = "gibbers" taste_sensitivity = 101 // ayys cannot taste anything. maxHealth = 120 //Ayys probe a lot - modifies_speech = TRUE + initial_accents = list(/datum/accent/abductor) var/mothership /obj/item/organ/tongue/abductor/attack_self(mob/living/carbon/human/H) @@ -138,26 +124,6 @@ else . += "It is attuned to [mothership]." -/obj/item/organ/tongue/abductor/handle_speech(datum/source, list/speech_args) - //Hacks - var/message = speech_args[SPEECH_MESSAGE] - var/mob/living/carbon/human/user = source - var/rendered = "[user.name]: [message]" - user.log_talk(message, LOG_SAY, tag="abductor") - for(var/mob/living/carbon/human/H in GLOB.alive_mob_list) - var/obj/item/organ/tongue/T = H.getorganslot(ORGAN_SLOT_TONGUE) - if(!T || T.type != type) - continue - if(H.dna && H.dna.species.id == "abductor" && user.dna && user.dna.species.id == "abductor") - var/datum/antagonist/abductor/A = user.mind.has_antag_datum(/datum/antagonist/abductor) - if(!A || !(H.mind in A.team.members)) - continue - to_chat(H, rendered) - for(var/mob/M in GLOB.dead_mob_list) - var/link = FOLLOW_LINK(M, user) - to_chat(M, "[link] [rendered]") - speech_args[SPEECH_MESSAGE] = "" - /obj/item/organ/tongue/zombie name = "rotting tongue" desc = "Between the decay and the fact that it's just lying there you doubt a tongue has ever seemed less sexy." @@ -165,23 +131,7 @@ say_mod = "moans" taste_sensitivity = 32 maxHealth = 65 //Stop! It's already dead...! - modifies_speech = TRUE - -/obj/item/organ/tongue/zombie/handle_speech(datum/source, list/speech_args) - var/list/message_list = splittext(speech_args[SPEECH_MESSAGE], " ") - var/maxchanges = max(round(message_list.len / 1.5), 2) - - for(var/i = rand(maxchanges / 2, maxchanges), i > 0, i--) - var/insertpos = rand(1, message_list.len - 1) - var/inserttext = message_list[insertpos] - - if(!(copytext(inserttext, -3) == "..."))//3 == length("...") - message_list[insertpos] = inserttext + "..." - - if(prob(20) && message_list.len > 3) - message_list.Insert(insertpos, "[pick("BRAINS", "Brains", "Braaaiinnnsss", "BRAAAIIINNSSS")]...") - - speech_args[SPEECH_MESSAGE] = jointext(message_list, " ") + initial_accents = list(/datum/accent/zombie) /obj/item/organ/tongue/alien name = "alien tongue" @@ -190,7 +140,7 @@ say_mod = "hisses" taste_sensitivity = 10 // LIZARDS ARE ALIENS CONFIRMED maxHealth = 500 //They've a little mouth for a tongue, so it's pretty rhobust - modifies_speech = TRUE // not really, they just hiss + initial_accents = list(/datum/accent/alien) var/static/list/languages_possible_alien = typecacheof(list( /datum/language/xenocommon, /datum/language/common, @@ -202,9 +152,6 @@ . = ..() languages_possible = languages_possible_alien -/obj/item/organ/tongue/alien/handle_speech(datum/source, list/speech_args) - playsound(owner, "hiss", 25, 1, 1) - /obj/item/organ/tongue/bone name = "bone \"tongue\"" desc = "Apparently skeletons alter the sounds they produce through oscillation of their teeth, hence their characteristic rattling." @@ -214,14 +161,13 @@ attack_verb = list("bitten", "chattered", "chomped", "enamelled", "boned") taste_sensitivity = 101 // skeletons cannot taste anything maxHealth = 75 //Take brute damage instead - modifies_speech = TRUE var/chattering = FALSE var/phomeme_type = "sans" - var/list/phomeme_types = list("sans", "papyrus") + var/list/phomeme_types = list(/datum/accent/bone/sans, /datum/accent/bone/papyrus) /obj/item/organ/tongue/bone/Initialize() . = ..() - phomeme_type = pick(phomeme_types) + initial_accents += pick(phomeme_types) /obj/item/organ/tongue/bone/applyOrganDamage(var/d, var/maximum = maxHealth) if(d < 0) @@ -234,19 +180,14 @@ return /obj/item/organ/tongue/bone/handle_speech(datum/source, list/speech_args) - if (chattering) + if(chattering) chatter(speech_args[SPEECH_MESSAGE], phomeme_type, source) - switch(phomeme_type) - if("sans") - speech_args[SPEECH_SPANS] |= SPAN_SANS - if("papyrus") - speech_args[SPEECH_SPANS] |= SPAN_PAPYRUS + ..() /obj/item/organ/tongue/bone/plasmaman name = "plasma bone \"tongue\"" desc = "Like animated skeletons, Plasmamen vibrate their teeth in order to produce speech." icon_state = "tongueplasma" - modifies_speech = FALSE /obj/item/organ/tongue/robot name = "robotic voicebox" @@ -256,7 +197,7 @@ icon_state = "tonguerobot" say_mod = "states" attack_verb = list("beeped", "booped") - modifies_speech = TRUE + initial_accents = list(/datum/accent/robot) taste_sensitivity = 25 // not as good as an organic tongue maxHealth = 100 //RoboTongue! var/electronics_magic = TRUE @@ -265,7 +206,7 @@ return ..() || electronics_magic /obj/item/organ/tongue/robot/handle_speech(datum/source, list/speech_args) - speech_args[SPEECH_SPANS] |= SPAN_ROBOT + ..() /obj/item/organ/tongue/fluffy name = "fluffy tongue" @@ -273,20 +214,7 @@ icon_state = "tonguefluffy" taste_sensitivity = 10 // extra sensitive and inquisitive uwu maxHealth = 35 //Sensitive tongue! - modifies_speech = TRUE - -/obj/item/organ/tongue/fluffy/handle_speech(datum/source, list/speech_args) - var/message = speech_args[SPEECH_MESSAGE] - if(message[1] != "*") - message = replacetext(message, "ne", "nye") - message = replacetext(message, "nu", "nyu") - message = replacetext(message, "na", "nya") - message = replacetext(message, "no", "nyo") - message = replacetext(message, "ove", "uv") - message = replacetext(message, "l", "w") - message = replacetext(message, "r", "w") - message = lowertext(message) - speech_args[SPEECH_MESSAGE] = message + initial_accents = list(/datum/accent/fluffy) /obj/item/organ/tongue/cybernetic name = "cybernetic tongue" @@ -305,6 +233,7 @@ /obj/item/organ/tongue/cybernetic/handle_speech(datum/source, list/speech_args) speech_args[SPEECH_SPANS] |= SPAN_ROBOT + ..() /obj/item/organ/tongue/robot/ipc name = "positronic voicebox" diff --git a/code/modules/tgui/external.dm b/code/modules/tgui/external.dm index 46b324e151..c4515b8a76 100644 --- a/code/modules/tgui/external.dm +++ b/code/modules/tgui/external.dm @@ -130,6 +130,13 @@ */ /client/var/list/tgui_windows = list() +/** + * global + * + * TRUE if cache was reloaded by tgui dev server at least once. + */ +/client/var/tgui_cache_reloaded = FALSE + /** * public * @@ -159,16 +166,29 @@ /** * Middleware for /client/Topic. * - * return bool Whether the topic is passed (TRUE), or cancelled (FALSE). + * return bool If TRUE, prevents propagation of the topic call. */ /proc/tgui_Topic(href_list) // Skip non-tgui topics if(!href_list["tgui"]) - return TRUE + return FALSE var/type = href_list["type"] // Unconditionally collect tgui logs if(type == "log") log_tgui(usr, href_list["message"]) + // Reload all tgui windows + if(type == "cacheReloaded") + if(!check_rights(R_ADMIN) || usr.client.tgui_cache_reloaded) + return TRUE + // Mark as reloaded + usr.client.tgui_cache_reloaded = TRUE + // Notify windows + var/list/windows = usr.client.tgui_windows + for(var/window_id in windows) + var/datum/tgui_window/window = windows[window_id] + if (window.status == TGUI_WINDOW_READY) + window.on_message(type, null, href_list) + return TRUE // Locate window var/window_id = href_list["window_id"] var/datum/tgui_window/window @@ -177,7 +197,7 @@ if(!window) log_tgui(usr, "Error: Couldn't find the window datum, force closing.") SStgui.force_close_window(usr, window_id) - return FALSE + return TRUE // Decode payload var/payload if(href_list["payload"]) @@ -185,4 +205,4 @@ // Pass message to window if(window) window.on_message(type, payload, href_list) - return FALSE + return TRUE diff --git a/code/modules/tgui/states/debug.dm b/code/modules/tgui/states/debug.dm new file mode 100644 index 0000000000..6c600b38ce --- /dev/null +++ b/code/modules/tgui/states/debug.dm @@ -0,0 +1,6 @@ +GLOBAL_DATUM_INIT(debug_state, /datum/ui_state/debug_state, new) + +/datum/ui_state/debug_state/can_use_topic(src_object, mob/user) + if(check_rights_for(user.client, R_DEBUG)) + return UI_INTERACTIVE + return UI_CLOSE diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm index d0d5ff8ebb..b3b07eb178 100644 --- a/code/modules/tgui/tgui.dm +++ b/code/modules/tgui/tgui.dm @@ -80,14 +80,20 @@ opened_at = world.time window.acquire_lock(src) if(!window.is_ready()) - window.initialize(inline_assets = list( - get_asset_datum(/datum/asset/simple/tgui), - )) + window.initialize( + fancy = user.client.prefs.tgui_fancy, + inline_assets = list( + get_asset_datum(/datum/asset/simple/tgui_common), + get_asset_datum(/datum/asset/simple/tgui), + )) else window.send_message("ping") - window.send_asset(get_asset_datum(/datum/asset/simple/fontawesome)) + var/flush_queue = window.send_asset(get_asset_datum( + /datum/asset/simple/namespaced/fontawesome)) for(var/datum/asset/asset in src_object.ui_assets(user)) - window.send_asset(asset) + flush_queue |= window.send_asset(asset) + if (flush_queue) + user.client.browse_queue_flush() window.send_message("update", get_payload( with_data = TRUE, with_static_data = TRUE)) @@ -143,11 +149,13 @@ * Makes an asset available to use in tgui. * * required asset datum/asset + * + * return bool - true if an asset was actually sent */ /datum/tgui/proc/send_asset(datum/asset/asset) if(!window) CRASH("send_asset() can only be called after open().") - window.send_asset(asset) + return window.send_asset(asset) /** * public @@ -199,13 +207,17 @@ "key" = window_key, "size" = window_size, "fancy" = user.client.prefs.tgui_fancy, - "locked" = user.client.prefs.tgui_lock + "locked" = user.client.prefs.tgui_lock, + ), + "client" = list( + "ckey" = user.client.ckey, + "address" = user.client.address, + "computer_id" = user.client.computer_id, ), "user" = list( "name" = "[user]", - "ckey" = "[user.ckey]", - "observer" = isobserver(user) - ) + "observer" = isobserver(user), + ), ) var/data = custom_data || with_data && src_object.ui_data(user) if(data) diff --git a/code/modules/tgui/tgui_window.dm b/code/modules/tgui/tgui_window.dm index 3f271163c9..b511fe4057 100644 --- a/code/modules/tgui/tgui_window.dm +++ b/code/modules/tgui/tgui_window.dm @@ -8,12 +8,18 @@ var/client/client var/pooled var/pool_index + var/is_browser = FALSE var/status = TGUI_WINDOW_CLOSED var/locked = FALSE var/datum/tgui/locked_by + var/datum/subscriber_object + var/subscriber_delegate var/fatally_errored = FALSE var/message_queue var/sent_assets = list() + // Vars passed to initialize proc (and saved for later) + var/inline_assets + var/fancy /** * public @@ -26,9 +32,9 @@ /datum/tgui_window/New(client/client, id, pooled = FALSE) src.id = id src.client = client + src.client.tgui_windows[id] = src src.pooled = pooled if(pooled) - client.tgui_windows[id] = src src.pool_index = TGUI_WINDOW_INDEX(id) /** @@ -39,18 +45,24 @@ * will be put into the queue until the window finishes loading. * * optional inline_assets list List of assets to inline into the html. + * optional inline_html string Custom HTML to inject. + * optional fancy bool If TRUE, will hide the window titlebar. */ -/datum/tgui_window/proc/initialize(inline_assets = list()) +/datum/tgui_window/proc/initialize( + inline_assets = list(), + inline_html = "", + fancy = FALSE) log_tgui(client, "[id]/initialize") if(!client) return + src.inline_assets = inline_assets + src.fancy = fancy status = TGUI_WINDOW_LOADING fatally_errored = FALSE - message_queue = null // Build window options var/options = "file=[id].html;can_minimize=0;auto_format=0;" // Remove titlebar and resize handles for a fancy window - if(client.prefs.tgui_fancy) + if(fancy) options += "titlebar=0;can_resize=0;" else options += "titlebar=1;can_resize=1;" @@ -69,13 +81,17 @@ inline_styles += "\n" else if(copytext(name, -3) == ".js") inline_scripts += "\n" - asset.send() + asset.send(client) html = replacetextEx(html, "\n", inline_styles) html = replacetextEx(html, "\n", inline_scripts) + // Inject custom HTML + html = replacetextEx(html, "\n", inline_html) // Open the window client << browse(html, "window=[id];[options]") // Instruct the client to signal UI when the window is closed. winset(client, id, "on-close=\"uiclose [id]\"") + // Detect whether the control is a browser + is_browser = winexists(client, id) == "BROWSER" /** * public @@ -107,8 +123,8 @@ * Acquire the window lock. Pool will not be able to provide this window * to other UIs for the duration of the lock. * - * Can be given an optional tgui datum, which will hook its on_message - * callback into the message stream. + * Can be given an optional tgui datum, which will be automatically + * subscribed to incoming messages via the on_message proc. * * optional ui /datum/tgui */ @@ -117,6 +133,8 @@ locked_by = ui /** + * public + * * Release the window lock. */ /datum/tgui_window/proc/release_lock() @@ -126,6 +144,28 @@ locked = FALSE locked_by = null +/** + * public + * + * Subscribes the datum to consume window messages on a specified proc. + * + * Note, that this supports only one subscriber, because code for that + * is simpler and therefore faster. If necessary, this can be rewritten + * to support multiple subscribers. + */ +/datum/tgui_window/proc/subscribe(datum/object, delegate) + subscriber_object = object + subscriber_delegate = delegate + +/** + * public + * + * Unsubscribes the datum. Do not forget to call this when cleaning up. + */ +/datum/tgui_window/proc/unsubscribe(datum/object) + subscriber_object = null + subscriber_delegate = null + /** * public * @@ -159,25 +199,40 @@ * required payload list Message payload * optional force bool Send regardless of the ready status. */ -/datum/tgui_window/proc/send_message(type, list/payload, force) +/datum/tgui_window/proc/send_message(type, payload, force) if(!client) return - var/message = json_encode(list( - "type" = type, - "payload" = payload, - )) - // Strip #255/improper. - message = replacetext(message, "\proper", "") - message = replacetext(message, "\improper", "") - // Pack for sending via output() - message = url_encode(message) + var/message = TGUI_CREATE_MESSAGE(type, payload) // Place into queue if window is still loading if(!force && status != TGUI_WINDOW_READY) if(!message_queue) message_queue = list() message_queue += list(message) return - client << output(message, "[id].browser:update") + client << output(message, is_browser \ + ? "[id]:update" \ + : "[id].browser:update") + +/** + * public + * + * Sends a raw payload to tgui window. + * + * required message string JSON+urlencoded blob to send. + * optional force bool Send regardless of the ready status. + */ +/datum/tgui_window/proc/send_raw_message(message, force) + if(!client) + return + // Place into queue if window is still loading + if(!force && status != TGUI_WINDOW_READY) + if(!message_queue) + message_queue = list() + message_queue += list(message) + return + client << output(message, is_browser \ + ? "[id]:update" \ + : "[id].browser:update") /** * public @@ -185,16 +240,18 @@ * Makes an asset available to use in tgui. * * required asset datum/asset + * + * return bool - TRUE if any assets had to be sent to the client */ /datum/tgui_window/proc/send_asset(datum/asset/asset) if(!client || !asset) return + sent_assets |= list(asset) + . = asset.send(client) if(istype(asset, /datum/asset/spritesheet)) var/datum/asset/spritesheet/spritesheet = asset send_message("asset/stylesheet", spritesheet.css_filename()) send_message("asset/mappings", asset.get_url_mappings()) - sent_assets += list(asset) - asset.send(client) /** * private @@ -205,7 +262,9 @@ if(!client || !message_queue) return for(var/message in message_queue) - client << output(message, "[id].browser:update") + client << output(message, is_browser \ + ? "[id]:update" \ + : "[id].browser:update") message_queue = null /** @@ -213,26 +272,45 @@ * * Callback for handling incoming tgui messages. */ -/datum/tgui_window/proc/on_message(type, list/payload, list/href_list) - switch(type) - if("ready") - // Status can be READY if user has refreshed the window. - if(status == TGUI_WINDOW_READY) - // Resend the assets - for(var/asset in sent_assets) - send_asset(asset) - status = TGUI_WINDOW_READY - if("log") - if(href_list["fatal"]) - fatally_errored = TRUE +/datum/tgui_window/proc/on_message(type, payload, href_list) + // Status can be READY if user has refreshed the window. + if(type == "ready" && status == TGUI_WINDOW_READY) + // Resend the assets + for(var/asset in sent_assets) + send_asset(asset) + // Mark this window as fatally errored which prevents it from + // being suspended. + if(type == "log" && href_list["fatal"]) + fatally_errored = TRUE + // Mark window as ready since we received this message from somewhere + if(status != TGUI_WINDOW_READY) + status = TGUI_WINDOW_READY + flush_message_queue() // Pass message to UI that requested the lock if(locked && locked_by) - locked_by.on_message(type, payload, href_list) - flush_message_queue() - return + var/prevent_default = locked_by.on_message(type, payload, href_list) + if(prevent_default) + return + // Pass message to the subscriber + else if(subscriber_object) + var/prevent_default = call( + subscriber_object, + subscriber_delegate)(type, payload, href_list) + if(prevent_default) + return // If not locked, handle these message types switch(type) + if("ping") + send_message("pingReply", payload) if("suspend") close(can_be_suspended = TRUE) if("close") close(can_be_suspended = FALSE) + if("openLink") + client << link(href_list["url"]) + if("cacheReloaded") + // Reinitialize + initialize(inline_assets = inline_assets, fancy = fancy) + // Resend the assets + for(var/asset in sent_assets) + send_asset(asset) diff --git a/code/modules/tgui_panel/audio.dm b/code/modules/tgui_panel/audio.dm new file mode 100644 index 0000000000..e62c4b5bc1 --- /dev/null +++ b/code/modules/tgui_panel/audio.dm @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + +/// Admin music volume, from 0 to 1. +/client/var/admin_music_volume = 1 + +/** + * public + * + * Sends music data to the browser. + * + * Optional settings: + * - pitch: the playback rate + * - start: the start time of the sound + * - end: when the musics stops playing + * + * required url string Must be an https URL. + * optional extra_data list Optional settings. + */ +/datum/tgui_panel/proc/play_music(url, extra_data) + if(!is_ready()) + return + if(!findtext(url, GLOB.is_http_protocol)) + return + var/list/payload = list() + if(length(extra_data) > 0) + for(var/key in extra_data) + payload[key] = extra_data[key] + payload["url"] = url + window.send_message("audio/playMusic", payload) + +/** + * public + * + * Stops playing music through the browser. + */ +/datum/tgui_panel/proc/stop_music() + if(!is_ready()) + return + window.send_message("audio/stopMusic") diff --git a/code/modules/tgui_panel/external.dm b/code/modules/tgui_panel/external.dm new file mode 100644 index 0000000000..57c89dc194 --- /dev/null +++ b/code/modules/tgui_panel/external.dm @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + +/client/var/datum/tgui_panel/tgui_panel + +/** + * tgui panel / chat troubleshooting verb + */ +/client/verb/fix_chat() + set name = "Fix chat" + set category = "OOC" + var/action + log_tgui(src, "tgui_panel: Started fix_chat.") + // Not initialized + if(!tgui_panel || !istype(tgui_panel)) + log_tgui(src, "tgui_panel: datum is missing") + action = alert(src, "tgui panel was not initialized!\nSet it up again?", "", "OK", "Cancel") + if(action != "OK") + return + tgui_panel = new(src) + tgui_panel.initialize() + action = alert(src, "Wait a bit and tell me if it's fixed", "", "Fixed", "Nope") + if(action == "Fixed") + log_tgui(src, "tgui_panel: Fixed by calling 'new' + 'initialize'") + return + // Not ready + if(!tgui_panel?.is_ready()) + log_tgui(src, "tgui_panel: not ready") + action = alert(src, "tgui panel looks like it's waiting for something.\nSend it a ping?", "", "OK", "Cancel") + if(action != "OK") + return + tgui_panel.window.send_message("ping", force = TRUE) + action = alert(src, "Wait a bit and tell me if it's fixed", "", "Fixed", "Nope") + if(action == "Fixed") + log_tgui(src, "tgui_panel: Fixed by sending a ping") + return + // Catch all solution + action = alert(src, "Looks like tgui panel was already setup, but we can always try again.\nSet it up again?", "", "OK", "Cancel") + if(action != "OK") + return + tgui_panel.initialize(force = TRUE) + action = alert(src, "Wait a bit and tell me if it's fixed", "", "Fixed", "Nope") + if(action == "Fixed") + log_tgui(src, "tgui_panel: Fixed by calling 'initialize'") + return + // Failed to fix + action = alert(src, "Welp, I'm all out of ideas. Try closing BYOND and reconnecting.\nWe could also disable tgui_panel and re-enable the old UI", "", "Thanks anyways", "Switch to old UI") + if (action == "Switch to old UI") + winset(src, "output", "on-show=&is-disabled=0&is-visible=1") + winset(src, "browseroutput", "is-disabled=1;is-visible=0") + log_tgui(src, "tgui_panel: Failed to fix.") diff --git a/code/modules/tgui_panel/telemetry.dm b/code/modules/tgui_panel/telemetry.dm new file mode 100644 index 0000000000..79087d8500 --- /dev/null +++ b/code/modules/tgui_panel/telemetry.dm @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + +/** + * Maximum number of connection records allowed to analyze. + * Should match the value set in the browser. + */ +#define TGUI_TELEMETRY_MAX_CONNECTIONS 5 + +/** + * Maximum time allocated for sending a telemetry packet. + */ +#define TGUI_TELEMETRY_RESPONSE_WINDOW 30 SECONDS + +/// Time of telemetry request +/datum/tgui_panel/var/telemetry_requested_at +/// Time of telemetry analysis completion +/datum/tgui_panel/var/telemetry_analyzed_at +/// List of previous client connections +/datum/tgui_panel/var/list/telemetry_connections + +/** + * private + * + * Requests some telemetry from the client. + */ +/datum/tgui_panel/proc/request_telemetry() + telemetry_requested_at = world.time + telemetry_analyzed_at = null + window.send_message("telemetry/request", list( + "limits" = list( + "connections" = TGUI_TELEMETRY_MAX_CONNECTIONS, + ), + )) + +/** + * private + * + * Analyzes a telemetry packet. + * + * Is currently only useful for detecting ban evasion attempts. + */ +/datum/tgui_panel/proc/analyze_telemetry(payload) + if(world.time > telemetry_requested_at + TGUI_TELEMETRY_RESPONSE_WINDOW) + message_admins("[key_name(client)] sent telemetry outside of the allocated time window.") + return + if(telemetry_analyzed_at) + message_admins("[key_name(client)] sent telemetry more than once.") + return + telemetry_analyzed_at = world.time + if(!payload) + return + telemetry_connections = payload["connections"] + var/len = length(telemetry_connections) + if(len == 0) + return + if(len > TGUI_TELEMETRY_MAX_CONNECTIONS) + message_admins("[key_name(client)] was kicked for sending a huge telemetry payload") + qdel(client) + return + var/list/found + for(var/i in 1 to len) + if(QDELETED(client)) + // He got cleaned up before we were done + return + var/list/row = telemetry_connections[i] + // Check for a malformed history object + if (!row || row.len < 3 || (!row["ckey"] || !row["address"] || !row["computer_id"])) + return + if (world.IsBanned(row["ckey"], row["address"], row["computer_id"], real_bans_only = TRUE)) + found = row + break + CHECK_TICK + // This fucker has a history of playing on a banned account. + if(found) + var/msg = "[key_name(client)] has a banned account in connection history! (Matched: [found["ckey"]], [found["address"]], [found["computer_id"]])" + message_admins(msg) + log_admin_private(msg) diff --git a/code/modules/tgui_panel/tgui_panel.dm b/code/modules/tgui_panel/tgui_panel.dm new file mode 100644 index 0000000000..b983484046 --- /dev/null +++ b/code/modules/tgui_panel/tgui_panel.dm @@ -0,0 +1,95 @@ +/** + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + +/** + * tgui_panel datum + * Hosts tgchat and other nice features. + */ +/datum/tgui_panel + var/client/client + var/datum/tgui_window/window + var/broken = FALSE + var/initialized_at + +/datum/tgui_panel/New(client/client) + src.client = client + window = new(client, "browseroutput") + window.subscribe(src, .proc/on_message) + +/datum/tgui_panel/Del() + window.unsubscribe(src) + window.close() + return ..() + +/** + * public + * + * TRUE if panel is initialized and ready to receive messages. + */ +/datum/tgui_panel/proc/is_ready() + return !broken && window.is_ready() + +/** + * public + * + * Initializes tgui panel. + */ +/datum/tgui_panel/proc/initialize(force = FALSE) + initialized_at = world.time + // Perform a clean initialization + window.initialize(inline_assets = list( + get_asset_datum(/datum/asset/simple/tgui_common), + get_asset_datum(/datum/asset/simple/tgui_panel), + )) + window.send_asset(get_asset_datum(/datum/asset/simple/namespaced/fontawesome)) + window.send_asset(get_asset_datum(/datum/asset/spritesheet/chat)) + request_telemetry() + addtimer(CALLBACK(src, .proc/on_initialize_timed_out), 2 SECONDS) + +/** + * private + * + * Called when initialization has timed out. + */ +/datum/tgui_panel/proc/on_initialize_timed_out() + // Currently does nothing but sending a message to old chat. + SEND_TEXT(client, "Failed to load fancy chat, reverting to old chat. Certain features won't work.") + +/** + * private + * + * Callback for handling incoming tgui messages. + */ +/datum/tgui_panel/proc/on_message(type, payload) + if(type == "ready") + broken = FALSE + window.send_message("update", list( + "config" = list( + "client" = list( + "ckey" = client.ckey, + "address" = client.address, + "computer_id" = client.computer_id, + ), + "window" = list( + "fancy" = FALSE, + "locked" = FALSE, + ), + ), + )) + return TRUE + if(type == "audio/setAdminMusicVolume") + client.admin_music_volume = payload["volume"] + return TRUE + if(type == "telemetry") + analyze_telemetry(payload) + return TRUE + +/** + * public + * + * Sends a round restart notification. + */ +/datum/tgui_panel/proc/send_roundrestart() + window.send_message("roundrestart") diff --git a/code/modules/tgui_panel/to_chat.dm b/code/modules/tgui_panel/to_chat.dm new file mode 100644 index 0000000000..aad27d4872 --- /dev/null +++ b/code/modules/tgui_panel/to_chat.dm @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + +/** + * global + * + * Circumvents the message queue and sends the message + * to the recipient (target) as soon as possible. + */ +/proc/to_chat_immediate( + target, + text, + handle_whitespace = TRUE, + trailing_newline = TRUE, + confidential = FALSE) + if(!target || !text) + return + if(target == world) + target = GLOB.clients + var/flags = handle_whitespace \ + | trailing_newline << 1 \ + | confidential << 2 + var/message = TGUI_CREATE_MESSAGE("chat/message", list( + "text" = text, + "flags" = flags, + )) + if(islist(target)) + for(var/_target in target) + var/client/client = CLIENT_FROM_VAR(_target) + if(client) + // Send to tgchat + client.tgui_panel?.window.send_raw_message(message) + // Send to old chat + SEND_TEXT(client, text) + return + var/client/client = CLIENT_FROM_VAR(target) + if(client) + // Send to tgchat + client.tgui_panel?.window.send_raw_message(message) + // Send to old chat + SEND_TEXT(client, text) + +/** + * global + * + * Sends the message to the recipient (target). + */ +/proc/to_chat( + target, + text, + handle_whitespace = TRUE, + trailing_newline = TRUE, + confidential = FALSE) + if(Master.current_runlevel == RUNLEVEL_INIT || !SSchat?.initialized) + to_chat_immediate( + target, + text, + handle_whitespace, + trailing_newline, + confidential) + return + if(!target || !text) + return + if(target == world) + target = GLOB.clients + var/flags = handle_whitespace \ + | trailing_newline << 1 \ + | confidential << 2 + SSchat.queue(target, text, flags) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index c739d426c2..e758a43589 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -3,6 +3,7 @@ #ifdef UNIT_TESTS #include "anchored_mobs.dm" +#include "character_saving.dm" #include "component_tests.dm" #include "reagent_id_typos.dm" #include "reagent_recipe_collisions.dm" diff --git a/code/modules/unit_tests/character_saving.dm b/code/modules/unit_tests/character_saving.dm new file mode 100644 index 0000000000..6c83d4142a --- /dev/null +++ b/code/modules/unit_tests/character_saving.dm @@ -0,0 +1,14 @@ +/datum/unit_test/character_saving/Run() + try + var/datum/preferences/P = new + P.load_path("test") + P.features["flavor_text"] = "Foo" + P.features["ooc_notes"] = "Bar" + P.save_character() + P.load_character() + if(P.features["flavor_text"] != "Foo") + Fail("Flavor text is failing to save.") + if(P.features["ooc_notes"] != "Bar") + Fail("OOC text is failing to save.") + catch(var/exception/e) + Fail("Failed to save and load character due to exception [e.name]") diff --git a/code/modules/uplink/uplink_items/uplink_clothing.dm b/code/modules/uplink/uplink_items/uplink_clothing.dm index c26a9ae1f0..745eddcc07 100644 --- a/code/modules/uplink/uplink_items/uplink_clothing.dm +++ b/code/modules/uplink/uplink_items/uplink_clothing.dm @@ -90,6 +90,7 @@ desc = "Through bluespace magic stolen from an organisation that hoards technology, these boots simply allow you to slip through the atoms that make up anything, but only while walking, for safety reasons. As well as this, they unfortunately cause minor breath loss as the majority of atoms in your lungs are sucked out into any solid object you walk through." item = /obj/item/clothing/shoes/wallwalkers cost = 6 + exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) /datum/uplink_item/device_tools/guerillagloves name = "Guerilla Gloves" diff --git a/code/modules/uplink/uplink_items/uplink_dangerous.dm b/code/modules/uplink/uplink_items/uplink_dangerous.dm index a43e3fc2ce..58cb43996d 100644 --- a/code/modules/uplink/uplink_items/uplink_dangerous.dm +++ b/code/modules/uplink/uplink_items/uplink_dangerous.dm @@ -177,6 +177,7 @@ organic host as a home base and source of fuel. Holoparasites come in various types and share damage with their host." item = /obj/item/storage/box/syndie_kit/guardian cost = 15 + limited_stock = 1 // you can only have one holopara apparently? refundable = TRUE cant_discount = TRUE surplus = 0 diff --git a/code/modules/uplink/uplink_items/uplink_explosives.dm b/code/modules/uplink/uplink_items/uplink_explosives.dm index 6cc1c9fe05..f44966fb3b 100644 --- a/code/modules/uplink/uplink_items/uplink_explosives.dm +++ b/code/modules/uplink/uplink_items/uplink_explosives.dm @@ -80,6 +80,7 @@ item = /obj/item/cartridge/virus/syndicate cost = 5 restricted = TRUE + limited_stock = 1 /datum/uplink_item/explosives/emp name = "EMP Grenades and Implanter Kit" diff --git a/code/modules/vending/kinkmate.dm b/code/modules/vending/kinkmate.dm index a78a4e6ef4..e522583772 100644 --- a/code/modules/vending/kinkmate.dm +++ b/code/modules/vending/kinkmate.dm @@ -26,7 +26,12 @@ /obj/item/clothing/under/shorts/polychromic/pantsu = 3, /obj/item/clothing/under/misc/poly_bottomless = 3, /obj/item/clothing/under/misc/poly_tanktop = 3, - /obj/item/clothing/under/misc/poly_tanktop/female = 3 + /obj/item/clothing/under/misc/poly_tanktop/female = 3, + /obj/item/autosurgeon/penis = 3, + /obj/item/autosurgeon/testicles = 3, + /obj/item/storage/pill_bottle/penis_enlargement = 5, + /obj/item/storage/pill_bottle/breast_enlargement = 5, + /obj/item/storage/daki = 4 ) contraband = list( /obj/item/clothing/neck/petcollar/locked = 2, diff --git a/config/config.txt b/config/config.txt index 46f9a0cdc4..a550e6bf8a 100644 --- a/config/config.txt +++ b/config/config.txt @@ -4,6 +4,8 @@ $include game_options.txt $include dbconfig.txt $include comms.txt $include antag_rep.txt +$include resources.txt +# Cit-specific imports $include donator_groupings.txt $include dynamic_config.txt $include plushies/defines.txt @@ -431,6 +433,8 @@ AUTOADMIN_RANK Game Master #CLIENT_WARN_MESSAGE Byond released 511 as the stable release. You can set the framerate your client runs at, which makes the game feel very different and cool. Shortly after its release we will end up using 511 client features and you will be forced to update. CLIENT_ERROR_VERSION 511 CLIENT_ERROR_MESSAGE Your version of byond is not supported. Please upgrade. +## The minimum build needed for joining the server, if using 512, a good minimum build would be 1421 as that disables the Middle Mouse Button exploit. +CLIENT_ERROR_BUILD 1421 ## TOPIC RATE LIMITING ## This allows you to limit how many topic calls (clicking on an interface window) the client can do in any given game second and/or game minute. diff --git a/config/policy.json b/config/policy.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/config/policy.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/config/resources.txt b/config/resources.txt new file mode 100644 index 0000000000..909bef0809 --- /dev/null +++ b/config/resources.txt @@ -0,0 +1,38 @@ +# External resources +# Set this to the location of a .zip with the server's .rsc inside of it. +# If you set this mutiple times, the server will rotate between the links. +# To use this, the compile option PRELOAD_RSC must be set to 0 to keep byond from preloading resources + +EXTERNAL_RSC_URLS http://tgstation13.download/byond/tgstationv2.zip + + +######################## +# Browser Asset Config # +######################## +# Browser assets are any file included in interfaces. css, images, javascript, etc. +# This handles configuring how we get these to the player so interfaces can access them. + +# Asset Transport +# The normal way of getting assets to clients is to use the internal byond system. This can be slow and delay the opening of interface windows. It also doesn't allow the internal IE windows byond uses to cache anything. +# You can instead have the server save them to a website via a folder within the game server that the web server can read. This could be a simple webserver or something backed by a CDN. +# Valid values: simple, webroot. Simple is the default. +#ASSET_TRANSPORT webroot + + +# Simple asset transport configurable values. + +# Uncomment this to have the server passively send all browser assets to each client in the background. (instead of waiting for them to be needed) +# This should be uncommented in production and commented in development +#ASSET_SIMPLE_PRELOAD + + +# Webroot asset transport configurable values. + +# Local folder to save assets to. +# Assets will be saved in the format of asset.MD5HASH.EXT or in namespaces/hash/ as ASSET_FILE_NAME or asset.MD5HASH.EXT +#ASSET_CDN_WEBROOT data/asset-store/ + +# URL the folder from above can be accessed from. +# for best results the webserver powering this should return a long cache validity time, as all assets sent via this transport use hash based urls +# if you want to test this locally, you simpily run the `localhost-asset-webroot-server.py` python3 script to host assets stored in `data/asset-store/` via http://localhost:58715/ +#ASSET_CDN_URL http://localhost:58715/ diff --git a/html/panels.css b/html/admin/panels.css similarity index 100% rename from html/panels.css rename to html/admin/panels.css diff --git a/html/search.js b/html/admin/search.js similarity index 100% rename from html/search.js rename to html/admin/search.js diff --git a/html/changelog.html b/html/changelog.html index d2f9fd9a86..01d3861fc5 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -50,6 +50,208 @@ -->
+

02 September 2020

+

Putnam3145 updated:

+
    +
  • Added a unit test for character saving.
  • +
  • Plastitanium rapier no longer silently sleeps with no chance at counterplay when used by pacifists.
  • +
  • Fusion scan is now actually useful.
  • +
+

Tupinambis updated:

+
    +
  • moved the dakis, genital growth pills, and genital autosurgeons out of the maintenance loot table and into kinkmates.
  • +
+

raspy-on-osu updated:

+
    +
  • pyroclastic anomaly client spam
  • +
+

timothyteakettle updated:

+
    +
  • you can hide your ckey now from the roundend report
  • +
+ +

01 September 2020

+

BlueWildrose updated:

+
    +
  • fixed slimes starting off hungry
  • +
+ +

31 August 2020

+

Arturlang updated:

+
    +
  • Slimes can now damage structures, don't leave them unfed!
  • +
+

Chiirno updated:

+
    +
  • Moves pill_bottles/dice to box/dice on CogStation.
  • +
+

Couls, ported by NecromancerAnne updated:

+
    +
  • cleans up mech backstabbing code
  • +
+

DeltaFire15 updated:

+
    +
  • teleport-to-ark ability of the eminence, commented out
  • +
  • teleport-to-obelisk ability for the eminence
  • +
+

Detective-Google updated:

+
    +
  • plasmamen have no more slowdown
  • +
  • object reskins now use very nice and cool radials
  • +
+

EmeraldSundisk updated:

+
    +
  • Adds a pool to MetaStation
  • +
  • Slight readjustments to the surrounding area
  • +
  • Fixes a handful of external airlocks
  • +
+

ForrestWick updated:

+
    +
  • removes wall walking boots from nukie uplink
  • +
+

Ghommie updated:

+
    +
  • e-gun overlays and some floor decals should have been fixed.
  • +
+

LetterN updated:

+
    +
  • tgchat
  • +
+

Lynxless updated:

+
    +
  • Changed anatomic panacea into a direct buff, instead of a chem injection
  • +
  • Changed the values of anatomic panacea
  • +
  • Added a new icon for panacea's buff alert
  • +
+

Putnam3145 updated:

+
    +
  • Pref for genital/vore examine text
  • +
  • Fixed a couple events having ghost roles eligible.
  • +
  • Buffed slaughter demon: gets stronger as it eats people
  • +
  • Nerfed slaughter demon: no longer permanently round-removes all who are eaten by it, instead releasing their now-heartless bodies
  • +
  • Dynamic storytellers now calculate property weights properly.
  • +
+

Sonic121x updated:

+
    +
  • Fix the four type of new tea that will stuck inside your vein.
  • +
  • drinking glass sprite for those tea.
  • +
+

kappa-sama updated:

+
    +
  • miners can no longer acquire funny antag item
  • +
+

lolman360 updated:

+
    +
  • shuttle engine/heater sprites now face the right way
  • +
+

raspy-on-osu updated:

+
    +
  • TEG power output
  • +
  • tesla movement priorities
  • +
  • tesla counterplay
  • +
  • tesla containment check (containment variable now usable)
  • +
+

silicons updated:

+
    +
  • brooms now sweep objects on MOVABLE_PRE_MOVE rather than MOVABLE_MOVED
  • +
  • firedoors no longer automatically open on touch when there's no pressure differences.
  • +
+

timothyteakettle updated:

+
    +
  • buzz, buzz2 and ping are now all unrestricted emotes and can be used by anyone
  • +
  • the drake credit and pickle credit sprites have been removed
  • +
  • tongue speech handling is now done by accent datums
  • +
+

zeroisthebiggay updated:

+
    +
  • waffleco
  • +
+ +

30 August 2020

+

raspy-on-osu updated:

+
    +
  • new explosion echoes
  • +
  • explosion echo range
  • +
  • 5 new explosion related sounds
  • +
+ +

28 August 2020

+

EmeraldSundisk updated:

+
    +
  • Adds more paper to the library
  • +
  • The law office now has a desk window
  • +
  • Expands most of CogStation's exterior airlocks. Slightly adjusts surrounding areas to accommodate this.
  • +
  • Updates some of CogStation's paperwork
  • +
  • The rat in the morgue turned themselves into a possum. Funniest shit I've ever seen.
  • +
  • Adjusts some area designations so cameras should receive power properly
  • +
  • Cleans up an errant decal
  • +
+

Hatterhat updated:

+
    +
  • Traitor holoparasites can now only be bought once, because apparently you can only have one active holopara.
  • +
  • PDA bombs can now only be bought once per uplink.
  • +
+

lolman360 updated:

+
    +
  • atmos = radiation = chemistry.
  • +
+

shellspeed1 updated:

+
    +
  • Adds slow mode for iv drips
  • +
+

timothyteakettle updated:

+
    +
  • an ancient game over a thousand years old has re-emerged among crewmembers - rock paper scissors
  • +
  • customization features appear in alphabetical order where necessary
  • +
  • bokken do two more stamina damage now
  • +
  • you can now choose a body sprite as an anthromorph or anthromorphic insect, and can choose from aquatic/avian and apid respectively (and obviously back to the defaults too)
  • +
+ +

27 August 2020

+

silicons updated:

+
    +
  • eyebeam lighting can only have 128 maximum HSV saturation now.
  • +
  • no more shotgun stripper clips in boxes.
  • +
  • goliath tentacles now do 20 damage to mechs at 25% ap
  • +
+

timothyteakettle updated:

+
    +
  • changing your character's gender won't randomize its hairstyle and facial hairstyle now
  • +
+ +

26 August 2020

+

ancientpower updated:

+
    +
  • Ghosts can read newscasters by clicking on them.
  • +
+

silicons updated:

+
    +
  • hierophant vortex blasts now have 50% armor penetration vs mecha
  • +
  • ventcrawling now kicks off every attached/buckled mob, even for non humans.
  • +
+ +

25 August 2020

+

Hatterhat updated:

+
    +
  • Insidious combat gloves have been replaced by insidious guerilla gloves. They're generally the same, except now you can tackle with them.
  • +
+

Literallynotpickles updated:

+
    +
  • You can now equip handheld crew monitors on all medical-related winter coats.
  • +
+

Putnam3145 updated:

+
    +
  • vore now ejects occupants on death
  • +
+

raspy-on-osu updated:

+
    +
  • Thermoelectric Generator power output
  • +
+

timothyteakettle updated:

+
    +
  • I.P.Cs now short their circuits when expressing emotion, causing sparks to appear around them.
  • +
+

24 August 2020

MrJWhit updated:

    @@ -1289,186 +1491,6 @@
    • bohbombing is a thing now
    - -

    30 June 2020

    -

    Fikou updated:

    -
      -
    • spray cans, airlock painters, and decal painters added to engineering/service/autolathe (where applicable)
    • -
    -

    Ghommie updated:

    -
      -
    • Fixed a gap on the male insect anthro torso sprite when facing south.
    • -
    • Fixed mecha ID access not being removable.
    • -
    • Fixed a peeve with the hypno trance status effect not sanitizing some heard hypnosis inputs (i.e. custom say messages like say"honks*clownem ipsum dolor")
    • -
    • fixed an issue about using stacks with only 1 amount left.
    • -
    • Fixed a peeve on attack messages against carbons/humans.
    • -
    • Fixed missing hypnochair board.
    • -
    • Fixed material walls and tiles. My bad on that port.
    • -
    -

    Ghommie (inspired by MrDoomBringer's work on tgstation) updated:

    -
      -
    • New check skills UI.
    • -
    -

    Ghommie (porting PRs by XTDM, coiax, MrDoomBringer) updated:

    -
      -
    • Random Events now have a follow link for ghosts!
    • -
    • Adds the Spontaneous Brain Trauma to the event pool. Sometimes your brain just goes a little wrong.
    • -
    • Sometimes a low level cloning pod will make errors in replicating your brain, leaving you with a mild brain trauma.
    • -
    • When a person is cloned, any mental traumas are cloned as well.
    • -
    • The wizard federation announces that the Curse of Madness is out of beta and is now available for purchase for 4 points. It causes long-lasting brain traumas to all inhabitants of a target space station.
    • -
    • The wizard federation declines responsibility for any self-harm caused by curses cast while inside the targeted station.
    • -
    • Due to the extensive testing of the Curse of Madness some unique new trauma types have appeared across Nanotrasen-controlled space.
    • -
    • Curse of Madness can now be triggered by a wizard's Summon Events, at the same chance as Summon Guns or Summon Magic.
    • -
    • When an admin triggers Curse of Madness manually, they can specify their own dark truth to horrify the station with.
    • -
    -

    nightred updated:

    -
      -
    • Created two_handed component
    • -
    • Updated all existing two handed items to use the new component
    • -
    -

    silicons updated:

    -
      -
    • typing indicators no longer generates duplicate message boxes.
    • -
    • config errors now have line numbers.
    • -
    • outgoing mentorpms are now blue instead of green for the sender.
    • -
    • *squish
    • -
    -

    timothyteakettle updated:

    -
      -
    • you can now select your tongue and speech verb in the character customization menu!
    • -
    • skeleton is now split into two more types, greater and lesser
    • -
    • non-carbon blood is now not white
    • -
    • fixed a bunch of grammar/spelling mistakes
    • -
    - -

    29 June 2020

    -

    b1tt3r1n0 updated:

    -
      -
    • Made teratomas from sdgf less powergame
    • -
    -

    timothyteakettle updated:

    -
      -
    • slimes no longer have white blood by default
    • -
    - -

    28 June 2020

    -

    Detective-Google updated:

    -
      -
    • cog is less the suck
    • -
    • piggybacking is no longer absolutely inferior
    • -
    -

    Ghommie updated:

    -
      -
    • Fixing windows interaction with spraycans.
    • -
    • Fixing kinetic accelerator guns not working well with gun circuitries.
    • -
    • Fixing Zoomba borgs lights overlays.
    • -
    • Fixing the "absorb another ling" and "absorb the most dna" objectives rolling when no other changeling is around.
    • -
    • Clarified a pet peeve about the spread infestation ability.
    • -
    • BEPIS nodes won't show up anymore in the expert mode ui of the r&d console anymore (good thing they weren't researchable).
    • -
    • Hopefully fixing sound loop edge cases.
    • -
    • Fixing pAI radios being permanently disabled by EMPs at times.
    • -
    • Windoors can now be obscured with spraycans just like windows.
    • -
    -

    Ghommie porting PRs by Qustinnus/Floyd, Willow, cacogen, nemvar, Ghilker and EOBGames (Inept) updated:

    -
      -
    • Fixes a material duplication bug.
    • -
    • unique combinations of custom_materials lists are now shared between objects
    • -
    • meat material. yes.
    • -
    • materials can now be used to build walls/floors. meat house
    • -
    • edible component now does not try to attack if you eat something with it
    • -
    • Texture support for mat datums with thanks to 4DPlanner!
    • -
    • you no longer hit yourself with organs when eating
    • -
    • A whole bunch of materials are now datumised! Check out bronze, runed metal, sand, sandstone, snow, paper, cardboard, bone and bamboo. Oh, and pizza. Yes, pizza.
    • -
    • Buffs material floor tiles' throwforces from 1 to 10 (same as iron) to better showcase the effect of different materials (e.g. meat vs. titanium)
    • -
    • Radioactive items no longer output a single . when examined at a distance
    • -
    -

    MrJWhit updated:

    -
      -
    • Removed air alarm in Snow Snaxi in Tcomms Sat
    • -
    • Removed trash bins in genetics and mining
    • -
    • Gives cargo techs a cargolathe
    • -
    -

    Putnam3145 updated:

    -
      -
    • lost my mind just a couple of times
    • -
    -

    b1tt3r1n0 updated:

    -
      -
    • pouches, again, and and material pouches.
    • -
    -

    timothyteakettle updated:

    -
      -
    • support for custom blood colours implemented, slimes blood colour now equivalent to their body colour
    • -
    - -

    27 June 2020

    -

    Detective-Google updated:

    -
      -
    • Lying down is better
    • -
    -

    timothyteakettle updated:

    -
      -
    • felinids now nya when tabled
    • -
    - -

    26 June 2020

    -

    Ghommie updated:

    -
      -
    • Snore spam.
    • -
    • Hostile mobs shouldn't hit their original spawner structures or thoses of the same faction.
    • -
    -

    silicons updated:

    -
      -
    • soap cleans blood again
    • -
    - -

    25 June 2020

    -

    Anonymous updated:

    -
      -
    • Added kepi and orvilike kepi. Available through loadout.
    • -
    -

    Detective Google updated:

    -
      -
    • Medigygax
    • -
    -

    Detective-Google updated:

    -
      -
    • malf AIs can no longer yeet the station while shunted
    • -
    • SMESes can now properly use self charging cells
    • -
    • ghosts now show up when the round ends
    • -
    • away missions
    • -
    -

    Funce updated:

    -
      -
    • Mentor SQL queries are now deleted properly.
    • -
    -

    Linzolle updated:

    -
      -
    • analyze function on chem master is no longer broken
    • -
    • organs now decay inside dead bodies again
    • -
    -

    dapnee updated:

    -
      -
    • wataur bottle item
    • -
    • wataur bottle and overlay
    • -
    - -

    24 June 2020

    -

    DeltaFire15 updated:

    -
      -
    • Choosing a random item in your uplink will no longer sometimes reroll your contract.
    • -
    • Syndicate crate event cannot fire as a random event anymore.
    • -
    -

    Detective-Google updated:

    -
      -
    • singulos no longer succ infinite rods out of the ice
    • -
    • one of the directions for the diag hudpatch was blu instead of orang
    • -
    -

    timothyteakettle updated:

    -
      -
    • bonfires/grills no longer produce infinite quantities of food
    • -
    • slime's alter form ability now updates their hair colour when changing their body colour
    • -
GoonStation 13 Development Team diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 88aef958e8..ff80f736e1 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -27072,3 +27072,137 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. - rscadd: three new items are in the loadout for all donators zeroisthebiggay: - rscadd: contraband black evening gloves in kinkvend +2020-08-25: + Hatterhat: + - rscadd: Insidious combat gloves have been replaced by insidious guerilla gloves. + They're generally the same, except now you can tackle with them. + Literallynotpickles: + - tweak: You can now equip handheld crew monitors on all medical-related winter + coats. + Putnam3145: + - tweak: vore now ejects occupants on death + raspy-on-osu: + - tweak: Thermoelectric Generator power output + timothyteakettle: + - tweak: I.P.Cs now short their circuits when expressing emotion, causing sparks + to appear around them. +2020-08-26: + ancientpower: + - tweak: Ghosts can read newscasters by clicking on them. + silicons: + - balance: hierophant vortex blasts now have 50% armor penetration vs mecha + - balance: ventcrawling now kicks off every attached/buckled mob, even for non humans. +2020-08-27: + silicons: + - tweak: eyebeam lighting can only have 128 maximum HSV saturation now. + - balance: no more shotgun stripper clips in boxes. + - balance: goliath tentacles now do 20 damage to mechs at 25% ap + timothyteakettle: + - tweak: changing your character's gender won't randomize its hairstyle and facial + hairstyle now +2020-08-28: + EmeraldSundisk: + - rscadd: Adds more paper to the library + - rscadd: The law office now has a desk window + - tweak: Expands most of CogStation's exterior airlocks. Slightly adjusts surrounding + areas to accommodate this. + - tweak: Updates some of CogStation's paperwork + - tweak: The rat in the morgue turned themselves into a possum. Funniest shit I've + ever seen. + - bugfix: Adjusts some area designations so cameras should receive power properly + - bugfix: Cleans up an errant decal + Hatterhat: + - tweak: Traitor holoparasites can now only be bought once, because apparently you + can only have one active holopara. + - balance: PDA bombs can now only be bought once per uplink. + lolman360: + - rscadd: atmos = radiation = chemistry. + shellspeed1: + - rscadd: Adds slow mode for iv drips + timothyteakettle: + - rscadd: an ancient game over a thousand years old has re-emerged among crewmembers + - rock paper scissors + - tweak: customization features appear in alphabetical order where necessary + - tweak: bokken do two more stamina damage now + - rscadd: you can now choose a body sprite as an anthromorph or anthromorphic insect, + and can choose from aquatic/avian and apid respectively (and obviously back + to the defaults too) +2020-08-30: + raspy-on-osu: + - rscadd: new explosion echoes + - tweak: explosion echo range + - soundadd: 5 new explosion related sounds +2020-08-31: + Arturlang: + - tweak: Slimes can now damage structures, don't leave them unfed! + Chiirno: + - bugfix: Moves pill_bottles/dice to box/dice on CogStation. + Couls, ported by NecromancerAnne: + - code_imp: cleans up mech backstabbing code + DeltaFire15: + - rscdel: teleport-to-ark ability of the eminence, commented out + - rscadd: teleport-to-obelisk ability for the eminence + Detective-Google: + - tweak: plasmamen have no more slowdown + - rscadd: object reskins now use very nice and cool radials + EmeraldSundisk: + - rscadd: Adds a pool to MetaStation + - tweak: Slight readjustments to the surrounding area + - bugfix: Fixes a handful of external airlocks + ForrestWick: + - balance: removes wall walking boots from nukie uplink + - tweak: removes wall walking boots from nukie uplink + Ghommie: + - bugfix: e-gun overlays and some floor decals should have been fixed. + LetterN: + - rscadd: tgchat + Lynxless: + - tweak: Changed anatomic panacea into a direct buff, instead of a chem injection + - balance: Changed the values of anatomic panacea + - imageadd: Added a new icon for panacea's buff alert + Putnam3145: + - tweak: Pref for genital/vore examine text + - bugfix: Fixed a couple events having ghost roles eligible. + - balance: 'Buffed slaughter demon: gets stronger as it eats people' + - balance: 'Nerfed slaughter demon: no longer permanently round-removes all who + are eaten by it, instead releasing their now-heartless bodies' + - bugfix: Dynamic storytellers now calculate property weights properly. + Sonic121x: + - bugfix: Fix the four type of new tea that will stuck inside your vein. + - rscadd: drinking glass sprite for those tea. + kappa-sama: + - balance: miners can no longer acquire funny antag item + lolman360: + - bugfix: shuttle engine/heater sprites now face the right way + raspy-on-osu: + - tweak: TEG power output + - tweak: tesla movement priorities + - rscadd: tesla counterplay + - rscadd: tesla containment check (containment variable now usable) + silicons: + - bugfix: brooms now sweep objects on MOVABLE_PRE_MOVE rather than MOVABLE_MOVED + - balance: firedoors no longer automatically open on touch when there's no pressure + differences. + timothyteakettle: + - tweak: buzz, buzz2 and ping are now all unrestricted emotes and can be used by + anyone + - imagedel: the drake credit and pickle credit sprites have been removed + - refactor: tongue speech handling is now done by accent datums + zeroisthebiggay: + - rscdel: waffleco +2020-09-01: + BlueWildrose: + - bugfix: fixed slimes starting off hungry +2020-09-02: + Putnam3145: + - code_imp: Added a unit test for character saving. + - balance: Plastitanium rapier no longer silently sleeps with no chance at counterplay + when used by pacifists. + - bugfix: Fusion scan is now actually useful. + Tupinambis: + - tweak: moved the dakis, genital growth pills, and genital autosurgeons out of + the maintenance loot table and into kinkmates. + raspy-on-osu: + - bugfix: pyroclastic anomaly client spam + timothyteakettle: + - rscadd: you can hide your ckey now from the roundend report diff --git a/html/changelogs/AutoChangeLog-pr-13225.yml b/html/changelogs/AutoChangeLog-pr-13225.yml deleted file mode 100644 index d185917e7f..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13225.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "raspy-on-osu" -delete-after: True -changes: - - tweak: "Thermoelectric Generator power output" diff --git a/html/changelogs/AutoChangeLog-pr-13238.yml b/html/changelogs/AutoChangeLog-pr-13238.yml deleted file mode 100644 index 8e3d2c148b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13238.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - rscadd: "Insidious combat gloves have been replaced by insidious guerilla gloves. They're generally the same, except now you can tackle with them." diff --git a/html/changelogs/AutoChangeLog-pr-13240.yml b/html/changelogs/AutoChangeLog-pr-13240.yml deleted file mode 100644 index 396515c90e..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13240.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "timothyteakettle" -delete-after: True -changes: - - tweak: "I.P.Cs now short their circuits when expressing emotion, causing sparks to appear around them." diff --git a/html/changelogs/AutoChangeLog-pr-13241.yml b/html/changelogs/AutoChangeLog-pr-13241.yml deleted file mode 100644 index f11a9408b3..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13241.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Putnam3145" -delete-after: True -changes: - - tweak: "vore now ejects occupants on death" diff --git a/html/changelogs/AutoChangeLog-pr-13242.yml b/html/changelogs/AutoChangeLog-pr-13242.yml deleted file mode 100644 index 0cfcdf183b..0000000000 --- a/html/changelogs/AutoChangeLog-pr-13242.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Literallynotpickles" -delete-after: True -changes: - - tweak: "You can now equip handheld crew monitors on all medical-related winter coats." diff --git a/code/modules/goonchat/browserassets/js/jquery.min.js b/html/jquery.min.js similarity index 100% rename from code/modules/goonchat/browserassets/js/jquery.min.js rename to html/jquery.min.js diff --git a/icons/mob/32x64.dmi b/icons/mob/32x64.dmi index cddf9599b4..79a4c8a7fd 100644 Binary files a/icons/mob/32x64.dmi and b/icons/mob/32x64.dmi differ diff --git a/icons/mob/cyborg/drakemech.dmi b/icons/mob/cyborg/drakemech.dmi index 6a4845d983..a9c47b2b78 100644 Binary files a/icons/mob/cyborg/drakemech.dmi and b/icons/mob/cyborg/drakemech.dmi differ diff --git a/icons/mob/human_parts.dmi b/icons/mob/human_parts.dmi index 916686e63f..60978d55a2 100644 Binary files a/icons/mob/human_parts.dmi and b/icons/mob/human_parts.dmi differ diff --git a/icons/mob/human_parts_greyscale.dmi b/icons/mob/human_parts_greyscale.dmi index 989ec8049c..794074bfe4 100644 Binary files a/icons/mob/human_parts_greyscale.dmi and b/icons/mob/human_parts_greyscale.dmi differ diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi index 30c23601a5..4ced910193 100644 Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ diff --git a/icons/mob/wings.dmi b/icons/mob/wings.dmi index ace37b1f17..4523403344 100644 Binary files a/icons/mob/wings.dmi and b/icons/mob/wings.dmi differ diff --git a/icons/obj/bureaucracy.dmi b/icons/obj/bureaucracy.dmi index 95ae326f1e..b778a9d1a2 100644 Binary files a/icons/obj/bureaucracy.dmi and b/icons/obj/bureaucracy.dmi differ diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi index cd12f4a457..14eb973e25 100644 Binary files a/icons/obj/chemical.dmi and b/icons/obj/chemical.dmi differ diff --git a/icons/obj/crates.dmi b/icons/obj/crates.dmi index a1bc443efb..9b42188f5e 100644 Binary files a/icons/obj/crates.dmi and b/icons/obj/crates.dmi differ diff --git a/icons/obj/custom.dmi b/icons/obj/custom.dmi index d0be1113ee..9067a4beca 100644 Binary files a/icons/obj/custom.dmi and b/icons/obj/custom.dmi differ diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi index 5962e7522d..008618199a 100644 Binary files a/icons/obj/drinks.dmi and b/icons/obj/drinks.dmi differ diff --git a/icons/stamp_icons/font.png b/icons/stamp_icons/font.png new file mode 100644 index 0000000000..4297937696 Binary files /dev/null and b/icons/stamp_icons/font.png differ diff --git a/icons/stamp_icons/large_stamp-cap.png b/icons/stamp_icons/large_stamp-cap.png index 7f7ce460a4..19883563b2 100644 Binary files a/icons/stamp_icons/large_stamp-cap.png and b/icons/stamp_icons/large_stamp-cap.png differ diff --git a/icons/stamp_icons/large_stamp-ce.png b/icons/stamp_icons/large_stamp-ce.png index 189db310cf..d07f70c4d5 100644 Binary files a/icons/stamp_icons/large_stamp-ce.png and b/icons/stamp_icons/large_stamp-ce.png differ diff --git a/icons/stamp_icons/large_stamp-centcom.png b/icons/stamp_icons/large_stamp-centcom.png new file mode 100644 index 0000000000..6250cbff88 Binary files /dev/null and b/icons/stamp_icons/large_stamp-centcom.png differ diff --git a/icons/stamp_icons/large_stamp-chap.png b/icons/stamp_icons/large_stamp-chap.png new file mode 100644 index 0000000000..2586c13bad Binary files /dev/null and b/icons/stamp_icons/large_stamp-chap.png differ diff --git a/icons/stamp_icons/large_stamp-clown.png b/icons/stamp_icons/large_stamp-clown.png index 5abbff7113..d606870507 100644 Binary files a/icons/stamp_icons/large_stamp-clown.png and b/icons/stamp_icons/large_stamp-clown.png differ diff --git a/icons/stamp_icons/large_stamp-cmo.png b/icons/stamp_icons/large_stamp-cmo.png index eb004be621..bac4c7b2f9 100644 Binary files a/icons/stamp_icons/large_stamp-cmo.png and b/icons/stamp_icons/large_stamp-cmo.png differ diff --git a/icons/stamp_icons/large_stamp-deny.png b/icons/stamp_icons/large_stamp-deny.png index 7c216fce48..1c7f416597 100644 Binary files a/icons/stamp_icons/large_stamp-deny.png and b/icons/stamp_icons/large_stamp-deny.png differ diff --git a/icons/stamp_icons/large_stamp-hop.png b/icons/stamp_icons/large_stamp-hop.png index 3f9aa4a76f..1447d58a87 100644 Binary files a/icons/stamp_icons/large_stamp-hop.png and b/icons/stamp_icons/large_stamp-hop.png differ diff --git a/icons/stamp_icons/large_stamp-hos.png b/icons/stamp_icons/large_stamp-hos.png index 67b69d7503..bd59590975 100644 Binary files a/icons/stamp_icons/large_stamp-hos.png and b/icons/stamp_icons/large_stamp-hos.png differ diff --git a/icons/stamp_icons/large_stamp-law.png b/icons/stamp_icons/large_stamp-law.png index d6d77eee9b..aee5aa3fbc 100644 Binary files a/icons/stamp_icons/large_stamp-law.png and b/icons/stamp_icons/large_stamp-law.png differ diff --git a/icons/stamp_icons/large_stamp-mime.png b/icons/stamp_icons/large_stamp-mime.png new file mode 100644 index 0000000000..c9a0143439 Binary files /dev/null and b/icons/stamp_icons/large_stamp-mime.png differ diff --git a/icons/stamp_icons/large_stamp-ok.png b/icons/stamp_icons/large_stamp-ok.png index e568ae0921..b40d3e3f1b 100644 Binary files a/icons/stamp_icons/large_stamp-ok.png and b/icons/stamp_icons/large_stamp-ok.png differ diff --git a/icons/stamp_icons/large_stamp-qm.png b/icons/stamp_icons/large_stamp-qm.png index ea863078b4..4ba31b3741 100644 Binary files a/icons/stamp_icons/large_stamp-qm.png and b/icons/stamp_icons/large_stamp-qm.png differ diff --git a/icons/stamp_icons/large_stamp-rd.png b/icons/stamp_icons/large_stamp-rd.png index 35479e805f..a9e7ad040b 100644 Binary files a/icons/stamp_icons/large_stamp-rd.png and b/icons/stamp_icons/large_stamp-rd.png differ diff --git a/icons/stamp_icons/large_stamp-syndicate.png b/icons/stamp_icons/large_stamp-syndicate.png new file mode 100644 index 0000000000..68f17d8f5e Binary files /dev/null and b/icons/stamp_icons/large_stamp-syndicate.png differ diff --git a/icons/turf/shuttle.dmi b/icons/turf/shuttle.dmi index 985b9991a0..fbca824f47 100644 Binary files a/icons/turf/shuttle.dmi and b/icons/turf/shuttle.dmi differ diff --git a/interface/interface.dm b/interface/interface.dm index 2b33ebb5e8..2aece7cb6c 100644 --- a/interface/interface.dm +++ b/interface/interface.dm @@ -71,7 +71,7 @@ return var/static/issue_template = file2text(".github/ISSUE_TEMPLATE.md") var/servername = CONFIG_GET(string/servername) - var/url_params = "Reporting client version: [byond_version]\n\n[issue_template]" + var/url_params = "Reporting client version: [byond_version].[byond_build]\n\n[issue_template]" if(GLOB.round_id || servername) url_params = "Issue reported from [GLOB.round_id ? " Round ID: [GLOB.round_id][servername ? " ([servername])" : ""]" : servername]\n\n[url_params]" DIRECT_OUTPUT(src, link("[githuburl]/issues/new?body=[url_encode(url_params)]")) @@ -79,151 +79,13 @@ to_chat(src, "The Github URL is not set in the server configuration.") return -/client/verb/hotkeys_help() - set name = "hotkeys-help" - set category = "OOC" - - var/adminhotkeys = {" -Admin: -\tF3 = asay -\tF5 = Aghost (admin-ghost) -\tF6 = player-panel -\tF7 = Buildmode -\tF8 = Invisimin -\tCtrl+F8 = Stealthmin -"} - - mob.hotkey_help() - - if(holder) - to_chat(src, adminhotkeys) - /client/verb/changelog() set name = "Changelog" set category = "OOC" - var/datum/asset/changelog = get_asset_datum(/datum/asset/simple/changelog) + var/datum/asset/simple/namespaced/changelog = get_asset_datum(/datum/asset/simple/namespaced/changelog) changelog.send(src) - src << browse('html/changelog.html', "window=changes;size=675x650") + src << browse(changelog.get_htmlloader("changelog.html"), "window=changes;size=675x650") if(prefs.lastchangelog != GLOB.changelog_hash) prefs.lastchangelog = GLOB.changelog_hash prefs.save_preferences() winset(src, "infowindow.changelog", "font-style=;") - - -/mob/proc/hotkey_help() - var/hotkey_mode = {" -Hotkey-Mode: (hotkey-mode must be on) -\tTAB = toggle hotkey-mode -\ta = left -\ts = down -\td = right -\tw = up -\tq = drop -\te = equip -\tr = throw -\tm = me -\tt = say -\to = OOC -\tb = resist -\tv = rest -\th = stop pulling -\tx = swap-hand -\tz = activate held object (or y) -\tShift+e = Put held item into belt or take out most recent item added to belt. -\tShift+b = Put held item into backpack or take out most recent item added to backpack. -\tf = cycle-intents-left -\tg = cycle-intents-right -\t1 = help-intent -\t2 = disarm-intent -\t3 = grab-intent -\t4 = harm-intent -\tNumpad = Body target selection (Press 8 repeatedly for Head->Eyes->Mouth) -\tAlt(HOLD) = Alter movement intent -"} - - var/other = {" -Any-Mode: (hotkey doesn't need to be on) -\tCtrl+a = left -\tCtrl+s = down -\tCtrl+d = right -\tCtrl+w = up -\tCtrl+q = drop -\tCtrl+e = equip -\tCtrl+r = throw -\tCtrl+b = resist -\tCtrl+h = stop pulling -\tCtrl+o = OOC -\tCtrl+x = swap-hand -\tCtrl+z = activate held object (or Ctrl+y) -\tCtrl+f = cycle-intents-left -\tCtrl+g = cycle-intents-right -\tCtrl+1 = help-intent -\tCtrl+2 = disarm-intent -\tCtrl+3 = grab-intent -\tCtrl+4 = harm-intent -\tCtrl+'+/-' OR -\tShift+Mousewheel = Ghost zoom in/out -\tDEL = stop pulling -\tINS = cycle-intents-right -\tHOME = drop -\tPGUP = swap-hand -\tPGDN = activate held object -\tEND = throw -\tCtrl+Numpad = Body target selection (Press 8 repeatedly for Head->Eyes->Mouth) -"} - - to_chat(src, hotkey_mode) - to_chat(src, other) - -/mob/living/silicon/robot/hotkey_help() - //h = talk-wheel has a nonsense tag in it because \th is an escape sequence in BYOND. - var/hotkey_mode = {" -Hotkey-Mode: (hotkey-mode must be on) -\tTAB = toggle hotkey-mode -\ta = left -\ts = down -\td = right -\tw = up -\tq = unequip active module -\tv = rest -\th = stop pulling -\tm = me -\tt = say -\to = OOC -\tx = cycle active modules -\tb = resist -\tz = activate held object (or y) -\tf = cycle-intents-left -\tg = cycle-intents-right -\t1 = activate module 1 -\t2 = activate module 2 -\t3 = activate module 3 -\t4 = toggle intents -"} - - var/other = {" -Any-Mode: (hotkey doesn't need to be on) -\tCtrl+a = left -\tCtrl+s = down -\tCtrl+d = right -\tCtrl+w = up -\tCtrl+q = unequip active module -\tCtrl+x = cycle active modules -\tCtrl+b = resist -\tCtrl+h = stop pulling -\tCtrl+o = OOC -\tCtrl+z = activate held object (or Ctrl+y) -\tCtrl+f = cycle-intents-left -\tCtrl+g = cycle-intents-right -\tCtrl+1 = activate module 1 -\tCtrl+2 = activate module 2 -\tCtrl+3 = activate module 3 -\tCtrl+4 = toggle intents -\tDEL = stop pulling -\tINS = toggle intents -\tPGUP = cycle active modules -\tPGDN = activate held object -"} - - to_chat(src, hotkey_mode) - to_chat(src, other) diff --git a/interface/menu.dm b/interface/menu.dm index 3c881656da..976abb16b3 100644 --- a/interface/menu.dm +++ b/interface/menu.dm @@ -63,7 +63,6 @@ GLOBAL_LIST_EMPTY(menulist) return M.Set_checked(src, verbpath) - /datum/verbs/menu/Icon/Load_checked(client/C) //So we can be lazy, we invoke the "checked" menu item on menu load. var/procpath/verbpath = Get_checked(C) if (!verbpath || !(verbpath in typesof("[type]/verb"))) @@ -115,4 +114,3 @@ GLOBAL_LIST_EMPTY(menulist) /datum/verbs/menu/Icon/Scaling/verb/BL() set name = "@.winset \"mapwindow.map.zoom-mode=blur\"" set desc = "Bilinear" - diff --git a/interface/skin.dmf b/interface/skin.dmf index 0f64bc89da..d7e461eadd 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -2,21 +2,21 @@ macro "default" menu "menu" - elem + elem name = "&File" command = "" saved-params = "is-checked" - elem + elem name = "&Quick screenshot\tF2" command = ".screenshot auto" category = "&File" saved-params = "is-checked" - elem + elem name = "&Save screenshot as...\tShift+F2" command = ".screenshot" category = "&File" saved-params = "is-checked" - elem + elem name = "" command = "" category = "&File" @@ -26,27 +26,26 @@ menu "menu" command = ".reconnect" category = "&File" saved-params = "is-checked" - elem + elem name = "&Quit\tAlt-F4" command = ".quit" category = "&File" saved-params = "is-checked" - elem + elem name = "&Help" command = "" saved-params = "is-checked" - elem + elem name = "&Admin Help\tF1" command = "adminhelp" category = "&Help" saved-params = "is-checked" - elem + elem name = "&Hotkeys" command = "hotkeys-help" category = "&Help" saved-params = "is-checked" - window "mainwindow" elem "mainwindow" type = MAIN @@ -54,7 +53,6 @@ window "mainwindow" size = 640x440 anchor1 = none anchor2 = none - background-color = #242424 is-default = true saved-params = "pos;size;is-minimized;is-maximized" icon = 'icons\\ss13_64.png' @@ -62,23 +60,20 @@ window "mainwindow" menu = "menu" elem "split" type = CHILD - pos = 0,0 + pos = 3,0 size = 637x440 anchor1 = 0,0 anchor2 = 100,100 - background-color = #272727 saved-params = "splitter" left = "mapwindow" right = "infowindow" is-vert = true - splitter = 75 elem "asset_cache_browser" type = BROWSER pos = 0,0 size = 200x200 anchor1 = none anchor2 = none - background-color = #272727 is-visible = false auto-format = false saved-params = "" @@ -88,23 +83,18 @@ window "mainwindow" size = 999x999 anchor1 = none anchor2 = none - background-color = #272727 is-visible = false saved-params = "" window "mapwindow" elem "mapwindow" type = MAIN - pos = 418,0 + pos = 0,0 size = 1024x1024 anchor1 = none anchor2 = none - background-color = none saved-params = "pos;size;is-minimized;is-maximized" - statusbar = false is-pane = true - outer-size = 684x617 - inner-size = 662x561 elem "map" type = MAP pos = 0,0 @@ -113,10 +103,9 @@ window "mapwindow" anchor2 = 100,100 font-family = "Arial" font-size = 7 + text-color = none is-default = true - saved-params = "icon-size" - zoom-mode = distort - style = ".center { text-align: center; }\n.maptext { font-family: 'Small Fonts'; font-size: 7px; -dm-text-outline: 1px black; color: white; line-height: 1.1; }\n.command_headset { font-weight: bold;\tfont-size: 8px; } .small { font-size: 6px; }\n.big { font-size: 8px; }\n.reallybig { font-size: 8px; }\n.extremelybig { font-size: 8px; }\n.greentext { color: #00ff00; font-size: 7px; }\n.redtext { color: #ff0000; font-size: 7px; }\n.clown { color: #ff69bf; font-size: 7px; font-weight: bold; }\n.his_grace { color: #15d512; }\n.hypnophrase { color: #0d0d0d; font-weight: bold; }\n.yell { font-weight: bold; }\n.italics { font-size: 6px; }" + style=".center { text-align: center; } .maptext { font-family: 'Small Fonts'; font-size: 7px; -dm-text-outline: 1px black; color: white; line-height: 1.1; } .command_headset { font-weight: bold; font-size: 8px; } .small { font-size: 6px; } .big { font-size: 8px; } .reallybig { font-size: 8px; } .extremelybig { font-size: 8px; } .greentext { color: #00FF00; font-size: 7px; } .redtext { color: #FF0000; font-size: 7px; } .clown { color: #FF69Bf; font-size: 7px; font-weight: bold; } .his_grace { color: #15D512; } .hypnophrase { color: #0d0d0d; font-weight: bold; } .yell { font-weight: bold; } .italics { font-size: 6px; }" window "infowindow" elem "infowindow" @@ -125,7 +114,6 @@ window "infowindow" size = 640x480 anchor1 = none anchor2 = none - background-color = #242424 saved-params = "pos;size;is-minimized;is-maximized" is-pane = true elem "info" @@ -134,7 +122,6 @@ window "infowindow" size = 640x445 anchor1 = 0,0 anchor2 = 100,100 - background-color = #272727 saved-params = "splitter" left = "statwindow" right = "outputwindow" @@ -145,8 +132,6 @@ window "infowindow" size = 104x20 anchor1 = 3,0 anchor2 = 19,0 - text-color = #e0e0e0 - background-color = #40628a saved-params = "is-checked" text = "Changelog" command = "changelog" @@ -156,8 +141,6 @@ window "infowindow" size = 100x20 anchor1 = 19,0 anchor2 = 34,0 - text-color = #e0e0e0 - background-color = #40628a saved-params = "is-checked" text = "Rules" command = "rules" @@ -167,8 +150,6 @@ window "infowindow" size = 100x20 anchor1 = 34,0 anchor2 = 50,0 - text-color = #e0e0e0 - background-color = #40628a saved-params = "is-checked" text = "Wiki" command = "wiki" @@ -178,8 +159,6 @@ window "infowindow" size = 100x20 anchor1 = 50,0 anchor2 = 66,0 - text-color = #e0e0e0 - background-color = #40628a saved-params = "is-checked" text = "Forum" command = "forum" @@ -189,10 +168,8 @@ window "infowindow" size = 100x20 anchor1 = 66,0 anchor2 = 81,0 - text-color = #e0e0e0 - background-color = #40628a saved-params = "is-checked" - text = "GitHub" + text = "Github" command = "github" elem "report-issue" type = BUTTON @@ -200,9 +177,6 @@ window "infowindow" size = 100x20 anchor1 = 81,0 anchor2 = 97,0 - font-size = 8 - text-color = #e0e0e0 - background-color = #a92c2c saved-params = "is-checked" text = "Report Issue" command = "report-issue" @@ -214,13 +188,7 @@ window "outputwindow" size = 640x480 anchor1 = none anchor2 = none - background-color = #272727 saved-params = "pos;size;is-minimized;is-maximized" - titlebar = false - statusbar = false - can-close = false - can-minimize = false - can-resize = false is-pane = true elem "input" type = INPUT @@ -232,17 +200,15 @@ window "outputwindow" is-default = true border = sunken saved-params = "command" - elem "say" + elem "saybutton" type = BUTTON pos = 600,460 size = 37x20 anchor1 = 100,100 anchor2 = none - text-color = #e0e0e0 - background-color = #272727 saved-params = "is-checked" text = "Chat" - command = ".winset \"say.is-checked=true ? input.command=\"!say \\\"\" : input.command=\"" + command = ".winset \"saybutton.is-checked=true ? input.command=\"!say \\\"\" : input.command=\"" is-flat = true button-type = pushbox elem "browseroutput" @@ -251,7 +217,7 @@ window "outputwindow" size = 640x456 anchor1 = 0,0 anchor2 = 100,100 - background-color = #272727 + background-color = #ffffff is-visible = false is-disabled = true saved-params = "" @@ -262,40 +228,26 @@ window "outputwindow" size = 640x456 anchor1 = 0,0 anchor2 = 100,100 - text-color = #e0e0e0 - background-color = #272727 is-default = true saved-params = "" -window "statwindow" - elem "statwindow" +window "popupwindow" + elem "popupwindow" type = MAIN pos = 281,0 - size = 640x480 + size = 120x120 anchor1 = none anchor2 = none - background-color = #242424 + background-color = none + is-visible = false saved-params = "pos;size;is-minimized;is-maximized" - is-pane = true - elem "stat" - type = INFO - pos = 0,0 - size = 640x480 - anchor1 = 0,0 - anchor2 = 100,100 - text-color = #e0e0e0 - background-color = #272727 - is-default = true - saved-params = "" - tab-text-color = #e0e0e0 - tab-background-color = #242424 - prefix-color = #e0e0e0 - suffix-color = #e0e0e0 + statusbar = false + can-resize = false window "preferences_window" elem "preferences_window" type = MAIN - pos = 372,0 + pos = 281,0 size = 1280x1000 anchor1 = none anchor2 = none @@ -318,3 +270,21 @@ window "preferences_window" right-click = true saved-params = "zoom;letterbox;zoom-mode" +window "statwindow" + elem "statwindow" + type = MAIN + pos = 281,0 + size = 640x480 + anchor1 = none + anchor2 = none + saved-params = "pos;size;is-minimized;is-maximized" + is-pane = true + elem "stat" + type = INFO + pos = 0,0 + size = 640x480 + anchor1 = 0,0 + anchor2 = 100,100 + is-default = true + saved-params = "" + diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm index 9c35ddb75f..f375fea88f 100644 --- a/interface/stylesheet.dm +++ b/interface/stylesheet.dm @@ -2,7 +2,7 @@ /// !!!!!!!!!!HEY LISTEN!!!!!!!!!!!!!!!!!!!!!!!! /// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// If you modify this file you ALSO need to modify code/modules/goonchat/browserAssets/browserOutput.css +// If you modify this file you ALSO need to modify code/modules/goonchat/browserAssets/browserOutput.css and browserOutput_white.css // BUT you have to use PX font sizes with are on a x8 scale of these font sizes // Sample font-size: DM: 8 CSS: 64px @@ -26,18 +26,24 @@ em {font-style: normal; font-weight: bold;} .prefix { font-weight: bold;} .ooc { font-weight: bold;} +.looc {color: #6699CC; font-weight: bold;} +.antagooc {color: #b8002e; font-weight: bold;} .adminobserverooc {color: #0099cc; font-weight: bold;} .adminooc {color: #700038; font-weight: bold;} .adminobserver {color: #996600; font-weight: bold;} +.adminsay {color: #FF4500; font-weight: bold;} .admin {color: #386aff; font-weight: bold;} +.mentorsay {color: #E236D8; font-weight: bold;} +.mentorsay_admin {color: #8A2BE2; font-weight: bold;} + .name { font-weight: bold;} .say {} .deadsay {color: #5c00e6;} -.binarysay {color: #20c20e; background-color: #000000; display: block;} -.binarysay a {color: #00ff00;} +.binarysay {color: #20c20e; background-color: #000000; display: block;} +.binarysay a {color: #00ff00;} .binarysay a:active, .binarysay a:visited {color: #88ff88;} .radio {color: #008000;} .sciradio {color: #993399;} @@ -50,8 +56,8 @@ em {font-style: normal; font-weight: bold;} .syndradio {color: #6d3f40;} .centcomradio {color: #686868;} .aiprivradio {color: #ff00ff;} -.redteamradio {color: #ff0000;} -.blueteamradio {color: #0000ff;} +.redteamradio {color: #ff0000;} +.blueteamradio {color: #0000ff;} .yell { font-weight: bold;} @@ -65,13 +71,13 @@ h1.alert, h2.alert {color: #000000;} .disarm {color: #990000;} .passive {color: #660000;} -.userdanger {color: #ff0000; font-weight: bold; font-size: 3;} +.userdanger {color: #ff0000; font-weight: bold; font-size: 3;} .danger {color: #ff0000; font-weight: bold;} .tinydanger {color: #ff0000; font-size: 85%;} .smalldanger {color: #ff0000; font-size: 90%;} .warning {color: #ff0000; font-style: italic;} .boldwarning {color: #ff0000; font-style: italic; font-weight: bold} -.announce {color: #228b22; font-weight: bold;} +.announce {color: #228b22; font-weight: bold;} .boldannounce {color: #ff0000; font-weight: bold;} .greenannounce {color: #00ff00; font-weight: bold;} .rose {color: #ff5050;} @@ -81,29 +87,31 @@ h1.alert, h2.alert {color: #000000;} .smallnotice {color: #000099; font-size: 90%;} .smallnoticeital {color: #000099; font-style: italic; font-size: 90%;} .boldnotice {color: #000099; font-weight: bold;} +.hear {color: #000099; font-style: italic;} .adminnotice {color: #0000ff;} -.adminhelp {color: #ff0000; font-weight: bold;} +.adminhelp {color: #ff0000; font-weight: bold;} .unconscious {color: #0000ff; font-weight: bold;} .suicide {color: #ff5050; font-style: italic;} .green {color: #03ff39;} -.nicegreen {color: #14a833;} +.nicegreen {color: #14a833;} .shadowling {color: #3b2769;} .cult {color: #960000;} -.cultlarge {color: #960000; font-weight: bold; font-size: 3;} -.narsie {color: #960000; font-weight: bold; font-size: 15;} -.narsiesmall {color: #960000; font-weight: bold; font-size: 6;} -.colossus {color: #7F282A; font-size: 5;} -.hierophant {color: #660099; font-weight: bold; font-style: italic;} -.hierophant_warning {color: #660099; font-style: italic;} +.cultlarge {color: #960000; font-weight: bold; font-size: 3;} +.narsie {color: #960000; font-weight: bold; font-size: 15;} +.narsiesmall {color: #960000; font-weight: bold; font-size: 6;} +.colossus {color: #7F282A; font-size: 5;} +.hierophant {color: #660099; font-weight: bold; font-style: italic;} +.hierophant_warning {color: #660099; font-style: italic;} .purple {color: #5e2d79;} .holoparasite {color: #35333a;} +.bounty {color: #ab6613; font-style: italic;} .revennotice {color: #1d2953;} .revenboldnotice {color: #1d2953; font-weight: bold;} -.revenbignotice {color: #1d2953; font-weight: bold; font-size: 3;} +.revenbignotice {color: #1d2953; font-weight: bold; font-size: 3;} .revenminor {color: #823abb} .revenwarning {color: #760fbb; font-style: italic;} -.revendanger {color: #760fbb; font-weight: bold; font-size: 3;} +.revendanger {color: #760fbb; font-weight: bold; font-size: 3;} .umbra {color: #5000A0;} .umbra_emphasis {color: #5000A0; font-weight: bold; font-style: italic;} .umbra_large {color: #5000A0; font-size: 3; font-weight: bold; font-style: italic;} @@ -133,8 +141,7 @@ h1.alert, h2.alert {color: #000000;} .neovgre {color: #6E001A; font-weight: bold; font-style: italic;} .neovgre_small {color: #6E001A;} -.newscaster {color: #800000;} -.ghostalert {color: #5c00e6; font-style: italic; font-weight: bold;} +.ghostalert {color: #5c00e6; font-style: italic; font-weight: bold;} .alien {color: #543354;} .noticealien {color: #00c000;} @@ -149,7 +156,7 @@ h1.alert, h2.alert {color: #000000;} .papyrus {font-family: "Papyrus", cursive, sans-serif;} .robot {font-family: "Courier New", cursive, sans-serif;} -.command_headset {font-weight: bold; font-size: 3;} +.command_headset {font-weight: bold; font-size: 3;} .small {font-size: 1;} .big {font-size: 3;} .reallybig {font-size: 4;} @@ -157,9 +164,9 @@ h1.alert, h2.alert {color: #000000;} .greentext {color: #00FF00; font-size: 3;} .redtext {color: #FF0000; font-size: 3;} .yellowtext {color: #FFCC00; font-size: 3;} -.clown {color: #FF69Bf; font-size: 3; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} -.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;} -.spooky {color: #FF9100;} +.clown {color: #FF69Bf; font-size: 3; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;} +.singing {font-family: "Trebuchet MS", cursive, sans-serif; font-style: italic;} +.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;} .velvet {color: #660015; font-weight: bold; animation: velvet 5000ms infinite;} @keyframes velvet { 0% { color: #400020; } @@ -169,28 +176,29 @@ h1.alert, h2.alert {color: #000000;} 100% { color: #400020; } } -.hypnophrase {color: #3bb5d3; font-weight: bold; animation: hypnocolor 1500ms infinite;} -@keyframes hypnocolor { - 0% { color: #0d0d0d; } - 25% { color: #410194; } - 50% { color: #7f17d8; } - 75% { color: #410194; } - 100% { color: #3bb5d3; } +.hypnophrase {color: #3bb5d3; font-weight: bold; animation: hypnocolor 1500ms infinite; animation-direction: alternate;} + @keyframes hypnocolor { + 0% {color: #0d0d0d;} + 25% {color: #410194;} + 50% {color: #7f17d8;} + 75% {color: #410194;} + 100% {color: #3bb5d3;} } -.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;} + +.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;} @keyframes phobia { - 0% { color: #0d0d0d; } - 50% { color: #dd0000; } - 100% { color: #0d0d0d; } + 0% {color: #0d0d0d;} + 50% {color: #dd0000;} + 100% {color: #0d0d0d;} } -.icon {height: 1em; width: auto;} +.icon {height: 1em; width: auto;} .memo {color: #638500; text-align: center;} .memoedit {text-align: center; font-size: 2;} -.abductor {color: #800080; font-style: italic;} -.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;} +.abductor {color: #800080; font-style: italic;} +.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;} .slime {color: #00CED1;} .drone {color: #848482;} .monkey {color: #975032;} diff --git a/modular_citadel/code/modules/client/loadout/__donator.dm b/modular_citadel/code/modules/client/loadout/__donator.dm index 06783df03d..478fb41a23 100644 --- a/modular_citadel/code/modules/client/loadout/__donator.dm +++ b/modular_citadel/code/modules/client/loadout/__donator.dm @@ -40,12 +40,6 @@ path = /obj/item/bikehorn/airhorn ckeywhitelist = list("kevinz000") -/datum/gear/donator/cebusoap - name = "Cebutris' soap" - slot = SLOT_IN_BACKPACK - path = /obj/item/custom/ceb_soap - ckeywhitelist = list("cebutris") - /datum/gear/donator/kiaracloak name = "Kiara's cloak" slot = SLOT_NECK diff --git a/modular_citadel/code/modules/custom_loadout/custom_items.dm b/modular_citadel/code/modules/custom_loadout/custom_items.dm index bd377d6081..374312a26a 100644 --- a/modular_citadel/code/modules/custom_loadout/custom_items.dm +++ b/modular_citadel/code/modules/custom_loadout/custom_items.dm @@ -1,26 +1,8 @@ - //For custom items. // Unless there's a digitigrade version make sure you add mutantrace_variation = NONE to all clothing/under and shoes - Pooj // Digitigrade stuff is uniform_digi.dmi and digishoes.dmi in icons/mob -/obj/item/custom/ceb_soap - name = "Cebutris' Soap" - desc = "A generic bar of soap that doesn't really seem to work right." - gender = PLURAL - icon = 'icons/obj/custom.dmi' - icon_state = "cebu" - w_class = WEIGHT_CLASS_TINY - item_flags = NOBLUDGEON - -/obj/item/soap/cebu //real versions, for admin shenanigans. Adminspawn only - desc = "A bright blue bar of soap that smells of wolves" - icon = 'icons/obj/custom.dmi' - icon_state = "cebu" - -/obj/item/soap/cebu/fast //speedyquick cleaning version. Still not as fast as Syndiesoap. Adminspawn only. - cleanspeed = 15 - /obj/item/clothing/neck/cloak/inferno name = "Kiara's Cloak" desc = "The design on this seems a little too familiar." @@ -316,7 +298,7 @@ /obj/item/clothing/neck/petcollar/naomi name = "worn pet collar" - desc = "a pet collar that looks well used." + desc = "A pet collar that looks well used." /obj/item/clothing/neck/cloak/green name = "Generic Green Cloak" diff --git a/modular_citadel/code/modules/mentor/mentorsay.dm b/modular_citadel/code/modules/mentor/mentorsay.dm index c13e3c6ef3..dc1281abe0 100644 --- a/modular_citadel/code/modules/mentor/mentorsay.dm +++ b/modular_citadel/code/modules/mentor/mentorsay.dm @@ -13,7 +13,7 @@ log_mentor("MSAY: [key_name(src)] : [msg]") if(check_rights_for(src, R_ADMIN,0)) - msg = "MENTOR: [key_name(src, 0, 0)]: [msg]" + msg = "MENTOR: [key_name(src, 0, 0)]: [msg]" else - msg = "MENTOR: [key_name(src, 0, 0)]: [msg]" - to_chat(GLOB.admins | GLOB.mentors, msg) \ No newline at end of file + msg = "MENTOR: [key_name(src, 0, 0)]: [msg]" + to_chat(GLOB.admins | GLOB.mentors, msg, confidential = TRUE) diff --git a/modular_citadel/code/modules/mob/cit_emotes.dm b/modular_citadel/code/modules/mob/cit_emotes.dm index e58c6bda30..3b442af1c7 100644 --- a/modular_citadel/code/modules/mob/cit_emotes.dm +++ b/modular_citadel/code/modules/mob/cit_emotes.dm @@ -3,10 +3,6 @@ /mob var/nextsoundemote = 1 -//Disables the custom emote blacklist from TG that normally applies to slimes. -/datum/emote/living/custom - mob_type_blacklist_typecache = list(/mob/living/brain) - /datum/emote/living/insult key = "insult" key_third_person = "insults" @@ -74,7 +70,6 @@ emote_type = EMOTE_AUDIBLE muzzle_ignore = TRUE restraint_check = TRUE - mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/snap/run_emote(mob/living/user, params) if(!(. = ..())) @@ -91,7 +86,6 @@ emote_type = EMOTE_AUDIBLE muzzle_ignore = TRUE restraint_check = TRUE - mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/snap2/run_emote(mob/living/user, params) if(!(. = ..())) @@ -108,7 +102,6 @@ emote_type = EMOTE_AUDIBLE muzzle_ignore = TRUE restraint_check = TRUE - mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/snap3/run_emote(mob/living/user, params) if(!(. = ..())) @@ -125,7 +118,6 @@ emote_type = EMOTE_AUDIBLE muzzle_ignore = FALSE restraint_check = FALSE - mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/awoo/run_emote(mob/living/user, params) if(!(. = ..())) @@ -142,7 +134,6 @@ emote_type = EMOTE_AUDIBLE muzzle_ignore = FALSE restraint_check = FALSE - mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/nya/run_emote(mob/living/user, params) if(!(. = ..())) @@ -159,7 +150,6 @@ emote_type = EMOTE_AUDIBLE muzzle_ignore = FALSE restraint_check = FALSE - mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/weh/run_emote(mob/living/user, params) if(!(. = ..())) @@ -176,7 +166,6 @@ emote_type = EMOTE_AUDIBLE muzzle_ignore = FALSE restraint_check = FALSE - mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/peep/run_emote(mob/living/user, params) if(!(. = ..())) @@ -200,7 +189,6 @@ emote_type = EMOTE_AUDIBLE muzzle_ignore = FALSE restraint_check = FALSE - mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/mothsqueak/run_emote(mob/living/user, params) if(!(. = ..())) @@ -217,7 +205,6 @@ emote_type = EMOTE_AUDIBLE muzzle_ignore = FALSE restraint_check = FALSE - mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/merp/run_emote(mob/living/user, params) if(!(. = ..())) @@ -234,7 +221,6 @@ emote_type = EMOTE_AUDIBLE muzzle_ignore = FALSE restraint_check = FALSE - mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/bark/run_emote(mob/living/user, params) if(!(. = ..())) @@ -252,7 +238,6 @@ emote_type = EMOTE_AUDIBLE muzzle_ignore = FALSE restraint_check = FALSE - mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/squish/run_emote(mob/living/user, params) if(!(. = ..())) diff --git a/modular_citadel/icons/mob/citadel_refs/furry_parts_greyscale.dmi b/modular_citadel/icons/mob/citadel_refs/furry_parts_greyscale.dmi deleted file mode 100644 index c8d5ceb0a6..0000000000 Binary files a/modular_citadel/icons/mob/citadel_refs/furry_parts_greyscale.dmi and /dev/null differ diff --git a/modular_citadel/icons/mob/mutant_bodyparts.dmi b/modular_citadel/icons/mob/mutant_bodyparts.dmi deleted file mode 100644 index 6098dd3567..0000000000 Binary files a/modular_citadel/icons/mob/mutant_bodyparts.dmi and /dev/null differ diff --git a/sound/effects/creak1.ogg b/sound/effects/creak1.ogg new file mode 100644 index 0000000000..0cad4802ff Binary files /dev/null and b/sound/effects/creak1.ogg differ diff --git a/sound/effects/creak2.ogg b/sound/effects/creak2.ogg new file mode 100644 index 0000000000..707bf39e33 Binary files /dev/null and b/sound/effects/creak2.ogg differ diff --git a/sound/effects/creak3.ogg b/sound/effects/creak3.ogg new file mode 100644 index 0000000000..88ff37a339 Binary files /dev/null and b/sound/effects/creak3.ogg differ diff --git a/sound/effects/explosioncreak1.ogg b/sound/effects/explosioncreak1.ogg new file mode 100644 index 0000000000..474f5febb5 Binary files /dev/null and b/sound/effects/explosioncreak1.ogg differ diff --git a/sound/effects/explosioncreak2.ogg b/sound/effects/explosioncreak2.ogg new file mode 100644 index 0000000000..75d323eb06 Binary files /dev/null and b/sound/effects/explosioncreak2.ogg differ diff --git a/sound/machines/card_slide.ogg b/sound/machines/card_slide.ogg new file mode 100644 index 0000000000..f97ed15fbf Binary files /dev/null and b/sound/machines/card_slide.ogg differ diff --git a/sound/machines/twobeep_high.ogg b/sound/machines/twobeep_high.ogg new file mode 100644 index 0000000000..b97b39a4f0 Binary files /dev/null and b/sound/machines/twobeep_high.ogg differ diff --git a/strings/traumas.json b/strings/traumas.json index 58170bd55a..f8fed95c98 100644 --- a/strings/traumas.json +++ b/strings/traumas.json @@ -131,7 +131,8 @@ "@pick(semicolon)*weh", "@pick(semicolon)My balls finally feel full, again.", "@pick(semicolon)Assaltign a sec osficer aren't crime if ur @pick(roles)", - ";SEC I SPILED MU JICE HELELPH HELPJ JLEP HELP" + ";SEC I SPILED MU JICE HELELPH HELPJ JLEP HELP", + "@pick(semicolon) atmos is chemistyr is radation fast air is FASTER cheemsitry and FASTER RADIATION AND FASTER DEATH!!!" ], "mutations": [ @@ -199,7 +200,7 @@ "abdoocters", "revinent" ], - + "bug": [ "", "IS TIS A BUG??", @@ -207,7 +208,7 @@ "BUG!!!", "HUE, FEATURE!!" ], - + "semicolon": [ "", ";", @@ -271,7 +272,7 @@ "arrdee", "sek" ], - + "cargo": [ "GUNS", "HATS", @@ -279,7 +280,7 @@ "MEMES", "GLOWY CYSTAL" ], - + "s_roles": [ "ert", "shadowlig", diff --git a/tgstation.dme b/tgstation.dme index 79c4274722..e742498527 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -96,6 +96,7 @@ #include "code\__DEFINES\reagents_specific_heat.dm" #include "code\__DEFINES\research.dm" #include "code\__DEFINES\robots.dm" +#include "code\__DEFINES\rockpaperscissors.dm" #include "code\__DEFINES\role_preferences.dm" #include "code\__DEFINES\rust_g.dm" #include "code\__DEFINES\say.dm" @@ -284,6 +285,7 @@ #include "code\controllers\configuration\entries\general.dm" #include "code\controllers\configuration\entries\plushies.dm" #include "code\controllers\configuration\entries\policy.dm" +#include "code\controllers\configuration\entries\resources.dm" #include "code\controllers\subsystem\acid.dm" #include "code\controllers\subsystem\adjacent_air.dm" #include "code\controllers\subsystem\air.dm" @@ -327,7 +329,6 @@ #include "code\controllers\subsystem\parallax.dm" #include "code\controllers\subsystem\pathfinder.dm" #include "code\controllers\subsystem\persistence.dm" -#include "code\controllers\subsystem\ping.dm" #include "code\controllers\subsystem\profiler.dm" #include "code\controllers\subsystem\radiation.dm" #include "code\controllers\subsystem\radio.dm" @@ -363,6 +364,7 @@ #include "code\controllers\subsystem\processing\status_effects.dm" #include "code\controllers\subsystem\processing\weather.dm" #include "code\controllers\subsystem\processing\wet_floors.dm" +#include "code\datums\accents.dm" #include "code\datums\action.dm" #include "code\datums\ai_laws.dm" #include "code\datums\armor.dm" @@ -435,6 +437,7 @@ #include "code\datums\components\footstep.dm" #include "code\datums\components\fried.dm" #include "code\datums\components\gps.dm" +#include "code\datums\components\honkspam.dm" #include "code\datums\components\identification.dm" #include "code\datums\components\igniter.dm" #include "code\datums\components\infective.dm" @@ -442,6 +445,7 @@ #include "code\datums\components\killerqueen.dm" #include "code\datums\components\knockback.dm" #include "code\datums\components\knockoff.dm" +#include "code\datums\components\label.dm" #include "code\datums\components\lifesteal.dm" #include "code\datums\components\lockon_aiming.dm" #include "code\datums\components\magnetic_catch.dm" @@ -1095,6 +1099,7 @@ #include "code\game\objects\items\devices\paicard.dm" #include "code\game\objects\items\devices\pipe_painter.dm" #include "code\game\objects\items\devices\polycircuit.dm" +#include "code\game\objects\items\devices\portable_chem_mixer.dm" #include "code\game\objects\items\devices\powersink.dm" #include "code\game\objects\items\devices\pressureplates.dm" #include "code\game\objects\items\devices\quantum_keycard.dm" @@ -1706,11 +1711,12 @@ #include "code\modules\assembly\signaler.dm" #include "code\modules\assembly\timer.dm" #include "code\modules\assembly\voice.dm" -#include "code\modules\asset_cache\asset_cache.dm" #include "code\modules\asset_cache\asset_cache_client.dm" #include "code\modules\asset_cache\asset_cache_item.dm" #include "code\modules\asset_cache\asset_list.dm" #include "code\modules\asset_cache\asset_list_items.dm" +#include "code\modules\asset_cache\transports\asset_transport.dm" +#include "code\modules\asset_cache\transports\webroot_transport.dm" #include "code\modules\atmospherics\multiz.dm" #include "code\modules\atmospherics\environmental\LINDA_fire.dm" #include "code\modules\atmospherics\environmental\LINDA_system.dm" @@ -1857,7 +1863,6 @@ #include "code\modules\client\client_colour.dm" #include "code\modules\client\client_defines.dm" #include "code\modules\client\client_procs.dm" -#include "code\modules\client\darkmode.dm" #include "code\modules\client\message.dm" #include "code\modules\client\player_details.dm" #include "code\modules\client\preferences.dm" @@ -2105,7 +2110,6 @@ #include "code\modules\food_and_drinks\recipes\tablecraft\recipes_spaghetti.dm" #include "code\modules\games\cas.dm" #include "code\modules\games\unum.dm" -#include "code\modules\goonchat\browserOutput.dm" #include "code\modules\holiday\easter.dm" #include "code\modules\holiday\holidays.dm" #include "code\modules\holiday\halloween\bartholomew.dm" @@ -2776,6 +2780,7 @@ #include "code\modules\modular_computers\file_system\programs\alarm.dm" #include "code\modules\modular_computers\file_system\programs\arcade.dm" #include "code\modules\modular_computers\file_system\programs\atmosscan.dm" +#include "code\modules\modular_computers\file_system\programs\borg_monitor.dm" #include "code\modules\modular_computers\file_system\programs\card.dm" #include "code\modules\modular_computers\file_system\programs\cargobounty.dm" #include "code\modules\modular_computers\file_system\programs\configurator.dm" @@ -2802,6 +2807,7 @@ #include "code\modules\modular_computers\hardware\portable_disk.dm" #include "code\modules\modular_computers\hardware\printer.dm" #include "code\modules\modular_computers\hardware\recharger.dm" +#include "code\modules\modular_computers\hardware\sensor_package.dm" #include "code\modules\modular_computers\NTNet\NTNRC\conversation.dm" #include "code\modules\movespeed\_movespeed_modifier.dm" #include "code\modules\movespeed\modifiers\components.dm" @@ -2846,6 +2852,7 @@ #include "code\modules\NTNet\network.dm" #include "code\modules\NTNet\relays.dm" #include "code\modules\NTNet\services\_service.dm" +#include "code\modules\paperwork\carbonpaper.dm" #include "code\modules\paperwork\clipboard.dm" #include "code\modules\paperwork\contract.dm" #include "code\modules\paperwork\filingcabinet.dm" @@ -2859,6 +2866,7 @@ #include "code\modules\paperwork\pen.dm" #include "code\modules\paperwork\photocopier.dm" #include "code\modules\paperwork\stamps.dm" +#include "code\modules\paperwork\ticketmachine.dm" #include "code\modules\photography\_pictures.dm" #include "code\modules\photography\camera\camera.dm" #include "code\modules\photography\camera\camera_image_capturing.dm" @@ -3424,6 +3432,7 @@ #include "code\modules\tgui\states\always.dm" #include "code\modules\tgui\states\conscious.dm" #include "code\modules\tgui\states\contained.dm" +#include "code\modules\tgui\states\debug.dm" #include "code\modules\tgui\states\deep_inventory.dm" #include "code\modules\tgui\states\default.dm" #include "code\modules\tgui\states\hands.dm" @@ -3436,6 +3445,11 @@ #include "code\modules\tgui\states\physical.dm" #include "code\modules\tgui\states\self.dm" #include "code\modules\tgui\states\zlevel.dm" +#include "code\modules\tgui_panel\audio.dm" +#include "code\modules\tgui_panel\external.dm" +#include "code\modules\tgui_panel\telemetry.dm" +#include "code\modules\tgui_panel\tgui_panel.dm" +#include "code\modules\tgui_panel\to_chat.dm" #include "code\modules\tooltip\tooltip.dm" #include "code\modules\unit_tests\_unit_tests.dm" #include "code\modules\uplink\uplink_devices.dm" diff --git a/tgui/.eslintrc.yml b/tgui/.eslintrc.yml index 9fd4db9fd2..e3c3144e5b 100644 --- a/tgui/.eslintrc.yml +++ b/tgui/.eslintrc.yml @@ -114,7 +114,7 @@ rules: ## Require return statements to either always or never specify values # consistent-return: error ## Enforce consistent brace style for all control statements - curly: [error, all] + curly: [error, multi-line] ## Require default cases in switch statements # default-case: error ## Enforce default parameters to be last @@ -374,6 +374,7 @@ rules: ignorePattern: '^(import\s.+\sfrom\s|.*require\()', ignoreUrls: true, ignoreRegExpLiterals: true, + ignoreStrings: true, }] ## Enforce a maximum number of lines per file # max-lines: error diff --git a/tgui/.gitattributes b/tgui/.gitattributes index 9382416e69..d9cdc20fbd 100644 --- a/tgui/.gitattributes +++ b/tgui/.gitattributes @@ -17,3 +17,4 @@ bin/tgui text eol=lf ## Treat bundles as binary and ignore them during conflicts *.bundle.* binary merge=tgui-merge-bundle +*.chunk.* binary merge=tgui-merge-bundle diff --git a/tgui/bin/tgui b/tgui/bin/tgui index 97a86159e6..5627b40413 100755 --- a/tgui/bin/tgui +++ b/tgui/bin/tgui @@ -67,7 +67,7 @@ task-clean() { task-validate-build() { cd "${base_dir}" local diff - diff="$(git diff packages/tgui/public/tgui.bundle.*)" + diff="$(git diff packages/tgui/public/*)" if [[ -n ${diff} ]]; then echo "Error: our build differs from the build committed into git." echo "Please rebuild tgui." diff --git a/tgui/docs/component-reference.md b/tgui/docs/component-reference.md index ff1b4e7dfd..23909c639f 100644 --- a/tgui/docs/component-reference.md +++ b/tgui/docs/component-reference.md @@ -227,7 +227,7 @@ be truncated with an ellipsis. Be careful however, because this prop breaks the baseline alignment. - `title: string` - A native browser tooltip, which appears when hovering over the button. -- `content/children: any` - Content to render inside the button. +- `children: any` - Content to render inside the button. - `onClick: function` - Called when element is clicked. ### `Button.Checkbox` @@ -389,7 +389,9 @@ to the left, and certain elements to the right: - ``` @@ -625,7 +627,9 @@ to perform some sort of action), there is a way to do that: + )}> Content @@ -643,7 +647,7 @@ to perform some sort of action), there is a way to do that: - `label: string` - Item label. - `color: string` - Sets the color of the text. - `buttons: any` - Buttons to render aside the content. -- `content/children: any` - Content of this labeled item. +- `children: any` - Content of this labeled item. ### `LabeledList.Divider` @@ -748,7 +752,7 @@ percentage and how filled the bar is. - `ranges: { color: [from, to] }` - Applies a `color` to the progress bar based on whether the value lands in the range between `from` and `to`. - `color: string` - Color of the progress bar. -- `content/children: any` - Content to render inside the progress bar. +- `children: any` - Content to render inside the progress bar. ### `Section` @@ -773,7 +777,9 @@ If you want to have a button on the right side of an section title
+ )}> Here you can order supply crates.
@@ -784,7 +790,10 @@ If you want to have a button on the right side of an section title - `level: number` - Section level in hierarchy. Default is 1, higher number means deeper level of nesting. Must be an integer number. - `buttons: any` - Buttons to render aside the section title. -- `content/children: any` - Content of this section. +- `fill: boolean` - If true, fills all available vertical space. +- `fitted: boolean` - If true, removes all section padding. +- `scrollable: boolean` - Shows or hides the scrollbar. +- `children: any` - Content of this section. ### `Slider` @@ -953,7 +962,7 @@ Usage: **Props:** - `position: string` - Tooltip position. -- `content/children: string` - Content of the tooltip. Must be a plain string. +- `content: string` - Content of the tooltip. Must be a plain string. Fragments or other elements are **not** supported. ## `tgui/layouts` @@ -978,6 +987,7 @@ Example: **Props:** +- See inherited props: [Box](#box) - `className: string` - Applies a CSS class to the element. - `theme: string` - A name of the theme. - For a list of themes, see `packages/tgui/styles/themes`. @@ -995,6 +1005,8 @@ Can be scrollable. **Props:** +- See inherited props: [Box](#box) - `className: string` - Applies a CSS class to the element. +- `fitted: boolean` - If true, removes all padding. - `scrollable: boolean` - Shows or hides the scrollbar. - `children: any` - Main content of your window. diff --git a/tgui/docs/converting-old-tgui-interfaces.md b/tgui/docs/converting-old-tgui-interfaces.md index fe2feebfee..a42724e05c 100644 --- a/tgui/docs/converting-old-tgui-interfaces.md +++ b/tgui/docs/converting-old-tgui-interfaces.md @@ -73,7 +73,6 @@ This might look a bit intimidating compared to the reactive part but it's not as You don't really need to know all this to understand how to use it, but I find it helps with understanding when things go wrong. Ractive conditionals can have an `else` as well - ```ractive {{#if data.condition}} value @@ -117,7 +116,7 @@ and you can mix string literals, values, and tags as well. Ractive has loops for iterating over data and inserting something for each member of an array or object -```ractive +``` {{#each data.list_of_foo}} foo {{number}} is here. {{/each}} @@ -136,7 +135,6 @@ Objects are represented by `{}`, arrays by `[]` `list("bla", "blo")` would become `["bla", "blo"]` and `list("foo" = 1, "bar" = 2)` would become `{"foo": 1, "bar": 2}` First things first, above the `return` of the function you're making the interface in, you're going to want to add something like this - ```jsx const things = data.things || []; ``` @@ -144,7 +142,6 @@ const things = data.things || []; This ensures that you'll never be reading a null entry by mistake. Substitute `{}` for objects as appropriate. If it's an array, you'll want to do this in the template - ```jsx {things.map(thing => ( @@ -190,7 +187,7 @@ const fooArray = toArray(fooObject); Also occasionally you'd see an else: -```ractive +``` {{#each data.potentially_empty_list}} Thing "{{name}}" is in this list! {{else}} @@ -223,7 +220,7 @@ This will be a reference of tgui components and the tgui-next equivalent. Equivalent of `` is `
` -```ractive +``` Contents @@ -239,7 +236,7 @@ becomes A feature sometimes used is if `ui-display` has the `button` property, it will contain a `partial` command. This becomes the `buttons` property on `Section`: -```ractive +``` {{#partial button}} // lots more button bullshit here @@ -266,7 +263,7 @@ Very important to note `ui-section` is NOT the equivalent of `Section` `` does not have a direct equivalent, but the closest equivalent is `` -```ractive +``` No Power @@ -296,7 +293,7 @@ Also good to know that if you need the contents of a `LabeledList.Item` to be co `` has a direct equivalent in `` -```ractive +``` Notice stuff! @@ -314,7 +311,7 @@ becomes The equivalent of `ui-button` is `Button` but it works quite a bit differently. -```ractive +``` ( + new Color( + parseInt(hex.substr(1, 2), 16), + parseInt(hex.substr(3, 2), 16), + parseInt(hex.substr(5, 2), 16)) +); + +/** + * Linear interpolation of two colors. + */ +Color.lerp = (c1, c2, n) => ( + new Color( + (c2.r - c1.r) * n + c1.r, + (c2.g - c1.g) * n + c1.g, + (c2.b - c1.b) * n + c1.b, + (c2.a - c1.a) * n + c1.a) +); + +/** + * Loops up the color in the provided list of colors + * with linear interpolation. + */ +Color.lookup = (value, colors = []) => { + const len = colors.length; + if (len < 2) { + throw new Error('Needs at least two colors!'); + } + const scaled = value * (len - 1); + if (value < EPSILON) { + return colors[0]; + } + if (value >= 1 - EPSILON) { + return colors[len - 1]; + } + const ratio = scaled % 1; + const index = scaled | 0; + return Color.lerp(colors[index], colors[index + 1], ratio); +}; diff --git a/tgui/packages/common/events.js b/tgui/packages/common/events.js new file mode 100644 index 0000000000..6d590a3445 --- /dev/null +++ b/tgui/packages/common/events.js @@ -0,0 +1,42 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +export class EventEmitter { + constructor() { + this.listeners = {}; + } + + on(name, listener) { + this.listeners[name] = this.listeners[name] || []; + this.listeners[name].push(listener); + } + + off(name, listener) { + const listeners = this.listeners[name]; + if (!listeners) { + throw new Error(`There is no listeners for "${name}"`); + } + this.listeners[name] = listeners + .filter(existingListener => { + return existingListener !== listener; + }); + } + + emit(name, ...params) { + const listeners = this.listeners[name]; + if (!listeners) { + return; + } + for (let i = 0, len = listeners.length; i < len; i += 1) { + const listener = listeners[i]; + listener(...params); + } + } + + clear() { + this.listeners = {}; + } +} diff --git a/tgui/packages/common/keycodes.js b/tgui/packages/common/keycodes.js new file mode 100644 index 0000000000..8f18b154b5 --- /dev/null +++ b/tgui/packages/common/keycodes.js @@ -0,0 +1,86 @@ +/** + * All possible browser keycodes, in one file. + * + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +export const KEY_BACKSPACE = 8; +export const KEY_TAB = 9; +export const KEY_ENTER = 13; +export const KEY_SHIFT = 16; +export const KEY_CTRL = 17; +export const KEY_ALT = 18; +export const KEY_PAUSE = 19; +export const KEY_CAPSLOCK = 20; +export const KEY_ESCAPE = 27; +export const KEY_SPACE = 32; +export const KEY_PAGEUP = 33; +export const KEY_PAGEDOWN = 34; +export const KEY_END = 35; +export const KEY_HOME = 36; +export const KEY_LEFT = 37; +export const KEY_UP = 38; +export const KEY_RIGHT = 39; +export const KEY_DOWN = 40; +export const KEY_INSERT = 45; +export const KEY_DELETE = 46; +export const KEY_0 = 48; +export const KEY_1 = 49; +export const KEY_2 = 50; +export const KEY_3 = 51; +export const KEY_4 = 52; +export const KEY_5 = 53; +export const KEY_6 = 54; +export const KEY_7 = 55; +export const KEY_8 = 56; +export const KEY_9 = 57; +export const KEY_A = 65; +export const KEY_B = 66; +export const KEY_C = 67; +export const KEY_D = 68; +export const KEY_E = 69; +export const KEY_F = 70; +export const KEY_G = 71; +export const KEY_H = 72; +export const KEY_I = 73; +export const KEY_J = 74; +export const KEY_K = 75; +export const KEY_L = 76; +export const KEY_M = 77; +export const KEY_N = 78; +export const KEY_O = 79; +export const KEY_P = 80; +export const KEY_Q = 81; +export const KEY_R = 82; +export const KEY_S = 83; +export const KEY_T = 84; +export const KEY_U = 85; +export const KEY_V = 86; +export const KEY_W = 87; +export const KEY_X = 88; +export const KEY_Y = 89; +export const KEY_Z = 90; +export const KEY_F1 = 112; +export const KEY_F2 = 113; +export const KEY_F3 = 114; +export const KEY_F4 = 115; +export const KEY_F5 = 116; +export const KEY_F6 = 117; +export const KEY_F7 = 118; +export const KEY_F8 = 119; +export const KEY_F9 = 120; +export const KEY_F10 = 121; +export const KEY_F11 = 122; +export const KEY_F12 = 123; +export const KEY_SEMICOLON = 186; +export const KEY_EQUAL = 187; +export const KEY_COMMA = 188; +export const KEY_MINUS = 189; +export const KEY_PERIOD = 190; +export const KEY_SLASH = 191; +export const KEY_LEFT_BRACKET = 219; +export const KEY_BACKSLASH = 220; +export const KEY_RIGHT_BRACKET = 221; +export const KEY_QUOTE = 222; diff --git a/tgui/packages/common/package.json b/tgui/packages/common/package.json index fbd255abab..22560d92f9 100644 --- a/tgui/packages/common/package.json +++ b/tgui/packages/common/package.json @@ -1,6 +1,6 @@ { "private": true, "name": "common", - "version": "3.0.0", + "version": "4.1.0", "type": "module" } diff --git a/tgui/packages/common/perf.js b/tgui/packages/common/perf.js index 319b77cea3..8414971f93 100644 --- a/tgui/packages/common/perf.js +++ b/tgui/packages/common/perf.js @@ -1,21 +1,32 @@ /** * Ghetto performance measurement tools. * - * Uses NODE_ENV to redact itself from production bundles. + * Uses NODE_ENV to remove itself from production builds. * * @file * @copyright 2020 Aleksej Komarov * @license MIT */ -let markersByLabel = {}; +const FPS = 60; +const FRAME_DURATION = 1000 / FPS; + +// True if Performance API is supported +const supportsPerf = !!window.performance?.now; +// High precision markers +let hpMarkersByName = {}; +// Low precision markers +let lpMarkersByName = {}; /** * Marks a certain spot in the code for later measurements. */ -const mark = (label, timestamp) => { +const mark = (name, timestamp) => { if (process.env.NODE_ENV !== 'production') { - markersByLabel[label] = timestamp || Date.now(); + if (supportsPerf && !timestamp) { + hpMarkersByName[name] = performance.now(); + } + lpMarkersByName[name] = timestamp || Date.now(); } }; @@ -24,18 +35,23 @@ const mark = (label, timestamp) => { * * Use logger.log() to print the measurement. */ -const measure = (markerA, markerB) => { +const measure = (markerNameA, markerNameB) => { if (process.env.NODE_ENV !== 'production') { - return timeDiff( - markersByLabel[markerA], - markersByLabel[markerB]); + let markerA = hpMarkersByName[markerNameA]; + let markerB = hpMarkersByName[markerNameB]; + if (!markerA || !markerB) { + markerA = lpMarkersByName[markerNameA]; + markerB = lpMarkersByName[markerNameB]; + } + const duration = Math.abs(markerB - markerA); + return formatDuration(duration); } }; -const timeDiff = (startedAt, finishedAt) => { - const diff = Math.abs(finishedAt - startedAt); - const diffFrames = (diff / 16.6667).toFixed(2); - return `${diff}ms (${diffFrames} frames)`; +const formatDuration = duration => { + const durationInFrames = duration / FRAME_DURATION; + return duration.toFixed(duration < 10 ? 1 : 0) + 'ms ' + + '(' + durationInFrames.toFixed(2) + ' frames)'; }; export const perf = { diff --git a/tgui/packages/common/react.js b/tgui/packages/common/react.js index dba84b7b10..c0b24563f1 100644 --- a/tgui/packages/common/react.js +++ b/tgui/packages/common/react.js @@ -64,10 +64,10 @@ export const pureComponentHooks = { }; /** - * A helper to determine whether to render an item. + * A helper to determine whether the object is renderable by React. */ -export const isFalsy = value => { - return value === undefined - || value === null - || value === false; +export const canRender = value => { + return value !== undefined + && value !== null + && typeof value !== 'boolean'; }; diff --git a/tgui/packages/common/redux.js b/tgui/packages/common/redux.js index dc486ff7b8..12aacadb5f 100644 --- a/tgui/packages/common/redux.js +++ b/tgui/packages/common/redux.js @@ -4,6 +4,7 @@ * @license MIT */ +import { Component } from 'inferno'; import { compose } from './fp'; /** @@ -26,7 +27,9 @@ export const createStore = (reducer, enhancer) => { const dispatch = action => { currentState = reducer(currentState, action); - listeners.forEach(fn => fn()); + for (let i = 0; i < listeners.length; i++) { + listeners[i](); + } }; // This creates the initial store by causing each reducer to be called @@ -81,7 +84,7 @@ export const applyMiddleware = (...middlewares) => { export const combineReducers = reducersObj => { const keys = Object.keys(reducersObj); let hasChanged = false; - return (prevState, action) => { + return (prevState = {}, action) => { const nextState = { ...prevState }; for (let key of keys) { const reducer = reducersObj[key]; @@ -97,3 +100,55 @@ export const combineReducers = reducersObj => { : prevState; }; }; + +/** + * A utility function to create an action creator for the given action + * type string. The action creator accepts a single argument, which will + * be included in the action object as a field called payload. The action + * creator function will also have its toString() overriden so that it + * returns the action type, allowing it to be used in reducer logic that + * is looking for that action type. + * + * @param type The action type to use for created actions. + * @param prepare (optional) a method that takes any number of arguments + * and returns { payload } or { payload, meta }. If this is given, the + * resulting action creator will pass it's arguments to this method to + * calculate payload & meta. + * + * @public + */ +export const createAction = (type, prepare) => { + const actionCreator = (...args) => { + if (!prepare) { + return { type, payload: args[0] }; + } + const prepared = prepare(...args); + if (!prepared) { + throw new Error('prepare function did not return an object'); + } + const action = { type }; + if ('payload' in prepared) { + action.payload = prepared.payload; + } + if ('meta' in prepared) { + action.meta = prepared.meta; + } + return action; + }; + actionCreator.toString = () => '' + type; + actionCreator.type = type; + actionCreator.match = action => action.type === type; + return actionCreator; +}; + + +// Implementation specific +// -------------------------------------------------------- + +export const useDispatch = context => { + return context.store.dispatch; +}; + +export const useSelector = (context, selector) => { + return selector(context.store.getState()); +}; diff --git a/tgui/packages/common/storage.js b/tgui/packages/common/storage.js index 8e1d2183e4..115a7ff0ff 100644 --- a/tgui/packages/common/storage.js +++ b/tgui/packages/common/storage.js @@ -6,71 +6,191 @@ * @license MIT */ -export const STORAGE_NONE = 0; -export const STORAGE_LOCAL_STORAGE = 1; -export const STORAGE_INDEXED_DB = 2; +export const IMPL_MEMORY = 0; +export const IMPL_LOCAL_STORAGE = 1; +export const IMPL_INDEXED_DB = 2; -const createMock = () => { - let storage = {}; - const get = key => storage[key]; - const set = (key, value) => { - storage[key] = value; - }; - const remove = key => { - storage[key] = undefined; - }; - const clear = () => { - // NOTE: On IE8, this will probably leak memory if used often. - storage = {}; - }; - return { - get, - set, - remove, - clear, - engine: STORAGE_NONE, - }; -}; +const INDEXED_DB_VERSION = 1; +const INDEXED_DB_NAME = 'tgui'; +const INDEXED_DB_STORE_NAME = 'storage-v1'; -const createLocalStorage = () => { - const get = key => { - const value = localStorage.getItem(key); - if (typeof value !== 'string') { - return; - } - return JSON.parse(value); - }; - const set = (key, value) => { - localStorage.setItem(key, JSON.stringify(value)); - }; - const remove = key => { - localStorage.removeItem(key); - }; - const clear = () => { - localStorage.clear(); - }; - return { - get, - set, - remove, - clear, - engine: STORAGE_LOCAL_STORAGE, - }; -}; +const READ_ONLY = 'readonly'; +const READ_WRITE = 'readwrite'; -const testLocalStorage = () => { - // Localstorage can sometimes throw an error, even if DOM storage is not - // disabled in IE11 settings. - // See: https://superuser.com/questions/1080011 +const testGeneric = testFn => () => { try { - return Boolean(window.localStorage && window.localStorage.getItem); + return Boolean(testFn()); } catch { return false; } }; -export const storage = ( - testLocalStorage() && createLocalStorage() - || createMock() -); +// Localstorage can sometimes throw an error, even if DOM storage is not +// disabled in IE11 settings. +// See: https://superuser.com/questions/1080011 +const testLocalStorage = testGeneric(() => ( + window.localStorage && window.localStorage.getItem +)); + +const testIndexedDb = testGeneric(() => ( + (window.indexedDB || window.msIndexedDB) + && (window.IDBTransaction || window.msIDBTransaction) +)); + +class MemoryBackend { + constructor() { + this.impl = IMPL_MEMORY; + this.store = {}; + } + + get(key) { + return this.store[key]; + } + + set(key, value) { + this.store[key] = value; + } + + remove(key) { + this.store[key] = undefined; + } + + clear() { + this.store = {}; + } +} + +class LocalStorageBackend { + constructor() { + this.impl = IMPL_LOCAL_STORAGE; + this.store = {}; + } + + get(key) { + const value = localStorage.getItem(key); + if (typeof value === 'string') { + return JSON.parse(value); + } + } + + set(key, value) { + localStorage.setItem(key, JSON.stringify(value)); + } + + remove(key) { + localStorage.removeItem(key); + } + + clear() { + localStorage.clear(); + } +} + +class IndexedDbBackend { + constructor() { + this.impl = IMPL_INDEXED_DB; + /** @type {Promise} */ + this.dbPromise = new Promise((resolve, reject) => { + const indexedDB = window.indexedDB || window.msIndexedDB; + const req = indexedDB.open(INDEXED_DB_NAME, INDEXED_DB_VERSION); + req.onupgradeneeded = () => { + try { + req.result.createObjectStore(INDEXED_DB_STORE_NAME); + } + catch (err) { + reject(new Error('Failed to upgrade IDB: ' + req.error)); + } + }; + req.onsuccess = () => resolve(req.result); + req.onerror = () => { + reject(new Error('Failed to open IDB: ' + req.error)); + }; + }); + } + + getStore(mode) { + return this.dbPromise.then(db => db + .transaction(INDEXED_DB_STORE_NAME, mode) + .objectStore(INDEXED_DB_STORE_NAME)); + } + + async get(key) { + const store = await this.getStore(READ_ONLY); + return new Promise((resolve, reject) => { + const req = store.get(key); + req.onsuccess = () => resolve(req.result); + req.onerror = () => reject(req.error); + }); + } + + async set(key, value) { + // The reason we don't _save_ null is because IE 10 does + // not support saving the `null` type in IndexedDB. How + // ironic, given the bug below! + // See: https://github.com/mozilla/localForage/issues/161 + if (value === null) { + value = undefined; + } + // NOTE: We deliberately make this operation transactionless + const store = await this.getStore(READ_WRITE); + store.put(value, key); + } + + async remove(key) { + // NOTE: We deliberately make this operation transactionless + const store = await this.getStore(READ_WRITE); + store.delete(key); + } + + async clear() { + // NOTE: We deliberately make this operation transactionless + const store = await this.getStore(READ_WRITE); + store.clear(); + } +} + +/** + * Web Storage Proxy object, which selects the best backend available + * depending on the environment. + */ +class StorageProxy { + constructor() { + this.backendPromise = (async () => { + if (testIndexedDb()) { + try { + const backend = new IndexedDbBackend(); + await backend.dbPromise; + return backend; + } + catch {} + } + if (testLocalStorage()) { + return new LocalStorageBackend(); + } + return new MemoryBackend(); + })(); + } + + async get(key) { + const backend = await this.backendPromise; + return backend.get(key); + } + + async set(key, value) { + const backend = await this.backendPromise; + return backend.set(key, value); + } + + async remove(key) { + const backend = await this.backendPromise; + return backend.remove(key); + } + + async clear() { + const backend = await this.backendPromise; + return backend.clear(); + } +} + +export const storage = new StorageProxy(); diff --git a/tgui/packages/common/timer.js b/tgui/packages/common/timer.js index f4e26fa5aa..1177071b9c 100644 --- a/tgui/packages/common/timer.js +++ b/tgui/packages/common/timer.js @@ -27,3 +27,12 @@ export const debounce = (fn, time, immediate = false) => { } }; }; + +/** + * Suspends an asynchronous function for N milliseconds. + * + * @param {number} time + */ +export const sleep = time => ( + new Promise(resolve => setTimeout(resolve, time)) +); diff --git a/tgui/packages/common/uuid.js b/tgui/packages/common/uuid.js new file mode 100644 index 0000000000..7721af6494 --- /dev/null +++ b/tgui/packages/common/uuid.js @@ -0,0 +1,19 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +/** + * Creates a UUID v4 string + * + * @return {string} + */ +export const createUuid = () => { + let d = new Date().getTime(); + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { + const r = (d + Math.random() * 16) % 16 | 0; + d = Math.floor(d / 16); + return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); + }); +}; diff --git a/tgui/packages/tgui-dev-server/dreamseeker.js b/tgui/packages/tgui-dev-server/dreamseeker.js new file mode 100644 index 0000000000..c36fe55f28 --- /dev/null +++ b/tgui/packages/tgui-dev-server/dreamseeker.js @@ -0,0 +1,87 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import axios from 'axios'; +import { exec } from 'child_process'; +import { createLogger } from 'common/logging.js'; +import { promisify } from 'util'; + +const logger = createLogger('dreamseeker'); + +const instanceByPid = new Map(); + +export class DreamSeeker { + constructor(pid, addr) { + this.pid = pid; + this.addr = addr; + this.client = axios.create({ + baseURL: `http://${addr}/`, + }); + } + + topic(params = {}) { + const query = Object.keys(params) + .map(key => encodeURIComponent(key) + + '=' + encodeURIComponent(params[key])) + .join('&'); + return this.client.get('/dummy?' + query); + } +} + +/** + * @param {number[]} pids + * @returns {DreamSeeker[]} + */ +DreamSeeker.getInstancesByPids = async pids => { + if (process.platform !== 'win32') { + return []; + } + const instances = []; + const pidsToResolve = []; + for (let pid of pids) { + const instance = instanceByPid.get(pid); + if (instance) { + instances.push(instance); + } + else { + pidsToResolve.push(pid); + } + } + if (pidsToResolve.length > 0) { + try { + const command = 'netstat -a -n -o'; + const { stdout } = await promisify(exec)(command); + // Line format: + // proto addr mask mode pid + const entries = stdout + .split('\r\n') + .filter(line => line.includes('LISTENING')) + .map(line => { + const words = line.match(/\S+/g); + return { + addr: words[1], + pid: parseInt(words[4], 10), + }; + }) + .filter(entry => pidsToResolve.includes(entry.pid)); + const len = entries.length; + logger.log('found', len, plural('instance', len)); + for (let entry of entries) { + const { pid, addr } = entry; + const instance = new DreamSeeker(pid, addr); + instances.push(instance); + instanceByPid.set(pid, instance); + } + } + catch (err) { + logger.error(err); + return []; + } + } + return instances; +}; + +const plural = (word, n) => n !== 1 ? word + 's' : word; diff --git a/tgui/packages/tgui-dev-server/index.js b/tgui/packages/tgui-dev-server/index.js index f4e8155d29..43acd87474 100644 --- a/tgui/packages/tgui-dev-server/index.js +++ b/tgui/packages/tgui-dev-server/index.js @@ -8,12 +8,15 @@ import { setupWebpack, getWebpackConfig } from './webpack.js'; import { reloadByondCache } from './reloader.js'; const noHot = process.argv.includes('--no-hot'); +const noTmp = process.argv.includes('--no-tmp'); const reloadOnce = process.argv.includes('--reload'); const setupServer = async () => { const config = await getWebpackConfig({ mode: 'development', hot: !noHot, + devServer: true, + useTmpFolder: !noTmp, }); // Reload cache once if (reloadOnce) { diff --git a/tgui/packages/tgui-dev-server/link/client.js b/tgui/packages/tgui-dev-server/link/client.js index 4671b340c5..5a4d2f6112 100644 --- a/tgui/packages/tgui-dev-server/link/client.js +++ b/tgui/packages/tgui-dev-server/link/client.js @@ -37,7 +37,7 @@ if (process.env.NODE_ENV !== 'production') { window.onunload = () => socket && socket.close(); } -const subscribe = fn => subscribers.push(fn); +export const subscribe = fn => subscribers.push(fn); /** * A json serializer which handles circular references and other junk. @@ -68,7 +68,10 @@ const serializeObject = obj => { } refs.push(value); // Error object - if (value instanceof Error) { + const isError = value instanceof Error || ( + value.code && value.message && value.message.includes('Error') + ); + if (isError) { return { __error__: true, string: String(value), @@ -88,7 +91,7 @@ const serializeObject = obj => { return json; }; -const sendRawMessage = msg => { +export const sendMessage = msg => { if (process.env.NODE_ENV !== 'production') { const json = serializeObject(msg); // Send message using WebSocket @@ -109,8 +112,8 @@ const sendRawMessage = msg => { else { const DEV_SERVER_IP = process.env.DEV_SERVER_IP || '127.0.0.1'; const req = new XMLHttpRequest(); - req.open('POST', `http://${DEV_SERVER_IP}:3001`); - req.timeout = 500; + req.open('POST', `http://${DEV_SERVER_IP}:3001`, true); + req.timeout = 250; req.send(json); } } @@ -119,7 +122,7 @@ const sendRawMessage = msg => { export const sendLogEntry = (level, ns, ...args) => { if (process.env.NODE_ENV !== 'production') { try { - sendRawMessage({ + sendMessage({ type: 'log', payload: { level, diff --git a/tgui/packages/tgui-dev-server/link/retrace.js b/tgui/packages/tgui-dev-server/link/retrace.js index e0b17a01d6..4bcb8e40c6 100644 --- a/tgui/packages/tgui-dev-server/link/retrace.js +++ b/tgui/packages/tgui-dev-server/link/retrace.js @@ -39,6 +39,10 @@ export const loadSourceMaps = async bundleDir => { }; export const retrace = stack => { + if (typeof stack !== 'string') { + logger.log('ERROR: Stack is not a string!', stack); + return stack; + } const header = stack.split(/\n\s.*at/)[0]; const mappedStack = StackTraceParser.parse(stack) .map(frame => { diff --git a/tgui/packages/tgui-dev-server/link/server.js b/tgui/packages/tgui-dev-server/link/server.js index 94a79c9ad5..2586d77779 100644 --- a/tgui/packages/tgui-dev-server/link/server.js +++ b/tgui/packages/tgui-dev-server/link/server.js @@ -16,37 +16,108 @@ const DEBUG = process.argv.includes('--debug'); export { loadSourceMaps }; -export const setupLink = () => { - logger.log('setting up'); - const wss = setupWebSocketLink(); - setupHttpLink(); - return { - wss, - }; -}; +export const setupLink = () => new LinkServer(); -export const broadcastMessage = (link, msg) => { - const { wss } = link; - const clients = [...wss.clients]; - logger.log(`broadcasting ${msg.type} to ${clients.length} clients`); - for (let client of clients) { - const json = JSON.stringify(msg); - client.send(json); +class LinkServer { + constructor() { + logger.log('setting up'); + this.wss = null; + this.setupWebSocketLink(); + this.setupHttpLink(); } -}; + + // WebSocket-based client link + setupWebSocketLink() { + const port = 3000; + this.wss = new WebSocket.Server({ port }); + this.wss.on('connection', ws => { + logger.log('client connected'); + ws.on('message', json => { + const msg = deserializeObject(json); + this.handleLinkMessage(ws, msg); + }); + ws.on('close', () => { + logger.log('client disconnected'); + }); + }); + logger.log(`listening on port ${port} (WebSocket)`); + } + + // One way HTTP-based client link for IE8 + setupHttpLink() { + const port = 3001; + this.httpServer = http.createServer((req, res) => { + if (req.method === 'POST') { + let body = ''; + req.on('data', chunk => { + body += chunk.toString(); + }); + req.on('end', () => { + const msg = deserializeObject(body); + this.handleLinkMessage(null, msg); + res.end(); + }); + return; + } + res.write('Hello'); + res.end(); + }); + this.httpServer.listen(port); + logger.log(`listening on port ${port} (HTTP)`); + } + + handleLinkMessage(ws, msg) { + const { type, payload } = msg; + if (type === 'log') { + const { level, ns, args } = payload; + // Skip debug messages + if (level <= 0 && !DEBUG) { + return; + } + directLog(ns, ...args.map(arg => { + if (typeof arg === 'object') { + return inspect(arg, { + depth: Infinity, + colors: true, + compact: 8, + }); + } + return arg; + })); + return; + } + if (type === 'relay') { + for (let client of this.wss.clients) { + if (client === ws) { + continue; + } + this.sendMessage(client, msg); + } + return; + } + logger.log('unhandled message', msg); + } + + sendMessage(ws, msg) { + ws.send(JSON.stringify(msg)); + } + + broadcastMessage(msg) { + const clients = [...this.wss.clients]; + if (clients.length === 0) { + return; + } + logger.log(`broadcasting ${msg.type} to ${clients.length} clients`); + for (let client of clients) { + const json = JSON.stringify(msg); + client.send(json); + } + } +} const deserializeObject = str => { return JSON.parse(str, (key, value) => { if (typeof value === 'object' && value !== null) { - if (value.__error__) { - if (!value.stack) { - return value.string; - } - return retrace(value.stack); - } - if (value.__number__) { - return parseFloat(value.__number__); - } if (value.__undefined__) { // NOTE: You should not rely on deserialized object's undefined, // this is purely for inspection purposes. @@ -54,80 +125,17 @@ const deserializeObject = str => { [inspect.custom]: () => undefined, }; } + if (value.__number__) { + return parseFloat(value.__number__); + } + if (value.__error__) { + if (!value.stack) { + return value.string; + } + return retrace(value.stack); + } return value; } return value; }); }; - -const handleLinkMessage = msg => { - const { type, payload } = msg; - - if (type === 'log') { - const { level, ns, args } = payload; - // Skip debug messages - if (level <= 0 && !DEBUG) { - return; - } - directLog(ns, ...args.map(arg => { - if (typeof arg === 'object') { - return inspect(arg, { - depth: Infinity, - colors: true, - compact: 8, - }); - } - return arg; - })); - return; - } - - logger.log('unhandled message', msg); -}; - -// WebSocket-based client link -const setupWebSocketLink = () => { - const port = 3000; - const wss = new WebSocket.Server({ port }); - - wss.on('connection', ws => { - logger.log('client connected'); - - ws.on('message', json => { - const msg = deserializeObject(json); - handleLinkMessage(msg); - }); - - ws.on('close', () => { - logger.log('client disconnected'); - }); - }); - - logger.log(`listening on port ${port} (WebSocket)`); - return wss; -}; - -// One way HTTP-based client link for IE8 -const setupHttpLink = () => { - const port = 3001; - - const server = http.createServer((req, res) => { - if (req.method === 'POST') { - let body = ''; - req.on('data', chunk => { - body += chunk.toString(); - }); - req.on('end', () => { - const msg = deserializeObject(body); - handleLinkMessage(msg); - res.end(); - }); - return; - } - res.write('Hello'); - res.end(); - }); - - server.listen(port); - logger.log(`listening on port ${port} (HTTP)`); -}; diff --git a/tgui/packages/tgui-dev-server/package.json b/tgui/packages/tgui-dev-server/package.json index e397fe3e0b..3e50a97f0e 100644 --- a/tgui/packages/tgui-dev-server/package.json +++ b/tgui/packages/tgui-dev-server/package.json @@ -1,9 +1,10 @@ { "private": true, "name": "tgui-dev-server", - "version": "3.0.0", + "version": "4.1.0", "type": "module", "dependencies": { + "axios": "^0.19.2", "glob": "^7.1.4", "source-map": "^0.7.3", "stacktrace-parser": "^0.1.7", diff --git a/tgui/packages/tgui-dev-server/reloader.js b/tgui/packages/tgui-dev-server/reloader.js index e33f7226b9..1271e67d2a 100644 --- a/tgui/packages/tgui-dev-server/reloader.js +++ b/tgui/packages/tgui-dev-server/reloader.js @@ -11,6 +11,7 @@ import { basename } from 'path'; import { promisify } from 'util'; import { resolveGlob, resolvePath } from './util.js'; import { regQuery } from './winreg.js'; +import { DreamSeeker } from './dreamseeker.js'; const logger = createLogger('reloader'); @@ -43,7 +44,7 @@ export const findCacheRoot = async () => { const paths = await resolveGlob(pattern); if (paths.length > 0) { cacheRoot = paths[0]; - logger.log(`found cache at '${cacheRoot}'`); + onCacheRootFound(cacheRoot); return cacheRoot; } } @@ -58,13 +59,19 @@ export const findCacheRoot = async () => { .replace(/\\$/, '') .replace(/\\/g, '/') + '/cache'; - logger.log(`found cache at '${cacheRoot}'`); + onCacheRootFound(cacheRoot); return cacheRoot; } } logger.log('found no cache directories'); }; +const onCacheRootFound = cacheRoot => { + logger.log(`found cache at '${cacheRoot}'`); + // Plant dummy + fs.closeSync(fs.openSync(cacheRoot + '/dummy', 'w')); +}; + export const reloadByondCache = async bundleDir => { const cacheRoot = await findCacheRoot(); if (!cacheRoot) { @@ -76,10 +83,16 @@ export const reloadByondCache = async bundleDir => { logger.log('found no tmp folder in cache'); return; } - const assets = await resolveGlob(bundleDir, './*.+(bundle|hot-update).*'); + // Get dreamseeker instances + const pids = cacheDirs.map(cacheDir => ( + parseInt(cacheDir.split('/cache/tmp').pop(), 10) + )); + const dssPromise = DreamSeeker.getInstancesByPids(pids); + // Copy assets + const assets = await resolveGlob(bundleDir, './*.+(bundle|chunk|hot-update).*'); for (let cacheDir of cacheDirs) { // Clear garbage - const garbage = await resolveGlob(cacheDir, './*.+(bundle|hot-update).*'); + const garbage = await resolveGlob(cacheDir, './*.+(bundle|chunk|hot-update).*'); for (let file of garbage) { await promisify(fs.unlink)(file); } @@ -90,4 +103,15 @@ export const reloadByondCache = async bundleDir => { } logger.log(`copied ${assets.length} files to '${cacheDir}'`); } + // Notify dreamseeker + const dss = await dssPromise; + if (dss.length > 0) { + logger.log(`notifying dreamseeker`); + for (let dreamseeker of dss) { + dreamseeker.topic({ + tgui: 1, + type: 'cacheReloaded', + }); + } + } }; diff --git a/tgui/packages/tgui-dev-server/webpack.js b/tgui/packages/tgui-dev-server/webpack.js index c625827409..7a1f600253 100644 --- a/tgui/packages/tgui-dev-server/webpack.js +++ b/tgui/packages/tgui-dev-server/webpack.js @@ -9,7 +9,7 @@ import fs from 'fs'; import { createRequire } from 'module'; import { promisify } from 'util'; import webpack from 'webpack'; -import { broadcastMessage, loadSourceMaps, setupLink } from './link/server.js'; +import { loadSourceMaps, setupLink } from './link/server.js'; import { reloadByondCache } from './reloader.js'; import { resolveGlob } from './util.js'; @@ -44,7 +44,7 @@ export const setupWebpack = async config => { // Reload cache await reloadByondCache(bundleDir); // Notify all clients that update has happened - broadcastMessage(link, { + link.broadcastMessage({ type: 'hotUpdate', }); }); @@ -55,6 +55,9 @@ export const setupWebpack = async config => { logger.error('compilation error', err); return; } - logger.log(stats.toString(config.devServer.stats)); + stats + .toString(config.devServer.stats) + .split('\n') + .forEach(line => logger.log(line)); }); }; diff --git a/tgui/packages/tgui-panel/Notifications.js b/tgui/packages/tgui-panel/Notifications.js new file mode 100644 index 0000000000..a64ddd8e30 --- /dev/null +++ b/tgui/packages/tgui-panel/Notifications.js @@ -0,0 +1,41 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { Flex } from 'tgui/components'; + +export const Notifications = props => { + const { children } = props; + return ( +
+ {children} +
+ ); +}; + +const NotificationsItem = props => { + const { + rightSlot, + children, + } = props; + return ( + + + {children} + + {rightSlot && ( + + {rightSlot} + + )} + + ); +}; + +Notifications.Item = NotificationsItem; diff --git a/tgui/packages/tgui-panel/Panel.js b/tgui/packages/tgui-panel/Panel.js new file mode 100644 index 0000000000..0350fb94c3 --- /dev/null +++ b/tgui/packages/tgui-panel/Panel.js @@ -0,0 +1,142 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { Button, Flex, Section } from 'tgui/components'; +import { Pane } from 'tgui/layouts'; +import { NowPlayingWidget, useAudio } from './audio'; +import { ChatPanel, ChatTabs } from './chat'; +import { useGame } from './game'; +import { Notifications } from './Notifications'; +import { PingIndicator } from './ping'; +import { SettingsPanel, useSettings } from './settings'; + +export const Panel = (props, context) => { + if (Byond.IS_LTE_IE8) { + return ( + + ); + } + const audio = useAudio(context); + const settings = useSettings(context); + const game = useGame(context); + if (process.env.NODE_ENV !== 'production') { + const { useDebug, KitchenSink } = require('tgui/debug'); + const debug = useDebug(context); + if (debug.kitchenSink) { + return ( + + ); + } + } + return ( // yes i know it's bad. + + + +
+ + + + + + + + +
+
+ {audio.visible && ( + +
+ +
+
+ )} + {settings.visible && ( + + + + )} + +
+ + + + + {game.connectionLostAt && ( + Byond.command('.reconnect')}> + Reconnect + + )}> + You are either AFK, experiencing lag or the connection + has closed. + + )} + {game.roundRestartedAt && ( + + The connection has been closed because the server is + restarting. Please wait while you automatically reconnect. + + )} + +
+
+
+
+ ); +}; + +// IE8: Needs special treatment +const HoboIE8Panel = (props, context) => { + const settings = useSettings(context); + return ( + + + + {settings.visible && ( + + + + ) || ( + + )} + + + ); +}; diff --git a/tgui/packages/tgui-panel/audio/NowPlayingWidget.js b/tgui/packages/tgui-panel/audio/NowPlayingWidget.js new file mode 100644 index 0000000000..654f2a6b7c --- /dev/null +++ b/tgui/packages/tgui-panel/audio/NowPlayingWidget.js @@ -0,0 +1,69 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { toFixed } from 'common/math'; +import { useDispatch, useSelector } from 'common/redux'; +import { Fragment } from 'inferno'; +import { Button, Flex, Knob } from 'tgui/components'; +import { useSettings } from '../settings'; +import { selectAudio } from './selectors'; + +export const NowPlayingWidget = (props, context) => { + const audio = useSelector(context, selectAudio); + const dispatch = useDispatch(context); + const settings = useSettings(context); + const title = audio.meta?.title; + return ( + + {audio.playing && ( + + + Now playing: + + + {title || 'Unknown Track'} + + + ) || ( + + Nothing to play. + + )} + {audio.playing && ( + + + + + +
+ {MESSAGE_TYPES + .filter(typeDef => !typeDef.important && !typeDef.admin) + .map(typeDef => ( + dispatch(toggleAcceptedType({ + pageId: page.id, + type: typeDef.type, + }))}> + {typeDef.name} + + ))} + + {MESSAGE_TYPES + .filter(typeDef => !typeDef.important && typeDef.admin) + .map(typeDef => ( + dispatch(toggleAcceptedType({ + pageId: page.id, + type: typeDef.type, + }))}> + {typeDef.name} + + ))} + +
+
+ ); +}; diff --git a/tgui/packages/tgui-panel/chat/ChatPanel.js b/tgui/packages/tgui-panel/chat/ChatPanel.js new file mode 100644 index 0000000000..bf7eb90e6f --- /dev/null +++ b/tgui/packages/tgui-panel/chat/ChatPanel.js @@ -0,0 +1,71 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { shallowDiffers } from 'common/react'; +import { Component, createRef, Fragment } from 'inferno'; +import { Button } from 'tgui/components'; +import { chatRenderer } from './renderer'; + +export class ChatPanel extends Component { + constructor() { + super(); + this.ref = createRef(); + this.state = { + scrollTracking: true, + }; + this.handleScrollTrackingChange = value => this.setState({ + scrollTracking: value, + }); + } + + componentDidMount() { + chatRenderer.mount(this.ref.current); + chatRenderer.events.on('scrollTrackingChanged', + this.handleScrollTrackingChange); + this.componentDidUpdate(); + } + + componentWillUnmount() { + chatRenderer.events.off('scrollTrackingChanged', + this.handleScrollTrackingChange); + } + + componentDidUpdate(prevProps) { + requestAnimationFrame(() => { + chatRenderer.ensureScrollTracking(); + }); + const shouldUpdateStyle = ( + !prevProps || shallowDiffers(this.props, prevProps) + ); + if (shouldUpdateStyle) { + chatRenderer.assignStyle({ + 'width': '100%', + 'white-space': 'pre-wrap', + 'font-size': this.props.fontSize, + 'line-height': this.props.lineHeight, + }); + } + } + + render() { + const { + scrollTracking, + } = this.state; + return ( + +
+ {!scrollTracking && ( + + )} + + ); + } +} diff --git a/tgui/packages/tgui-panel/chat/ChatTabs.js b/tgui/packages/tgui-panel/chat/ChatTabs.js new file mode 100644 index 0000000000..a0e6cc59e5 --- /dev/null +++ b/tgui/packages/tgui-panel/chat/ChatTabs.js @@ -0,0 +1,61 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { useDispatch, useSelector } from 'common/redux'; +import { Box, Tabs, Flex, Button } from 'tgui/components'; +import { changeChatPage, addChatPage } from './actions'; +import { selectChatPages, selectCurrentChatPage } from './selectors'; +import { openChatSettings } from '../settings/actions'; + +const UnreadCountWidget = ({ value }) => ( + + {Math.min(value, 99)} + +); + +export const ChatTabs = (props, context) => { + const pages = useSelector(context, selectChatPages); + const currentPage = useSelector(context, selectCurrentChatPage); + const dispatch = useDispatch(context); + return ( + + + + {pages.map(page => ( + 0 && ( + + )} + onClick={() => dispatch(changeChatPage({ + pageId: page.id, + }))}> + {page.name} + + ))} + + + +