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/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/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/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..6dcb5f2534 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() diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index 7a18d2ce01..c4d105a3a6 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -620,6 +620,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/objects.dm b/code/_globalvars/lists/objects.dm index fee70ee3d5..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 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/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/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/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/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/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/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 2fe674e59e..b077a0c8db 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -857,6 +857,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"]
" @@ -2353,6 +2355,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 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/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/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/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/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/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 04747ffcb4..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" 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_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/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/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/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/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 470b34e82c..7e515bf0f5 100644 --- a/code/modules/newscaster/newscaster_machine.dm +++ b/code/modules/newscaster/newscaster_machine.dm @@ -340,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 392eba5f56..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,9 +59,42 @@ 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" 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/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/research/designs/computer_part_designs.dm b/code/modules/research/designs/computer_part_designs.dm index ab487b0aaa..db37b13e87 100644 --- a/code/modules/research/designs/computer_part_designs.dm +++ b/code/modules/research/designs/computer_part_designs.dm @@ -143,7 +143,7 @@ departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING // APC Link -/datum/design/APClink +/datum/design/apc_link name = "Area Power Connector" id = "APClink" build_type = PROTOLATHE @@ -230,7 +230,7 @@ name = "Photonic Processor Board" id = "pcpu_normal" build_type = IMPRINTER - materials = list(/datum/material/glass= 6400, /datum/material/gold = 2000) + materials = list(/datum/material/glass = 6400, /datum/material/gold = 2000) build_path = /obj/item/computer_hardware/processor_unit/photonic category = list("Computer Parts") departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING @@ -243,3 +243,12 @@ build_path = /obj/item/computer_hardware/processor_unit/photonic/small category = list("Computer Parts") departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING + +/datum/design/sensorpackage + name = "Sensor Package" + id = "sensorpackage" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 200, /datum/material/glass = 100, /datum/material/gold = 50, /datum/material/silver = 50) + build_path = /obj/item/computer_hardware/sensorpackage + category = list("Computer Parts") + departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index 0a9fce2e67..7013412e6d 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -354,6 +354,16 @@ category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL +/datum/design/portable_chem_mixer + name = "Portable Chemical Mixer" + desc = "A portable device that dispenses and mixes chemicals. Reagents have to be supplied with beakers." + id = "portable_chem_mixer" + build_type = PROTOLATHE + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL + materials = list(/datum/material/plastic = 5000, /datum/material/iron = 10000, /datum/material/glass = 3000) + build_path = /obj/item/storage/portable_chem_mixer + category = list("Equipment") + ///////////////////////////////////////// //////////Cybernetic Implants//////////// ///////////////////////////////////////// diff --git a/code/modules/research/techweb/nodes/computer_hud_nodes.dm b/code/modules/research/techweb/nodes/computer_hud_nodes.dm index 2835edc52b..2db03861e9 100644 --- a/code/modules/research/techweb/nodes/computer_hud_nodes.dm +++ b/code/modules/research/techweb/nodes/computer_hud_nodes.dm @@ -13,10 +13,10 @@ display_name = "Computer Hardware" description = "How computer hardware are made." prereq_ids = list("comptech") - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1250) //they are really kinda shitty + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) //they are really shitty design_ids = list("hdd_basic", "hdd_advanced", "hdd_super", "hdd_cluster", "ssd_small", "ssd_micro", "netcard_basic", "netcard_advanced", "netcard_wired", "portadrive_basic", "portadrive_advanced", "portadrive_super", "cardslot", "aislot", "miniprinter", "APClink", "bat_control", "bat_normal", "bat_advanced", - "bat_super", "bat_micro", "bat_nano", "cpu_normal", "pcpu_normal", "cpu_small", "pcpu_small") + "bat_super", "bat_micro", "bat_nano", "cpu_normal", "pcpu_normal", "cpu_small", "pcpu_small", "sensorpackage") /datum/techweb_node/comp_recordkeeping id = "comp_recordkeeping" diff --git a/code/modules/shuttle/computer.dm b/code/modules/shuttle/computer.dm index 682a7fa14b..cee83c5b23 100644 --- a/code/modules/shuttle/computer.dm +++ b/code/modules/shuttle/computer.dm @@ -33,7 +33,6 @@ var/datum/browser/popup = new(user, "computer", M ? M.name : "shuttle", 300, 200) popup.set_content("
[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/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/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/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 97% rename from html/panels.css rename to html/admin/panels.css index 1f969c690e..22373ee0ca 100644 --- a/html/panels.css +++ b/html/admin/panels.css @@ -1,10 +1,10 @@ -body {padding:0px;margin:0px;} -#top {position:fixed;top:5px;left:10%;width:80%;text-align:center;background-color:#fff;border:2px solid #ccc;} -#main {position:relative;top:10px;left:3%;width:96%;text-align:center;z-index:0;} -#searchable {table-layout:fixed;width:100%;text-align:center;"#f4f4f4";} -tr.norm {background-color:#f4f4f4;} -tr.title {background-color:#ccc;} -tr.alt {background-color:#e7e7e7;} -.small {font-size:80%;} -a {text-decoration:none;} -a:hover {color:#d3d;} +body {padding:0px;margin:0px;} +#top {position:fixed;top:5px;left:10%;width:80%;text-align:center;background-color:#fff;border:2px solid #ccc;} +#main {position:relative;top:10px;left:3%;width:96%;text-align:center;z-index:0;} +#searchable {table-layout:fixed;width:100%;text-align:center;"#f4f4f4";} +tr.norm {background-color:#f4f4f4;} +tr.title {background-color:#ccc;} +tr.alt {background-color:#e7e7e7;} +.small {font-size:80%;} +a {text-decoration:none;} +a:hover {color:#d3d;} 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/changelogs/AutoChangeLog-pr-12957.yml b/html/changelogs/AutoChangeLog-pr-12957.yml new file mode 100644 index 0000000000..84e733b162 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12957.yml @@ -0,0 +1,4 @@ +author: "kappa-sama" +delete-after: True +changes: + - balance: "miners can no longer acquire funny antag item" diff --git a/html/changelogs/AutoChangeLog-pr-13024.yml b/html/changelogs/AutoChangeLog-pr-13024.yml new file mode 100644 index 0000000000..1992b4dfeb --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13024.yml @@ -0,0 +1,4 @@ +author: "zeroisthebiggay" +delete-after: True +changes: + - rscdel: "waffleco" diff --git a/html/changelogs/AutoChangeLog-pr-13058.yml b/html/changelogs/AutoChangeLog-pr-13058.yml new file mode 100644 index 0000000000..d507879410 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13058.yml @@ -0,0 +1,4 @@ +author: "silicons" +delete-after: True +changes: + - bugfix: "brooms now sweep objects on MOVABLE_PRE_MOVE rather than MOVABLE_MOVED" diff --git a/html/changelogs/AutoChangeLog-pr-13125.yml b/html/changelogs/AutoChangeLog-pr-13125.yml new file mode 100644 index 0000000000..4fd3e478e9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13125.yml @@ -0,0 +1,4 @@ +author: "Chiirno" +delete-after: True +changes: + - bugfix: "Moves pill_bottles/dice to box/dice on CogStation." diff --git a/html/changelogs/AutoChangeLog-pr-13173.yml b/html/changelogs/AutoChangeLog-pr-13173.yml new file mode 100644 index 0000000000..5a41fdaa19 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13173.yml @@ -0,0 +1,4 @@ +author: "LetterN" +delete-after: True +changes: + - rscadd: "tgchat" diff --git a/html/changelogs/AutoChangeLog-pr-13184.yml b/html/changelogs/AutoChangeLog-pr-13184.yml new file mode 100644 index 0000000000..85660e2fcc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13184.yml @@ -0,0 +1,4 @@ +author: "timothyteakettle" +delete-after: True +changes: + - imagedel: "the drake credit and pickle credit sprites have been removed" diff --git a/html/changelogs/AutoChangeLog-pr-13192.yml b/html/changelogs/AutoChangeLog-pr-13192.yml new file mode 100644 index 0000000000..857d3ca1ea --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13192.yml @@ -0,0 +1,5 @@ +author: "Putnam3145" +delete-after: True +changes: + - 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" diff --git a/html/changelogs/AutoChangeLog-pr-13229.yml b/html/changelogs/AutoChangeLog-pr-13229.yml new file mode 100644 index 0000000000..1cc156e675 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13229.yml @@ -0,0 +1,5 @@ +author: "Sonic121x" +delete-after: True +changes: + - bugfix: "Fix the four type of new tea that will stuck inside your vein." + - rscadd: "drinking glass sprite for those tea." diff --git a/html/changelogs/AutoChangeLog-pr-13230.yml b/html/changelogs/AutoChangeLog-pr-13230.yml new file mode 100644 index 0000000000..36addf5717 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13230.yml @@ -0,0 +1,4 @@ +author: "Detective-Google" +delete-after: True +changes: + - rscadd: "object reskins now use very nice and cool radials" diff --git a/html/changelogs/AutoChangeLog-pr-13249.yml b/html/changelogs/AutoChangeLog-pr-13249.yml new file mode 100644 index 0000000000..f4d00c3832 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13249.yml @@ -0,0 +1,4 @@ +author: "silicons" +delete-after: True +changes: + - balance: "firedoors no longer automatically open on touch when there's no pressure differences." diff --git a/html/changelogs/AutoChangeLog-pr-13263.yml b/html/changelogs/AutoChangeLog-pr-13263.yml new file mode 100644 index 0000000000..460d06ae50 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13263.yml @@ -0,0 +1,6 @@ +author: "raspy-on-osu" +delete-after: True +changes: + - tweak: "tesla movement priorities" + - rscadd: "tesla counterplay" + - rscadd: "tesla containment check (containment variable now usable)" diff --git a/html/changelogs/AutoChangeLog-pr-13266.yml b/html/changelogs/AutoChangeLog-pr-13266.yml new file mode 100644 index 0000000000..4ecbd44647 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13266.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "e-gun overlays and some floor decals should have been fixed." diff --git a/html/changelogs/AutoChangeLog-pr-13267.yml b/html/changelogs/AutoChangeLog-pr-13267.yml new file mode 100644 index 0000000000..9017747c84 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13267.yml @@ -0,0 +1,4 @@ +author: "Arturlang" +delete-after: True +changes: + - tweak: "Slimes can now damage structures, don't leave them unfed!" diff --git a/html/changelogs/AutoChangeLog-pr-13268.yml b/html/changelogs/AutoChangeLog-pr-13268.yml new file mode 100644 index 0000000000..941ff7ac5a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13268.yml @@ -0,0 +1,4 @@ +author: "timothyteakettle" +delete-after: True +changes: + - refactor: "tongue speech handling is now done by accent datums" diff --git a/html/changelogs/AutoChangeLog-pr-13269.yml b/html/changelogs/AutoChangeLog-pr-13269.yml new file mode 100644 index 0000000000..152245e430 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13269.yml @@ -0,0 +1,6 @@ +author: "EmeraldSundisk" +delete-after: True +changes: + - rscadd: "Adds a pool to MetaStation" + - tweak: "Slight readjustments to the surrounding area" + - bugfix: "Fixes a handful of external airlocks" diff --git a/html/changelogs/AutoChangeLog-pr-13272.yml b/html/changelogs/AutoChangeLog-pr-13272.yml new file mode 100644 index 0000000000..9b0f64d7a0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13272.yml @@ -0,0 +1,4 @@ +author: "Detective-Google" +delete-after: True +changes: + - tweak: "plasmamen have no more slowdown" diff --git a/html/changelogs/AutoChangeLog-pr-13276.yml b/html/changelogs/AutoChangeLog-pr-13276.yml new file mode 100644 index 0000000000..48ad4ed26c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13276.yml @@ -0,0 +1,4 @@ +author: "timothyteakettle" +delete-after: True +changes: + - tweak: "buzz, buzz2 and ping are now all unrestricted emotes and can be used by anyone" diff --git a/html/changelogs/AutoChangeLog-pr-13277.yml b/html/changelogs/AutoChangeLog-pr-13277.yml new file mode 100644 index 0000000000..d6d0d89ed6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13277.yml @@ -0,0 +1,6 @@ +author: "Lynxless" +delete-after: True +changes: + - 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" diff --git a/html/changelogs/AutoChangeLog-pr-13280.yml b/html/changelogs/AutoChangeLog-pr-13280.yml new file mode 100644 index 0000000000..e69aefd961 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13280.yml @@ -0,0 +1,4 @@ +author: "raspy-on-osu" +delete-after: True +changes: + - tweak: "TEG power output" diff --git a/html/changelogs/AutoChangeLog-pr-13281.yml b/html/changelogs/AutoChangeLog-pr-13281.yml new file mode 100644 index 0000000000..b39f9b66e0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13281.yml @@ -0,0 +1,4 @@ +author: "Putnam3145" +delete-after: True +changes: + - tweak: "Pref for genital/vore examine text" diff --git a/html/changelogs/AutoChangeLog-pr-13290.yml b/html/changelogs/AutoChangeLog-pr-13290.yml new file mode 100644 index 0000000000..c2faacf790 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13290.yml @@ -0,0 +1,5 @@ +author: "ForrestWick" +delete-after: True +changes: + - balance: "removes wall walking boots from nukie uplink" + - tweak: "removes wall walking boots from nukie uplink" diff --git a/html/changelogs/AutoChangeLog-pr-13292.yml b/html/changelogs/AutoChangeLog-pr-13292.yml new file mode 100644 index 0000000000..cd239b63e1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13292.yml @@ -0,0 +1,4 @@ +author: "Putnam3145" +delete-after: True +changes: + - bugfix: "Dynamic storytellers now calculate property weights properly." diff --git a/html/changelogs/AutoChangeLog-pr-13293.yml b/html/changelogs/AutoChangeLog-pr-13293.yml new file mode 100644 index 0000000000..a03ccef29c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13293.yml @@ -0,0 +1,4 @@ +author: "lolman360" +delete-after: True +changes: + - bugfix: "shuttle engine/heater sprites now face the right way" diff --git a/html/changelogs/AutoChangeLog-pr-13294.yml b/html/changelogs/AutoChangeLog-pr-13294.yml new file mode 100644 index 0000000000..e594a7350a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13294.yml @@ -0,0 +1,4 @@ +author: "Putnam3145" +delete-after: True +changes: + - bugfix: "Fixed a couple events having ghost roles eligible." diff --git a/html/changelogs/AutoChangeLog-pr-13298.yml b/html/changelogs/AutoChangeLog-pr-13298.yml new file mode 100644 index 0000000000..d05c29838b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13298.yml @@ -0,0 +1,5 @@ +author: "DeltaFire15" +delete-after: True +changes: + - rscdel: "teleport-to-ark ability of the eminence, commented out" + - rscadd: "teleport-to-obelisk ability for the eminence" diff --git a/html/changelogs/AutoChangeLog-pr-13302.yml b/html/changelogs/AutoChangeLog-pr-13302.yml new file mode 100644 index 0000000000..5978601890 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-13302.yml @@ -0,0 +1,4 @@ +author: "Couls, ported by NecromancerAnne" +delete-after: True +changes: + - code_imp: "cleans up mech backstabbing code" 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/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/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 cf49f0f30f..d7e461eadd 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -1,320 +1,290 @@ -macro "default" - - -menu "menu" - elem - name = "&File" - command = "" - saved-params = "is-checked" - elem - name = "&Quick screenshot\tF2" - command = ".screenshot auto" - category = "&File" - saved-params = "is-checked" - elem - name = "&Save screenshot as...\tShift+F2" - command = ".screenshot" - category = "&File" - saved-params = "is-checked" - elem - name = "" - command = "" - category = "&File" - saved-params = "is-checked" - elem "reconnectbutton" - name = "&Reconnect" - command = ".reconnect" - category = "&File" - saved-params = "is-checked" - elem - name = "&Quit\tAlt-F4" - command = ".quit" - category = "&File" - saved-params = "is-checked" - elem - name = "&Help" - command = "" - saved-params = "is-checked" - elem - name = "&Admin Help\tF1" - command = "adminhelp" - category = "&Help" - saved-params = "is-checked" - elem - name = "&Hotkeys" - command = "hotkeys-help" - category = "&Help" - saved-params = "is-checked" - - -window "mainwindow" - elem "mainwindow" - type = MAIN - pos = 0,0 - 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' - macro = "default" - menu = "menu" - elem "split" - type = CHILD - pos = 0,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 = "" - elem "tooltip" - type = BROWSER - pos = 0,0 - size = 999x999 - anchor1 = none - anchor2 = none - background-color = #272727 - is-visible = false - saved-params = "" - -window "mapwindow" - elem "mapwindow" - type = MAIN - pos = 418,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 - size = 1024x1024 - anchor1 = 0,0 - anchor2 = 100,100 - font-family = "Arial" - font-size = 7 - 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; }" - -window "infowindow" - elem "infowindow" - type = MAIN - pos = 0,0 - size = 640x480 - anchor1 = none - anchor2 = none - background-color = #242424 - saved-params = "pos;size;is-minimized;is-maximized" - is-pane = true - elem "info" - type = CHILD - pos = 0,30 - size = 640x445 - anchor1 = 0,0 - anchor2 = 100,100 - background-color = #272727 - saved-params = "splitter" - left = "statwindow" - right = "outputwindow" - is-vert = false - elem "changelog" - type = BUTTON - pos = 16,5 - size = 104x20 - anchor1 = 3,0 - anchor2 = 19,0 - text-color = #e0e0e0 - background-color = #40628a - saved-params = "is-checked" - text = "Changelog" - command = "changelog" - elem "rules" - type = BUTTON - pos = 120,5 - size = 100x20 - anchor1 = 19,0 - anchor2 = 34,0 - text-color = #e0e0e0 - background-color = #40628a - saved-params = "is-checked" - text = "Rules" - command = "rules" - elem "wiki" - type = BUTTON - pos = 220,5 - size = 100x20 - anchor1 = 34,0 - anchor2 = 50,0 - text-color = #e0e0e0 - background-color = #40628a - saved-params = "is-checked" - text = "Wiki" - command = "wiki" - elem "forum" - type = BUTTON - pos = 320,5 - size = 100x20 - anchor1 = 50,0 - anchor2 = 66,0 - text-color = #e0e0e0 - background-color = #40628a - saved-params = "is-checked" - text = "Forum" - command = "forum" - elem "github" - type = BUTTON - pos = 420,5 - size = 100x20 - anchor1 = 66,0 - anchor2 = 81,0 - text-color = #e0e0e0 - background-color = #40628a - saved-params = "is-checked" - text = "GitHub" - command = "github" - elem "report-issue" - type = BUTTON - pos = 520,5 - 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" - -window "outputwindow" - elem "outputwindow" - type = MAIN - pos = 0,0 - 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 - pos = 2,460 - size = 595x20 - anchor1 = 0,100 - anchor2 = 100,100 - background-color = #d3b5b5 - is-default = true - border = sunken - saved-params = "command" - elem "say" - 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=\"" - is-flat = true - button-type = pushbox - elem "browseroutput" - type = BROWSER - pos = 0,0 - size = 640x456 - anchor1 = 0,0 - anchor2 = 100,100 - background-color = #272727 - is-visible = false - is-disabled = true - saved-params = "" - auto-format = false - elem "output" - type = OUTPUT - pos = 0,0 - size = 640x456 - anchor1 = 0,0 - anchor2 = 100,100 - text-color = #e0e0e0 - background-color = #272727 - is-default = true - saved-params = "" - -window "statwindow" - elem "statwindow" - type = MAIN - pos = 281,0 - size = 640x480 - anchor1 = none - anchor2 = none - background-color = #242424 - 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 - -window "preferences_window" - elem "preferences_window" - type = MAIN - pos = 372,0 - size = 1280x1000 - anchor1 = none - anchor2 = none - is-visible = false - saved-params = "pos;size;is-minimized;is-maximized" - statusbar = false - elem "preferences_browser" - type = BROWSER - pos = 0,0 - size = 960x1000 - anchor1 = 0,0 - anchor2 = 75,100 - saved-params = "" - elem "character_preview_map" - type = MAP - pos = 960,0 - size = 320x1000 - anchor1 = 75,0 - anchor2 = 100,100 - right-click = true - saved-params = "zoom;letterbox;zoom-mode" - +macro "default" + + +menu "menu" + elem + name = "&File" + command = "" + saved-params = "is-checked" + elem + name = "&Quick screenshot\tF2" + command = ".screenshot auto" + category = "&File" + saved-params = "is-checked" + elem + name = "&Save screenshot as...\tShift+F2" + command = ".screenshot" + category = "&File" + saved-params = "is-checked" + elem + name = "" + command = "" + category = "&File" + saved-params = "is-checked" + elem "reconnectbutton" + name = "&Reconnect" + command = ".reconnect" + category = "&File" + saved-params = "is-checked" + elem + name = "&Quit\tAlt-F4" + command = ".quit" + category = "&File" + saved-params = "is-checked" + elem + name = "&Help" + command = "" + saved-params = "is-checked" + elem + name = "&Admin Help\tF1" + command = "adminhelp" + category = "&Help" + saved-params = "is-checked" + elem + name = "&Hotkeys" + command = "hotkeys-help" + category = "&Help" + saved-params = "is-checked" + +window "mainwindow" + elem "mainwindow" + type = MAIN + pos = 0,0 + size = 640x440 + anchor1 = none + anchor2 = none + is-default = true + saved-params = "pos;size;is-minimized;is-maximized" + icon = 'icons\\ss13_64.png' + macro = "default" + menu = "menu" + elem "split" + type = CHILD + pos = 3,0 + size = 637x440 + anchor1 = 0,0 + anchor2 = 100,100 + saved-params = "splitter" + left = "mapwindow" + right = "infowindow" + is-vert = true + elem "asset_cache_browser" + type = BROWSER + pos = 0,0 + size = 200x200 + anchor1 = none + anchor2 = none + is-visible = false + auto-format = false + saved-params = "" + elem "tooltip" + type = BROWSER + pos = 0,0 + size = 999x999 + anchor1 = none + anchor2 = none + is-visible = false + saved-params = "" + +window "mapwindow" + elem "mapwindow" + type = MAIN + pos = 0,0 + size = 1024x1024 + anchor1 = none + anchor2 = none + saved-params = "pos;size;is-minimized;is-maximized" + is-pane = true + elem "map" + type = MAP + pos = 0,0 + size = 1024x1024 + anchor1 = 0,0 + anchor2 = 100,100 + font-family = "Arial" + font-size = 7 + text-color = none + is-default = true + 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" + type = MAIN + pos = 0,0 + size = 640x480 + anchor1 = none + anchor2 = none + saved-params = "pos;size;is-minimized;is-maximized" + is-pane = true + elem "info" + type = CHILD + pos = 0,30 + size = 640x445 + anchor1 = 0,0 + anchor2 = 100,100 + saved-params = "splitter" + left = "statwindow" + right = "outputwindow" + is-vert = false + elem "changelog" + type = BUTTON + pos = 16,5 + size = 104x20 + anchor1 = 3,0 + anchor2 = 19,0 + saved-params = "is-checked" + text = "Changelog" + command = "changelog" + elem "rules" + type = BUTTON + pos = 120,5 + size = 100x20 + anchor1 = 19,0 + anchor2 = 34,0 + saved-params = "is-checked" + text = "Rules" + command = "rules" + elem "wiki" + type = BUTTON + pos = 220,5 + size = 100x20 + anchor1 = 34,0 + anchor2 = 50,0 + saved-params = "is-checked" + text = "Wiki" + command = "wiki" + elem "forum" + type = BUTTON + pos = 320,5 + size = 100x20 + anchor1 = 50,0 + anchor2 = 66,0 + saved-params = "is-checked" + text = "Forum" + command = "forum" + elem "github" + type = BUTTON + pos = 420,5 + size = 100x20 + anchor1 = 66,0 + anchor2 = 81,0 + saved-params = "is-checked" + text = "Github" + command = "github" + elem "report-issue" + type = BUTTON + pos = 520,5 + size = 100x20 + anchor1 = 81,0 + anchor2 = 97,0 + saved-params = "is-checked" + text = "Report Issue" + command = "report-issue" + +window "outputwindow" + elem "outputwindow" + type = MAIN + pos = 0,0 + size = 640x480 + anchor1 = none + anchor2 = none + saved-params = "pos;size;is-minimized;is-maximized" + is-pane = true + elem "input" + type = INPUT + pos = 2,460 + size = 595x20 + anchor1 = 0,100 + anchor2 = 100,100 + background-color = #d3b5b5 + is-default = true + border = sunken + saved-params = "command" + elem "saybutton" + type = BUTTON + pos = 600,460 + size = 37x20 + anchor1 = 100,100 + anchor2 = none + saved-params = "is-checked" + text = "Chat" + command = ".winset \"saybutton.is-checked=true ? input.command=\"!say \\\"\" : input.command=\"" + is-flat = true + button-type = pushbox + elem "browseroutput" + type = BROWSER + pos = 0,0 + size = 640x456 + anchor1 = 0,0 + anchor2 = 100,100 + background-color = #ffffff + is-visible = false + is-disabled = true + saved-params = "" + auto-format = false + elem "output" + type = OUTPUT + pos = 0,0 + size = 640x456 + anchor1 = 0,0 + anchor2 = 100,100 + is-default = true + saved-params = "" + +window "popupwindow" + elem "popupwindow" + type = MAIN + pos = 281,0 + size = 120x120 + anchor1 = none + anchor2 = none + background-color = none + is-visible = false + saved-params = "pos;size;is-minimized;is-maximized" + statusbar = false + can-resize = false + +window "preferences_window" + elem "preferences_window" + type = MAIN + pos = 281,0 + size = 1280x1000 + anchor1 = none + anchor2 = none + is-visible = false + saved-params = "pos;size;is-minimized;is-maximized" + statusbar = false + elem "preferences_browser" + type = BROWSER + pos = 0,0 + size = 960x1000 + anchor1 = 0,0 + anchor2 = 75,100 + saved-params = "" + elem "character_preview_map" + type = MAP + pos = 960,0 + size = 320x1000 + anchor1 = 75,0 + anchor2 = 100,100 + 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/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/tgstation.dme b/tgstation.dme index de6ee1a6bf..e742498527 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -285,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" @@ -328,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" @@ -364,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" @@ -436,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" @@ -443,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" @@ -1096,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" @@ -1707,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" @@ -1858,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" @@ -2106,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" @@ -2777,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" @@ -2803,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" @@ -2847,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" @@ -2860,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" @@ -3425,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" @@ -3437,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} + + ))} + + + +