diff --git a/.dockerignore b/.dockerignore index 4b33ec5099..2e6259d23d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -17,7 +17,7 @@ TGS3.json cfg data SQL -tgui/node_modules +node_modules tgstation.dmb tgstation.int tgstation.rsc diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e14c5d1624..817626d228 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -257,6 +257,12 @@ This prevents nesting levels from getting deeper then they need to be. * Please attempt to clean out any dirty variables that may be contained within items you alter through var-editing. For example, due to how DM functions, changing the `pixel_x` variable from 23 to 0 will leave a dirty record in the map's code of `pixel_x = 0`. Likewise this can happen when changing an item's icon to something else and then back. This can lead to some issues where an item's icon has changed within the code, but becomes broken on the map due to it still attempting to use the old entry. * Areas should not be var-edited on a map to change it's name or attributes. All areas of a single type and it's altered instances are considered the same area within the code, and editing their variables on a map can lead to issues with powernets and event subsystems which are difficult to debug. +### User Interfaces +* All new player-facing user interfaces must use TGUI. +* Raw HTML is permitted for admin and debug UIs. +* Documentation for TGUI can be found at: + * [tgui/README.md](../tgui/README.md) + * [tgui/tutorial-and-examples.md](../tgui/docs/tutorial-and-examples.md) ### Other Notes * Code should be modular where possible; if you are working on a new addition, then strongly consider putting it in its own file unless it makes sense to put it with similar ones (i.e. a new tool would go in the "tools.dm" file) @@ -337,7 +343,7 @@ for(var/obj/item/sword/S in bag_of_swords) if(!best_sword || S.damage > best_sword.damage) best_sword = S ``` -specifies a type for DM to filter by. +specifies a type for DM to filter by. With the previous example that's perfectly fine, we only want swords, but here the bag only contains swords? Is DM still going to try to filter because we gave it a type to filter by? YES, and here comes the inefficiency. Wherever a list (or other container, such as an atom (in which case you're technically accessing their special contents list, but that's irrelevant)) contains datums of the same datatype or subtypes of the datatype you require for your loop's body, you can circumvent DM's filtering and automatic ```istype()``` checks by writing the loop as such: @@ -374,7 +380,7 @@ mob ``` This does NOT mean that you can access it everywhere like a global var. Instead, it means that that var will only exist once for all instances of its type, in this case that var will only exist once for all mobs - it's shared across everything in its type. (Much more like the keyword `static` in other languages like PHP/C++/C#/Java) -Isn't that confusing? +Isn't that confusing? There is also an undocumented keyword called `static` that has the same behaviour as global but more correctly describes BYOND's behaviour. Therefore, we always use static instead of global where we need it, as it reduces suprise when reading BYOND code. @@ -394,6 +400,10 @@ There is no strict process when it comes to merging pull requests. Pull requests * Please explain why you are submitting the pull request, and how you think your change will be beneficial to the game. Failure to do so will be grounds for rejecting the PR. +* If your pull request is not finished make sure it is at least testable in a live environment. Pull requests that do not at least meet this requirement will be closed. You may request a maintainer reopen the pull request when you're ready, or make a new one. + +* While we have no issue helping contributors (and especially new contributors) bring reasonably sized contributions up to standards via the pull request review process, larger contributions are expected to pass a higher bar of completeness and code quality *before* you open a pull request. Maintainers may close such pull requests that are deemed to be substantially flawed. You should take some time to discuss with maintainers or other contributors on how to improve the changes. + ## Porting features/sprites/sounds/tools from other codebases If you are porting features/tools from other codebases, you must give them credit where it's due. Typically, crediting them in your pull request and the changelog is the recommended way of doing it. Take note of what license they use though, porting stuff from AGPLv3 and GPLv3 codebases are allowed. diff --git a/.github/workflows/autobuild_tgui.yml b/.github/workflows/autobuild_tgui.yml index b680139f74..226ea2b7ce 100644 --- a/.github/workflows/autobuild_tgui.yml +++ b/.github/workflows/autobuild_tgui.yml @@ -5,8 +5,8 @@ on: branches: - 'master' paths: - - 'tgui-next/**.js' - - 'tgui-next/**.scss' + - 'tgui/**.js' + - 'tgui/**.scss' jobs: build: @@ -23,7 +23,7 @@ jobs: node-version: '>=12.13' - name: Build TGUI run: bin/tgui --ci - working-directory: ./tgui-next + working-directory: ./tgui - name: Commit Artifacts run: | git config --local user.email "action@github.com" diff --git a/.travis.yml b/.travis.yml index 3082e1a18e..2214df3aee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ matrix: - tools/travis/check_filedirs.sh tgstation.dme - tools/travis/check_changelogs.sh - find . -name "*.php" -print0 | xargs -0 -n1 php -l - - find . -name "*.json" -not -path "./tgui/node_modules/*" -print0 | xargs -0 python3 ./tools/json_verifier.py + - find . -name "*.json" -not -path "*/node_modules/*" -print0 | xargs -0 python3 ./tools/json_verifier.py - tools/travis/build_tgui.sh - tools/travis/check_grep.sh - python3 tools/travis/check_line_endings.py diff --git a/_maps/RandomRuins/SpaceRuins/spacediner.dmm b/_maps/RandomRuins/SpaceRuins/spacediner.dmm index 21670da9e4..16a6850130 100644 --- a/_maps/RandomRuins/SpaceRuins/spacediner.dmm +++ b/_maps/RandomRuins/SpaceRuins/spacediner.dmm @@ -932,7 +932,6 @@ /obj/machinery/airalarm/all_access{ dir = 1; icon_state = "alarm0"; - pixel_x = 0; pixel_y = -24 }, /turf/open/floor/plasteel/dark, diff --git a/_maps/RandomZLevels/away_mission/Academy.dmm b/_maps/RandomZLevels/away_mission/Academy.dmm index 832e4f23fa..37b0098fd2 100644 --- a/_maps/RandomZLevels/away_mission/Academy.dmm +++ b/_maps/RandomZLevels/away_mission/Academy.dmm @@ -3594,36 +3594,12 @@ }, /turf/open/floor/carpet, /area/awaymission/academy/academygate) -"km" = ( -/obj/machinery/gateway{ - dir = 9 - }, -/obj/structure/cable{ - icon_state = "1-4" - }, -/turf/open/floor/plating, -/area/awaymission/academy/academygate) "kn" = ( -/obj/machinery/gateway{ - dir = 1 - }, /obj/structure/cable{ icon_state = "2-8" }, /turf/open/floor/plating, /area/awaymission/academy/academygate) -"ko" = ( -/obj/machinery/gateway{ - dir = 5 - }, -/turf/open/floor/plating, -/area/awaymission/academy/academygate) -"kp" = ( -/obj/machinery/gateway{ - dir = 8 - }, -/turf/open/floor/plating, -/area/awaymission/academy/academygate) "kq" = ( /mob/living/simple_animal/hostile/wizard, /obj/effect/turf_decal/tile/yellow{ @@ -3634,28 +3610,6 @@ }, /turf/open/floor/plasteel, /area/awaymission/academy/classrooms) -"kr" = ( -/obj/machinery/gateway{ - dir = 4 - }, -/turf/open/floor/plating, -/area/awaymission/academy/academygate) -"ks" = ( -/obj/machinery/gateway{ - dir = 10 - }, -/turf/open/floor/plating, -/area/awaymission/academy/academygate) -"kt" = ( -/obj/machinery/gateway, -/turf/open/floor/plating, -/area/awaymission/academy/academygate) -"ku" = ( -/obj/machinery/gateway{ - dir = 6 - }, -/turf/open/floor/plating, -/area/awaymission/academy/academygate) "kv" = ( /obj/machinery/light, /turf/open/floor/carpet, @@ -3737,7 +3691,7 @@ /area/awaymission/academy/academyaft) "kI" = ( /obj/structure/cable, -/obj/machinery/gateway/centeraway, +/obj/machinery/gateway/away, /turf/open/floor/plating, /area/awaymission/academy/academygate) "kJ" = ( @@ -13173,10 +13127,10 @@ jZ kb ke kj -km -kp -ks -Ao +kk +kf +kf +kf kf ky kf @@ -13305,8 +13259,8 @@ jW Ao kn kI -kt -Ao +kf +kf kf ky mF @@ -13432,11 +13386,11 @@ jV jY kc jW -Ao -ko -kr -ku -Ao +kf +kf +kf +kf +kf kf ky kf diff --git a/_maps/RandomZLevels/away_mission/SnowCabin.dmm b/_maps/RandomZLevels/away_mission/SnowCabin.dmm index cd6cefc8ad..249cb68b5d 100644 --- a/_maps/RandomZLevels/away_mission/SnowCabin.dmm +++ b/_maps/RandomZLevels/away_mission/SnowCabin.dmm @@ -633,24 +633,6 @@ /obj/machinery/processor, /turf/open/floor/plasteel/freezer, /area/awaymission/cabin) -"cb" = ( -/obj/machinery/gateway{ - dir = 9 - }, -/turf/open/floor/wood, -/area/awaymission/cabin) -"cc" = ( -/obj/machinery/gateway{ - dir = 1 - }, -/turf/open/floor/wood, -/area/awaymission/cabin) -"cd" = ( -/obj/machinery/gateway{ - dir = 5 - }, -/turf/open/floor/wood, -/area/awaymission/cabin) "ce" = ( /obj/structure/chair/wood{ dir = 4 @@ -733,20 +715,8 @@ "cn" = ( /turf/open/lava, /area/awaymission/cabin/caves/mountain) -"co" = ( -/obj/machinery/gateway{ - dir = 8 - }, -/turf/open/floor/wood, -/area/awaymission/cabin) "cp" = ( -/obj/machinery/gateway/centeraway, -/turf/open/floor/wood, -/area/awaymission/cabin) -"cq" = ( -/obj/machinery/gateway{ - dir = 4 - }, +/obj/machinery/gateway/away, /turf/open/floor/wood, /area/awaymission/cabin) "cr" = ( @@ -787,23 +757,6 @@ }, /turf/open/floor/plasteel/white, /area/awaymission/cabin) -"cw" = ( -/obj/machinery/gateway{ - dir = 10 - }, -/turf/open/floor/wood, -/area/awaymission/cabin) -"cx" = ( -/obj/machinery/gateway, -/obj/effect/mapping_helpers/network_builder/power_cable/yellow/auto, -/turf/open/floor/wood, -/area/awaymission/cabin) -"cy" = ( -/obj/machinery/gateway{ - dir = 6 - }, -/turf/open/floor/wood, -/area/awaymission/cabin) "cz" = ( /obj/machinery/light{ dir = 1 @@ -35769,9 +35722,9 @@ an bk bJ an -cb -co -cw +aq +aq +aq aq cH cQ @@ -36026,9 +35979,9 @@ an nU an an -cc +aq cp -cx +eg eg eg cQ @@ -36283,9 +36236,9 @@ an jf ay an -cd -cq -cy +aq +aq +aq aq cH hH diff --git a/_maps/RandomZLevels/away_mission/TheBeach.dmm b/_maps/RandomZLevels/away_mission/TheBeach.dmm index 68eb5c164f..6877eb4b35 100644 --- a/_maps/RandomZLevels/away_mission/TheBeach.dmm +++ b/_maps/RandomZLevels/away_mission/TheBeach.dmm @@ -224,63 +224,13 @@ /mob/living/simple_animal/crab, /turf/open/floor/plating/beach/sand, /area/awaymission/beach) -"aL" = ( -/obj/machinery/gateway{ - dir = 9 - }, -/obj/effect/turf_decal/sand, -/obj/effect/turf_decal/stripes/asteroid/line{ - dir = 9 - }, -/turf/open/floor/plating/beach/sand, -/area/awaymission/beach) -"aM" = ( -/obj/machinery/gateway{ - dir = 1 - }, -/obj/effect/turf_decal/sand, -/obj/effect/turf_decal/stripes/asteroid/line{ - dir = 1 - }, -/turf/open/floor/plating/beach/sand, -/area/awaymission/beach) -"aN" = ( -/obj/machinery/gateway{ - dir = 5 - }, -/obj/effect/turf_decal/sand, -/obj/effect/turf_decal/stripes/asteroid/line{ - dir = 5 - }, -/turf/open/floor/plating/beach/sand, -/area/awaymission/beach) "aO" = ( /obj/effect/baseturf_helper/beach/sand, /turf/open/floor/plating/beach/sand, /area/awaymission/beach) -"aP" = ( -/obj/machinery/gateway{ - dir = 8 - }, -/obj/effect/turf_decal/sand, -/obj/effect/turf_decal/stripes/asteroid/line{ - dir = 8 - }, -/turf/open/floor/plating/beach/sand, -/area/awaymission/beach) "aQ" = ( -/obj/machinery/gateway/centeraway, /obj/effect/turf_decal/sand, -/turf/open/floor/plating/beach/sand, -/area/awaymission/beach) -"aR" = ( -/obj/machinery/gateway{ - dir = 4 - }, -/obj/effect/turf_decal/sand, -/obj/effect/turf_decal/stripes/asteroid/line{ - dir = 4 - }, +/obj/machinery/gateway/away, /turf/open/floor/plating/beach/sand, /area/awaymission/beach) "aS" = ( @@ -295,32 +245,6 @@ dir = 8 }, /area/awaymission/beach) -"aU" = ( -/obj/machinery/gateway{ - dir = 10 - }, -/obj/effect/turf_decal/sand, -/obj/effect/turf_decal/stripes/asteroid/line{ - dir = 10 - }, -/turf/open/floor/plating/beach/sand, -/area/awaymission/beach) -"aV" = ( -/obj/machinery/gateway, -/obj/effect/turf_decal/sand, -/obj/effect/turf_decal/stripes/asteroid/line, -/turf/open/floor/plating/beach/sand, -/area/awaymission/beach) -"aW" = ( -/obj/machinery/gateway{ - dir = 6 - }, -/obj/effect/turf_decal/sand, -/obj/effect/turf_decal/stripes/asteroid/line{ - dir = 6 - }, -/turf/open/floor/plating/beach/sand, -/area/awaymission/beach) "aX" = ( /turf/closed/wall/mineral/sandstone, /area/awaymission/beach) @@ -6896,9 +6820,9 @@ ak ak ak ak -aL -aP -aU +bf +bp +bx ak ak ba @@ -7003,9 +6927,9 @@ ak ak ak ak -aM +bg aQ -aV +by ba ba ba @@ -7110,9 +7034,9 @@ ak ak ak ak -aN -aR -aW +bh +br +bz ak ak ak diff --git a/_maps/RandomZLevels/away_mission/caves.dmm b/_maps/RandomZLevels/away_mission/caves.dmm index 159559d0af..33aca48f29 100644 --- a/_maps/RandomZLevels/away_mission/caves.dmm +++ b/_maps/RandomZLevels/away_mission/caves.dmm @@ -71,11 +71,6 @@ initial_gas_mix = "n2=23;o2=14" }, /area/awaymission/caves/BMP_asteroid/level_four) -"ao" = ( -/turf/open/floor/engine/cult{ - initial_gas_mix = "n2=23;o2=14" - }, -/area/awaymission/caves/BMP_asteroid/level_four) "ap" = ( /obj/structure/destructible/cult/pylon, /turf/open/floor/engine/cult{ @@ -394,50 +389,8 @@ initial_gas_mix = "n2=23;o2=14" }, /area/awaymission/caves/BMP_asteroid/level_three) -"bi" = ( -/obj/machinery/gateway{ - dir = 9 - }, -/turf/open/floor/engine/cult{ - initial_gas_mix = "n2=23;o2=14" - }, -/area/awaymission/caves/BMP_asteroid/level_four) -"bj" = ( -/obj/machinery/gateway{ - dir = 1 - }, -/turf/open/floor/engine/cult{ - initial_gas_mix = "n2=23;o2=14" - }, -/area/awaymission/caves/BMP_asteroid/level_four) -"bk" = ( -/obj/machinery/gateway{ - dir = 5 - }, -/turf/open/floor/engine/cult{ - initial_gas_mix = "n2=23;o2=14" - }, -/area/awaymission/caves/BMP_asteroid/level_four) -"bl" = ( -/obj/machinery/gateway{ - dir = 8 - }, -/turf/open/floor/engine/cult{ - initial_gas_mix = "n2=23;o2=14" - }, -/area/awaymission/caves/BMP_asteroid/level_four) "bm" = ( -/obj/machinery/gateway/centeraway{ - calibrated = 0 - }, -/turf/open/floor/engine/cult{ - initial_gas_mix = "n2=23;o2=14" - }, -/area/awaymission/caves/BMP_asteroid/level_four) -"bn" = ( -/obj/machinery/gateway{ - dir = 4 - }, +/obj/machinery/gateway/away, /turf/open/floor/engine/cult{ initial_gas_mix = "n2=23;o2=14" }, @@ -448,24 +401,7 @@ initial_gas_mix = "n2=23;o2=14" }, /area/awaymission/caves/BMP_asteroid/level_four) -"bp" = ( -/obj/machinery/gateway{ - dir = 10 - }, -/turf/open/floor/engine/cult{ - initial_gas_mix = "n2=23;o2=14" - }, -/area/awaymission/caves/BMP_asteroid/level_four) -"bq" = ( -/obj/machinery/gateway, -/turf/open/floor/engine/cult{ - initial_gas_mix = "n2=23;o2=14" - }, -/area/awaymission/caves/BMP_asteroid/level_four) "br" = ( -/obj/machinery/gateway{ - dir = 6 - }, /turf/open/floor/engine/cult{ initial_gas_mix = "n2=23;o2=14" }, @@ -1390,12 +1326,6 @@ /mob/living/simple_animal/hostile/mining_drone, /turf/open/floor/plating, /area/awaymission/caves/listeningpost) -"el" = ( -/obj/machinery/gateway{ - dir = 9 - }, -/turf/open/floor/plasteel, -/area/awaymission/caves/listeningpost) "em" = ( /obj/structure/closet/secure_closet/personal, /turf/open/floor/wood{ @@ -1492,12 +1422,6 @@ /obj/item/stack/sheet/mineral/plasma, /turf/open/floor/plasteel, /area/awaymission/caves/listeningpost) -"eB" = ( -/obj/machinery/gateway{ - dir = 1 - }, -/turf/open/floor/plasteel, -/area/awaymission/caves/listeningpost) "eC" = ( /obj/structure/table, /obj/item/gps/mining, @@ -1513,12 +1437,6 @@ /obj/item/extinguisher/mini, /turf/open/floor/plasteel, /area/awaymission/caves/listeningpost) -"eE" = ( -/obj/machinery/gateway{ - dir = 5 - }, -/turf/open/floor/plasteel, -/area/awaymission/caves/listeningpost) "eF" = ( /turf/closed/wall, /area/awaymission/caves/listeningpost) @@ -1704,15 +1622,6 @@ initial_gas_mix = "n2=23;o2=14" }, /area/awaymission/caves/BMP_asteroid/level_two) -"fk" = ( -/obj/machinery/gateway{ - dir = 8 - }, -/obj/machinery/light{ - dir = 8 - }, -/turf/open/floor/plasteel, -/area/awaymission/caves/listeningpost) "fl" = ( /obj/effect/decal/remains/human, /turf/open/floor/plating/asteroid/basalt{ @@ -1792,12 +1701,10 @@ }, /area/awaymission/caves/BMP_asteroid/level_two) "fw" = ( -/obj/machinery/gateway/centeraway{ - calibrated = 0 - }, /obj/structure/cable{ icon_state = "0-2" }, +/obj/machinery/gateway/away, /turf/open/floor/plasteel, /area/awaymission/caves/listeningpost) "fx" = ( @@ -2038,9 +1945,6 @@ /turf/open/floor/plasteel, /area/awaymission/caves/BMP_asteroid) "gk" = ( -/obj/machinery/gateway{ - dir = 4 - }, /obj/machinery/light{ dir = 4 }, @@ -2281,12 +2185,6 @@ /obj/effect/baseturf_helper/asteroid/basalt, /turf/closed/wall, /area/awaymission/caves/northblock) -"tk" = ( -/obj/machinery/gateway{ - dir = 6 - }, -/turf/open/floor/plasteel, -/area/awaymission/caves/listeningpost) "CY" = ( /obj/structure/cable{ icon_state = "1-2" @@ -2301,7 +2199,6 @@ /turf/open/floor/plasteel, /area/awaymission/caves/listeningpost) "Hp" = ( -/obj/machinery/gateway, /obj/structure/cable{ icon_state = "0-2" }, @@ -2310,12 +2207,6 @@ }, /turf/open/floor/plasteel, /area/awaymission/caves/listeningpost) -"If" = ( -/obj/machinery/gateway{ - dir = 10 - }, -/turf/open/floor/plasteel, -/area/awaymission/caves/listeningpost) (1,1,1) = {" aa @@ -10730,9 +10621,9 @@ bL bM bM eF -el -fk -If +eJ +eq +eJ eJ eF ey @@ -10987,7 +10878,7 @@ bL bL bM eG -eB +eJ fw Hp CY @@ -11244,9 +11135,9 @@ bL bL bM eG -eE +eJ gk -tk +eJ eJ eG eA @@ -53527,11 +53418,11 @@ ai ai ai ai -ao +br ai ai -ao -ao +br +br ai ai ai @@ -53780,19 +53671,19 @@ ad ad ad ai -ao -ao +br +br ai ai am ai ai -ao -ao -ao +br +br +br aw -ao -ao +br +br ai ai ad @@ -54035,7 +53926,7 @@ ad ad ai ai -ao +br ai ai ai @@ -54048,8 +53939,8 @@ ai ai ai ai -ao -ao +br +br ai ai ad @@ -54289,9 +54180,9 @@ ad ad ad ai -ao -ao -ao +br +br +br ai ax ad @@ -54306,7 +54197,7 @@ ai ad ad ai -ao +br ai ai ad @@ -54545,7 +54436,7 @@ ad ad ai ai -ao +br am ai ad @@ -54802,7 +54693,7 @@ ai ai ai ai -ao +br ai ai ad @@ -54817,9 +54708,9 @@ ad ad ad ax -ao +br ai -ao +br ai ai ai @@ -55016,10 +54907,10 @@ ad ad al am -ao -ao +br +br ap -ao +br am ai al @@ -55055,7 +54946,7 @@ aV aV ax aA -ao +br ax ax ai @@ -55073,7 +54964,7 @@ ad ad ad ad -ao +br ai ai ai @@ -55273,11 +55164,11 @@ ad ad al am -ao +br ar as ar -ao +br am al ad @@ -55290,29 +55181,29 @@ ad ad ad ad -ao +br ad ad ad -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao +br +br +br +br +br +br +br +br +br +br +br +br +br ad ad ad -ao -ao -ao +br +br +br aB ax ai @@ -55330,7 +55221,7 @@ ad ad ad ax -ao +br ai ai ai @@ -55545,32 +55436,32 @@ ad ad ad ad -ao +br ad -ao +br ad ad ad ad ad -ao -ao -ao +br +br +br ap ad ad ad -ao -ao +br +br ap -ao +br ad ad -ao -ao -ao +br +br +br ap -ao +br ax ai ai @@ -55586,8 +55477,8 @@ ad ad ad ad -ao -ao +br +br ai ai ai @@ -55787,11 +55678,11 @@ ad ad al am -ao +br ar as ar -ao +br am al ad @@ -55802,31 +55693,31 @@ ad ad ad ad -ao +br ad ad -ao +br ad ad ad ad -ao -ao +br +br ad ad -ao -ao +br +br ad ad -ao -ao -ao +br +br +br ad ad -ao -ao -ao -ao +br +br +br +br aR ax ai @@ -55843,7 +55734,7 @@ ad ad ad ad -ao +br ai am at @@ -56044,10 +55935,10 @@ ad ad al am -ao -ao +br +br ap -ao +br am ai al @@ -56059,8 +55950,8 @@ ad ad ad ad -ao -ao +br +br ad ad ad @@ -56083,8 +55974,8 @@ aV aV ax aR -ao -ao +br +br ax ai ai @@ -56100,7 +55991,7 @@ ad ad ad ax -ao +br ai ai ai @@ -56302,8 +56193,8 @@ ad ai al am -ao -ao +br +br am ai al @@ -56316,9 +56207,9 @@ ad ad ad ad -ao -ao -ao +br +br +br ad ad ad @@ -56339,9 +56230,9 @@ ai ad ad ax -ao -ao -ao +br +br +br ax ai ai @@ -56357,8 +56248,8 @@ ad ad ad ax -ao -ao +br +br ai ai ai @@ -56560,7 +56451,7 @@ ad ai al al -ao +br al al ai @@ -56573,9 +56464,9 @@ ax ax ax ax -ao -ao -ao +br +br +br ad ad ai @@ -56596,9 +56487,9 @@ ax ad ai ax -ao -ao -ao +br +br +br ax ai ai @@ -56615,12 +56506,12 @@ ad ad ad ax -ao +br am ai ai ad -ao +br ai ai ai @@ -56817,7 +56708,7 @@ ad ai aq ai -ao +br ai ai ad @@ -56827,12 +56718,12 @@ ad ad ax ay -ao +br aD ax -ao -ao -ao +br +br +br ad ad ai @@ -56846,16 +56737,16 @@ aR ax ai ax -ao -ao -ao +br +br +br ax ad ai ax -ao +br av -ao +br ax ai ai @@ -56873,15 +56764,15 @@ ad ad ad aR -ao -ao -ao -ao +br +br +br +br ai -ao -ao -ao -ao +br +br +br +br ai ad ad @@ -57084,12 +56975,12 @@ ad ad ax az -ao -ao +br +br ax -ao -ao -ao +br +br +br ai ai ai @@ -57097,22 +56988,22 @@ ai ai ai ax -ao -ao -ao +br +br +br ax ai ax -ao -ao -ao +br +br +br ad ad ai ax -ao -ao -ao +br +br +br ax ai ai @@ -57132,14 +57023,14 @@ ad ad ax ax -ao +br ax ad ad ai ai ai -ao +br ai ad ad @@ -57340,13 +57231,13 @@ ad ad ad ax -ao -ao +br +br av aF -ao -ao -ao +br +br +br ai ai ai @@ -57354,22 +57245,22 @@ aq ai ai ax -ao -ao -ao +br +br +br ax ai ax -ao -ao +br +br aR ax ai ai ax -ao -ao -ao +br +br +br ax ai ai @@ -57380,10 +57271,10 @@ ad ai ai ax -ao -ao -ao -ao +br +br +br +br aR aR ad @@ -57397,8 +57288,8 @@ ad ad ai ai -ao -ao +br +br ad ad ad @@ -57588,7 +57479,7 @@ ad an ai ai -ao +br ai ai ai @@ -57597,13 +57488,13 @@ ad ad ad ax -ao +br av -ao +br ax -ao -ao -ao +br +br +br ai ai ai @@ -57611,22 +57502,22 @@ ai ai ai ax -ao -ao +br +br aG ax ai ax -ao -ao -ao +br +br +br ax ai ai ax -ao +br aG -ao +br ax ai ai @@ -57636,13 +57527,13 @@ ad ad ai aR -ao -ao +br +br bf -ao -ao -ao -ao +br +br +br +br aR ad ad @@ -57655,7 +57546,7 @@ ad ad ad ax -ao +br ad ad ad @@ -57845,8 +57736,8 @@ ad ai ai ai -ao -ao +br +br ai ai ai @@ -57858,9 +57749,9 @@ aA ax ax ax -ao -ao -ao +br +br +br ai ai ai @@ -57868,21 +57759,21 @@ ax ax ax ax -ao +br ax -ao +br ax ax ax -ao +br ap -ao +br ax ax ax ax -ao -ao +br +br aR ax ax @@ -57892,15 +57783,15 @@ ad ax ax aR -ao -ao +br +br bf ap bf -ao -ao -ao -ao +br +br +br +br ax ai ad @@ -57911,7 +57802,7 @@ ad ad ad aR -ao +br ai ad ad @@ -58102,62 +57993,62 @@ ad ad ai ai -ao -ao -ao +br +br +br ai ai ai ai ai -ao -ao -ao -ao -ao -ao -ao -ao +br +br +br +br +br +br +br +br ai ai ai ax -ao -ao +br +br ax -ao -ao +br +br av ad ad ad ad -ao -ao -ao -ao -ao +br +br +br +br +br ad ad -ao -ao -ao +br +br +br al ad ad al -ao -ao -ao -ao +br +br +br +br bf -bi -bl -bp +br +br +br aw -ao +br bz -ao +br aR am ai @@ -58168,7 +58059,7 @@ ad ad ad ax -ao +br ai ai ad @@ -58361,20 +58252,20 @@ ai ai ai ai -ao -ao +br +br ai -ao -ao -ao -ao +br +br +br +br aB av -ao -ao -ao +br +br +br ap -ao +br ai ai ai @@ -58382,35 +58273,35 @@ ax aP aw aF -ao +br ap -ao +br ad ad -ao -ao -ao -ao -ao -ao -ao -ao -ao +br +br +br +br +br +br +br +br +br ap -ao +br al ad ad ad ad al -ao -ao +br +br bf ap -bj +br bm -bq +br bf bw bA @@ -58424,8 +58315,8 @@ ad ad ad ax -ao -ao +br +br am ai ai @@ -58619,59 +58510,59 @@ ad ai ai ai -ao -ao -ao +br +br +br ai ai -ao -ao -ao -ao -ao -ao +br +br +br +br +br +br aG -ao +br ai ai ai ax -ao -ao +br +br ax -ao -ao -ao -ao -ao -ao -ao +br +br +br +br +br +br +br av ad ad ad -ao -ao -ao -ao -ao -ao -al -ad -ad -al -ao -ao -ao -ao -bf -bk -bn br -ao -ao +br +br +br +br +br +al +ad +ad +al +br +br +br +br +bf +br +br +br +br +br bz -ao +br aR ai ai @@ -58681,8 +58572,8 @@ ad ad ad ax -ao -ao +br +br ai ai ai @@ -58877,7 +58768,7 @@ ai ai ai ai -ao +br ai ai ai @@ -58886,9 +58777,9 @@ ax ax ax ax -ao -ao -ao +br +br +br ai ai ai @@ -58896,22 +58787,22 @@ ax ax ax ax -ao +br ax -ao +br ax ax ax -ao +br ap -ao +br ax ax ax ax aR -ao -ao +br +br ax ax ad @@ -58921,14 +58812,14 @@ ax ax aR aR -ao +br bf ap bf -ao -ao -ao -ao +br +br +br +br ax ai ai @@ -59139,13 +59030,13 @@ ai ai ad ax -ao -ao -ao +br +br +br ax -ao -ao -ao +br +br +br ad ai ai @@ -59154,21 +59045,21 @@ ai ai ax aR -ao -ao +br +br ax ai ax -ao -ao -ao +br +br +br ax ai ai ax -ao -ao -ao +br +br +br ax ai ad @@ -59179,12 +59070,12 @@ ai ad ad aR -ao +br bf -ao -ao -ao -ao +br +br +br +br aR ai ai @@ -59194,7 +59085,7 @@ ad ad ad ax -ao +br am ai bs @@ -59396,13 +59287,13 @@ ad ad ad ax -ao -ao -ao +br +br +br aF -ao -ao -ao +br +br +br ad ai ai @@ -59410,22 +59301,22 @@ ai ai ai ax -ao -ao -ao +br +br +br ax ai ax -ao -ao +br +br aR ax ai ai ax -ao -ao -ao +br +br +br ax ai ad @@ -59436,11 +59327,11 @@ ai ad ad aR -ao -ao -ao -ao -ao +br +br +br +br +br aR ai ai @@ -59451,7 +59342,7 @@ ad ad ad aR -ao +br ai ai ai @@ -59653,13 +59544,13 @@ ad ad ad ax -ao -ao -ao +br +br +br ax -ao -ao -ao +br +br +br ai ai ai @@ -59667,22 +59558,22 @@ ai ai ai ax -ao -ao -ao +br +br +br ax ai ax -ao -ao -ao +br +br +br ax ad ad ax -ao -ao -ao +br +br +br ax ai ai @@ -59694,9 +59585,9 @@ ad ad ai ax -ao -ao -ao +br +br +br ax ai ai @@ -59708,7 +59599,7 @@ ad ad ad ax -ao +br ai ai ai @@ -59911,12 +59802,12 @@ ad ad ax aC -ao +br aE ax -ao -ao -ao +br +br +br ai ai ai @@ -59926,20 +59817,20 @@ ai ax aR aR -ao +br ax ai ax -ao -ao -ao +br +br +br ax ad ad ax -ao -ao -ao +br +br +br ax ai ai @@ -59964,8 +59855,8 @@ ad ad ad ad -ao -ao +br +br ai ai ai @@ -60171,9 +60062,9 @@ ax ax ax ax -ao -ao -ao +br +br +br ai ai ai @@ -60187,7 +60078,7 @@ ai ai ai ax -ao +br aR aR ax @@ -60195,7 +60086,7 @@ ad ai ax aw -ao +br aR ax ai @@ -60221,8 +60112,8 @@ ad ad ax ax -ao -ao +br +br am ai ad @@ -60428,9 +60319,9 @@ ad ad ad ad -ao -ao -ao +br +br +br ad ai ai @@ -60451,9 +60342,9 @@ ai ad ai ax -ao +br aw -ao +br ax ai ai @@ -60465,7 +60356,7 @@ ad ad ad al -ao +br al ad ad @@ -60477,8 +60368,8 @@ ad ax al ai -ao -ao +br +br ai ai ai @@ -60686,8 +60577,8 @@ ad ad ad ad -ao -ao +br +br ad ai ai @@ -60696,7 +60587,7 @@ ai ai ax aS -ao +br aS ax ax @@ -60708,9 +60599,9 @@ ax ad ad ax -ao +br av -ao +br ax ai ai @@ -60721,7 +60612,7 @@ ad ad ad ai -ao +br ai ax ad @@ -60731,8 +60622,8 @@ ad ad ad ad -ao -ao +br +br ai ai ai @@ -60943,31 +60834,31 @@ ad ad ad ad -ao -ao -ao -ao +br +br +br +br ad ad -ao -ao -ao -ao -ao -ao -ao -ao -ao -ao +br +br +br +br +br +br +br +br +br +br aG -ao -ao +br +br ad ad ad -ao -ao -ao +br +br +br ax ai ai @@ -60978,7 +60869,7 @@ ad ad ad ai -ao +br ai ad ad @@ -60988,8 +60879,8 @@ ad ad ad ad -ao -ao +br +br ai ai ai @@ -61201,30 +61092,30 @@ ad ad ad ad -ao -ao -ao +br +br +br ad ad -ao -ao -ao -ao +br +br +br +br ap av -ao +br ad ad ad ap ad -ao -ao +br +br ad ad -ao +br ap -ao +br ax ai ai @@ -61245,7 +61136,7 @@ ai ad ax ai -ao +br ai ai ad @@ -61463,24 +61354,24 @@ ad ad ad ad -ao -ao -ao -ao -ao +br +br +br +br +br ad ad ad ad -ao -ao +br +br ad ad -ao -ao -ao -ao -ao +br +br +br +br +br aB ax ai @@ -61494,13 +61385,13 @@ ad ai ai ai -ao +br ai ai ai ai -ao -ao +br +br ai ai ai @@ -61751,10 +61642,10 @@ ad ad ad ai -ao -ao -ao -ao +br +br +br +br ai ai ai @@ -64051,7 +63942,7 @@ ad ai ai aY -ao +br aZ ai ad @@ -64307,9 +64198,9 @@ ad ad ad an -ao +br ba -ao +br an ad ad @@ -64565,7 +64456,7 @@ ad ad ai aZ -ao +br aY ad ad diff --git a/_maps/RandomZLevels/away_mission/challenge.dmm b/_maps/RandomZLevels/away_mission/challenge.dmm index 91b209ae9b..7342f7ffe6 100644 --- a/_maps/RandomZLevels/away_mission/challenge.dmm +++ b/_maps/RandomZLevels/away_mission/challenge.dmm @@ -866,21 +866,10 @@ }, /area/awaymission/challenge/start) "cS" = ( -/obj/machinery/gateway{ - dir = 9 - }, -/turf/open/floor/bluespace, -/area/awaymission/challenge/start) -"cT" = ( -/obj/machinery/gateway{ - dir = 1 - }, +/obj/machinery/gateway/away, /turf/open/floor/bluespace, /area/awaymission/challenge/start) "cV" = ( -/obj/machinery/gateway{ - dir = 5 - }, /obj/structure/cable{ icon_state = "1-2" }, @@ -894,24 +883,12 @@ /turf/open/floor/plasteel/dark, /area/awaymission/challenge/end) "cX" = ( -/obj/machinery/gateway{ - dir = 8 - }, /obj/machinery/light{ dir = 8 }, /turf/open/floor/bluespace, /area/awaymission/challenge/start) -"cY" = ( -/obj/machinery/gateway/centeraway{ - calibrated = 0 - }, -/turf/open/floor/bluespace, -/area/awaymission/challenge/start) "cZ" = ( -/obj/machinery/gateway{ - dir = 4 - }, /obj/structure/cable{ icon_state = "1-2" }, @@ -920,18 +897,11 @@ }, /turf/open/floor/bluespace, /area/awaymission/challenge/start) -"da" = ( -/obj/machinery/gateway{ - dir = 10 - }, -/turf/open/floor/bluespace, -/area/awaymission/challenge/start) "db" = ( /obj/structure/window/reinforced, /turf/open/floor/circuit, /area/awaymission/challenge/end) "dc" = ( -/obj/machinery/gateway, /obj/structure/cable{ icon_state = "0-4" }, @@ -996,9 +966,6 @@ /turf/open/floor/plasteel/dark, /area/awaymission/challenge/end) "dn" = ( -/obj/machinery/gateway{ - dir = 6 - }, /obj/structure/cable{ icon_state = "1-8" }, @@ -28109,9 +28076,9 @@ aa ab ab ab -cS +dq cX -da +dq ab ab at @@ -28366,8 +28333,8 @@ aa ab aB ab -cT -cY +dq +cS dc dq dq diff --git a/_maps/RandomZLevels/away_mission/moonoutpost19.dmm b/_maps/RandomZLevels/away_mission/moonoutpost19.dmm index 83d1227c5e..ff2db79c83 100644 --- a/_maps/RandomZLevels/away_mission/moonoutpost19.dmm +++ b/_maps/RandomZLevels/away_mission/moonoutpost19.dmm @@ -191,60 +191,6 @@ heat_capacity = 1e+006 }, /area/awaymission/moonoutpost19/syndicate) -"aG" = ( -/obj/machinery/gateway{ - dir = 9 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark{ - heat_capacity = 1e+006 - }, -/area/awaymission/moonoutpost19/syndicate) -"aH" = ( -/obj/machinery/gateway{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark{ - heat_capacity = 1e+006 - }, -/area/awaymission/moonoutpost19/syndicate) -"aI" = ( -/obj/machinery/gateway{ - dir = 5 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark{ - heat_capacity = 1e+006 - }, -/area/awaymission/moonoutpost19/syndicate) "aJ" = ( /obj/structure/alien/weeds, /obj/structure/alien/weeds{ @@ -291,46 +237,8 @@ heat_capacity = 1e+006 }, /area/awaymission/moonoutpost19/syndicate) -"aO" = ( -/obj/machinery/gateway{ - dir = 8 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark{ - heat_capacity = 1e+006 - }, -/area/awaymission/moonoutpost19/syndicate) "aP" = ( -/obj/machinery/gateway/centeraway{ - calibrated = 0 - }, -/turf/open/floor/plasteel/dark{ - heat_capacity = 1e+006 - }, -/area/awaymission/moonoutpost19/syndicate) -"aQ" = ( -/obj/machinery/gateway{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, +/obj/machinery/gateway/away, /turf/open/floor/plasteel/dark{ heat_capacity = 1e+006 }, @@ -377,9 +285,6 @@ }, /area/awaymission/moonoutpost19/syndicate) "aW" = ( -/obj/machinery/gateway{ - dir = 10 - }, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -395,7 +300,6 @@ }, /area/awaymission/moonoutpost19/syndicate) "aX" = ( -/obj/machinery/gateway, /obj/structure/cable{ icon_state = "0-2" }, @@ -414,9 +318,6 @@ }, /area/awaymission/moonoutpost19/syndicate) "aY" = ( -/obj/machinery/gateway{ - dir = 6 - }, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -41927,8 +41828,8 @@ ac ac at az -aG -aO +aW +aW aW aV br @@ -42184,7 +42085,7 @@ ac ac at aA -aH +aW aP aX bg @@ -42441,8 +42342,8 @@ ac ac at aB -aI -aQ +aW +aW aY bh bt diff --git a/_maps/RandomZLevels/away_mission/research.dmm b/_maps/RandomZLevels/away_mission/research.dmm index d2b6099eb1..cdb7cf680b 100644 --- a/_maps/RandomZLevels/away_mission/research.dmm +++ b/_maps/RandomZLevels/away_mission/research.dmm @@ -592,27 +592,18 @@ /turf/open/floor/plasteel/dark, /area/awaymission/research/interior/gateway) "bA" = ( -/obj/machinery/gateway{ - dir = 9 - }, /obj/effect/turf_decal/stripes/line{ dir = 9 }, /turf/open/floor/plasteel/dark, /area/awaymission/research/interior/gateway) "bB" = ( -/obj/machinery/gateway{ - dir = 1 - }, /obj/effect/turf_decal/stripes/line{ dir = 1 }, /turf/open/floor/plasteel/dark, /area/awaymission/research/interior/gateway) "bC" = ( -/obj/machinery/gateway{ - dir = 5 - }, /obj/effect/turf_decal/stripes/line{ dir = 5 }, @@ -764,24 +755,16 @@ /turf/open/floor/plasteel/dark, /area/awaymission/research/interior/gateway) "bS" = ( -/obj/machinery/gateway{ - dir = 8 - }, /obj/effect/turf_decal/stripes/line{ dir = 8 }, /turf/open/floor/plasteel/dark, /area/awaymission/research/interior/gateway) "bT" = ( -/obj/machinery/gateway/centeraway{ - calibrated = 0 - }, +/obj/machinery/gateway/away, /turf/open/floor/plasteel/dark, /area/awaymission/research/interior/gateway) "bU" = ( -/obj/machinery/gateway{ - dir = 4 - }, /obj/effect/turf_decal/stripes/line{ dir = 4 }, @@ -830,24 +813,17 @@ /turf/open/floor/plasteel/white, /area/awaymission/research/interior/engineering) "bY" = ( -/obj/machinery/gateway{ - dir = 10 - }, /obj/effect/turf_decal/stripes/line{ dir = 10 }, /turf/open/floor/plasteel/dark, /area/awaymission/research/interior/gateway) "bZ" = ( -/obj/machinery/gateway, /obj/effect/landmark/awaystart, /obj/effect/turf_decal/stripes/line, /turf/open/floor/plasteel/dark, /area/awaymission/research/interior/gateway) "ca" = ( -/obj/machinery/gateway{ - dir = 6 - }, /obj/effect/turf_decal/stripes/line{ dir = 6 }, diff --git a/_maps/RandomZLevels/away_mission/snowdin.dmm b/_maps/RandomZLevels/away_mission/snowdin.dmm index c6b675acf6..00530695e9 100644 --- a/_maps/RandomZLevels/away_mission/snowdin.dmm +++ b/_maps/RandomZLevels/away_mission/snowdin.dmm @@ -2514,27 +2514,6 @@ "fF" = ( /turf/open/floor/plasteel, /area/awaymission/snowdin/post/gateway) -"fG" = ( -/obj/machinery/gateway{ - dir = 9 - }, -/obj/effect/turf_decal/bot, -/turf/open/floor/plasteel, -/area/awaymission/snowdin/post/gateway) -"fH" = ( -/obj/machinery/gateway{ - dir = 1 - }, -/obj/effect/turf_decal/bot, -/turf/open/floor/plasteel, -/area/awaymission/snowdin/post/gateway) -"fI" = ( -/obj/machinery/gateway{ - dir = 5 - }, -/obj/effect/turf_decal/bot, -/turf/open/floor/plasteel, -/area/awaymission/snowdin/post/gateway) "fJ" = ( /obj/structure/table/reinforced, /obj/effect/turf_decal/tile/bar, @@ -2894,29 +2873,16 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plasteel, /area/awaymission/snowdin/post/gateway) -"gw" = ( -/obj/machinery/gateway{ - dir = 8 - }, -/obj/effect/turf_decal/bot, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/plasteel, -/area/awaymission/snowdin/post/gateway) "gx" = ( -/obj/machinery/gateway/centeraway{ - calibrated = 0 - }, /obj/effect/turf_decal/bot, /obj/structure/cable/yellow{ icon_state = "0-2" }, /obj/effect/decal/cleanable/dirt, +/obj/machinery/gateway/away, /turf/open/floor/plasteel, /area/awaymission/snowdin/post/gateway) "gy" = ( -/obj/machinery/gateway{ - dir = 4 - }, /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, /area/awaymission/snowdin/post/gateway) @@ -3263,15 +3229,11 @@ /turf/open/floor/plasteel, /area/awaymission/snowdin/post/gateway) "hl" = ( -/obj/machinery/gateway{ - dir = 10 - }, /obj/effect/turf_decal/bot, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plasteel, /area/awaymission/snowdin/post/gateway) "hm" = ( -/obj/machinery/gateway, /obj/effect/turf_decal/bot, /obj/structure/cable/yellow{ icon_state = "0-2" @@ -3283,9 +3245,6 @@ /turf/open/floor/plasteel, /area/awaymission/snowdin/post/gateway) "hn" = ( -/obj/machinery/gateway{ - dir = 6 - }, /obj/effect/turf_decal/bot, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, @@ -26601,8 +26560,8 @@ bE az en fh -fG -gw +gy +hl hl hR iA @@ -26858,7 +26817,7 @@ bE dK eo fh -fH +gy gx hm hS @@ -27115,7 +27074,7 @@ dk dK ep fh -fI +gy gy hn hT diff --git a/_maps/RandomZLevels/away_mission/undergroundoutpost45.dmm b/_maps/RandomZLevels/away_mission/undergroundoutpost45.dmm index 10992c70bf..78a656128c 100644 --- a/_maps/RandomZLevels/away_mission/undergroundoutpost45.dmm +++ b/_maps/RandomZLevels/away_mission/undergroundoutpost45.dmm @@ -3324,60 +3324,6 @@ icon_state = "platingdmg1" }, /area/awaymission/undergroundoutpost45/central) -"gR" = ( -/obj/machinery/gateway{ - dir = 9 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark{ - heat_capacity = 1e+006 - }, -/area/awaymission/undergroundoutpost45/gateway) -"gS" = ( -/obj/machinery/gateway{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark{ - heat_capacity = 1e+006 - }, -/area/awaymission/undergroundoutpost45/gateway) -"gT" = ( -/obj/machinery/gateway{ - dir = 5 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark{ - heat_capacity = 1e+006 - }, -/area/awaymission/undergroundoutpost45/gateway) "gU" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating{ @@ -3634,46 +3580,8 @@ heat_capacity = 1e+006 }, /area/awaymission/undergroundoutpost45/crew_quarters) -"ht" = ( -/obj/machinery/gateway{ - dir = 8 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark{ - heat_capacity = 1e+006 - }, -/area/awaymission/undergroundoutpost45/gateway) "hu" = ( -/obj/machinery/gateway/centeraway{ - calibrated = 0 - }, -/turf/open/floor/plasteel/dark{ - heat_capacity = 1e+006 - }, -/area/awaymission/undergroundoutpost45/gateway) -"hv" = ( -/obj/machinery/gateway{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, +/obj/machinery/gateway/away, /turf/open/floor/plasteel/dark{ heat_capacity = 1e+006 }, @@ -3958,26 +3866,7 @@ heat_capacity = 1e+006 }, /area/awaymission/undergroundoutpost45/central) -"hY" = ( -/obj/machinery/gateway{ - dir = 10 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark{ - heat_capacity = 1e+006 - }, -/area/awaymission/undergroundoutpost45/gateway) "hZ" = ( -/obj/machinery/gateway, /obj/structure/cable{ icon_state = "0-2" }, @@ -3996,9 +3885,6 @@ }, /area/awaymission/undergroundoutpost45/gateway) "ia" = ( -/obj/machinery/gateway{ - dir = 6 - }, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -33198,9 +33084,9 @@ ad ad gv gJ -gR -ht -hY +ia +ia +ia it iO jh @@ -33455,7 +33341,7 @@ ad ad gv gJ -gS +ia hu hZ iu @@ -33712,8 +33598,8 @@ ad ad gw gJ -gT -hv +ia +ia ia iv iQ diff --git a/_maps/RandomZLevels/away_mission/wildwest.dmm b/_maps/RandomZLevels/away_mission/wildwest.dmm index ef4eabdc65..77d11a4552 100644 --- a/_maps/RandomZLevels/away_mission/wildwest.dmm +++ b/_maps/RandomZLevels/away_mission/wildwest.dmm @@ -63,72 +63,11 @@ /obj/structure/destructible/cult/pylon, /turf/open/floor/circuit/green/off, /area/awaymission/wildwest/vault) -"ar" = ( -/obj/machinery/gateway{ - dir = 9 - }, -/turf/open/floor/plating/ironsand{ - icon_state = "ironsand1" - }, -/area/awaymission/wildwest/mines) -"as" = ( -/obj/machinery/gateway{ - dir = 1 - }, -/turf/open/floor/plating/ironsand{ - icon_state = "ironsand1" - }, -/area/awaymission/wildwest/mines) -"at" = ( -/obj/machinery/gateway{ - dir = 5 - }, -/turf/open/floor/plating/ironsand{ - icon_state = "ironsand1" - }, -/area/awaymission/wildwest/mines) -"au" = ( -/obj/machinery/gateway{ - dir = 8 - }, -/turf/open/floor/plating/ironsand{ - icon_state = "ironsand1" - }, -/area/awaymission/wildwest/mines) -"av" = ( -/obj/machinery/gateway/centeraway{ - calibrated = 0 - }, -/turf/open/floor/plating/ironsand{ - icon_state = "ironsand1" - }, -/area/awaymission/wildwest/mines) "aw" = ( -/obj/machinery/gateway{ - dir = 4 - }, /turf/open/floor/plating/ironsand{ icon_state = "ironsand1" - }, -/area/awaymission/wildwest/mines) -"ax" = ( -/obj/machinery/gateway{ - dir = 10 - }, -/turf/open/floor/plating/ironsand{ - icon_state = "ironsand1" - }, -/area/awaymission/wildwest/mines) -"ay" = ( -/obj/machinery/gateway, -/turf/open/floor/plating/ironsand{ - icon_state = "ironsand1" - }, -/area/awaymission/wildwest/mines) + }) "az" = ( -/obj/machinery/gateway{ - dir = 6 - }, /turf/open/floor/plating/ironsand{ icon_state = "ironsand1" }, @@ -32745,9 +32684,9 @@ aT aN aN aT -ar -au -ax +aT +aT +aT aT aT aT @@ -33002,9 +32941,9 @@ aT aN aN aT -as -av -ay +aT +aT +aT aT aT aT @@ -33259,7 +33198,7 @@ aT aN aN aT -at +aT aw az aT diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index ed4a150e09..3a1ce84ba2 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -11788,63 +11788,12 @@ /obj/item/instrument/eguitar, /turf/open/floor/wood, /area/crew_quarters/theatre) -"azJ" = ( -/obj/machinery/gateway{ - dir = 9 - }, -/obj/effect/turf_decal/bot_white/right, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/gateway) "azK" = ( /obj/machinery/light{ dir = 8 }, /turf/open/floor/plasteel/dark, /area/gateway) -"azL" = ( -/obj/machinery/gateway{ - dir = 5 - }, -/obj/effect/turf_decal/bot_white/left, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/gateway) -"azM" = ( -/obj/machinery/gateway{ - dir = 1 - }, -/obj/effect/turf_decal/bot_white, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/gateway) "azN" = ( /obj/machinery/light{ dir = 4 @@ -12316,30 +12265,10 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/closed/wall/r_wall, /area/ai_monitored/nuke_storage) -"aBd" = ( -/obj/machinery/gateway{ - dir = 8 - }, -/obj/effect/turf_decal/bot_white, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/gateway) "aBe" = ( /turf/open/floor/plasteel/dark, /area/gateway) "aBf" = ( -/obj/machinery/gateway{ - dir = 4 - }, /obj/effect/turf_decal/bot_white, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -12692,9 +12621,6 @@ /turf/open/floor/plasteel/dark, /area/ai_monitored/nuke_storage) "aBX" = ( -/obj/machinery/gateway{ - dir = 10 - }, /obj/effect/turf_decal/bot_white/left, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -12709,9 +12635,6 @@ /turf/open/floor/plasteel/dark, /area/gateway) "aBY" = ( -/obj/machinery/gateway{ - dir = 6 - }, /obj/effect/turf_decal/bot_white/right, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -12726,7 +12649,6 @@ /turf/open/floor/plasteel/dark, /area/gateway) "aBZ" = ( -/obj/machinery/gateway, /obj/structure/cable{ icon_state = "0-2" }, @@ -13795,8 +13717,7 @@ /turf/open/floor/plasteel/dark, /area/ai_monitored/nuke_storage) "aEQ" = ( -/obj/structure/table, -/obj/item/paper/pamphlet/gateway, +/obj/machinery/computer/gateway_control, /turf/open/floor/plasteel, /area/gateway) "aER" = ( @@ -84053,8 +83974,8 @@ esK awb axt ayG -azJ -aBd +aBY +aBf aBX aDi aEQ @@ -84310,7 +84231,7 @@ arP awb axt ayG -azM +aBf aBg aBZ aDx @@ -84567,7 +84488,7 @@ arP vgJ hSl ayG -azL +aBX aBf aBY aDw diff --git a/_maps/map_files/CogStation/CogStation.dmm b/_maps/map_files/CogStation/CogStation.dmm index 5f79f64c57..182f1a4f27 100644 --- a/_maps/map_files/CogStation/CogStation.dmm +++ b/_maps/map_files/CogStation/CogStation.dmm @@ -22362,6 +22362,9 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, +/obj/machinery/computer/gateway_control{ + dir = 8 + }, /turf/open/floor/plasteel/dark/side{ dir = 4 }, @@ -22381,12 +22384,6 @@ /obj/effect/spawner/lootdrop/maintenance, /turf/open/floor/plating, /area/maintenance/department/eva) -"aWr" = ( -/obj/machinery/gateway{ - dir = 10 - }, -/turf/open/floor/engine, -/area/gateway) "aWs" = ( /obj/machinery/light{ dir = 8; @@ -22840,10 +22837,6 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/central) -"aXm" = ( -/obj/machinery/gateway, -/turf/open/floor/engine, -/area/gateway) "aXn" = ( /obj/effect/turf_decal/tile/bar, /obj/effect/turf_decal/tile/bar{ @@ -22883,12 +22876,6 @@ "aXr" = ( /turf/open/floor/plasteel, /area/ai_monitored/storage/eva) -"aXs" = ( -/obj/machinery/gateway{ - dir = 6 - }, -/turf/open/floor/engine, -/area/gateway) "aXt" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/sign/warning/securearea, @@ -30329,12 +30316,6 @@ }, /turf/open/floor/plasteel, /area/science/mixing) -"bnl" = ( -/obj/machinery/gateway{ - dir = 9 - }, -/turf/open/floor/engine, -/area/gateway) "bnm" = ( /obj/machinery/atmospherics/pipe/manifold/orange/hidden{ dir = 4 @@ -34660,9 +34641,6 @@ c_tag = "Research - Gateway Chamber"; network = list("ss13","rd") }, -/obj/machinery/gateway{ - dir = 1 - }, /turf/open/floor/engine, /area/gateway) "bwL" = ( @@ -34672,12 +34650,6 @@ }, /turf/open/floor/plating, /area/router) -"bwM" = ( -/obj/machinery/gateway{ - dir = 5 - }, -/turf/open/floor/engine, -/area/gateway) "bwN" = ( /obj/machinery/atmospherics/pipe/simple/general/visible{ dir = 4 @@ -36403,12 +36375,6 @@ /area/medical/medbay/zone2{ name = "Medbay Treatment Center" }) -"bAz" = ( -/obj/machinery/gateway{ - dir = 8 - }, -/turf/open/floor/engine, -/area/gateway) "bAA" = ( /obj/structure/lattice, /obj/structure/cable{ @@ -36566,12 +36532,6 @@ /area/medical/medbay/zone2{ name = "Medbay Treatment Center" }) -"bAN" = ( -/obj/machinery/gateway{ - dir = 4 - }, -/turf/open/floor/engine, -/area/gateway) "bAO" = ( /obj/machinery/atmospherics/pipe/simple/supplymain/hidden{ dir = 4 @@ -62112,7 +62072,6 @@ departmentType = 2; name = "Chemistry RC"; pixel_x = 30; - pixel_y = 0; receive_ore_updates = 1 }, /turf/open/floor/plasteel/white, @@ -99510,9 +99469,9 @@ aaa aaa aaa aUk -bnl -bAz -aWr +bmG +bmG +bmG cDN bmG aUk @@ -99769,7 +99728,7 @@ aaa aUk bwK bAF -aXm +bmG cDN bmG aUk @@ -100024,9 +99983,9 @@ aaa aaa aaa aUk -bwM -bAN -aXs +bmG +bmG +bmG cDN bmG aUk diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 0d3665c58d..c44f6807fa 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -124,6 +124,45 @@ }, /turf/open/floor/plating, /area/crew_quarters/abandoned_gambling_den) +"aaq" = ( +/obj/machinery/button/door{ + id = "cargounload"; + layer = 4; + name = "Loading Doors"; + pixel_x = 24; + pixel_y = 8 + }, +/obj/machinery/button/door{ + id = "cargoload"; + layer = 4; + name = "Loading Doors"; + pixel_x = 24; + pixel_y = -8 + }, +/obj/machinery/computer/cargo{ + dir = 8 + }, +/obj/machinery/camera{ + c_tag = "Cargo Bay - Starboard"; + dir = 8; + name = "cargo camera" + }, +/obj/effect/turf_decal/bot, +/obj/machinery/light{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/quartermaster/storage) +"aar" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/hallway/primary/central) "aas" = ( /obj/docking_port/stationary/random{ id = "pod_lavaland1"; @@ -143,10 +182,215 @@ /obj/effect/landmark/xeno_spawn, /turf/open/space, /area/solar/starboard/fore) +"aav" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/turf/open/floor/plasteel{ + heat_capacity = 1e+006 + }, +/area/crew_quarters/fitness/recreation) +"aaw" = ( +/obj/effect/turf_decal/tile/neutral, +/turf/open/floor/plasteel{ + heat_capacity = 1e+006 + }, +/area/crew_quarters/fitness/recreation) +"aax" = ( +/obj/machinery/light, +/obj/machinery/camera{ + c_tag = "Recreation - Aft"; + dir = 1; + name = "recreation camera" + }, +/obj/effect/turf_decal/tile/neutral, +/turf/open/floor/plasteel, +/area/crew_quarters/fitness/recreation) +"aay" = ( +/turf/closed/wall, +/area/crew_quarters/fitness/pool) +"aaz" = ( +/obj/machinery/door/firedoor, +/obj/effect/turf_decal/stripes/line, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/machinery/door/airlock/public/glass{ + name = "Pool" + }, +/turf/open/floor/plasteel, +/area/crew_quarters/fitness/pool) +"aaA" = ( +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) +"aaB" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/effect/turf_decal/delivery, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) +"aaC" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/machinery/portable_atmospherics/canister/air, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) +"aaD" = ( +/obj/effect/spawner/structure/window/reinforced/tinted, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) "aaE" = ( /obj/structure/lattice/catwalk, /turf/open/space, /area/solar/starboard/fore) +"aaF" = ( +/obj/structure/closet/athletic_mixed, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 6 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/item/toy/poolnoodle/blue, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) +"aaG" = ( +/obj/structure/closet/athletic_mixed, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/item/toy/poolnoodle/red, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) +"aaH" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) +"aaI" = ( +/obj/machinery/light{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/structure/table/glass, +/obj/structure/bedsheetbin/towel, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) +"aaJ" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/structure/table/glass, +/obj/item/storage/firstaid/regular, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) +"aaK" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) +"aaL" = ( +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) +"aaM" = ( +/obj/structure/bed, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) +"aaN" = ( +/turf/open/pool, +/area/crew_quarters/fitness/pool) "aaO" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -154,9 +398,147 @@ "aaP" = ( /turf/closed/wall/mineral/plastitanium, /area/hallway/secondary/entry) +"aaQ" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/structure/sign/poster/official/walk{ + pixel_x = -32 + }, +/turf/open/floor/plasteel/yellowsiding/corner, +/area/crew_quarters/fitness/pool) +"aaR" = ( +/obj/machinery/space_heater, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) "aaS" = ( /turf/closed/wall/mineral/plastitanium, /area/construction/mining/aux_base) +"aaT" = ( +/obj/effect/turf_decal/delivery, +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) +"aaU" = ( +/obj/machinery/door/airlock/maintenance_hatch/abandoned{ + name = "Maintenance Hatch"; + req_access_txt = "12" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) +"aaV" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/yellowsiding, +/area/crew_quarters/fitness/pool) +"aaW" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) +"aaX" = ( +/obj/machinery/pool/controller, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/yellowsiding, +/area/crew_quarters/fitness/pool) +"aaY" = ( +/obj/structure/pool/Lboard, +/turf/open/pool, +/area/crew_quarters/fitness/pool) +"aaZ" = ( +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/yellowsiding/corner{ + icon_state = "yellowcornersiding"; + dir = 8 + }, +/area/crew_quarters/fitness/pool) +"aba" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = -24; + pixel_y = 0 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel/yellowsiding{ + icon_state = "yellowsiding"; + dir = 4 + }, +/area/crew_quarters/fitness/pool) +"abb" = ( +/obj/effect/turf_decal/delivery, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) +"abc" = ( +/obj/machinery/door/airlock/maintenance_hatch/abandoned{ + name = "Maintenance Hatch"; + req_access_txt = "12" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) +"abd" = ( +/obj/structure/pool/ladder{ + dir = 2; + pixel_y = 24 + }, +/turf/open/pool, +/area/crew_quarters/fitness/pool) "abe" = ( /obj/effect/turf_decal/stripes/line{ dir = 9 @@ -166,6 +548,31 @@ "abf" = ( /turf/closed/wall, /area/hallway/secondary/entry) +"abg" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/structure/rack, +/obj/item/weldingtool, +/obj/item/assembly/voice, +/obj/item/clothing/head/welding, +/obj/effect/spawner/lootdrop/maintenance, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) +"abh" = ( +/obj/effect/landmark/blobstart, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) "abi" = ( /turf/closed/wall, /area/construction/mining/aux_base) @@ -173,6 +580,61 @@ /obj/structure/lattice/catwalk, /turf/open/space, /area/space/nearstation) +"abk" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/effect/landmark/event_spawn, +/obj/structure/reagent_dispensers/watertank, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) +"abl" = ( +/obj/machinery/pool/filter{ + pixel_y = 16 + }, +/turf/open/pool, +/area/crew_quarters/fitness/pool) +"abm" = ( +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/yellowsiding{ + icon_state = "yellowsiding"; + dir = 8 + }, +/area/crew_quarters/fitness/pool) +"abn" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 9 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel/yellowsiding{ + icon_state = "yellowsiding"; + dir = 4 + }, +/area/crew_quarters/fitness/pool) +"abo" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) "abp" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/light/small{ @@ -196,6 +658,18 @@ }, /turf/open/floor/plasteel, /area/hallway/secondary/entry) +"abr" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/simple/supply/hidden, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) "abs" = ( /obj/docking_port/stationary{ dwidth = 1; @@ -207,11 +681,94 @@ /obj/structure/fans/tiny/invisible, /turf/open/space/basic, /area/space) +"abt" = ( +/obj/effect/spawner/structure/window/reinforced/tinted, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/turf/open/floor/plating, +/area/crew_quarters/fitness/pool) +"abu" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/machinery/camera{ + c_tag = "Pool - Portside"; + dir = 4; + name = "pool camera" + }, +/turf/open/floor/plasteel/yellowsiding{ + icon_state = "yellowsiding"; + dir = 4 + }, +/area/crew_quarters/fitness/pool) "abv" = ( /obj/item/stack/cable_coil, /obj/structure/lattice/catwalk, /turf/open/space, /area/solar/starboard/fore) +"abw" = ( +/obj/machinery/pool/drain, +/turf/open/pool, +/area/crew_quarters/fitness/pool) +"abx" = ( +/obj/structure/pool/Rboard, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/yellowsiding{ + icon_state = "yellowsiding"; + dir = 8 + }, +/area/crew_quarters/fitness/pool) +"aby" = ( +/obj/machinery/light{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/machinery/camera{ + c_tag = "Pool - Starboard"; + dir = 8; + name = "pool camera" + }, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) +"abz" = ( +/obj/structure/closet/firecloset, +/turf/open/floor/plating, +/area/hallway/secondary/construction) +"abA" = ( +/obj/structure/dresser, +/turf/open/floor/wood, +/area/maintenance/starboard/aft) +"abB" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel/yellowsiding{ + icon_state = "yellowsiding"; + dir = 4 + }, +/area/crew_quarters/fitness/pool) "abC" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -262,6 +819,95 @@ }, /turf/open/floor/plasteel, /area/construction/mining/aux_base) +"abI" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/turf/open/floor/wood, +/area/maintenance/starboard/aft) +"abJ" = ( +/obj/structure/chair/office/dark{ + dir = 4 + }, +/obj/effect/landmark/xeno_spawn, +/obj/machinery/atmospherics/components/unary/vent_pump/on{ + dir = 8 + }, +/turf/open/floor/wood, +/area/maintenance/starboard/aft) +"abK" = ( +/obj/structure/cable/white{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/structure/reagent_dispensers/fueltank, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel{ + heat_capacity = 1e+006 + }, +/area/maintenance/starboard/aft) +"abL" = ( +/obj/structure/cable/white{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 9 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) +"abM" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/structure/closet/emcloset, +/obj/item/clothing/mask/breath, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) +"abN" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 9 + }, +/obj/machinery/portable_atmospherics/canister/air, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/maintenance/starboard/aft) +"abO" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/machinery/airalarm{ + dir = 4; + pixel_x = -23 + }, +/turf/open/floor/plasteel/yellowsiding{ + icon_state = "yellowsiding"; + dir = 4 + }, +/area/crew_quarters/fitness/pool) "abP" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/door/airlock/external{ @@ -306,6 +952,71 @@ /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, /area/construction/mining/aux_base) +"abU" = ( +/obj/structure/pool/ladder{ + dir = 1; + pixel_y = -24 + }, +/turf/open/pool, +/area/crew_quarters/fitness/pool) +"abV" = ( +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/item/radio/intercom{ + name = "Station Intercom"; + pixel_x = -26 + }, +/turf/open/floor/plasteel/yellowsiding/corner{ + icon_state = "yellowcornersiding"; + dir = 4 + }, +/area/crew_quarters/fitness/pool) +"abW" = ( +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/plasteel/yellowsiding{ + icon_state = "yellowsiding"; + dir = 1 + }, +/area/crew_quarters/fitness/pool) +"abX" = ( +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/yellowsiding/corner{ + icon_state = "yellowcornersiding"; + dir = 1 + }, +/area/crew_quarters/fitness/pool) +"abY" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/structure/closet/secure_closet/personal, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/item/toy/poolnoodle/yellow, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) "abZ" = ( /obj/machinery/door/firedoor, /obj/effect/turf_decal/stripes/line, @@ -365,6 +1076,117 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/maintenance/solars/starboard/fore) +"acg" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/structure/closet/secure_closet/personal, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/item/toy/poolnoodle/red, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) +"ach" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) +"aci" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/structure/chair{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) +"acj" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/structure/table/glass, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) +"ack" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/structure/chair{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) +"acl" = ( +/obj/structure/table/wood, +/obj/item/clothing/suit/toggle/owlwings, +/obj/item/clothing/under/costume/owl, +/obj/item/clothing/mask/gas/owl_mask, +/obj/machinery/light/small{ + dir = 1 + }, +/turf/open/floor/wood, +/area/maintenance/starboard/aft) +"acm" = ( +/obj/structure/table/wood, +/obj/item/storage/secure/briefcase, +/obj/item/restraints/handcuffs, +/obj/item/grenade/smokebomb, +/turf/open/floor/wood, +/area/maintenance/starboard/aft) +"acn" = ( +/obj/structure/table/wood, +/obj/item/modular_computer/tablet/preset/cheap, +/turf/open/floor/wood, +/area/maintenance/starboard/aft) "aco" = ( /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -452,6 +1274,43 @@ }, /turf/open/floor/plating, /area/maintenance/solars/starboard/fore) +"acw" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/structure/closet/secure_closet/personal, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/item/toy/poolnoodle/blue, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) +"acx" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ + dir = 4 + }, +/obj/machinery/light, +/obj/structure/closet/secure_closet/personal, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/item/toy/poolnoodle/blue, +/turf/open/floor/plasteel/dark, +/area/crew_quarters/fitness/pool) "acF" = ( /obj/docking_port/stationary{ dir = 2; @@ -13899,32 +14758,6 @@ }, /turf/open/floor/plasteel, /area/quartermaster/storage) -"aEg" = ( -/obj/machinery/button/door{ - id = "cargounload"; - layer = 4; - name = "Loading Doors"; - pixel_x = 24; - pixel_y = 8 - }, -/obj/machinery/button/door{ - id = "cargoload"; - layer = 4; - name = "Loading Doors"; - pixel_x = 24; - pixel_y = -8 - }, -/obj/machinery/computer/cargo{ - dir = 8 - }, -/obj/machinery/camera{ - c_tag = "Cargo Bay - Starboard"; - dir = 8; - name = "cargo camera" - }, -/obj/effect/turf_decal/bot, -/turf/open/floor/plasteel, -/area/quartermaster/storage) "aEi" = ( /obj/structure/cable/white{ icon_state = "0-2" @@ -64841,7 +65674,6 @@ pixel_x = -26 }, /obj/structure/sign/painting/library{ - pixel_x = 0; pixel_y = -32 }, /turf/open/floor/wood, @@ -75577,9 +76409,6 @@ /turf/open/floor/plating, /area/gateway) "cyE" = ( -/obj/machinery/gateway{ - dir = 9 - }, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/bot_white/right, /obj/effect/turf_decal/tile/neutral{ @@ -75595,9 +76424,6 @@ /turf/open/floor/plasteel/dark, /area/gateway) "cyF" = ( -/obj/machinery/gateway{ - dir = 1 - }, /obj/machinery/status_display/evac{ pixel_y = 32 }, @@ -75616,9 +76442,6 @@ /turf/open/floor/plasteel/dark, /area/gateway) "cyG" = ( -/obj/machinery/gateway{ - dir = 5 - }, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/bot_white/left, /obj/effect/turf_decal/tile/neutral{ @@ -76575,26 +77398,10 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/gateway) -"cAi" = ( -/obj/machinery/gateway{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/bot_white, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/gateway) "cAj" = ( -/obj/machinery/gateway/centerstation, +/obj/machinery/gateway/centerstation{ + dir = 0 + }, /obj/structure/cable/white{ icon_state = "0-2" }, @@ -76602,9 +77409,6 @@ /turf/open/floor/plasteel/dark, /area/gateway) "cAk" = ( -/obj/machinery/gateway{ - dir = 4 - }, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/bot_white, /obj/effect/turf_decal/tile/neutral{ @@ -77428,9 +78232,6 @@ /turf/closed/wall, /area/gateway) "cBD" = ( -/obj/machinery/gateway{ - dir = 10 - }, /obj/machinery/light{ dir = 8 }, @@ -77449,7 +78250,6 @@ /turf/open/floor/plasteel/dark, /area/gateway) "cBE" = ( -/obj/machinery/gateway, /obj/structure/cable/white{ icon_state = "0-2" }, @@ -77471,9 +78271,6 @@ /turf/open/floor/plasteel/dark, /area/gateway) "cBF" = ( -/obj/machinery/gateway{ - dir = 6 - }, /obj/effect/decal/cleanable/dirt, /obj/machinery/camera{ c_tag = "Bridge - Gateway Chamber"; @@ -78596,6 +79393,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 5 }, +/obj/machinery/computer/gateway_control{ + dir = 8 + }, /turf/open/floor/plasteel, /area/gateway) "cDj" = ( @@ -94085,27 +94885,6 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, /area/crew_quarters/fitness/recreation) -"ddw" = ( -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel{ - heat_capacity = 1e+006 - }, -/area/crew_quarters/fitness/recreation) -"ddx" = ( -/obj/machinery/light, -/obj/machinery/camera{ - c_tag = "Recreation - Aft"; - dir = 1; - name = "recreation camera" - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel, -/area/crew_quarters/fitness/recreation) "ddy" = ( /obj/item/kirbyplants/random, /obj/effect/turf_decal/tile/neutral, @@ -97420,28 +98199,6 @@ }, /turf/open/floor/plasteel, /area/maintenance/starboard/aft) -"diX" = ( -/obj/effect/decal/cleanable/cobweb, -/obj/structure/dresser, -/turf/open/floor/wood, -/area/maintenance/starboard/aft) -"diY" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/structure/table/wood, -/obj/item/clothing/suit/toggle/owlwings, -/obj/item/clothing/under/costume/owl, -/obj/item/clothing/mask/gas/owl_mask, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) -"diZ" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/table/wood, -/obj/item/storage/secure/briefcase, -/obj/item/restraints/handcuffs, -/obj/item/grenade/smokebomb, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "dja" = ( /obj/machinery/vending/assist, /obj/machinery/newscaster{ @@ -98454,20 +99211,6 @@ }, /turf/open/floor/plasteel/dark, /area/medical/abandoned) -"dkO" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/space_heater, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) -"dkP" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ - dir = 8 - }, -/obj/effect/turf_decal/delivery, -/turf/open/floor/plasteel, -/area/maintenance/starboard/aft) "dkQ" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/door/airlock/maintenance_hatch/abandoned{ @@ -98485,30 +99228,6 @@ }, /turf/open/floor/plasteel, /area/maintenance/starboard/aft) -"dkR" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/landmark/xeno_spawn, -/obj/machinery/atmospherics/components/unary/vent_pump/on{ - dir = 8 - }, -/turf/open/floor/wood{ - icon_state = "wood-broken2" - }, -/area/maintenance/starboard/aft) -"dkS" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/chair/office/dark{ - dir = 4 - }, -/turf/open/floor/wood, -/area/maintenance/starboard/aft) -"dkT" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/table/wood, -/obj/item/modular_computer/tablet/preset/cheap, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "dkU" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/plating, @@ -99911,41 +100630,6 @@ }, /turf/open/floor/plasteel, /area/maintenance/starboard/aft) -"dnV" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ - dir = 8 - }, -/obj/effect/turf_decal/delivery, -/turf/open/floor/plasteel, -/area/maintenance/starboard/aft) -"dnW" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 9 - }, -/turf/open/floor/plasteel, -/area/maintenance/starboard/aft) -"dnX" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/landmark/xeno_spawn, -/obj/machinery/atmospherics/components/unary/vent_pump/on{ - dir = 8 - }, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) -"dnY" = ( -/obj/machinery/portable_atmospherics/canister/air, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/delivery, -/turf/open/floor/plasteel, -/area/maintenance/starboard/aft) "dnZ" = ( /obj/machinery/light/small{ dir = 8 @@ -100876,29 +101560,6 @@ }, /turf/open/floor/plasteel, /area/hallway/secondary/construction) -"dpJ" = ( -/obj/effect/landmark/blobstart, -/obj/machinery/atmospherics/pipe/simple/supply/hidden, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) -"dpK" = ( -/obj/structure/closet/emcloset, -/obj/item/clothing/mask/breath, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) -"dpL" = ( -/obj/structure/reagent_dispensers/watertank, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/stripes/line{ - dir = 6 - }, -/turf/open/floor/plasteel, -/area/maintenance/starboard/aft) -"dpM" = ( -/obj/machinery/portable_atmospherics/canister/air, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "dpN" = ( /obj/structure/table/wood/poker, /obj/item/clothing/glasses/sunglasses/big, @@ -101766,11 +102427,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/hallway/secondary/construction) -"drr" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/obj/effect/landmark/event_spawn, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "drs" = ( /obj/structure/chair/stool/bar, /obj/machinery/light/small{ @@ -104182,36 +104838,6 @@ }, /turf/open/floor/plasteel, /area/maintenance/starboard/aft) -"dvQ" = ( -/obj/structure/rack, -/obj/effect/decal/cleanable/dirt, -/obj/item/weldingtool, -/obj/item/assembly/voice, -/obj/item/clothing/head/welding, -/obj/effect/spawner/lootdrop/maintenance, -/obj/effect/turf_decal/stripes/line{ - dir = 9 - }, -/turf/open/floor/plasteel, -/area/maintenance/starboard/aft) -"dvR" = ( -/obj/machinery/light/small{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/oil, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/turf/open/floor/plasteel, -/area/maintenance/starboard/aft) -"dvS" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/cobweb/cobweb2, -/obj/structure/reagent_dispensers/fueltank, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "dvT" = ( /obj/structure/table/wood, /obj/machinery/newscaster{ @@ -105172,22 +105798,6 @@ }, /turf/open/floor/plating, /area/maintenance/starboard/aft) -"dxz" = ( -/obj/effect/landmark/xeno_spawn, -/obj/machinery/atmospherics/components/unary/vent_pump/on{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line, -/turf/open/floor/plasteel, -/area/maintenance/starboard/aft) -"dxA" = ( -/obj/structure/closet/firecloset, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/stripes/line{ - dir = 6 - }, -/turf/open/floor/plasteel, -/area/maintenance/starboard/aft) "dxB" = ( /obj/structure/chair/wood/normal{ dir = 1 @@ -106023,13 +106633,6 @@ /obj/effect/turf_decal/bot, /turf/open/floor/plasteel, /area/hallway/secondary/construction) -"dyT" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "dyU" = ( /turf/closed/wall/r_wall, /area/maintenance/solars/starboard/aft) @@ -107639,16 +108242,6 @@ heat_capacity = 1e+006 }, /area/maintenance/starboard/aft) -"dBE" = ( -/obj/structure/cable/white{ - icon_state = "4-8" - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ - dir = 9 - }, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "dBF" = ( /obj/structure/cable/white{ icon_state = "4-8" @@ -108410,12 +109003,6 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, /area/maintenance/starboard/aft) -"dDa" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 9 - }, -/turf/open/floor/plating, -/area/maintenance/starboard/aft) "dDb" = ( /obj/structure/sign/warning/electricshock, /turf/closed/wall/r_wall, @@ -125456,7 +126043,6 @@ /area/chapel/office) "iNK" = ( /obj/structure/sign/painting/library{ - pixel_x = 0; pixel_y = -32 }, /turf/open/floor/wood, @@ -161357,7 +161943,7 @@ bvL cjw bYU bvL -bvL +aar bvL bun bvL @@ -169589,7 +170175,7 @@ cur cvC cvz cyE -cAi +cAk cBD cDk cEY @@ -172869,7 +173455,7 @@ ayD ayD hdH azD -aEg +aaq azD kam aHV @@ -178613,7 +179199,7 @@ dnR dpG dpG dpG -dpG +abz dpG dxu dyQ @@ -179132,7 +179718,7 @@ dvO dxw dyS dmh -dBz +abK dCV dEk dFt @@ -179632,22 +180218,22 @@ cZX dbD ddt ddt -dfV +aaB dbD diW -dkO +aaR dbA dnU -dbD -drr -diW +abg +abk +abo due dbD dbD -dyT diW -dBE -dCV +diW +abL +abM dEk dFv dGN @@ -179889,22 +180475,22 @@ cZY dbE cRr cRr -dfW +aaC dhB -cRr -dkP -dbE -dnV -dpJ dfW -dhB +aaT +aaW +abb +abh +dfW +abr dhB dvP dxx dfW dvP dBF -dDa +abN dEk dFw dGO @@ -180145,17 +180731,17 @@ cYp cZZ cIX ddu -cHU -dfX -cHU -cHU -dkQ -cHU -dkQ -cHU -cHU -dfX -cHU +aay +aaD +aay +aay +aaU +aay +abc +aay +aay +abt +aay cHU dkQ dyU @@ -180402,19 +180988,19 @@ cYq daa cuL cuL -cuL -aad -cHU -diX -dkR -cHU -dnW -dpK -cHU -aad -cHU -dvQ -dxy +aay +aaF +aaQ +aba +abn +abu +abB +abO +abV +abY +aay +abA +abI dyU dAl dBH @@ -180659,19 +181245,19 @@ cYr dab dbF ddv -cuL -aaa -dhC -diY -dkS -cHU -dnX -dpL -dfX -aaa -dfX -dvR -dxz +aay +aaG +aaV +aaN +aaN +aaN +aaN +aaN +abW +acg +aay +acl +abJ dyU dAm dBI @@ -180915,20 +181501,20 @@ cWD cAz dac cxy -ddw -cuM -aad -dhC -diZ -dkT -cHU -dnY -dpM -dfX -aad -dfX -dvS -dxA +aav +aaz +aaH +aaV +aaN +aaN +aaN +aaN +aaN +abW +acw +aay +acm +acn dyU dAn dBJ @@ -181172,19 +181758,19 @@ cWE cYs dad cTe -ddw -cuM -aaa +aav +aaz +aaH +aaV +aaN +aaN +aaN +aaN +aaN +abW +abY +aay dhC -dhC -cHU -cHU -cHU -dfX -dfX -aaa -dfX -dfX cHU dyV dyV @@ -181429,18 +182015,18 @@ cTe cYt dae dbG -ddw -cuM -aad -aad -aad -aad -aad -aad -aad -aad -aad -aad +aaw +aaA +aaH +aaV +abd +aaN +aaN +aaN +abU +abW +acg +aay aad aad aad @@ -181686,18 +182272,18 @@ cxy cYt daf dbH -ddx -cuM -aad -aaa -ajr -ajr -ajr -ajr -ajr -aaa -ajr -aaa +aax +aaA +aaI +aaV +aaN +aaN +abw +aaN +aaN +abW +acx +aay ajr ajr aad @@ -181943,18 +182529,18 @@ cWF cYu dag dbI -cDL -cuM -aad -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +dbJ +aaA +aaJ +aaV +aaN +aaN +aaN +aaN +aaN +abW +ach +aaA aaa aaa aad @@ -182201,17 +182787,17 @@ cYv dah cTe dbJ -cuM -aad -ajr -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +aaA +aaH +aaV +aaN +aaN +aaN +aaN +aaN +abW +aci +aaA aaa aaa ajr @@ -182458,19 +183044,19 @@ cYw czl cxy dbJ -cuM -aad -ajr -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +aaA +aaH +aaX +aaN +aaN +aaN +aaN +aaN +abW +acj +aaA +qgU +qgU aad aaa dBO @@ -182715,17 +183301,17 @@ cQa dai dbJ ddy -cuM -aad -aaa -aaa -aaa -hZh -hZh -hZh -hZh -hZh -hZh +aaA +aaK +aaV +abl +aaN +aaY +aaN +aaN +abW +ack +aaA aaa aaa ajr @@ -182972,17 +183558,17 @@ cuM daj dbK ddz -cuM -aad -ajr -aaa -aaa -hZh -hZh -hZh -hZh -hZh -hZh +aaA +aaL +aaZ +abm +abm +abx +abm +abm +abX +aaL +aaA aaa aaa ajr @@ -183229,17 +183815,17 @@ cuM dak dbL ddA -cuM -aad -ajr -aaa -aaa -hZh -hZh -hZh -hZh -hZh -hZh +aaA +aaM +aaM +aaM +aaM +aby +aaM +aaM +aaM +aaM +aaA aaa aaa ajr @@ -183486,19 +184072,19 @@ cuL cuM cuM cuM -cuL -aad -aaa -aaa -aaa -hZh -hZh -hZh -hZh -hZh -hZh -aaa -aaa +aay +aaA +aaA +aaA +aaA +aay +aaA +aaA +aaA +aaA +aay +qgU +qgU aad aaa dBO @@ -183745,18 +184331,18 @@ aad aad aad aad -ajr +aad +qgU aaa aaa -hZh -hZh -hZh -hZh -hZh -hZh aaa aaa -ajr +qgU +aaa +aaa +aaa +aaa +aad aad dBO dDf @@ -184003,16 +184589,16 @@ aaa ajr ajr ajr -aaa -aaa -hZh -hZh -hZh -hZh -hZh -hZh -aaa -aaa +qgU +ajr +ajr +ajr +ajr +qgU +ajr +ajr +ajr +qgU ajr aaa aaa @@ -184262,12 +184848,12 @@ aaa aaa aaa aaa -hZh -hZh -hZh -hZh -hZh -hZh +aaa +aaa +aaa +aaa +aaa +aaa aaa aaa ajr @@ -184519,12 +185105,12 @@ aaa aaa aaa aaa -hZh -hZh -hZh -hZh -hZh -hZh +aaa +aaa +aaa +aaa +aaa +aaa aaa aaa aaa @@ -184776,12 +185362,12 @@ aaa aaa aaa aaa -hZh -hZh -hZh -hZh -hZh -hZh +aaa +aaa +aaa +aaa +aaa +aaa aaa aaa aaa @@ -185033,12 +185619,12 @@ aaa aaa aaa aaa -hZh -hZh -hZh -hZh -hZh -hZh +aaa +aaa +aaa +aaa +aaa +aaa aaa aaa aaa @@ -185290,12 +185876,12 @@ aaa aaa aaa aaa -hZh -hZh -hZh -hZh -hZh -hZh +aaa +aaa +aaa +aaa +aaa +aaa aaa aaa aaa @@ -185547,12 +186133,12 @@ aaa aaa aab aaa -hZh -hZh -hZh -hZh -hZh -hZh +aaa +aaa +aaa +aaa +aaa +aaa aaa aaa aaa diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index b4c6b0c12d..1fc5ae5729 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -7205,9 +7205,6 @@ /turf/open/floor/plasteel/dark, /area/tcommsat/computer) "amk" = ( -/obj/machinery/gateway{ - dir = 1 - }, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -13604,9 +13601,6 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, -/obj/machinery/gateway{ - dir = 10 - }, /obj/effect/decal/cleanable/dirt, /obj/machinery/airalarm{ dir = 4; @@ -13851,7 +13845,6 @@ /obj/item/lighter, /obj/item/clothing/mask/cigarette/cigar/cohiba, /obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/machinery/suit_storage_unit/ce, /turf/open/floor/plasteel, /area/crew_quarters/heads/chief) "axi" = ( @@ -76334,9 +76327,6 @@ /obj/effect/turf_decal/tile/neutral{ dir = 4 }, -/obj/machinery/gateway{ - dir = 9 - }, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/box/corners{ dir = 4 @@ -76403,9 +76393,6 @@ /obj/effect/turf_decal/tile/neutral{ dir = 4 }, -/obj/machinery/gateway{ - dir = 5 - }, /obj/effect/decal/cleanable/dirt, /obj/machinery/camera{ c_tag = "Gateway"; @@ -77551,9 +77538,6 @@ dir = 8 }, /obj/effect/decal/cleanable/greenglow, -/obj/machinery/gateway{ - dir = 8 - }, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plasteel/dark, /area/gateway) @@ -77573,9 +77557,6 @@ dir = 4 }, /obj/effect/decal/cleanable/greenglow, -/obj/machinery/gateway{ - dir = 4 - }, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plasteel/dark, /area/gateway) @@ -77588,8 +77569,6 @@ /turf/open/floor/plasteel/dark, /area/maintenance/disposal) "cvQ" = ( -/obj/effect/turf_decal/bot, -/obj/structure/closet/cardboard, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/machinery/light/small{ @@ -77599,6 +77578,9 @@ dir = 8; pixel_x = 32 }, +/obj/machinery/computer/gateway_control{ + dir = 8 + }, /turf/open/floor/plasteel/dark, /area/gateway) "cvR" = ( @@ -77635,7 +77617,6 @@ dir = 8 }, /obj/effect/decal/cleanable/greenglow, -/obj/machinery/gateway, /obj/effect/decal/cleanable/dirt, /obj/structure/cable{ icon_state = "0-2" @@ -77652,9 +77633,6 @@ /obj/effect/turf_decal/tile/neutral{ dir = 4 }, -/obj/machinery/gateway{ - dir = 6 - }, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plasteel/dark, /area/gateway) @@ -85287,7 +85265,6 @@ icon_state = "1-2" }, /obj/structure/table/wood, -/obj/item/folder/paperwork, /turf/open/floor/wood, /area/security/vacantoffice) "ppP" = ( diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index a143bf9bdf..794f05498d 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -44580,27 +44580,7 @@ }, /turf/open/floor/plating, /area/gateway) -"bJY" = ( -/obj/machinery/gateway{ - dir = 9 - }, -/obj/effect/turf_decal/bot_white/right, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/gateway) "bJZ" = ( -/obj/machinery/gateway{ - dir = 1 - }, /obj/machinery/status_display/evac{ pixel_y = 32 }, @@ -44617,23 +44597,6 @@ }, /turf/open/floor/plasteel/dark, /area/gateway) -"bKa" = ( -/obj/machinery/gateway{ - dir = 5 - }, -/obj/effect/turf_decal/bot_white/left, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/gateway) "bKb" = ( /obj/structure/cable/yellow{ icon_state = "1-2" @@ -45306,31 +45269,13 @@ /obj/structure/cable/yellow, /turf/open/floor/plating, /area/gateway) -"bLD" = ( -/obj/machinery/gateway{ - dir = 8 - }, -/obj/effect/turf_decal/bot_white, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/plasteel/dark, -/area/gateway) "bLE" = ( -/obj/machinery/gateway/centerstation, +/obj/machinery/gateway/centerstation{ + dir = 0 + }, /turf/open/floor/plasteel/dark, /area/gateway) "bLF" = ( -/obj/machinery/gateway{ - dir = 4 - }, /obj/effect/turf_decal/bot_white, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -46196,9 +46141,6 @@ }, /area/gateway) "bNp" = ( -/obj/machinery/gateway{ - dir = 10 - }, /obj/effect/turf_decal/bot_white/left, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -46213,7 +46155,6 @@ /turf/open/floor/plasteel/dark, /area/gateway) "bNq" = ( -/obj/machinery/gateway, /obj/structure/cable/yellow{ icon_state = "0-2" }, @@ -46231,9 +46172,6 @@ /turf/open/floor/plasteel/dark, /area/gateway) "bNr" = ( -/obj/machinery/gateway{ - dir = 6 - }, /obj/effect/turf_decal/bot_white/right, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -46829,6 +46767,9 @@ /obj/effect/turf_decal/stripes/line{ dir = 5 }, +/obj/machinery/computer/gateway_control{ + dir = 8 + }, /turf/open/floor/plasteel, /area/gateway) "bOJ" = ( @@ -67172,8 +67113,7 @@ layer = 4; name = "Test Chamber Telescreen"; network = list("toxins"); - pixel_x = -32; - pixel_y = 0 + pixel_x = -32 }, /turf/open/floor/plasteel, /area/science/mixing) @@ -113599,8 +113539,8 @@ bDj bFb bGQ bGM -bJY -bLD +bNr +bLF bNp bOK bQu @@ -114113,7 +114053,7 @@ bDw bFd bGS bGM -bKa +bNp bLF bNr bOM diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm index a4315eb699..79d665b63c 100644 --- a/_maps/map_files/OmegaStation/OmegaStation.dmm +++ b/_maps/map_files/OmegaStation/OmegaStation.dmm @@ -4294,8 +4294,7 @@ department = "Head of Security's Desk"; departmentType = 5; name = "Head of Security RC"; - pixel_x = 30; - pixel_y = 0 + pixel_x = 30 }, /obj/machinery/computer/security/hos{ icon_state = "computer"; @@ -7141,8 +7140,7 @@ }, /obj/effect/turf_decal/tile/red, /obj/machinery/status_display{ - pixel_x = 32; - pixel_y = 0 + pixel_x = 32 }, /turf/open/floor/plasteel, /area/security/brig) @@ -13298,7 +13296,6 @@ dir = 9 }, /obj/machinery/computer/security/wooden_tv{ - pixel_x = 0; pixel_y = 4 }, /turf/open/floor/wood, diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm index ca155d6e94..be9812b1e9 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -22136,6 +22136,9 @@ /obj/item/kirbyplants{ icon_state = "plant-05" }, +/obj/machinery/light/small{ + dir = 1 + }, /turf/open/floor/plasteel/dark, /area/crew_quarters/bar) "aYZ" = ( diff --git a/_maps/map_files/Snaxi/Snaxi.dmm b/_maps/map_files/Snaxi/Snaxi.dmm index 2c0ee99d77..c8b76b4922 100644 --- a/_maps/map_files/Snaxi/Snaxi.dmm +++ b/_maps/map_files/Snaxi/Snaxi.dmm @@ -3545,8 +3545,8 @@ name = "supply dock loading door" }, /obj/machinery/conveyor{ - id = "QMLoad2"; - dir = 1 + dir = 1; + id = "QMLoad2" }, /turf/open/floor/plating, /area/quartermaster/storage) @@ -11666,6 +11666,9 @@ /obj/structure/disposalpipe/segment{ dir = 9 }, +/obj/machinery/computer/gateway_control{ + dir = 8 + }, /turf/open/floor/plasteel/dark, /area/teleporter) "eFy" = ( @@ -12398,8 +12401,8 @@ /area/bridge/meeting_room) "eZU" = ( /obj/machinery/conveyor{ - id = "QMLoad2"; - dir = 1 + dir = 1; + id = "QMLoad2" }, /turf/open/floor/plating, /area/quartermaster/storage) @@ -19924,7 +19927,6 @@ /obj/structure/cable{ icon_state = "0-2" }, -/obj/machinery/gateway, /obj/effect/turf_decal/bot_white, /turf/open/floor/plasteel/dark, /area/teleporter) @@ -20693,13 +20695,6 @@ }, /turf/open/floor/plasteel, /area/hallway/secondary/exit/departure_lounge) -"jPP" = ( -/obj/machinery/gateway{ - dir = 8 - }, -/obj/effect/turf_decal/bot_white, -/turf/open/floor/plasteel/dark, -/area/teleporter) "jQj" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable{ @@ -21094,8 +21089,8 @@ "kdM" = ( /obj/effect/turf_decal/stripes, /obj/machinery/conveyor{ - id = "QMLoad2"; - dir = 1 + dir = 1; + id = "QMLoad2" }, /turf/open/floor/plasteel, /area/quartermaster/storage) @@ -27641,9 +27636,6 @@ /turf/closed/wall, /area/quartermaster/sorting) "ohf" = ( -/obj/machinery/gateway{ - dir = 5 - }, /obj/effect/turf_decal/bot_white/left, /turf/open/floor/plasteel/dark, /area/teleporter) @@ -32098,8 +32090,8 @@ /area/hallway/secondary/exit/departure_lounge) "qGt" = ( /obj/structure/bodycontainer/crematorium{ - id = "crematoriumChapel"; - dir = 8 + dir = 8; + id = "crematoriumChapel" }, /obj/machinery/button/crematorium{ id = "crematoriumChapel"; @@ -35403,9 +35395,6 @@ /turf/open/floor/plating, /area/hallway/secondary/exit/departure_lounge) "sLr" = ( -/obj/machinery/gateway{ - dir = 6 - }, /obj/effect/turf_decal/bot_white/right, /obj/effect/turf_decal/stripes/corner{ dir = 1 @@ -36573,9 +36562,9 @@ /obj/effect/turf_decal/delivery, /obj/structure/table/reinforced, /obj/machinery/door/window/eastleft{ + dir = 8; name = "Hydroponics Desk"; - req_access_txt = "35"; - dir = 8 + req_access_txt = "35" }, /obj/machinery/door/firedoor/border_only{ dir = 8; @@ -39247,8 +39236,8 @@ name = "supply dock loading door" }, /obj/machinery/conveyor{ - id = "QMLoad2"; - dir = 1 + dir = 1; + id = "QMLoad2" }, /turf/open/floor/plating, /area/quartermaster/storage) @@ -39695,8 +39684,8 @@ /area/security/checkpoint/supply) "vgX" = ( /obj/machinery/conveyor{ - id = "QMLoad2"; - dir = 1 + dir = 1; + id = "QMLoad2" }, /turf/open/floor/plasteel, /area/quartermaster/storage) @@ -40096,9 +40085,6 @@ /turf/open/floor/plasteel, /area/engine/engineering) "vse" = ( -/obj/machinery/gateway{ - dir = 10 - }, /obj/machinery/light{ dir = 8 }, @@ -41638,13 +41624,6 @@ }, /turf/open/floor/engine, /area/engine/engineering) -"wie" = ( -/obj/machinery/gateway{ - dir = 1 - }, -/obj/effect/turf_decal/bot_white, -/turf/open/floor/plasteel/dark, -/area/teleporter) "wje" = ( /turf/open/floor/plasteel, /area/hallway/primary/port) @@ -42940,9 +42919,6 @@ /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors) "xcd" = ( -/obj/machinery/gateway{ - dir = 4 - }, /obj/effect/turf_decal/bot_white, /turf/open/floor/plasteel/dark, /area/teleporter) @@ -43874,9 +43850,6 @@ /turf/open/floor/plating/snowed/smoothed/icemoon, /area/engine/atmos) "xHk" = ( -/obj/machinery/gateway{ - dir = 9 - }, /obj/effect/turf_decal/bot_white/right, /turf/open/floor/plasteel/dark, /area/teleporter) @@ -56913,7 +56886,7 @@ avT avT gLH xHk -jPP +xcd vse mSs qQH @@ -57169,7 +57142,7 @@ bBh avT avT gLH -wie +xcd ePa jrR nTQ diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index c9e03389f1..2af331b777 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -108,6 +108,8 @@ #define TR_KEEPSE (1<<5) // changelings shouldn't edit the DNA's SE when turning into a monkey #define TR_DEFAULTMSG (1<<6) #define TR_KEEPORGANS (1<<8) +#define TR_KEEPREAGENTS (1<<10) +#define TR_KEEPSTUNS (1<<9) #define CLONER_FRESH_CLONE "fresh" @@ -184,4 +186,4 @@ #define G_MALE 1 #define G_FEMALE 2 #define G_PLURAL 3 -#define G_NEUTER 4 \ No newline at end of file +#define G_NEUTER 4 diff --git a/code/__DEFINES/_flags/_flags.dm b/code/__DEFINES/_flags/_flags.dm index 7daf9fa8a3..3a31eebb19 100644 --- a/code/__DEFINES/_flags/_flags.dm +++ b/code/__DEFINES/_flags/_flags.dm @@ -142,6 +142,10 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 /// The attack is from a parry counterattack. #define ATTACKCHAIN_PARRY_COUNTERATTACK (1<<0) +// UnarmedAttack() flags +/// Attack is from a parry counterattack +#define UNARMED_ATTACK_PARRY (1<<0) + /// If the thing can reflect light (lasers/energy) #define RICOCHET_SHINY (1<<0) /// If the thing can reflect matter (bullets/bomb shrapnel) diff --git a/code/__DEFINES/flags/do_after.dm b/code/__DEFINES/_flags/do_after.dm similarity index 100% rename from code/__DEFINES/flags/do_after.dm rename to code/__DEFINES/_flags/do_after.dm diff --git a/code/__DEFINES/flags/shields.dm b/code/__DEFINES/_flags/shields.dm similarity index 100% rename from code/__DEFINES/flags/shields.dm rename to code/__DEFINES/_flags/shields.dm diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index e8e75c132a..054a8e36eb 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -74,6 +74,7 @@ #define ADMIN_PUNISHMENT_MAZING "Puzzle" #define ADMIN_PUNISHMENT_PIE "Cream Pie" #define ADMIN_PUNISHMENT_CUSTOM_PIE "Custom Cream Pie" +#define ADMIN_PUNISHMENT_PICKLE "Pickle-ify" #define AHELP_ACTIVE 1 #define AHELP_CLOSED 2 diff --git a/code/__DEFINES/chemistry/reactions.dm b/code/__DEFINES/chemistry/reactions.dm new file mode 100644 index 0000000000..0deadcbfe0 --- /dev/null +++ b/code/__DEFINES/chemistry/reactions.dm @@ -0,0 +1,4 @@ +// Reaction priorities, higher makes it checked first. Otherwise, it goes based on reaction temperature requirements. + +#define CHEMICAL_REACTION_PRIORITY_DEFAULT 100 +#define CHEMICAL_REACTION_PRIORITY_SMOKE 1000 diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 5c28694005..1882effe38 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -32,6 +32,8 @@ #define COMSIG_ELEMENT_DETACH "element_detach" // /atom signals +//from base of atom/proc/Initialize(): sent any time a new atom is created +#define COMSIG_ATOM_CREATED "atom_created" #define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params) #define COMPONENT_NO_AFTERATTACK 1 //Return this in response if you don't want afterattack to be called #define COMSIG_ATOM_HULK_ATTACK "hulk_attack" //from base of atom/attack_hulk(): (/mob/living/carbon/human) diff --git a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm index 7e1559cede..71de692410 100644 --- a/code/__DEFINES/logging.dm +++ b/code/__DEFINES/logging.dm @@ -38,6 +38,7 @@ #define LOG_ADMIN_PRIVATE (1 << 14) #define LOG_ASAY (1 << 15) #define LOG_VIRUS (1 << 16) +#define LOG_SHUTTLE (1 << 18) //Individual logging panel pages #define INDIVIDUAL_ATTACK_LOG (LOG_ATTACK) diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 2ec21c83b3..071dab20b1 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -534,3 +534,5 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S #define LOOT_RESTRICTION_CKEY 2 #define LOOT_RESTRICTION_MIND_PILE 3 //limited to the current pile. #define LOOT_RESTRICTION_CKEY_PILE 4 //Idem + +#define WANTED_FILE "wanted_message.json" diff --git a/code/__DEFINES/rust_g.dm b/code/__DEFINES/rust_g.dm index aeacdb7c51..20e7975ec4 100644 --- a/code/__DEFINES/rust_g.dm +++ b/code/__DEFINES/rust_g.dm @@ -6,7 +6,7 @@ #define RUSTG_JOB_ERROR "JOB PANICKED" #define rustg_dmi_strip_metadata(fname) call(RUST_G, "dmi_strip_metadata")(fname) -#define rustg_dmi_create_png(fname,width,height,data) call(RUST_G, "dmi_create_png")(fname,width,height,data) +#define rustg_dmi_create_png(path, width, height, data) call(RUST_G, "dmi_create_png")(path, width, height, data) #define rustg_git_revparse(rev) call(RUST_G, "rg_git_revparse")(rev) #define rustg_git_commit_date(rev) call(RUST_G, "rg_git_commit_date")(rev) @@ -14,14 +14,12 @@ #define rustg_log_write(fname, text, format) call(RUST_G, "log_write")(fname, text, format) /proc/rustg_log_close_all() return call(RUST_G, "log_close_all")() -// RUST-G defines & procs for HTTP component #define RUSTG_HTTP_METHOD_GET "get" -#define RUSTG_HTTP_METHOD_POST "post" #define RUSTG_HTTP_METHOD_PUT "put" #define RUSTG_HTTP_METHOD_DELETE "delete" #define RUSTG_HTTP_METHOD_PATCH "patch" #define RUSTG_HTTP_METHOD_HEAD "head" - +#define RUSTG_HTTP_METHOD_POST "post" #define rustg_http_request_blocking(method, url, body, headers) call(RUST_G, "http_request_blocking")(method, url, body, headers) #define rustg_http_request_async(method, url, body, headers) call(RUST_G, "http_request_async")(method, url, body, headers) #define rustg_http_check_request(req_id) call(RUST_G, "http_check_request")(req_id) diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index 889e1bb1c0..101330cc8b 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -76,6 +76,13 @@ #define VV_HK_ADDCOMPONENT "addcomponent" #define VV_HK_MODIFY_TRAITS "modtraits" +// /datum/gas_mixture +#define VV_HK_SET_MOLES "set_moles" +#define VV_HK_EMPTY "empty" +#define VV_HK_SET_TEMPERATURE "set_temp" +#define VV_HK_PARSE_GASSTRING "parse_gasstring" +#define VV_HK_SET_VOLUME "set_volume" + // /atom #define VV_HK_MODIFY_TRANSFORM "atom_transform" #define VV_HK_ADD_REAGENT "addreagent" diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm index 1935dcc8a5..84709a78b1 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/_logging.dm @@ -118,6 +118,9 @@ //reusing the PDA option because I really don't think news comments are worth a config option WRITE_LOG(GLOB.world_pda_log, "COMMENT: [text]") +/proc/log_paper(text) + WRITE_LOG(GLOB.world_paper_log, "PAPER: [text]") + /proc/log_telecomms(text) if (CONFIG_GET(flag/log_telecomms)) WRITE_LOG(GLOB.world_telecomms_log, "TCOMMS: [text]") @@ -131,6 +134,10 @@ if (CONFIG_GET(flag/log_vote)) WRITE_LOG(GLOB.world_game_log, "VOTE: [text]") +/proc/log_shuttle(text) + if (CONFIG_GET(flag/log_shuttle)) + WRITE_LOG(GLOB.world_shuttle_log, "SHUTTLE: [text]") + /proc/log_craft(text) if (CONFIG_GET(flag/log_craft)) WRITE_LOG(GLOB.world_crafting_log, "CRAFT: [text]") diff --git a/code/__HELPERS/_string_lists.dm b/code/__HELPERS/_string_lists.dm index 7d694c1844..43d45594e0 100644 --- a/code/__HELPERS/_string_lists.dm +++ b/code/__HELPERS/_string_lists.dm @@ -1,4 +1,5 @@ #define pick_list(FILE, KEY) (pick(strings(FILE, KEY))) +#define pick_list_weighted(FILE, KEY) (pickweight(strings(FILE, KEY))) #define pick_list_replacements(FILE, KEY) (strings_replacement(FILE, KEY)) #define json_load(FILE) (json_decode(file2text(FILE))) diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index dce4d554b7..0825e51ae4 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -125,3 +125,11 @@ GLOBAL_VAR_INIT(cmp_field, "name") if(A.ui_category == B.ui_category) return sorttext(A.name, B.name) return sorttext(A.ui_category, B.ui_category) + +/proc/cmp_chemical_reactions_default(datum/chemical_reaction/A, datum/chemical_reaction/B) + if(A.priority != B.priority) + return B.priority - A.priority + else if(A.is_cold_recipe) + return A.required_temp - B.required_temp //return coldest + else + return B.required_temp - A.required_temp //return hottest diff --git a/code/__HELPERS/dna.dm b/code/__HELPERS/dna.dm index bb0c89d1f3..b74dacdc09 100644 --- a/code/__HELPERS/dna.dm +++ b/code/__HELPERS/dna.dm @@ -5,8 +5,9 @@ #define GET_INITIALIZED_MUTATION(A) GLOB.all_mutations[A] #define GET_GENE_STRING(A, B) (B.mutation_index[A]) #define GET_SEQUENCE(A) (GLOB.full_sequences[A]) +#define GET_MUTATION_TYPE_FROM_ALIAS(A) (GLOB.alias_mutations[A]) #define GET_MUTATION_STABILIZER(A) ((A.stabilizer_coeff < 0) ? 1 : A.stabilizer_coeff) #define GET_MUTATION_SYNCHRONIZER(A) ((A.synchronizer_coeff < 0) ? 1 : A.synchronizer_coeff) #define GET_MUTATION_POWER(A) ((A.power_coeff < 0) ? 1 : A.power_coeff) -#define GET_MUTATION_ENERGY(A) ((A.energy_coeff < 0) ? 1 : A.energy_coeff) \ No newline at end of file +#define GET_MUTATION_ENERGY(A) ((A.energy_coeff < 0) ? 1 : A.energy_coeff) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 8d7941fdf8..b9f180ac4a 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -53,6 +53,27 @@ for(var/I in adjacent_turfs) . |= get_area(I) +/** + * Get a bounding box of a list of atoms. + * + * Arguments: + * - atoms - List of atoms. Can accept output of view() and range() procs. + * + * Returns: list(x1, y1, x2, y2) + */ +/proc/get_bbox_of_atoms(list/atoms) + var/list/list_x = list() + var/list/list_y = list() + for(var/_a in atoms) + var/atom/a = _a + list_x += a.x + list_y += a.y + return list( + min(list_x), + min(list_y), + max(list_x), + max(list_y)) + // Like view but bypasses luminosity check /proc/get_hear(range, atom/source) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 0b5c60a95a..d66e83d651 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -90,7 +90,6 @@ init_subtypes(/datum/crafting_recipe, GLOB.crafting_recipes) INVOKE_ASYNC(GLOBAL_PROC, /proc/init_ref_coin_values) //so the current procedure doesn't sleep because of UNTIL() - INVOKE_ASYNC(GLOBAL_PROC, /proc/setupGenetics) //creates every subtype of prototype (excluding prototype) and adds it to list L. //if no list/L is provided, one is created. @@ -117,24 +116,3 @@ GLOB.coin_values[path] = C.value qdel(C) -/proc/setupGenetics() - var/list/mutations = subtypesof(/datum/mutation/human) - shuffle_inplace(mutations) - for(var/A in subtypesof(/datum/generecipe)) - var/datum/generecipe/GR = A - GLOB.mutation_recipes[initial(GR.required)] = initial(GR.result) - for(var/i in 1 to LAZYLEN(mutations)) - var/path = mutations[i] //byond gets pissy when we do it in one line - var/datum/mutation/human/B = new path () - B.alias = "Mutation #[i]" - GLOB.all_mutations[B.type] = B - GLOB.full_sequences[B.type] = generate_gene_sequence(B.blocks) - if(B.locked) - continue - if(B.quality == POSITIVE) - GLOB.good_mutations |= B - else if(B.quality == NEGATIVE) - GLOB.bad_mutations |= B - else if(B.quality == MINOR_NEGATIVE) - GLOB.not_good_mutations |= B - CHECK_TICK \ No newline at end of file diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 337d44aa1e..cbe004ed90 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1509,6 +1509,8 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) set waitfor = FALSE return call(source, proctype)(arglist(arguments)) +#define TURF_FROM_COORDS_LIST(List) (locate(List[1], List[2], List[3])) + /proc/num2sign(numeric) if(numeric > 0) return 1 diff --git a/code/_globalvars/genetics.dm b/code/_globalvars/genetics.dm index 39702fd62f..cebeab7a78 100644 --- a/code/_globalvars/genetics.dm +++ b/code/_globalvars/genetics.dm @@ -27,5 +27,6 @@ GLOBAL_LIST_EMPTY(full_sequences) GLOBAL_LIST_EMPTY(bad_mutations) GLOBAL_LIST_EMPTY(good_mutations) GLOBAL_LIST_EMPTY(not_good_mutations) +GLOBAL_LIST_EMPTY(alias_mutations) //alias = type -GLOBAL_LIST_EMPTY(mutation_recipes) \ No newline at end of file +GLOBAL_LIST_EMPTY(mutation_recipes) diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index 4c912b9c1e..a25381f266 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -116,15 +116,16 @@ GLOBAL_LIST_INIT(ai_core_display_screens, list( GLOBAL_LIST_INIT(security_depts_prefs, list(SEC_DEPT_RANDOM, SEC_DEPT_NONE, SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY)) - //Backpacks -#define GBACKPACK "Grey Backpack" -#define GSATCHEL "Grey Satchel" -#define GDUFFELBAG "Grey Duffel Bag" -#define LSATCHEL "Leather Satchel" +//Backpacks #define DBACKPACK "Department Backpack" #define DSATCHEL "Department Satchel" #define DDUFFELBAG "Department Duffel Bag" -GLOBAL_LIST_INIT(backbaglist, list(DBACKPACK, DSATCHEL, DDUFFELBAG, GBACKPACK, GSATCHEL, GDUFFELBAG, LSATCHEL)) +GLOBAL_LIST_INIT(backbaglist, list(DBACKPACK, DSATCHEL, DDUFFELBAG, //everything after this point is a non-department backpack + "Grey Backpack" = /obj/item/storage/backpack, + "Grey Satchel" = /obj/item/storage/backpack/satchel, + "Grey Duffel Bag" = /obj/item/storage/backpack/duffelbag, + "Leather Satchel" = /obj/item/storage/backpack/satchel/leather, + "Snail Shell" = /obj/item/storage/backpack/snail)) //Suit/Skirt #define PREF_SUIT "Jumpsuit" diff --git a/code/_globalvars/lists/mapping.dm b/code/_globalvars/lists/mapping.dm index d214ec94ef..94b0338412 100644 --- a/code/_globalvars/lists/mapping.dm +++ b/code/_globalvars/lists/mapping.dm @@ -38,8 +38,7 @@ GLOBAL_LIST_EMPTY(servant_spawns) //Servants of Ratvar spawn here GLOBAL_LIST_EMPTY(city_of_cogs_spawns) //Anyone entering the City of Cogs spawns here GLOBAL_LIST_EMPTY(ruin_landmarks) - //away missions -GLOBAL_LIST_EMPTY(awaydestinations) //a list of landmarks that the warpgate can take you to +//away missions GLOBAL_LIST_EMPTY(vr_spawnpoints) //used by jump-to-area etc. Updated by area/updateName() diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 959a62ebf8..134f9d9cbe 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -23,6 +23,7 @@ GLOBAL_LIST_EMPTY(joined_player_list) //all clients that have joined the game a GLOBAL_LIST_EMPTY(silicon_mobs) //all silicon mobs GLOBAL_LIST_EMPTY(mob_living_list) //all instances of /mob/living and subtypes GLOBAL_LIST_EMPTY(carbon_list) //all instances of /mob/living/carbon and subtypes, notably does not contain brains or simple animals +GLOBAL_LIST_EMPTY(human_list) //all instances of /mob/living/carbon/human and subtypes GLOBAL_LIST_EMPTY(ai_list) GLOBAL_LIST_EMPTY(pai_list) GLOBAL_LIST_EMPTY(available_ai_shells) diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm index 3bce9c560a..e9f98f836e 100644 --- a/code/_globalvars/logging.dm +++ b/code/_globalvars/logging.dm @@ -32,6 +32,8 @@ GLOBAL_VAR(world_asset_log) GLOBAL_PROTECT(world_asset_log) GLOBAL_VAR(world_map_error_log) GLOBAL_PROTECT(world_map_error_log) +GLOBAL_VAR(world_paper_log) +GLOBAL_PROTECT(world_paper_log) GLOBAL_VAR(subsystem_log) GLOBAL_PROTECT(subsystem_log) GLOBAL_VAR(reagent_log) @@ -49,10 +51,10 @@ GLOBAL_LIST_EMPTY(lastsignalers) //keeps last 100 signals here in format: "[src] GLOBAL_PROTECT(lastsignalers) GLOBAL_LIST_EMPTY(lawchanges) //Stores who uploaded laws to which silicon-based lifeform, and what the law was GLOBAL_PROTECT(lawchanges) - GLOBAL_VAR(tgui_log) GLOBAL_PROTECT(tgui_log) - +GLOBAL_VAR(world_shuttle_log) +GLOBAL_PROTECT(world_shuttle_log) GLOBAL_LIST_EMPTY(combatlog) GLOBAL_PROTECT(combatlog) GLOBAL_LIST_EMPTY(IClog) diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index 79058f7b19..0699915859 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -90,8 +90,9 @@ The below is only really for safety, or you can alter the way it functions and re-insert it above. */ -/mob/living/silicon/ai/UnarmedAttack(atom/A) +/mob/living/silicon/ai/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) A.attack_ai(src) + /mob/living/silicon/ai/RangedAttack(atom/A) A.attack_ai(src) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index c909ce03d8..45fc2187e6 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -237,9 +237,9 @@ proximity_flag is not currently passed to attack_hand, and is instead used in human click code to allow glove touches only at melee range. */ -/mob/proc/UnarmedAttack(atom/A, proximity_flag) - DelayNextAction(ismob(A)? 8 : 0) - return +/mob/proc/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) + if(ismob(A)) + changeNext_move(CLICK_CD_MELEE) /* Ranged unarmed attack: diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index c9e53fc10e..49941237f6 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -171,8 +171,9 @@ clicks, you can do so here, but you will have to change attack_robot() above to the proper function */ -/mob/living/silicon/robot/UnarmedAttack(atom/A) +/mob/living/silicon/robot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) A.attack_robot(src) + /mob/living/silicon/robot/RangedAttack(atom/A) A.attack_robot(src) diff --git a/code/_onclick/hud/map_popups.dm b/code/_onclick/hud/map_popups.dm new file mode 100644 index 0000000000..777ebb0718 --- /dev/null +++ b/code/_onclick/hud/map_popups.dm @@ -0,0 +1,165 @@ +/client + /** + * Assoc list with all the active maps - when a screen obj is added to + * a map, it's put in here as well. + * + * Format: list( = list(/obj/screen)) + */ + var/list/screen_maps = list() + +/** + * A screen object, which acts as a container for turfs and other things + * you want to show on the map, which you usually attach to "vis_contents". + */ +/obj/screen + /** + * Map name assigned to this object. + * Automatically set by /client/proc/add_obj_to_map. + */ + var/assigned_map + /** + * Mark this object as garbage-collectible after you clean the map + * it was registered on. + * + * This could probably be changed to be a proc, for conditional removal. + * But for now, this works. + */ + var/del_on_map_removal = TRUE + +/** + * A generic background object. + * It is also implicitly used to allocate a rectangle on the map, which will + * be used for auto-scaling the map. + */ +/obj/screen/background + name = "background" + icon = 'icons/mob/map_backgrounds.dmi' + icon_state = "clear" + layer = GAME_PLANE + plane = GAME_PLANE + +/** + * Sets screen_loc of this screen object, in form of point coordinates, + * with optional pixel offset (px, py). + * + * If applicable, "assigned_map" has to be assigned before this proc call. + */ +/obj/screen/proc/set_position(x, y, px = 0, py = 0) + if(assigned_map) + screen_loc = "[assigned_map]:[x]:[px],[y]:[py]" + else + screen_loc = "[x]:[px],[y]:[py]" + +/** + * Sets screen_loc to fill a rectangular area of the map. + * + * If applicable, "assigned_map" has to be assigned before this proc call. + */ +/obj/screen/proc/fill_rect(x1, y1, x2, y2) + if(assigned_map) + screen_loc = "[assigned_map]:[x1],[y1] to [x2],[y2]" + else + screen_loc = "[x1],[y1] to [x2],[y2]" + +/** + * Registers screen obj with the client, which makes it visible on the + * assigned map, and becomes a part of the assigned map's lifecycle. + */ +/client/proc/register_map_obj(obj/screen/screen_obj) + if(!screen_obj.assigned_map) + CRASH("Can't register [screen_obj] without 'assigned_map' property.") + if(!screen_maps[screen_obj.assigned_map]) + screen_maps[screen_obj.assigned_map] = list() + // NOTE: Possibly an expensive operation + var/list/screen_map = screen_maps[screen_obj.assigned_map] + if(!screen_map.Find(screen_obj)) + screen_map += screen_obj + if(!screen.Find(screen_obj)) + screen += screen_obj + +/** + * Clears the map of registered screen objects. + * + * Not really needed most of the time, as the client's screen list gets reset + * on relog. any of the buttons are going to get caught by garbage collection + * anyway. they're effectively qdel'd. + */ +/client/proc/clear_map(map_name) + if(!map_name || !(map_name in screen_maps)) + return FALSE + for(var/obj/screen/screen_obj in screen_maps[map_name]) + screen_maps[map_name] -= screen_obj + if(screen_obj.del_on_map_removal) + qdel(screen_obj) + screen_maps -= map_name + +/** + * Clears all the maps of registered screen objects. + */ +/client/proc/clear_all_maps() + for(var/map_name in screen_maps) + clear_map(map_name) + +/** + * Creates a popup window with a basic map element in it, without any + * further initialization. + * + * Ratio is how many pixels by how many pixels (keep it simple). + * + * Returns a map name. + */ +/client/proc/create_popup(name, ratiox = 100, ratioy = 100) + winclone(src, "popupwindow", name) + var/list/winparams = list() + winparams["size"] = "[ratiox]x[ratioy]" + winparams["on-close"] = "handle-popup-close [name]" + winset(src, "[name]", list2params(winparams)) + winshow(src, "[name]", 1) + + var/list/params = list() + params["parent"] = "[name]" + params["type"] = "map" + params["size"] = "[ratiox]x[ratioy]" + params["anchor1"] = "0,0" + params["anchor2"] = "[ratiox],[ratioy]" + winset(src, "[name]_map", list2params(params)) + + return "[name]_map" + +/** + * Create the popup, and get it ready for generic use by giving + * it a background. + * + * Width and height are multiplied by 64 by default. + */ +/client/proc/setup_popup(popup_name, width = 9, height = 9, \ + tilesize = 2, bg_icon) + if(!popup_name) + return + clear_map("[popup_name]_map") + var/x_value = world.icon_size * tilesize * width + var/y_value = world.icon_size * tilesize * height + var/map_name = create_popup(popup_name, x_value, y_value) + + var/obj/screen/background/background = new + background.assigned_map = map_name + background.fill_rect(1, 1, width, height) + if(bg_icon) + background.icon_state = bg_icon + register_map_obj(background) + + return map_name + +/** + * Closes a popup. + */ +/client/proc/close_popup(popup) + winshow(src, popup, 0) + handle_popup_close(popup) + +/** + * When the popup closes in any way (player or proc call) it calls this. + */ +/client/verb/handle_popup_close(window_id as text) + set hidden = TRUE + clear_map("[window_id]_map") diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index 9f9870a9e5..ed7384697c 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -63,18 +63,9 @@ // And here are some good things for free: // Now you can click through portals, wormholes, gateways, and teleporters while observing. -Sayu -/obj/machinery/gateway/centerstation/attack_ghost(mob/user) - if(awaygate) - user.forceMove(awaygate.loc) - else - to_chat(user, "[src] has no destination.") - return ..() - -/obj/machinery/gateway/centeraway/attack_ghost(mob/user) - if(stationgate) - user.forceMove(stationgate.loc) - else - to_chat(user, "[src] has no destination.") +/obj/effect/gateway_portal_bumper/attack_ghost(mob/user) + if(gateway) + gateway.Transfer(user) return ..() /obj/machinery/teleport/hub/attack_ghost(mob/user) diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index 7e74dc0e71..ae10358b66 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -4,7 +4,7 @@ Otherwise pretty standard. */ -/mob/living/carbon/human/UnarmedAttack(atom/A, proximity) +/mob/living/carbon/human/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) if(!has_active_hand()) //can't attack without a hand. to_chat(src, "You look at your arm and sigh.") @@ -20,21 +20,16 @@ var/override = 0 for(var/datum/mutation/human/HM in dna.mutations) - override += HM.on_attack_hand(A, proximity) + override += HM.on_attack_hand(A, proximity, intent, flags) if(override) return SEND_SIGNAL(src, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, A) - if(!CheckActionCooldown(A.clickdelay_attack_hand_preattack_cooldown)) - if(A.clickdelay_attack_hand_is_action && A.clickdelay_attack_hand_set_preattack) - DelayNextAction() - A.attack_hand(src) - if(A.clickdelay_attack_hand_is_action && !A.clickdelay_attack_hand_set_preattack) - DelayNextAction() + A.attack_hand(src, intent, flags) //Return TRUE to cancel other attack hand effects that respect it. -/atom/proc/attack_hand(mob/user) +/atom/proc/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = FALSE if(!(interaction_flags_atom & INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND)) add_fingerprint(user) @@ -109,8 +104,8 @@ /* Animals & All Unspecified */ -/mob/living/UnarmedAttack(atom/A) - A.attack_animal(src) +/mob/living/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) + A.attack_animal(src, intent, flags) /atom/proc/attack_animal(mob/user) SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_ANIMAL, user) @@ -121,8 +116,8 @@ /* Monkeys */ -/mob/living/carbon/monkey/UnarmedAttack(atom/A) - A.attack_paw(src) +/mob/living/carbon/monkey/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) + A.attack_paw(src, intent, flags) /atom/proc/attack_paw(mob/user) if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_PAW, user) & COMPONENT_NO_ATTACK_HAND) @@ -167,8 +162,8 @@ Aliens Defaults to same as monkey in most places */ -/mob/living/carbon/alien/UnarmedAttack(atom/A) - A.attack_alien(src) +/mob/living/carbon/alien/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) + A.attack_alien(src, intent, flags) /atom/proc/attack_alien(mob/living/carbon/alien/user) attack_paw(user) @@ -178,29 +173,29 @@ return // Babby aliens -/mob/living/carbon/alien/larva/UnarmedAttack(atom/A) - A.attack_larva(src) +/mob/living/carbon/alien/larva/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) + A.attack_larva(src, intent, flags) + /atom/proc/attack_larva(mob/user) return - /* Slimes Nothing happening here */ -/mob/living/simple_animal/slime/UnarmedAttack(atom/A) - A.attack_slime(src) +/mob/living/simple_animal/slime/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) + A.attack_slime(src, intent, flags) + /atom/proc/attack_slime(mob/user) return /mob/living/simple_animal/slime/RestrainedClickOn(atom/A) return - /* Drones */ -/mob/living/simple_animal/drone/UnarmedAttack(atom/A) - A.attack_drone(src) +/mob/living/simple_animal/drone/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) + A.attack_drone(src, intent, flags) /atom/proc/attack_drone(mob/living/simple_animal/drone/user) attack_hand(user) //defaults to attack_hand. Override it when you don't want drones to do same stuff as humans. @@ -208,55 +203,44 @@ /mob/living/simple_animal/slime/RestrainedClickOn(atom/A) return - /* True Devil */ - -/mob/living/carbon/true_devil/UnarmedAttack(atom/A, proximity) +/mob/living/carbon/true_devil/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) A.attack_hand(src) /* Brain */ - -/mob/living/brain/UnarmedAttack(atom/A)//Stops runtimes due to attack_animal being the default +/mob/living/brain/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) return - /* pAI */ - -/mob/living/silicon/pai/UnarmedAttack(atom/A)//Stops runtimes due to attack_animal being the default +/mob/living/silicon/pai/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) return - /* Simple animals */ - -/mob/living/simple_animal/UnarmedAttack(atom/A, proximity) +/mob/living/simple_animal/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) if(!dextrous) return ..() if(!ismob(A)) - A.attack_hand(src) + A.attack_hand(src, intent, flags) update_inv_hands() - /* Hostile animals */ - -/mob/living/simple_animal/hostile/UnarmedAttack(atom/A) +/mob/living/simple_animal/hostile/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) target = A if(dextrous && !ismob(A)) ..() else AttackingTarget() - - /* New Players: Have no reason to click on anything at all. diff --git a/code/controllers/configuration/config_entry.dm b/code/controllers/configuration/config_entry.dm index 7e8b1c8f38..259082a6ba 100644 --- a/code/controllers/configuration/config_entry.dm +++ b/code/controllers/configuration/config_entry.dm @@ -83,7 +83,7 @@ var/auto_trim = TRUE /datum/config_entry/string/vv_edit_var(var_name, var_value) - return var_name != "auto_trim" && ..() + return var_name != NAMEOF(src, auto_trim) && ..() /datum/config_entry/string/ValidateAndSet(str_val, during_load) if(!VASProcCallGuard(str_val)) @@ -110,7 +110,7 @@ return FALSE /datum/config_entry/number/vv_edit_var(var_name, var_value) - var/static/list/banned_edits = list("max_val", "min_val", "integer") + var/static/list/banned_edits = list(NAMEOF(src, max_val), NAMEOF(src, min_val), NAMEOF(src, integer)) return !(var_name in banned_edits) && ..() /datum/config_entry/flag @@ -216,7 +216,7 @@ return FALSE /datum/config_entry/keyed_list/vv_edit_var(var_name, var_value) - return var_name != "splitter" && ..() + return var_name != NAMEOF(src, splitter) && ..() /datum/config_entry/keyed_list/proc/preprocess_key(key) return key diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index a1f8f098d3..1be413f065 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -56,6 +56,8 @@ /datum/config_entry/flag/log_adminchat // log admin chat messages protection = CONFIG_ENTRY_LOCKED +/datum/config_entry/flag/log_shuttle // log shuttle related actions, ie shuttle computers, shuttle manipulator, emergency console + /datum/config_entry/flag/log_pda // log pda messages /datum/config_entry/flag/log_telecomms // log telecomms messages diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index a16de2ba4c..4ee3a01956 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -210,10 +210,10 @@ /datum/controller/subsystem/vv_edit_var(var_name, var_value) switch (var_name) - if ("can_fire") + if (NAMEOF(src, can_fire)) //this is so the subsystem doesn't rapid fire to make up missed ticks causing more lag if (var_value) next_fire = world.time + wait - if ("queued_priority") //editing this breaks things. - return 0 + if (NAMEOF(src, queued_priority)) //editing this breaks things. + return FALSE . = ..() diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm index c1644df9c9..db1fced637 100644 --- a/code/controllers/subsystem/atoms.dm +++ b/code/controllers/subsystem/atoms.dm @@ -16,6 +16,7 @@ SUBSYSTEM_DEF(atoms) /datum/controller/subsystem/atoms/Initialize(timeofday) GLOB.fire_overlay.appearance_flags = RESET_COLOR + setupGenetics() initialized = INITIALIZATION_INNEW_MAPLOAD InitializeAtoms() return ..() @@ -106,6 +107,29 @@ SUBSYSTEM_DEF(atoms) old_initialized = SSatoms.old_initialized BadInitializeCalls = SSatoms.BadInitializeCalls +/datum/controller/subsystem/atoms/proc/setupGenetics() + var/list/mutations = subtypesof(/datum/mutation/human) + shuffle_inplace(mutations) + for(var/A in subtypesof(/datum/generecipe)) + var/datum/generecipe/GR = A + GLOB.mutation_recipes[initial(GR.required)] = initial(GR.result) + for(var/i in 1 to LAZYLEN(mutations)) + var/path = mutations[i] //byond gets pissy when we do it in one line + var/datum/mutation/human/B = new path () + B.alias = "Mutation [i]" + GLOB.all_mutations[B.type] = B + GLOB.full_sequences[B.type] = generate_gene_sequence(B.blocks) + GLOB.alias_mutations[B.alias] = B.type + if(B.locked) + continue + if(B.quality == POSITIVE) + GLOB.good_mutations |= B + else if(B.quality == NEGATIVE) + GLOB.bad_mutations |= B + else if(B.quality == MINOR_NEGATIVE) + GLOB.not_good_mutations |= B + CHECK_TICK + /datum/controller/subsystem/atoms/proc/InitLog() . = "" for(var/path in BadInitializeCalls) diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm index d6991a40b4..dc1f246e3d 100644 --- a/code/controllers/subsystem/blackbox.dm +++ b/code/controllers/subsystem/blackbox.dm @@ -60,9 +60,9 @@ SUBSYSTEM_DEF(blackbox) /datum/controller/subsystem/blackbox/vv_edit_var(var_name, var_value) switch(var_name) - if("feedback") + if(NAMEOF(src, feedback)) return FALSE - if("sealed") + if(NAMEOF(src, sealed)) if(var_value) return Seal() return FALSE diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index b234c4c4f2..ac2afa7cae 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -334,6 +334,7 @@ GLOBAL_LIST_EMPTY(the_station_areas) for (var/map in mapvotes) if (!map) mapvotes.Remove(map) + continue if (!(map in global.config.maplist)) mapvotes.Remove(map) continue @@ -468,9 +469,9 @@ GLOBAL_LIST_EMPTY(the_station_areas) else return - possible_options += "Custom" - var/lvl_name - var/datum/space_level/level + possible_options = "Custom" + var/away_name + var/datum/space_level/away_level var/answer = input("What kind ? ","Away/VR") as null|anything in possible_options switch(answer) @@ -480,34 +481,22 @@ GLOBAL_LIST_EMPTY(the_station_areas) var/mapfile = input("Pick file:", "File") as null|file if(!mapfile) return - lvl_name = "[mapfile] custom" - to_chat(usr,"Loading [lvl_name]...") + away_name = "[mapfile] custom" + to_chat(usr,"Loading [away_name]...") var/datum/map_template/template = new(mapfile, choice, ztraits) - level = template.load_new_z(ztraits) + away_level = template.load_new_z(ztraits) else - lvl_name = answer - to_chat(usr,"Loading [lvl_name]...") - var/datum/map_template/template = new(lvl_name, choice) - level = template.load_new_z(ztraits) + away_name = answer + to_chat(usr,"Loading [away_name]...") + var/datum/map_template/template = new(away_name, choice) + away_level = template.load_new_z(ztraits) - message_admins("Admin [key_name_admin(usr)] has loaded [lvl_name] [choice].") - log_admin("Admin [key_name(usr)] has loaded [lvl_name] [choice].") - if(!level) - message_admins("Loading [lvl_name] failed!") + message_admins("Admin [key_name_admin(usr)] has loaded [away_name] away mission.") + log_admin("Admin [key_name(usr)] has loaded [away_name] away mission.") + if(!away_level) + message_admins("Loading [away_name] failed!") return - - if(choice == AWAY_MISSION_NAME && GLOB.the_gateway) - //Link any found away gate with station gate - var/obj/machinery/gateway/centeraway/new_gate - for(var/obj/machinery/gateway/centeraway/G in GLOB.machines) - if(G.z == level.z_value) //I'll have to refactor gateway shitcode before multi-away support. - new_gate = G - break - //Link station gate with away gate and remove wait time. - GLOB.the_gateway.awaygate = new_gate - GLOB.the_gateway.wait = world.time - /datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override, border_type_override) UNTIL((!z || reservation_ready["[z]"]) && !clearing_reserved_turfs) var/datum/turf_reservation/reserve = new type diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 532eb19bc9..9bda1cd233 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -7,10 +7,9 @@ SUBSYSTEM_DEF(shuttle) flags = SS_KEEP_TIMING|SS_NO_TICK_CHECK runlevels = RUNLEVEL_SETUP | RUNLEVEL_GAME - var/obj/machinery/shuttle_manipulator/manipulator - var/list/mobile = list() var/list/stationary = list() + var/list/beacons = list() var/list/transit = list() var/list/transit_requesters = list() @@ -57,6 +56,15 @@ SUBSYSTEM_DEF(shuttle) var/realtimeofstart = 0 + var/datum/map_template/shuttle/selected + + var/obj/docking_port/mobile/existing_shuttle + + var/obj/docking_port/mobile/preview_shuttle + var/datum/map_template/shuttle/preview_template + + var/datum/turf_reservation/preview_reservation + /datum/controller/subsystem/shuttle/Initialize(timeofday) ordernum = rand(1, 9000) @@ -76,13 +84,10 @@ SUBSYSTEM_DEF(shuttle) WARNING("No /obj/docking_port/mobile/emergency/backup placed on the map!") if(!supply) WARNING("No /obj/docking_port/mobile/supply placed on the map!") - realtimeofstart = world.realtime + realtimeofstart = world.realtime return ..() /datum/controller/subsystem/shuttle/proc/initial_load() - if(!istype(manipulator)) - CRASH("No shuttle manipulator found.") - for(var/s in stationary) var/obj/docking_port/stationary/S = s S.load_roundstart() @@ -143,11 +148,13 @@ SUBSYSTEM_DEF(shuttle) ++alive var/total = GLOB.joined_player_list.len + if(total <= 0) + return //no players no autoevac if(alive / total <= threshold) - var/msg = "Automatically dispatching shuttle due to crew death." + var/msg = "Automatically dispatching emergency shuttle due to crew death." message_admins(msg) - log_game("[msg] Alive: [alive], Roundstart: [total], Threshold: [threshold]") + log_shuttle("[msg] Alive: [alive], Roundstart: [total], Threshold: [threshold]") emergencyNoRecall = TRUE priority_announce("Catastrophic casualties detected: crisis shuttle protocols activated - jamming recall signals across all frequencies.") if(emergency.timeLeft(1) > emergencyCallTime * 0.4) @@ -172,6 +179,34 @@ SUBSYSTEM_DEF(shuttle) return S WARNING("couldn't find dock with id: [id]") +/datum/controller/subsystem/shuttle/proc/canEvac(mob/user) + var/srd = CONFIG_GET(number/shuttle_refuel_delay) + if(world.time - SSticker.round_start_time < srd) + to_chat(user, "The emergency shuttle is refueling. Please wait [DisplayTimeText(srd - (world.time - SSticker.round_start_time))] before trying again.") + return FALSE + + switch(emergency.mode) + if(SHUTTLE_RECALL) + to_chat(user, "The emergency shuttle may not be called while returning to CentCom.") + return FALSE + if(SHUTTLE_CALL) + to_chat(user, "The emergency shuttle is already on its way.") + return FALSE + if(SHUTTLE_DOCKED) + to_chat(user, "The emergency shuttle is already here.") + return FALSE + if(SHUTTLE_IGNITING) + to_chat(user, "The emergency shuttle is firing its engines to leave.") + return FALSE + if(SHUTTLE_ESCAPE) + to_chat(user, "The emergency shuttle is moving away to a safe distance.") + return FALSE + if(SHUTTLE_STRANDED) + to_chat(user, "The emergency shuttle has been disabled by CentCom.") + return FALSE + + return TRUE + /datum/controller/subsystem/shuttle/proc/requestEvac(mob/user, call_reason) if(!emergency) WARNING("requestEvac(): There is no emergency shuttle, but the \ @@ -185,35 +220,14 @@ SUBSYSTEM_DEF(shuttle) manually, and then calling register() on the mobile docking port. \ Good luck.") emergency = backup_shuttle - var/srd = CONFIG_GET(number/shuttle_refuel_delay) - if(world.time - SSticker.round_start_time < srd) - to_chat(user, "The emergency shuttle is refueling. Please wait [DisplayTimeText(srd - (world.time - SSticker.round_start_time))] before trying again.") - return - switch(emergency.mode) - if(SHUTTLE_RECALL) - to_chat(user, "The emergency shuttle may not be called while returning to CentCom.") - return - if(SHUTTLE_CALL) - to_chat(user, "The emergency shuttle is already on its way.") - return - if(SHUTTLE_DOCKED) - to_chat(user, "The emergency shuttle is already here.") - return - if(SHUTTLE_IGNITING) - to_chat(user, "The emergency shuttle is firing its engines to leave.") - return - if(SHUTTLE_ESCAPE) - to_chat(user, "The emergency shuttle is moving away to a safe distance.") - return - if(SHUTTLE_STRANDED) - to_chat(user, "The emergency shuttle has been disabled by CentCom.") - return + if(!canEvac(user)) + return call_reason = trim(html_encode(call_reason)) if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH && GLOB.security_level > SEC_LEVEL_GREEN) - to_chat(user, "You must provide a reason.") + to_chat(user, "You must provide a reason.") return var/area/signal_origin = get_area(user) @@ -235,11 +249,11 @@ SUBSYSTEM_DEF(shuttle) var/area/A = get_area(user) - log_game("[key_name(user)] has called the shuttle.") - deadchat_broadcast("[user.real_name] has called the shuttle at [A.name].", user) + log_shuttle("[key_name(user)] has called the emergency shuttle.") + deadchat_broadcast(" has called the shuttle at [A.name].", "[user.real_name]", user) if(call_reason) SSblackbox.record_feedback("text", "shuttle_reason", 1, "[call_reason]") - log_game("Shuttle call reason: [call_reason]") + log_shuttle("Shuttle call reason: [call_reason]") message_admins("[ADMIN_LOOKUPFLW(user)] has called the shuttle. (TRIGGER CENTCOM RECALL)") /datum/controller/subsystem/shuttle/proc/centcom_recall(old_timer, admiral_message) @@ -272,9 +286,9 @@ SUBSYSTEM_DEF(shuttle) /datum/controller/subsystem/shuttle/proc/cancelEvac(mob/user) if(canRecall()) emergency.cancel(get_area(user)) - log_game("[key_name(user)] has recalled the shuttle.") + log_shuttle("[key_name(user)] has recalled the shuttle.") message_admins("[ADMIN_LOOKUPFLW(user)] has recalled the shuttle.") - deadchat_broadcast("[user.real_name] has recalled the shuttle from [get_area_name(user, TRUE)].", user) + deadchat_broadcast(" has recalled the shuttle from [get_area_name(user, TRUE)].", "[user.real_name]", user) return 1 /datum/controller/subsystem/shuttle/proc/canRecall() @@ -294,7 +308,7 @@ SUBSYSTEM_DEF(shuttle) else if(emergency.timeLeft(1) < emergencyCallTime * 0.25) return - return 1 + return TRUE /datum/controller/subsystem/shuttle/proc/autoEvac() if (!SSticker.IsRoundInProgress()) @@ -322,7 +336,7 @@ SUBSYSTEM_DEF(shuttle) if(callShuttle) if(EMERGENCY_IDLE_OR_RECALLED) emergency.request(null, set_coefficient = 2.5) - log_game("There is no means of calling the shuttle anymore. Shuttle automatically called.") + log_shuttle("There is no means of calling the emergency shuttle anymore. Shuttle automatically called.") message_admins("All the communications consoles were destroyed and all AIs are inactive. Shuttle called.") /datum/controller/subsystem/shuttle/proc/registerHostileEnvironment(datum/bad) @@ -559,6 +573,14 @@ SUBSYSTEM_DEF(shuttle) shuttle_purchased = SSshuttle.shuttle_purchased lockdown = SSshuttle.lockdown + selected = SSshuttle.selected + + existing_shuttle = SSshuttle.existing_shuttle + + preview_shuttle = SSshuttle.preview_shuttle + preview_template = SSshuttle.preview_template + + preview_reservation = SSshuttle.preview_reservation /datum/controller/subsystem/shuttle/proc/is_in_shuttle_bounds(atom/A) var/area/current = get_area(A) @@ -641,3 +663,252 @@ SUBSYSTEM_DEF(shuttle) message_admins("Round end vote passed. Shuttle has been auto-called.") emergencyNoRecall = TRUE endvote_passed = TRUE + +/datum/controller/subsystem/shuttle/proc/action_load(datum/map_template/shuttle/loading_template, obj/docking_port/stationary/destination_port) + // Check for an existing preview + if(preview_shuttle && (loading_template != preview_template)) + preview_shuttle.jumpToNullSpace() + preview_shuttle = null + preview_template = null + QDEL_NULL(preview_reservation) + + if(!preview_shuttle) + if(load_template(loading_template)) + preview_shuttle.linkup(loading_template, destination_port) + preview_template = loading_template + + // get the existing shuttle information, if any + var/timer = 0 + var/mode = SHUTTLE_IDLE + var/obj/docking_port/stationary/D + + if(istype(destination_port)) + D = destination_port + else if(existing_shuttle) + timer = existing_shuttle.timer + mode = existing_shuttle.mode + D = existing_shuttle.get_docked() + + if(!D) + D = generate_transit_dock(preview_shuttle) + + if(!D) + CRASH("No dock found for preview shuttle ([preview_template.name]), aborting.") + + var/result = preview_shuttle.canDock(D) + // truthy value means that it cannot dock for some reason + // but we can ignore the someone else docked error because we'll + // be moving into their place shortly + if((result != SHUTTLE_CAN_DOCK) && (result != SHUTTLE_SOMEONE_ELSE_DOCKED)) + WARNING("Template shuttle [preview_shuttle] cannot dock at [D] ([result]).") + return + + if(existing_shuttle) + existing_shuttle.jumpToNullSpace() + + var/list/force_memory = preview_shuttle.movement_force + preview_shuttle.movement_force = list("KNOCKDOWN" = 0, "THROW" = 0) + preview_shuttle.initiate_docking(D) + preview_shuttle.movement_force = force_memory + + . = preview_shuttle + + // Shuttle state involves a mode and a timer based on world.time, so + // plugging the existing shuttles old values in works fine. + preview_shuttle.timer = timer + preview_shuttle.mode = mode + + preview_shuttle.register() + + // TODO indicate to the user that success happened, rather than just + // blanking the modification tab + preview_shuttle = null + preview_template = null + existing_shuttle = null + selected = null + QDEL_NULL(preview_reservation) + +/datum/controller/subsystem/shuttle/proc/load_template(datum/map_template/shuttle/S) + . = FALSE + // load shuttle template, centred at shuttle import landmark, + preview_reservation = SSmapping.RequestBlockReservation(S.width, S.height, SSmapping.transit.z_value, /datum/turf_reservation/transit) + if(!preview_reservation) + CRASH("failed to reserve an area for shuttle template loading") + var/turf/BL = TURF_FROM_COORDS_LIST(preview_reservation.bottom_left_coords) + S.load(BL, centered = FALSE, register = FALSE) + + var/affected = S.get_affected_turfs(BL, centered=FALSE) + + var/found = 0 + // Search the turfs for docking ports + // - We need to find the mobile docking port because that is the heart of + // the shuttle. + // - We need to check that no additional ports have slipped in from the + // template, because that causes unintended behaviour. + for(var/T in affected) + for(var/obj/docking_port/P in T) + if(istype(P, /obj/docking_port/mobile)) + found++ + if(found > 1) + qdel(P, force=TRUE) + log_world("Map warning: Shuttle Template [S.mappath] has multiple mobile docking ports.") + else + preview_shuttle = P + if(istype(P, /obj/docking_port/stationary)) + log_world("Map warning: Shuttle Template [S.mappath] has a stationary docking port.") + if(!found) + var/msg = "load_template(): Shuttle Template [S.mappath] has no mobile docking port. Aborting import." + for(var/T in affected) + var/turf/T0 = T + T0.empty() + + message_admins(msg) + WARNING(msg) + return + //Everything fine + S.post_load(preview_shuttle) + return TRUE + +/datum/controller/subsystem/shuttle/proc/unload_preview() + if(preview_shuttle) + preview_shuttle.jumpToNullSpace() + preview_shuttle = null + + +/datum/controller/subsystem/shuttle/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) + if(!ui) + ui = new(user, src, ui_key, "ShuttleManipulator", name, 800, 600, master_ui, state) + ui.open() + + +/datum/controller/subsystem/shuttle/ui_data(mob/user) + var/list/data = list() + data["tabs"] = list("Status", "Templates", "Modification") + + // Templates panel + data["templates"] = list() + var/list/templates = data["templates"] + data["templates_tabs"] = list() + data["selected"] = list() + + for(var/shuttle_id in SSmapping.shuttle_templates) + var/datum/map_template/shuttle/S = SSmapping.shuttle_templates[shuttle_id] + + if(!templates[S.port_id]) + data["templates_tabs"] += S.port_id + templates[S.port_id] = list( + "port_id" = S.port_id, + "templates" = list()) + + var/list/L = list() + L["name"] = S.name + L["shuttle_id"] = S.shuttle_id + L["port_id"] = S.port_id + L["description"] = S.description + L["admin_notes"] = S.admin_notes + + if(selected == S) + data["selected"] = L + + templates[S.port_id]["templates"] += list(L) + + data["templates_tabs"] = sortList(data["templates_tabs"]) + + data["existing_shuttle"] = null + + // Status panel + data["shuttles"] = list() + for(var/i in mobile) + var/obj/docking_port/mobile/M = i + var/timeleft = M.timeLeft(1) + var/list/L = list() + L["name"] = M.name + L["id"] = M.id + L["timer"] = M.timer + L["timeleft"] = M.getTimerStr() + if (timeleft > 1 HOURS) + L["timeleft"] = "Infinity" + L["can_fast_travel"] = M.timer && timeleft >= 50 + L["can_fly"] = TRUE + if(istype(M, /obj/docking_port/mobile/emergency)) + L["can_fly"] = FALSE + else if(!M.destination) + L["can_fast_travel"] = FALSE + if (M.mode != SHUTTLE_IDLE) + L["mode"] = capitalize(M.mode) + L["status"] = M.getDbgStatusText() + if(M == existing_shuttle) + data["existing_shuttle"] = L + + data["shuttles"] += list(L) + + return data + +/datum/controller/subsystem/shuttle/ui_act(action, params) + if(..()) + return + + var/mob/user = usr + + // Preload some common parameters + var/shuttle_id = params["shuttle_id"] + var/datum/map_template/shuttle/S = SSmapping.shuttle_templates[shuttle_id] + + switch(action) + if("select_template") + if(S) + existing_shuttle = getShuttle(S.port_id) + selected = S + . = TRUE + if("jump_to") + if(params["type"] == "mobile") + for(var/i in mobile) + var/obj/docking_port/mobile/M = i + if(M.id == params["id"]) + user.forceMove(get_turf(M)) + . = TRUE + break + + if("fly") + for(var/i in mobile) + var/obj/docking_port/mobile/M = i + if(M.id == params["id"]) + . = TRUE + M.admin_fly_shuttle(user) + break + + if("fast_travel") + for(var/i in mobile) + var/obj/docking_port/mobile/M = i + if(M.id == params["id"] && M.timer && M.timeLeft(1) >= 50) + M.setTimer(50) + . = TRUE + message_admins("[key_name_admin(usr)] fast travelled [M]") + log_admin("[key_name(usr)] fast travelled [M]") + SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[M.name]") + break + + if("preview") + if(S) + . = TRUE + unload_preview() + load_template(S) + if(preview_shuttle) + preview_template = S + user.forceMove(get_turf(preview_shuttle)) + if("load") + if(existing_shuttle == backup_shuttle) + // TODO make the load button disabled + WARNING("The shuttle that the selected shuttle will replace \ + is the backup shuttle. Backup shuttle is required to be \ + intact for round sanity.") + else if(S) + . = TRUE + // If successful, returns the mobile docking port + var/obj/docking_port/mobile/mdp = action_load(S) + if(mdp) + user.forceMove(get_turf(mdp)) + message_admins("[key_name_admin(usr)] loaded [mdp] with the shuttle manipulator.") + log_admin("[key_name(usr)] loaded [mdp] with the shuttle manipulator.") + SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[mdp.name]") diff --git a/code/controllers/subsystem/tgui.dm b/code/controllers/subsystem/tgui.dm index dacbac409d..58bc28fa2f 100644 --- a/code/controllers/subsystem/tgui.dm +++ b/code/controllers/subsystem/tgui.dm @@ -11,7 +11,7 @@ SUBSYSTEM_DEF(tgui) var/basehtml // The HTML base used for all UIs. /datum/controller/subsystem/tgui/PreInit() - basehtml = file2text('tgui-next/packages/tgui/public/tgui-main.html') + basehtml = file2text('tgui/packages/tgui/public/tgui.html') /datum/controller/subsystem/tgui/Shutdown() close_all_uis() diff --git a/code/controllers/subsystem/title.dm b/code/controllers/subsystem/title.dm index b19cf47693..bd843f959d 100644 --- a/code/controllers/subsystem/title.dm +++ b/code/controllers/subsystem/title.dm @@ -47,7 +47,7 @@ SUBSYSTEM_DEF(title) . = ..() if(.) switch(var_name) - if("icon") + if(NAMEOF(src, icon)) if(splash_turf) splash_turf.icon = icon @@ -66,4 +66,4 @@ SUBSYSTEM_DEF(title) icon = SStitle.icon splash_turf = SStitle.splash_turf file_path = SStitle.file_path - previous_icon = SStitle.previous_icon \ No newline at end of file + previous_icon = SStitle.previous_icon diff --git a/code/datums/brain_damage/special.dm b/code/datums/brain_damage/special.dm index bc1f566f23..13cf2add97 100644 --- a/code/datums/brain_damage/special.dm +++ b/code/datums/brain_damage/special.dm @@ -104,7 +104,7 @@ QDEL_IN(src, 300) //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/effect/hallucination/simple/bluespace_stream/attack_hand(mob/user) +/obj/effect/hallucination/simple/bluespace_stream/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(user != seer || !linked_to) return var/slip_in_message = pick("slides sideways in an odd way, and disappears", "jumps into an unseen dimension",\ diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm new file mode 100644 index 0000000000..b9a1b5ec3b --- /dev/null +++ b/code/datums/components/crafting/crafting.dm @@ -0,0 +1,463 @@ +/datum/component/personal_crafting/Initialize() + if(ismob(parent)) + RegisterSignal(parent, COMSIG_MOB_CLIENT_LOGIN, .proc/create_mob_button) + +/datum/component/personal_crafting/proc/create_mob_button(mob/user, client/CL) + var/datum/hud/H = user.hud_used + var/obj/screen/craft/C = new() + C.icon = H.ui_style + H.static_inventory += C + CL.screen += C + RegisterSignal(C, COMSIG_CLICK, .proc/component_ui_interact) + +/datum/component/personal_crafting + var/busy + var/viewing_category = 1 //typical powergamer starting on the Weapons tab + var/viewing_subcategory = 1 + var/list/categories = list( + CAT_WEAPONRY = list( + CAT_WEAPON, + CAT_AMMO, + ), + CAT_ROBOT = CAT_NONE, + CAT_MISC = list( + CAT_MISCELLANEOUS, + CAT_TOOL, + CAT_FURNITURE, + ), + CAT_PRIMAL = CAT_NONE, + CAT_FOOD = list( + CAT_BREAD, + CAT_BURGER, + CAT_CAKE, + CAT_DONUT, + CAT_EGG, + CAT_ICE, + CAT_MEAT, + CAT_MEXICAN, + CAT_MISCFOOD, + CAT_PASTRY, + CAT_PIE, + CAT_PIZZA, + CAT_SEAFOOD, + CAT_SALAD, + CAT_SANDWICH, + CAT_SOUP, + CAT_SPAGHETTI, + ), + CAT_DRINK = CAT_NONE, + CAT_CLOTHING = CAT_NONE, + ) + + var/cur_category = CAT_NONE + var/cur_subcategory = CAT_NONE + var/datum/action/innate/crafting/button + var/display_craftable_only = FALSE + var/display_compact = TRUE + +/* This is what procs do: + get_environment - gets a list of things accessable for crafting by user + get_surroundings - takes a list of things and makes a list of key-types to values-amounts of said type in the list + check_contents - takes a recipe and a key-type list and checks if said recipe can be done with available stuff + check_tools - takes recipe, a key-type list, and a user and checks if there are enough tools to do the stuff, checks bugs one level deep + construct_item - takes a recipe and a user, call all the checking procs, calls do_after, checks all the things again, calls del_reqs, creates result, calls CheckParts of said result with argument being list returned by deel_reqs + del_reqs - takes recipe and a user, loops over the recipes reqs var and tries to find everything in the list make by get_environment and delete it/add to parts list, then returns the said list +*/ + +/** + * Check that the contents of the recipe meet the requirements. + * + * user: The /mob that initated the crafting. + * R: The /datum/crafting_recipe being attempted. + * contents: List of items to search for R's reqs. + */ +/datum/component/personal_crafting/proc/check_contents(atom/a, datum/crafting_recipe/R, list/contents) + var/list/item_instances = contents["instances"] + contents = contents["other"] + + var/list/requirements_list = list() + + // Process all requirements + for(var/requirement_path in R.reqs) + // Check we have the appropriate amount available in the contents list + var/needed_amount = R.reqs[requirement_path] + for(var/content_item_path in contents) + // Right path and not blacklisted + if(!ispath(content_item_path, requirement_path) || R.blacklist.Find(content_item_path)) + continue + + needed_amount -= contents[content_item_path] + if(needed_amount <= 0) + break + + if(needed_amount > 0) + return FALSE + + // Store the instances of what we will use for R.check_requirements() for requirement_path + var/list/instances_list = list() + for(var/instance_path in item_instances) + if(ispath(instance_path, requirement_path)) + instances_list += item_instances[instance_path] + + requirements_list[requirement_path] = instances_list + + for(var/requirement_path in R.chem_catalysts) + if(contents[requirement_path] < R.chem_catalysts[requirement_path]) + return FALSE + + return R.check_requirements(a, requirements_list) + +/datum/component/personal_crafting/proc/get_environment(atom/a, list/blacklist = null, radius_range = 1) + . = list() + + if(!isturf(a.loc)) + return + + for(var/atom/movable/AM in range(radius_range, a)) + if(AM.flags_1 & HOLOGRAM_1) + continue + . += AM + +/datum/component/personal_crafting/proc/get_surroundings(atom/a) + . = list() + .["tool_behaviour"] = list() + .["other"] = list() + .["instances"] = list() + for(var/obj/item/I in get_environment(a)) + if(I.flags_1 & HOLOGRAM_1) + continue + if(.["instances"][I.type]) + .["instances"][I.type] += I + else + .["instances"][I.type] = list(I) + if(istype(I, /obj/item/stack)) + var/obj/item/stack/S = I + .["other"][I.type] += S.amount + else if(I.tool_behaviour) + .["tool_behaviour"] += I.tool_behaviour + .["other"][I.type] += 1 + else + if(istype(I, /obj/item/reagent_containers)) + var/obj/item/reagent_containers/RC = I + if(RC.is_drainable()) + for(var/datum/reagent/A in RC.reagents.reagent_list) + .["other"][A.type] += A.volume + .["other"][I.type] += 1 + +/datum/component/personal_crafting/proc/check_tools(atom/a, datum/crafting_recipe/R, list/contents) + if(!R.tools.len) + return TRUE + var/list/possible_tools = list() + var/list/present_qualities = list() + present_qualities |= contents["tool_behaviour"] + for(var/obj/item/I in a.contents) + if(istype(I, /obj/item/storage)) + for(var/obj/item/SI in I.contents) + possible_tools += SI.type + if(SI.tool_behaviour) + present_qualities.Add(SI.tool_behaviour) + + possible_tools += I.type + + if(I.tool_behaviour) + present_qualities.Add(I.tool_behaviour) + + possible_tools |= contents["other"] + + main_loop: + for(var/A in R.tools) + if(A in present_qualities) + continue + else + for(var/I in possible_tools) + if(ispath(I, A)) + continue main_loop + return FALSE + return TRUE + +/datum/component/personal_crafting/proc/construct_item(atom/a, datum/crafting_recipe/R) + var/list/contents = get_surroundings(a) + var/send_feedback = 1 + if(check_contents(a, R, contents)) + if(check_tools(a, R, contents)) + //If we're a mob we'll try a do_after; non mobs will instead instantly construct the item + if(ismob(a) && !do_after(a, R.time, target = a)) + return "." + contents = get_surroundings(a) + if(!check_contents(a, R, contents)) + return ", missing component." + if(!check_tools(a, R, contents)) + return ", missing tool." + var/list/parts = del_reqs(R, a) + var/atom/movable/I = new R.result (get_turf(a.loc)) + I.CheckParts(parts, R) + if(send_feedback) + SSblackbox.record_feedback("tally", "object_crafted", 1, I.type) + return I //Send the item back to whatever called this proc so it can handle whatever it wants to do with the new item + return ", missing tool." + return ", missing component." + +/*Del reqs works like this: + + Loop over reqs var of the recipe + Set var amt to the value current cycle req is pointing to, its amount of type we need to delete + Get var/surroundings list of things accessable to crafting by get_environment() + Check the type of the current cycle req + If its reagent then do a while loop, inside it try to locate() reagent containers, inside such containers try to locate needed reagent, if there isnt remove thing from surroundings + If there is enough reagent in the search result then delete the needed amount, create the same type of reagent with the same data var and put it into deletion list + If there isnt enough take all of that reagent from the container, put into deletion list, substract the amt var by the volume of reagent, remove the container from surroundings list and keep searching + While doing above stuff check deletion list if it already has such reagnet, if yes merge instead of adding second one + If its stack check if it has enough amount + If yes create new stack with the needed amount and put in into deletion list, substract taken amount from the stack + If no put all of the stack in the deletion list, substract its amount from amt and keep searching + While doing above stuff check deletion list if it already has such stack type, if yes try to merge them instead of adding new one + If its anything else just locate() in in the list in a while loop, each find --s the amt var and puts the found stuff in deletion loop + + Then do a loop over parts var of the recipe + Do similar stuff to what we have done above, but now in deletion list, until the parts conditions are satisfied keep taking from the deletion list and putting it into parts list for return + + After its done loop over deletion list and delete all the shit that wasnt taken by parts loop + + del_reqs return the list of parts resulting object will receive as argument of CheckParts proc, on the atom level it will add them all to the contents, on all other levels it calls ..() and does whatever is needed afterwards but from contents list already +*/ + +/datum/component/personal_crafting/proc/del_reqs(datum/crafting_recipe/R, atom/a) + var/list/surroundings + var/list/Deletion = list() + . = list() + var/data + var/amt + main_loop: + for(var/A in R.reqs) + amt = R.reqs[A] + surroundings = get_environment(a, R.blacklist) + surroundings -= Deletion + if(ispath(A, /datum/reagent)) + var/datum/reagent/RG = new A + var/datum/reagent/RGNT + while(amt > 0) + var/obj/item/reagent_containers/RC = locate() in surroundings + RG = RC.reagents.get_reagent(A) + if(RG) + if(!locate(RG.type) in Deletion) + Deletion += new RG.type() + if(RG.volume > amt) + RG.volume -= amt + data = RG.data + RC.reagents.conditional_update(RC) + RG = locate(RG.type) in Deletion + RG.volume = amt + RG.data += data + continue main_loop + else + surroundings -= RC + amt -= RG.volume + RC.reagents.reagent_list -= RG + RC.reagents.conditional_update(RC) + RGNT = locate(RG.type) in Deletion + RGNT.volume += RG.volume + RGNT.data += RG.data + qdel(RG) + RC.on_reagent_change() + else + surroundings -= RC + else if(ispath(A, /obj/item/stack)) + var/obj/item/stack/S + var/obj/item/stack/SD + while(amt > 0) + S = locate(A) in surroundings + if(S.amount >= amt) + if(!locate(S.type) in Deletion) + SD = new S.type() + Deletion += SD + S.use(amt) + SD = locate(S.type) in Deletion + SD.amount += amt + continue main_loop + else + amt -= S.amount + if(!locate(S.type) in Deletion) + Deletion += S + else + data = S.amount + S = locate(S.type) in Deletion + S.add(data) + surroundings -= S + else + var/atom/movable/I + while(amt > 0) + I = locate(A) in surroundings + Deletion += I + surroundings -= I + amt-- + var/list/partlist = list(R.parts.len) + for(var/M in R.parts) + partlist[M] = R.parts[M] + for(var/A in R.parts) + if(istype(A, /datum/reagent)) + var/datum/reagent/RG = locate(A) in Deletion + if(RG.volume > partlist[A]) + RG.volume = partlist[A] + . += RG + Deletion -= RG + continue + else if(istype(A, /obj/item/stack)) + var/obj/item/stack/ST = locate(A) in Deletion + if(ST.amount > partlist[A]) + ST.amount = partlist[A] + . += ST + Deletion -= ST + continue + else + while(partlist[A] > 0) + var/atom/movable/AM = locate(A) in Deletion + . += AM + Deletion -= AM + partlist[A] -= 1 + while(Deletion.len) + var/DL = Deletion[Deletion.len] + Deletion.Cut(Deletion.len) + qdel(DL) + +/datum/component/personal_crafting/proc/component_ui_interact(obj/screen/craft/image, location, control, params, user) + if(user == parent) + ui_interact(user) + +//For the UI related things we're going to assume the user is a mob rather than typesetting it to an atom as the UI isn't generated if the parent is an atom +/datum/component/personal_crafting/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_turf_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + cur_category = categories[1] + if(islist(categories[cur_category])) + var/list/subcats = categories[cur_category] + cur_subcategory = subcats[1] + else + cur_subcategory = CAT_NONE + ui = new(user, src, ui_key, "PersonalCrafting", "Crafting Menu", 700, 800, master_ui, state) + ui.open() + +/datum/component/personal_crafting/ui_data(mob/user) + var/list/data = list() + data["busy"] = busy + data["category"] = cur_category + data["subcategory"] = cur_subcategory + data["display_craftable_only"] = display_craftable_only + data["display_compact"] = display_compact + + var/list/surroundings = get_surroundings(user) + var/list/craftability = list() + for(var/rec in GLOB.crafting_recipes) + var/datum/crafting_recipe/R = rec + + if(!R.always_availible && !(R.type in user?.mind?.learned_recipes)) //User doesn't actually know how to make this. + continue + + if((R.category != cur_category) || (R.subcategory != cur_subcategory)) + continue + + craftability["[REF(R)]"] = check_contents(user, R, surroundings) + + data["craftability"] = craftability + return data + +/datum/component/personal_crafting/ui_static_data(mob/user) + var/list/data = list() + + var/list/crafting_recipes = list() + for(var/rec in GLOB.crafting_recipes) + var/datum/crafting_recipe/R = rec + + if(R.name == "") //This is one of the invalid parents that sneaks in + continue + + if(!R.always_availible && !(R.type in user?.mind?.learned_recipes)) //User doesn't actually know how to make this. + continue + + if(isnull(crafting_recipes[R.category])) + crafting_recipes[R.category] = list() + + if(R.subcategory == CAT_NONE) + crafting_recipes[R.category] += list(build_recipe_data(R)) + else + if(isnull(crafting_recipes[R.category][R.subcategory])) + crafting_recipes[R.category][R.subcategory] = list() + crafting_recipes[R.category]["has_subcats"] = TRUE + crafting_recipes[R.category][R.subcategory] += list(build_recipe_data(R)) + + data["crafting_recipes"] = crafting_recipes + return data + +/datum/component/personal_crafting/ui_act(action, params) + if(..()) + return + switch(action) + if("make") + var/mob/user = usr + var/datum/crafting_recipe/TR = locate(params["recipe"]) in GLOB.crafting_recipes + busy = TRUE + ui_interact(user) + var/atom/movable/result = construct_item(user, TR) + if(!istext(result)) //We made an item and didn't get a fail message + if(ismob(user) && isitem(result)) //In case the user is actually possessing a non mob like a machine + user.put_in_hands(result) + else + result.forceMove(user.drop_location()) + to_chat(user, "[TR.name] constructed.") + else + to_chat(user, "Construction failed[result]") + busy = FALSE + if("toggle_recipes") + display_craftable_only = !display_craftable_only + . = TRUE + if("toggle_compact") + display_compact = !display_compact + . = TRUE + if("set_category") + if(!isnull(params["category"])) + cur_category = params["category"] + if(!isnull(params["subcategory"])) + if(params["subcategory"] == "0") + cur_subcategory = "" + else + cur_subcategory = params["subcategory"] + . = TRUE + +/datum/component/personal_crafting/proc/build_recipe_data(datum/crafting_recipe/R) + var/list/data = list() + data["name"] = R.name + data["ref"] = "[REF(R)]" + var/req_text = "" + var/tool_text = "" + var/catalyst_text = "" + + for(var/a in R.reqs) + //We just need the name, so cheat-typecast to /atom for speed (even tho Reagents are /datum they DO have a "name" var) + //Also these are typepaths so sadly we can't just do "[a]" + var/atom/A = a + req_text += " [R.reqs[A]] [initial(A.name)]," + req_text = replacetext(req_text,",","",-1) + data["req_text"] = req_text + + for(var/a in R.chem_catalysts) + var/atom/A = a //cheat-typecast + catalyst_text += " [R.chem_catalysts[A]] [initial(A.name)]," + catalyst_text = replacetext(catalyst_text,",","",-1) + data["catalyst_text"] = catalyst_text + + for(var/a in R.tools) + if(ispath(a, /obj/item)) + var/obj/item/b = a + tool_text += " [initial(b.name)]," + else + tool_text += " [a]," + tool_text = replacetext(tool_text,",","",-1) + data["tool_text"] = tool_text + + return data + +//Mind helpers + +/datum/mind/proc/teach_crafting_recipe(R) + if(!learned_recipes) + learned_recipes = list() + learned_recipes |= R diff --git a/code/datums/components/gps.dm b/code/datums/components/gps.dm new file mode 100644 index 0000000000..200ec2b956 --- /dev/null +++ b/code/datums/components/gps.dm @@ -0,0 +1,153 @@ +///Global GPS_list. All GPS components get saved in here for easy reference. +GLOBAL_LIST_EMPTY(GPS_list) +///GPS component. Atoms that have this show up on gps. Pretty simple stuff. +/datum/component/gps + var/gpstag = "COM0" + var/tracking = TRUE + var/emped = FALSE + +/datum/component/gps/Initialize(_gpstag = "COM0") + if(!isatom(parent)) + return COMPONENT_INCOMPATIBLE + gpstag = _gpstag + GLOB.GPS_list += src + +/datum/component/gps/Destroy() + GLOB.GPS_list -= src + return ..() + +///GPS component subtype. Only gps/item's can be used to open the UI. +/datum/component/gps/item + var/updating = TRUE //Automatic updating of GPS list. Can be set to manual by user. + var/global_mode = TRUE //If disabled, only GPS signals of the same Z level are shown + +/datum/component/gps/item/Initialize(_gpstag = "COM0", emp_proof = FALSE) + . = ..() + if(. == COMPONENT_INCOMPATIBLE || !isitem(parent)) + return COMPONENT_INCOMPATIBLE + var/atom/A = parent + A.add_overlay("working") + A.name = "[initial(A.name)] ([gpstag])" + RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/interact) + if(!emp_proof) + RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/on_emp_act) + RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine) + RegisterSignal(parent, COMSIG_CLICK_ALT, .proc/on_AltClick) + +///Called on COMSIG_ITEM_ATTACK_SELF +/datum/component/gps/item/proc/interact(datum/source, mob/user) + if(user) + ui_interact(user) + +///Called on COMSIG_PARENT_EXAMINE +/datum/component/gps/item/proc/on_examine(datum/source, mob/user, list/examine_list) + examine_list += "Alt-click to switch it [tracking ? "off":"on"]." + +///Called on COMSIG_ATOM_EMP_ACT +/datum/component/gps/item/proc/on_emp_act(datum/source, severity) + emped = TRUE + var/atom/A = parent + A.cut_overlay("working") + A.add_overlay("emp") + addtimer(CALLBACK(src, .proc/reboot), 300, TIMER_UNIQUE|TIMER_OVERRIDE) //if a new EMP happens, remove the old timer so it doesn't reactivate early + SStgui.close_uis(src) //Close the UI control if it is open. + +///Restarts the GPS after getting turned off by an EMP. +/datum/component/gps/item/proc/reboot() + emped = FALSE + var/atom/A = parent + A.cut_overlay("emp") + A.add_overlay("working") + +///Calls toggletracking +/datum/component/gps/item/proc/on_AltClick(datum/source, mob/user) + toggletracking(user) + +///Toggles the tracking for the gps +/datum/component/gps/item/proc/toggletracking(mob/user) + if(!user.canUseTopic(parent, BE_CLOSE)) + return //user not valid to use gps + if(emped) + to_chat(user, "It's busted!") + return + var/atom/A = parent + if(tracking) + A.cut_overlay("working") + to_chat(user, "[parent] is no longer tracking, or visible to other GPS devices.") + tracking = FALSE + else + A.add_overlay("working") + to_chat(user, "[parent] is now tracking, and visible to other GPS devices.") + tracking = TRUE + +/datum/component/gps/item/ui_interact(mob/user, ui_key = "gps", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state. + if(emped) + to_chat(user, "[parent] fizzles weakly.") + return + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + // Variable window height, depending on how many GPS units there are + // to show, clamped to relatively safe range. + var/gps_window_height = clamp(325 + GLOB.GPS_list.len * 14, 325, 700) + ui = new(user, src, ui_key, "Gps", "Global Positioning System", 470, gps_window_height, master_ui, state) //width, height + ui.open() + + ui.set_autoupdate(state = updating) + +/datum/component/gps/item/ui_data(mob/user) + var/list/data = list() + data["power"] = tracking + data["tag"] = gpstag + data["updating"] = updating + data["globalmode"] = global_mode + if(!tracking || emped) //Do not bother scanning if the GPS is off or EMPed + return data + + var/turf/curr = get_turf(parent) + data["currentArea"] = "[get_area_name(curr, TRUE)]" + data["currentCoords"] = "[curr.x], [curr.y], [curr.z]" + + var/list/signals = list() + data["signals"] = list() + + for(var/gps in GLOB.GPS_list) + var/datum/component/gps/G = gps + if(G.emped || !G.tracking || G == src) + continue + var/turf/pos = get_turf(G.parent) + if(!pos || !global_mode && pos.z != curr.z) + continue + var/list/signal = list() + signal["entrytag"] = G.gpstag //Name or 'tag' of the GPS + signal["coords"] = "[pos.x], [pos.y], [pos.z]" + if(pos.z == curr.z) //Distance/Direction calculations for same z-level only + signal["dist"] = max(get_dist(curr, pos), 0) //Distance between the src and remote GPS turfs + signal["degrees"] = round(Get_Angle(curr, pos)) //0-360 degree directional bearing, for more precision. + signals += list(signal) //Add this signal to the list of signals + data["signals"] = signals + return data + +/datum/component/gps/item/ui_act(action, params) + if(..()) + return + switch(action) + if("rename") + var/atom/parentasatom = parent + var/a = stripped_input(usr, "Please enter desired tag.", parentasatom.name, gpstag, 20) + + if (!a) + return + + gpstag = a + . = TRUE + parentasatom.name = "global positioning system ([gpstag])" + + if("power") + toggletracking(usr) + . = TRUE + if("updating") + updating = !updating + . = TRUE + if("globalmode") + global_mode = !global_mode + . = TRUE diff --git a/code/datums/components/material_container.dm b/code/datums/components/material_container.dm index 51dc4ee8f7..7adc634621 100644 --- a/code/datums/components/material_container.dm +++ b/code/datums/components/material_container.dm @@ -105,7 +105,7 @@ /// Proc specifically for inserting items, returns the amount of materials entered. /datum/component/material_container/proc/insert_item(obj/item/I, var/multiplier = 1, stack_amt) - if(!I) + if(QDELETED(I)) return FALSE multiplier = CEILING(multiplier, 0.01) diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index dde8961482..a269e24974 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -24,16 +24,17 @@ GLOBAL_LIST_EMPTY(uplinks) var/unlock_note var/unlock_code var/failsafe_code - var/datum/ui_state/checkstate var/compact_mode = FALSE var/debug = FALSE var/saved_player_population = 0 var/list/filters = list() + /datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/ui_state/_checkstate, datum/traitor_class/traitor_class) if(!isitem(parent)) return COMPONENT_INCOMPATIBLE + RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/OnAttackBy) RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/interact) if(istype(parent, /obj/item/implant)) @@ -65,7 +66,6 @@ GLOBAL_LIST_EMPTY(uplinks) active = _enabled gamemode = _gamemode telecrystals = starting_tc - checkstate = _checkstate if(!lockable) active = TRUE locked = FALSE @@ -136,13 +136,13 @@ GLOBAL_LIST_EMPTY(uplinks) /datum/component/uplink/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state) - state = checkstate ? checkstate : state active = TRUE ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "uplink", name, 620, 580, master_ui, state) - ui.set_autoupdate(FALSE) // This UI is only ever opened by one person, and never is updated outside of user input. - ui.set_style("syndicate") + ui = new(user, src, ui_key, "Uplink", name, 620, 580, master_ui, state) + // This UI is only ever opened by one person, + // and never is updated outside of user input. + ui.set_autoupdate(FALSE) ui.open() /datum/component/uplink/ui_host(mob/user) @@ -157,8 +157,7 @@ GLOBAL_LIST_EMPTY(uplinks) var/list/data = list() data["telecrystals"] = telecrystals data["lockable"] = lockable - data["compact_mode"] = compact_mode - + data["compactMode"] = compact_mode return data /datum/component/uplink/ui_static_data(mob/user) @@ -192,21 +191,16 @@ GLOBAL_LIST_EMPTY(uplinks) /datum/component/uplink/ui_act(action, params) if(!active) return - switch(action) if("buy") - var/item = params["item"] - + var/item_name = params["name"] var/list/buyable_items = list() for(var/category in uplink_items) buyable_items += uplink_items[category] - - if(item in buyable_items) - var/datum/uplink_item/I = buyable_items[item] - //check to make sure people cannot buy items when the player pop is below the requirement - if(GLOB.joined_player_list.len >= I.player_minimum) - MakePurchase(usr, I) - . = TRUE + if(item_name in buyable_items) + var/datum/uplink_item/I = buyable_items[item_name] + MakePurchase(usr, I) + return TRUE if("lock") active = FALSE locked = TRUE @@ -215,9 +209,10 @@ GLOBAL_LIST_EMPTY(uplinks) SStgui.close_uis(src) if("select") selected_cat = params["category"] + return TRUE if("compact_toggle") compact_mode = !compact_mode - return TRUE + return TRUE /datum/component/uplink/proc/MakePurchase(mob/user, datum/uplink_item/U) if(!istype(U)) @@ -262,12 +257,12 @@ GLOBAL_LIST_EMPTY(uplinks) var/obj/item/pda/master = parent if(trim(lowertext(new_ring_text)) != trim(lowertext(unlock_code))) if(trim(lowertext(new_ring_text)) == trim(lowertext(failsafe_code))) - failsafe() + failsafe(user) return COMPONENT_STOP_RINGTONE_CHANGE return locked = FALSE interact(null, user) - to_chat(user, "The PDA softly beeps.") + to_chat(user, "The PDA softly beeps.") user << browse(null, "window=pda") master.mode = 0 return COMPONENT_STOP_RINGTONE_CHANGE @@ -279,7 +274,7 @@ GLOBAL_LIST_EMPTY(uplinks) var/frequency = arguments[1] if(frequency != unlock_code) if(frequency == failsafe_code) - failsafe() + failsafe(master.loc) return locked = FALSE if(ismob(master.loc)) @@ -316,11 +311,13 @@ GLOBAL_LIST_EMPTY(uplinks) else if(istype(parent,/obj/item/pen)) return rand(1, 360) -/datum/component/uplink/proc/failsafe() +/datum/component/uplink/proc/failsafe(mob/living/carbon/user) if(!parent) return var/turf/T = get_turf(parent) if(!T) return + message_admins("[ADMIN_LOOKUPFLW(user)] has triggered an uplink failsafe explosion at [AREACOORD(T)] The owner of the uplink was [ADMIN_LOOKUPFLW(owner)].") + log_game("[key_name(user)] triggered an uplink failsafe explosion. The owner of the uplink was [key_name(owner)].") explosion(T,1,2,3) qdel(parent) //Alternatively could brick the uplink. diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index 84ea6b6458..94940b3855 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -81,7 +81,7 @@ if(N.new_character) log_manifest(N.ckey,N.new_character.mind,N.new_character) if(ishuman(N.new_character)) - manifest_inject(N.new_character, N.client) + manifest_inject(N.new_character, N.client, N.client.prefs) CHECK_TICK /datum/datacore/proc/manifest_modify(name, assignment) @@ -197,7 +197,7 @@ return dat -/datum/datacore/proc/manifest_inject(mob/living/carbon/human/H, client/C) +/datum/datacore/proc/manifest_inject(mob/living/carbon/human/H, client/C, datum/preferences/prefs) set waitfor = FALSE var/static/list/show_directions = list(SOUTH, WEST) if(H.mind && (H.mind.assigned_role != H.mind.special_role)) @@ -260,7 +260,7 @@ M.fields["alg_d"] = "No allergies have been detected in this patient." M.fields["cdi"] = "None" M.fields["cdi_d"] = "No diseases have been diagnosed at the moment." - M.fields["notes"] = H.get_trait_string(medical) + M.fields["notes"] = "Trait information as of shift start: [H.get_trait_string(medical)]
[prefs.medical_records]" medical += M //Security Record @@ -270,7 +270,7 @@ S.fields["criminal"] = "None" S.fields["mi_crim"] = list() S.fields["ma_crim"] = list() - S.fields["notes"] = "No notes." + S.fields["notes"] = prefs.security_records || "No notes." security += S //Locked Record diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 80059bece7..23b6704080 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -15,6 +15,7 @@ var/mob/living/holder var/delete_species = TRUE //Set to FALSE when a body is scanned by a cloner to fix #38875 var/mutation_index[DNA_MUTATION_BLOCKS] //List of which mutations this carbon has and its assigned block + var/default_mutation_genes[DNA_MUTATION_BLOCKS] //List of the default genes from this mutation to allow DNA Scanner highlighting var/stability = 100 var/scrambled = FALSE //Did we take something like mutagen? In that case we cant get our genes scanned to instantly cheese all the powers. var/skin_tone_override //because custom skin tones are not found in the skin_tones global list. @@ -58,6 +59,7 @@ H.give_genitals(TRUE)//This gives the body the genitals of this DNA. Used for any transformations based on DNA if(transfer_SE) destination.dna.mutation_index = mutation_index + destination.dna.default_mutation_genes = default_mutation_genes destination.dna.update_body_size(old_size) @@ -66,6 +68,7 @@ /datum/dna/proc/copy_dna(datum/dna/new_dna) new_dna.unique_enzymes = unique_enzymes new_dna.mutation_index = mutation_index + new_dna.default_mutation_genes = default_mutation_genes new_dna.uni_identity = uni_identity new_dna.blood_type = blood_type new_dna.skin_tone_override = skin_tone_override @@ -160,15 +163,18 @@ if(!LAZYLEN(mutations_temp)) return mutation_index.Cut() + default_mutation_genes.Cut() shuffle_inplace(mutations_temp) if(ismonkey(holder)) mutations |= new RACEMUT(MUT_NORMAL) mutation_index[RACEMUT] = GET_SEQUENCE(RACEMUT) else mutation_index[RACEMUT] = create_sequence(RACEMUT, FALSE) + default_mutation_genes[RACEMUT] = mutation_index[RACEMUT] for(var/i in 2 to DNA_MUTATION_BLOCKS) var/datum/mutation/human/M = mutations_temp[i] - mutation_index[M.type] = create_sequence(M.type, FALSE,M.difficulty) + mutation_index[M.type] = create_sequence(M.type, FALSE, M.difficulty) + default_mutation_genes[M.type] = mutation_index[M.type] shuffle_inplace(mutation_index) //Used to generate original gene sequences for every mutation @@ -389,7 +395,7 @@ return dna -/mob/living/carbon/human/proc/hardset_dna(ui, list/mutation_index, newreal_name, newblood_type, datum/species/mrace, newfeatures) +/mob/living/carbon/human/proc/hardset_dna(ui, list/mutation_index, newreal_name, newblood_type, datum/species/mrace, newfeatures, list/default_mutation_genes) if(newreal_name) real_name = newreal_name @@ -414,6 +420,10 @@ if(LAZYLEN(mutation_index)) dna.mutation_index = mutation_index.Copy() + if(LAZYLEN(default_mutation_genes)) + dna.default_mutation_genes = default_mutation_genes.Copy() + else + dna.default_mutation_genes = mutation_index.Copy() domutcheck() SEND_SIGNAL(src, COMSIG_HUMAN_HARDSET_DNA, ui, mutation_index, newreal_name, newblood_type, mrace, newfeatures) @@ -505,8 +515,11 @@ . = TRUE if(on) mutation_index[HM.type] = GET_SEQUENCE(HM.type) + default_mutation_genes[HM.type] = mutation_index[HM.type] else if(GET_SEQUENCE(HM.type) == mutation_index[HM.type]) mutation_index[HM.type] = create_sequence(HM.type, FALSE, HM.difficulty) + default_mutation_genes[HM.type] = mutation_index[HM.type] + /datum/dna/proc/activate_mutation(mutation) //note that this returns a boolean and not a new mob if(!mutation) diff --git a/code/datums/elements/flavor_text.dm b/code/datums/elements/flavor_text.dm index 92251861ed..3562345d26 100644 --- a/code/datums/elements/flavor_text.dm +++ b/code/datums/elements/flavor_text.dm @@ -82,9 +82,10 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code return if(href_list["show_flavor"]) var/atom/target = locate(href_list["show_flavor"]) + var/mob/living/L = target var/text = texts_by_atom[target] if(text) - usr << browse("[target.name][replacetext(texts_by_atom[target], "\n", "
")]
", "window=[target.name];size=500x200") + usr << browse("[isliving(target) ? L.get_visible_name() : target.name][replacetext(texts_by_atom[target], "\n", "
")]
", "window=[isliving(target) ? L.get_visible_name() : target.name];size=500x200") onclose(usr, "[target.name]") return TRUE diff --git a/code/datums/martial/wrestling.dm b/code/datums/martial/wrestling.dm index 18fd8e7b18..8dc1afba81 100644 --- a/code/datums/martial/wrestling.dm +++ b/code/datums/martial/wrestling.dm @@ -215,11 +215,17 @@ /datum/martial_art/wrestling/proc/FlipAnimation(mob/living/carbon/human/D) set waitfor = FALSE + var/transform_before + var/laying_before if (D) + transform_before = D.transform + laying_before = D.lying animate(D, transform = matrix(180, MATRIX_ROTATE), time = 1, loop = 0) sleep(15) if (D) - animate(D, transform = null, time = 1, loop = 0) + if(transform_before && laying_before == D.lying) //animate calls sleep so this should be fine and stop a bug with transforms + D.transform = transform_before + animate(D, transform = null, time = 1, loop = 0) /datum/martial_art/wrestling/proc/slam(mob/living/carbon/human/A, mob/living/carbon/human/D) if(!D) @@ -415,11 +421,17 @@ to_chat(A, "You can't drop onto [D] from here!") return FALSE + var/transform_before + var/laying_before if(A) + transform_before = A.transform + laying_before = A.lying animate(A, transform = matrix(90, MATRIX_ROTATE), time = 1, loop = 0) sleep(10) if(A) - animate(A, transform = null, time = 1, loop = 0) + if(transform_before && laying_before == A.lying) //if they suddenly dropped to the floor between this period, don't revert their animation + animate(A, transform = null, time = 1, loop = 0) + A.transform = transform_before A.forceMove(D.loc) diff --git a/code/datums/mutations/_mutations.dm b/code/datums/mutations/_mutations.dm index db739c5100..fb5f6ed5f6 100644 --- a/code/datums/mutations/_mutations.dm +++ b/code/datums/mutations/_mutations.dm @@ -42,6 +42,7 @@ var/synchronizer_coeff = -1 //makes the mutation hurt the user less var/power_coeff = -1 //boosts mutation strength var/energy_coeff = -1 //lowers mutation cooldown + var/list/valid_chrom_list = list() //List of strings of valid chromosomes this mutation can accept. /datum/mutation/human/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut) . = ..() @@ -90,7 +91,7 @@ /datum/mutation/human/proc/get_visual_indicator() return -/datum/mutation/human/proc/on_attack_hand(atom/target, proximity) +/datum/mutation/human/proc/on_attack_hand(atom/target, proximity, act_intent, unarmed_attack_flags) return /datum/mutation/human/proc/on_ranged_attack(atom/target, mouseparams) @@ -167,6 +168,7 @@ energy_coeff = HM.energy_coeff mutadone_proof = HM.mutadone_proof can_chromosome = HM.can_chromosome + valid_chrom_list = HM.valid_chrom_list /datum/mutation/human/proc/remove_chromosome() stabilizer_coeff = initial(stabilizer_coeff) @@ -192,3 +194,23 @@ power.panel = "Genetic" owner.AddSpell(power) return TRUE + +// Runs through all the coefficients and uses this to determine which chromosomes the +// mutation can take. Stores these as text strings in a list. +/datum/mutation/human/proc/update_valid_chromosome_list() + valid_chrom_list.Cut() + + if(can_chromosome == CHROMOSOME_NEVER) + valid_chrom_list += "none" + return + + valid_chrom_list += "Reinforcement" + + if(stabilizer_coeff != -1) + valid_chrom_list += "Stabilizer" + if(synchronizer_coeff != -1) + valid_chrom_list += "Synchronizer" + if(power_coeff != -1) + valid_chrom_list += "Power" + if(energy_coeff != -1) + valid_chrom_list += "Energetic" diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm index 4f8cd6b25e..2df2b20cbc 100644 --- a/code/datums/mutations/hulk.dm +++ b/code/datums/mutations/hulk.dm @@ -19,8 +19,8 @@ SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "hulk", /datum/mood_event/hulk) RegisterSignal(owner, COMSIG_MOB_SAY, .proc/handle_speech) -/datum/mutation/human/hulk/on_attack_hand(atom/target, proximity) - if(proximity) //no telekinetic hulk attack +/datum/mutation/human/hulk/on_attack_hand(atom/target, proximity, act_intent, unarmed_attack_flags) + if(proximity && (act_intent == INTENT_HARM)) //no telekinetic hulk attack return target.attack_hulk(owner) /datum/mutation/human/hulk/on_life() diff --git a/code/datums/mutations/speech.dm b/code/datums/mutations/speech.dm index d4db7e34c2..531837e583 100644 --- a/code/datums/mutations/speech.dm +++ b/code/datums/mutations/speech.dm @@ -14,7 +14,7 @@ /datum/mutation/human/wacky name = "Wacky" - desc = "Unknown." + desc = "Unknown." quality = MINOR_NEGATIVE text_gain_indication = "You feel an off sensation in your voicebox." text_lose_indication = "The off sensation passes." diff --git a/code/datums/shuttles.dm b/code/datums/shuttles.dm index d275684bba..d6b73f96ed 100644 --- a/code/datums/shuttles.dm +++ b/code/datums/shuttles.dm @@ -104,6 +104,9 @@ rack.AddComponent(/datum/component/magnetic_catch) //Whatever special stuff you want +/datum/map_template/shuttle/proc/post_load(obj/docking_port/mobile/M) + return + /datum/map_template/shuttle/proc/on_bought() return diff --git a/code/datums/skills/_check_skills.dm b/code/datums/skills/_check_skills.dm index d02a716b8a..41939dbee3 100644 --- a/code/datums/skills/_check_skills.dm +++ b/code/datums/skills/_check_skills.dm @@ -17,7 +17,7 @@ /datum/skill_holder/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "skillpanel", "[owner.name]'s Skills", 620, 580, master_ui, state) + ui = new(user, src, ui_key, "SkillPanel", "[owner.name]'s Skills", 620, 580, master_ui, state) ui.set_autoupdate(FALSE) // This UI is only ever opened by one person, and never is updated outside of user input. ui.open() else if(need_static_data_update) diff --git a/code/datums/spawners_menu.dm b/code/datums/spawners_menu.dm index 1adcb6fde6..d66445b8a1 100644 --- a/code/datums/spawners_menu.dm +++ b/code/datums/spawners_menu.dm @@ -9,7 +9,7 @@ /datum/spawners_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "spawners_menu", "Spawners Menu", 700, 600, master_ui, state) + ui = new(user, src, ui_key, "SpawnersMenu", "Spawners Menu", 700, 600, master_ui, state) ui.open() /datum/spawners_menu/ui_data(mob/user) diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index 11e7e12bd8..75bd4f5c17 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -242,8 +242,8 @@ /datum/wires/ui_interact(mob/user, ui_key = "wires", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "wires", "[holder.name] Wires", 350, 150 + wires.len * 30, master_ui, state) + if (!ui) + ui = new(user, src, ui_key, "Wires", "[holder.name] Wires", 350, 150 + wires.len * 30, master_ui, state) ui.open() /datum/wires/ui_data(mob/user) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 5d29ef1598..e24da67611 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -101,6 +101,8 @@ stack_trace("Warning: [src]([type]) initialized multiple times!") flags_1 |= INITIALIZED_1 + if(loc) + SEND_SIGNAL(loc, COMSIG_ATOM_CREATED, src) /// Sends a signal that the new atom `src`, has been created at `loc` //atom color stuff if(color) add_atom_colour(color, FIXED_COLOUR_PRIORITY) @@ -741,7 +743,7 @@ flags_1 |= ADMIN_SPAWNED_1 . = ..() switch(var_name) - if("color") + if(NAMEOF(src, color)) add_atom_colour(color, ADMIN_COLOUR_PRIORITY) /atom/vv_get_dropdown() @@ -930,6 +932,8 @@ log_game(log_text) if(LOG_GAME) log_game(log_text) + if(LOG_SHUTTLE) + log_shuttle(log_text) else stack_trace("Invalid individual logging type: [message_type]. Defaulting to [LOG_GAME] (LOG_GAME).") log_game(log_text) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 9736f473e8..0238529195 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -120,25 +120,25 @@ if((var_name in careful_edits) && (var_value % world.icon_size) != 0) return FALSE switch(var_name) - if("x") + if(NAMEOF(src, x)) var/turf/T = locate(var_value, y, z) if(T) forceMove(T) return TRUE return FALSE - if("y") + if(NAMEOF(src, y)) var/turf/T = locate(x, var_value, z) if(T) forceMove(T) return TRUE return FALSE - if("z") + if(NAMEOF(src, z)) var/turf/T = locate(x, y, var_value) if(T) forceMove(T) return TRUE return FALSE - if("loc") + if(NAMEOF(src, loc)) if(istype(var_value, /atom)) forceMove(var_value) return TRUE diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index 7b798f19e4..5666f2442f 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -350,8 +350,9 @@ Credit where due: for(var/entry in changelog) changelog_contents += "
  • [entry]
  • " info = replacetext(info, "CLOCKCULTCHANGELOG", changelog_contents) - +/* /obj/item/paper/servant_primer/oui_getcontent(mob/target) if(!is_servant_of_ratvar(target) && !isobserver(target)) return "[name][stars(info)]
    [stamps]" return ..() +*/ diff --git a/code/game/gamemodes/gangs/dominator.dm b/code/game/gamemodes/gangs/dominator.dm index db145ffacc..b4028dc0fd 100644 --- a/code/game/gamemodes/gangs/dominator.dm +++ b/code/game/gamemodes/gangs/dominator.dm @@ -149,7 +149,7 @@ add_fingerprint(user) return ..() -/obj/machinery/dominator/attack_hand(mob/user) +/obj/machinery/dominator/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(operating || (stat & BROKEN)) examine(user) return diff --git a/code/game/machinery/PDApainter.dm b/code/game/machinery/PDApainter.dm index 88dc0ebb56..634ed2da48 100644 --- a/code/game/machinery/PDApainter.dm +++ b/code/game/machinery/PDApainter.dm @@ -107,7 +107,7 @@ stat |= BROKEN update_icon() -/obj/machinery/pdapainter/attack_hand(mob/user) +/obj/machinery/pdapainter/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm index 5402c8f41e..55976d69c2 100644 --- a/code/game/machinery/Sleeper.dm +++ b/code/game/machinery/Sleeper.dm @@ -209,7 +209,7 @@ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "sleeper", name, 550, 700, master_ui, state) + ui = new(user, src, ui_key, "Sleeper", name, 550, 700, master_ui, state) ui.open() /obj/machinery/sleeper/process() @@ -421,7 +421,8 @@ desc = "A large cryogenics unit built from brass. Its surface is pleasantly cool the touch." icon_state = "sleeper_clockwork" enter_message = "You hear the gentle hum and click of machinery, and are lulled into a sense of peace." - possible_chems = list(list("epinephrine", "salbutamol", "bicaridine", "kelotane", "oculine", "inacusiate", "mannitol")) + possible_chems = list(list(/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/salbutamol, /datum/reagent/medicine/bicaridine, + /datum/reagent/medicine/kelotane, /datum/reagent/medicine/oculine, /datum/reagent/medicine/inacusiate, /datum/reagent/medicine/mannitol)) /obj/machinery/sleeper/clockwork/process() if(occupant && isliving(occupant)) diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 096b40ddb7..6ef13ac36f 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -121,7 +121,7 @@ Class Procs: var/ui_style // ID of custom TGUI style (optional) var/ui_x var/ui_y - + var/init_process = TRUE //Stop processing from starting on init var/interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_SET_MACHINE var/fair_market_price = 69 @@ -138,7 +138,7 @@ Class Procs: circuit = new circuit circuit.apply_default_parts(src) - if(!speed_process) + if(!speed_process && init_process) START_PROCESSING(SSmachines, src) else START_PROCESSING(SSfastprocess, src) diff --git a/code/game/machinery/airlock_control.dm b/code/game/machinery/airlock_control.dm index 557adf488b..31fdf675ca 100644 --- a/code/game/machinery/airlock_control.dm +++ b/code/game/machinery/airlock_control.dm @@ -122,7 +122,7 @@ else icon_state = "airlock_sensor_off" -/obj/machinery/airlock_sensor/attack_hand(mob/user) +/obj/machinery/airlock_sensor/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -161,4 +161,4 @@ /obj/machinery/airlock_sensor/Destroy() SSradio.remove_object(src,frequency) - return ..() \ No newline at end of file + return ..() diff --git a/code/game/machinery/announcement_system.dm b/code/game/machinery/announcement_system.dm index 7eef48ebdd..8db5ca1d17 100644 --- a/code/game/machinery/announcement_system.dm +++ b/code/game/machinery/announcement_system.dm @@ -39,7 +39,7 @@ GLOBAL_LIST_EMPTY(announcement_systems) icon_state = (panel_open ? "AAS_Off_Open" : "AAS_Off") /obj/machinery/announcement_system/update_overlays() - . =..() + . = ..() if(arrivalToggle) . += greenlight @@ -54,19 +54,15 @@ GLOBAL_LIST_EMPTY(announcement_systems) GLOB.announcement_systems -= src //"OH GOD WHY ARE THERE 100,000 LISTED ANNOUNCEMENT SYSTEMS?!!" return ..() -/obj/machinery/announcement_system/power_change() - ..() - update_icon() - /obj/machinery/announcement_system/attackby(obj/item/P, mob/user, params) - if(istype(P, /obj/item/screwdriver)) + if(P.tool_behaviour == TOOL_SCREWDRIVER) P.play_tool_sound(src) panel_open = !panel_open to_chat(user, "You [panel_open ? "open" : "close"] the maintenance hatch of [src].") update_icon() else if(default_deconstruction_crowbar(P)) return - else if(istype(P, /obj/item/multitool) && panel_open && (stat & BROKEN)) + else if(P.tool_behaviour == TOOL_MULTITOOL && panel_open && (stat & BROKEN)) to_chat(user, "You reset [src]'s firmware.") stat &= ~BROKEN update_icon() @@ -88,10 +84,6 @@ GLOBAL_LIST_EMPTY(announcement_systems) message = CompileText(arrival, user, rank) else if(message_type == "NEWHEAD" && newheadToggle) message = CompileText(newhead, user, rank) - //CITADEL EDIT for cryopods - else if(message_type == "CRYOSTORAGE") - message = CompileText("%PERSON, %RANK has been moved to cryo storage.", user, rank) - //END EDIT else if(message_type == "ARRIVALS_BROKEN") message = "The arrivals shuttle has been damaged. Docking for repairs..." @@ -103,61 +95,59 @@ GLOBAL_LIST_EMPTY(announcement_systems) //config stuff -/obj/machinery/announcement_system/ui_interact(mob/user) +/obj/machinery/announcement_system/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) . = ..() - if(!user.canUseTopic(src, !hasSiliconAccessInArea(user))) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "AutomatedAnnouncement", "Automated Announcement System", 500, 225, master_ui, state) + ui.open() + +/obj/machinery/announcement_system/ui_data() + var/list/data = list() + data["arrival"] = arrival + data["arrivalToggle"] = arrivalToggle + data["newhead"] = newhead + data["newheadToggle"] = newheadToggle + return data + +/obj/machinery/announcement_system/ui_act(action, param) + . = ..() + if(.) + return + if(!usr.canUseTopic(src, !issilicon(usr))) return if(stat & BROKEN) - visible_message("[src] buzzes.", "You hear a faint buzz.") - playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 1) + visible_message("[src] buzzes.", "You hear a faint buzz.") + playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, TRUE) return - - - var/contents = "Arrival Announcement: ([(arrivalToggle ? "On" : "Off")])
    \n[arrival]

    \n" - contents += "Departmental Head Announcement: ([(newheadToggle ? "On" : "Off")])
    \n[newhead]

    \n" - - var/datum/browser/popup = new(user, "announcement_config", "Automated Announcement Configuration", 370, 220) - popup.set_content(contents) - popup.open() - -/obj/machinery/announcement_system/Topic(href, href_list) - if(..()) - return - if(!usr.canUseTopic(src, !hasSiliconAccessInArea(usr))) - return - if(stat & BROKEN) - visible_message("[src] buzzes.", "You hear a faint buzz.") - playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 1) - return - - if(href_list["ArrivalTopic"]) - var/NewMessage = stripped_input(usr, "Enter in the arrivals announcement configuration.", "Arrivals Announcement Config", arrival) - if(!usr.canUseTopic(src, !hasSiliconAccessInArea(usr))) - return - if(NewMessage) - arrival = NewMessage - else if(href_list["NewheadTopic"]) - var/NewMessage = stripped_input(usr, "Enter in the departmental head announcement configuration.", "Head Departmental Announcement Config", newhead) - if(!usr.canUseTopic(src, !hasSiliconAccessInArea(usr))) - return - if(NewMessage) - newhead = NewMessage - - else if(href_list["NewheadT-Topic"]) - newheadToggle = !newheadToggle - update_icon() - else if(href_list["ArrivalT-Topic"]) - arrivalToggle = !arrivalToggle - update_icon() - + switch(action) + if("ArrivalText") + var/NewMessage = trim(html_encode(param["newText"]), MAX_MESSAGE_LEN) + if(!usr.canUseTopic(src, !issilicon(usr))) + return + if(NewMessage) + arrival = NewMessage + log_game("The arrivals announcement was updated: [NewMessage] by:[key_name(usr)]") + if("NewheadText") + var/NewMessage = trim(html_encode(param["newText"]), MAX_MESSAGE_LEN) + if(!usr.canUseTopic(src, !issilicon(usr))) + return + if(NewMessage) + newhead = NewMessage + log_game("The head announcement was updated: [NewMessage] by:[key_name(usr)]") + if("NewheadToggle") + newheadToggle = !newheadToggle + update_icon() + if("ArrivalToggle") + arrivalToggle = !arrivalToggle + update_icon() add_fingerprint(usr) - interact(usr) /obj/machinery/announcement_system/attack_robot(mob/living/silicon/user) . = attack_ai(user) /obj/machinery/announcement_system/attack_ai(mob/user) - if(!user.canUseTopic(src, !hasSiliconAccessInArea(user))) + if(!user.canUseTopic(src, !issilicon(user))) return if(stat & BROKEN) to_chat(user, "[src]'s firmware appears to be malfunctioning!") @@ -165,8 +155,8 @@ GLOBAL_LIST_EMPTY(announcement_systems) interact(user) /obj/machinery/announcement_system/proc/act_up() //does funny breakage stuff - stat |= BROKEN - update_icon() + if(!obj_break()) // if badmins flag this unbreakable or its already broken + return arrival = pick("#!@%ERR-34%2 CANNOT LOCAT@# JO# F*LE!", "CRITICAL ERROR 99.", "ERR)#: DA#AB@#E NOT F(*ND!") newhead = pick("OV#RL()D: \[UNKNOWN??\] DET*#CT)D!", "ER)#R - B*@ TEXT F*O(ND!", "AAS.exe is not responding. NanoOS is searching for a solution to the problem.") @@ -177,9 +167,7 @@ GLOBAL_LIST_EMPTY(announcement_systems) act_up() /obj/machinery/announcement_system/emag_act() - . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED act_up() - return TRUE diff --git a/code/game/machinery/aug_manipulator.dm b/code/game/machinery/aug_manipulator.dm index b95e3149ea..d13c167a22 100644 --- a/code/game/machinery/aug_manipulator.dm +++ b/code/game/machinery/aug_manipulator.dm @@ -100,7 +100,7 @@ stat |= BROKEN update_icon() -/obj/machinery/aug_manipulator/attack_hand(mob/user) +/obj/machinery/aug_manipulator/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/machinery/bank_machine.dm b/code/game/machinery/bank_machine.dm index 2b683f16a3..8033f538ba 100644 --- a/code/game/machinery/bank_machine.dm +++ b/code/game/machinery/bank_machine.dm @@ -64,7 +64,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "bank_machine", name, 320, 165, master_ui, state) + ui = new(user, src, ui_key, "BankMachine", name, 320, 165, master_ui, state) ui.open() /obj/machinery/computer/bank_machine/ui_data(mob/user) diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index 71de04ee99..4661e1bd8f 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -43,7 +43,11 @@ board.one_access = 1 board.accesses = req_one_access -/obj/machinery/button/update_icon_state() + setup_device() + + +/obj/machinery/button/update_icon() + cut_overlays() if(panel_open) icon_state = "button-open" else if(stat & (NOPOWER|BROKEN)) @@ -129,6 +133,11 @@ A.id = id initialized_button = 1 +/obj/machinery/button/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) + if(id && istype(device, /obj/item/assembly/control)) + var/obj/item/assembly/control/A = device + A.id = "[idnum][id]" + /obj/machinery/button/attack_hand(mob/user) . = ..() if(.) diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index e386674b9e..5a1547aae0 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -72,6 +72,11 @@ if(mapload && is_station_level(z) && prob(3) && !start_active) toggle_cam() +/obj/machinery/camera/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) + for(var/i in network) + network -= i + network += "[idnum][i]" + /obj/machinery/camera/Destroy() if(can_use()) toggle_cam(null, 0) //kick anyone viewing out and remove from the camera chunks diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm index 83b0c0ee2d..01f73a3c75 100644 --- a/code/game/machinery/cell_charger.dm +++ b/code/game/machinery/cell_charger.dm @@ -79,7 +79,7 @@ charging = null update_icon() -/obj/machinery/cell_charger/attack_hand(mob/user) +/obj/machinery/cell_charger/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -103,8 +103,18 @@ removecell() /obj/machinery/cell_charger/attack_ai(mob/user) + if(!charging) + return + + charging.forceMove(loc) + to_chat(user, "You remotely disconnect the battery port and eject [charging] from [src].") + + removecell() return +/obj/machinery/cell_charger/attack_robot(mob/user) + attack_ai(user) + /obj/machinery/cell_charger/emp_act(severity) . = ..() diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 512e3108d4..5bbd3f8a65 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -75,31 +75,6 @@ speed_coeff = max(1, speed_coeff) heal_level = clamp((efficiency * 10) + 10, MINIMUM_HEAL_LEVEL, 100) -//The return of data disks?? Just for transferring between genetics machine/cloning machine. -//TO-DO: Make the genetics machine accept them. -/obj/item/disk/data - name = "cloning data disk" - icon_state = "datadisk0" //Gosh I hope syndies don't mistake them for the nuke disk. - var/list/fields = list() - var/list/mutations = list() - var/max_mutations = 6 - var/read_only = 0 //Well,it's still a floppy disk - -//Disk stuff. -/obj/item/disk/data/Initialize() - . = ..() - icon_state = "datadisk[rand(0,6)]" - add_overlay("datadisk_gene") - -/obj/item/disk/data/attack_self(mob/user) - read_only = !read_only - to_chat(user, "You flip the write-protect tab to [read_only ? "protected" : "unprotected"].") - -/obj/item/disk/data/examine(mob/user) - . = ..() - . += "The write-protect tab is set to [read_only ? "protected" : "unprotected"]." - - //Clonepod /obj/machinery/clonepod/examine(mob/user) diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm index 7439fd1b8b..c8efe319db 100644 --- a/code/game/machinery/computer/Operating.dm +++ b/code/game/machinery/computer/Operating.dm @@ -46,7 +46,7 @@ /obj/machinery/computer/operating/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "operating_computer", name, 350, 470, master_ui, state) + ui = new(user, src, ui_key, "OperatingComputer", name, 350, 470, master_ui, state) ui.open() /obj/machinery/computer/operating/ui_data(mob/user) @@ -108,6 +108,49 @@ )) else data["patient"] = null + return data + switch(patient.stat) + if(CONSCIOUS) + data["patient"]["stat"] = "Conscious" + data["patient"]["statstate"] = "good" + if(SOFT_CRIT) + data["patient"]["stat"] = "Conscious" + data["patient"]["statstate"] = "average" + if(UNCONSCIOUS) + data["patient"]["stat"] = "Unconscious" + data["patient"]["statstate"] = "average" + if(DEAD) + data["patient"]["stat"] = "Dead" + data["patient"]["statstate"] = "bad" + data["patient"]["health"] = patient.health + data["patient"]["blood_type"] = patient.dna.blood_type + data["patient"]["maxHealth"] = patient.maxHealth + data["patient"]["minHealth"] = HEALTH_THRESHOLD_DEAD + data["patient"]["bruteLoss"] = patient.getBruteLoss() + data["patient"]["fireLoss"] = patient.getFireLoss() + data["patient"]["toxLoss"] = patient.getToxLoss() + data["patient"]["oxyLoss"] = patient.getOxyLoss() + data["procedures"] = list() + if(patient.surgeries.len) + for(var/datum/surgery/procedure in patient.surgeries) + var/datum/surgery_step/surgery_step = procedure.get_surgery_step() + var/chems_needed = surgery_step.get_chem_list() + var/alternative_step + var/alt_chems_needed = "" + if(surgery_step.repeatable) + var/datum/surgery_step/next_step = procedure.get_surgery_next_step() + if(next_step) + alternative_step = capitalize(next_step.name) + alt_chems_needed = next_step.get_chem_list() + else + alternative_step = "Finish operation" + data["procedures"] += list(list( + "name" = capitalize("[parse_zone(procedure.location)] [procedure.name]"), + "next_step" = capitalize(surgery_step.name), + "chems_needed" = chems_needed, + "alternative_step" = alternative_step, + "alt_chems_needed" = alt_chems_needed + )) return data /obj/machinery/computer/operating/ui_act(action, params) diff --git a/code/game/machinery/computer/aifixer.dm b/code/game/machinery/computer/aifixer.dm index 9ff46c021b..d8553854b2 100644 --- a/code/game/machinery/computer/aifixer.dm +++ b/code/game/machinery/computer/aifixer.dm @@ -8,6 +8,8 @@ icon_keyboard = "tech_key" icon_screen = "ai-fixer" light_color = LIGHT_COLOR_PINK + ui_x = 370 + ui_y = 360 /obj/machinery/computer/aifixer/attackby(obj/I, mob/user, params) if(occupier && istype(I, /obj/item/screwdriver)) @@ -18,8 +20,12 @@ else return ..() -/obj/machinery/computer/aifixer/ui_interact(mob/user) - . = ..() +/obj/machinery/computer/aifixer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "AiRestorer", name, ui_x, ui_y, master_ui, state) + ui.open() var/dat = "" diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index 8a91c266a0..4fb39c04e1 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -136,3 +136,17 @@ empprize = pickweight(prizes) new empprize(loc) explosion(loc, -1, 0, 1+num_of_prizes, flame_range = 1+num_of_prizes) + +/obj/machinery/computer/arcade/attackby(obj/item/O, mob/user, params) + if(istype(O, /obj/item/stack/arcadeticket)) + var/obj/item/stack/arcadeticket/T = O + var/amount = T.get_amount() + if(amount <2) + to_chat(user, "You need 2 tickets to claim a prize!") + return + prizevend(user) + T.pay_tickets() + T.update_icon() + O = T + to_chat(user, "You turn in 2 tickets to the [src] and claim a prize!") + return diff --git a/code/game/machinery/computer/arcade/misc_arcade.dm b/code/game/machinery/computer/arcade/misc_arcade.dm index 78b4a6863c..9b7d3d3f6f 100644 --- a/code/game/machinery/computer/arcade/misc_arcade.dm +++ b/code/game/machinery/computer/arcade/misc_arcade.dm @@ -8,7 +8,7 @@ icon_state = "arcade" circuit = /obj/item/circuitboard/computer/arcade/amputation -/obj/machinery/computer/arcade/amputation/attack_hand(mob/user) +/obj/machinery/computer/arcade/amputation/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(!iscarbon(user)) return var/mob/living/carbon/c_user = user @@ -28,4 +28,4 @@ for(var/i=1; i<=rand(3,5); i++) prizevend(user) else - to_chat(c_user, "You (wisely) decide against putting your hand in the machine.") \ No newline at end of file + to_chat(c_user, "You (wisely) decide against putting your hand in the machine.") diff --git a/code/game/machinery/computer/atmos_alert.dm b/code/game/machinery/computer/atmos_alert.dm index 6df7120dcc..fbedf62734 100644 --- a/code/game/machinery/computer/atmos_alert.dm +++ b/code/game/machinery/computer/atmos_alert.dm @@ -23,7 +23,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "atmos_alert", name, 350, 300, master_ui, state) + ui = new(user, src, ui_key, "AtmosAlertConsole", name, 350, 300, master_ui, state) ui.open() /obj/machinery/computer/atmos_alert/ui_data(mob/user) diff --git a/code/game/machinery/computer/atmos_control.dm b/code/game/machinery/computer/atmos_control.dm index 2faf76ca94..6ee975b338 100644 --- a/code/game/machinery/computer/atmos_control.dm +++ b/code/game/machinery/computer/atmos_control.dm @@ -127,7 +127,7 @@ GLOBAL_LIST_EMPTY(atmos_air_controllers) datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "atmos_control", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "AtmosControlConsole", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/computer/atmos_control/ui_data(mob/user) @@ -269,7 +269,7 @@ GLOBAL_LIST_EMPTY(atmos_air_controllers) datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "atmos_control", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "AtmosControlConsole", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/computer/atmos_control/tank/ui_data(mob/user) diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 70a59230b2..2b3416e1c8 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -4,109 +4,166 @@ icon_screen = "cameras" icon_keyboard = "security_key" circuit = /obj/item/circuitboard/computer/security - var/last_pic = 1 - var/list/network = list("ss13") - var/list/watchers = list() //who's using the console, associated with the camera they're on. - light_color = LIGHT_COLOR_RED + ui_x = 870 + ui_y = 708 + + var/list/network = list("ss13") + var/obj/machinery/camera/active_camera + var/list/concurrent_users = list() + + // Stuff needed to render the map + var/map_name + var/const/default_map_size = 15 + var/obj/screen/cam_screen + var/obj/screen/plane_master/lighting/cam_plane_master + var/obj/screen/background/cam_background /obj/machinery/computer/security/Initialize() . = ..() + // Map name has to start and end with an A-Z character, + // and definitely NOT with a square bracket or even a number. + // I wasted 6 hours on this. :agony: + map_name = "camera_console_[REF(src)]_map" + // Convert networks to lowercase for(var/i in network) network -= i network += lowertext(i) - -/obj/machinery/computer/security/check_eye(mob/user) - if(!can_interact(user) || !(user in watchers) || !watchers[user]) - user.unset_machine() - return - var/obj/machinery/camera/C = watchers[user] - if(!C.can_use()) - user.unset_machine() - return - -/obj/machinery/computer/security/on_unset_machine(mob/user) - watchers.Remove(user) - user.reset_perspective(null) + // Initialize map objects + cam_screen = new + cam_screen.name = "screen" + cam_screen.assigned_map = map_name + cam_screen.del_on_map_removal = FALSE + cam_screen.screen_loc = "[map_name]:1,1" + cam_plane_master = new + cam_plane_master.name = "plane_master" + cam_plane_master.assigned_map = map_name + cam_plane_master.del_on_map_removal = FALSE + cam_plane_master.screen_loc = "[map_name]:CENTER" + cam_background = new + cam_background.assigned_map = map_name + cam_background.del_on_map_removal = FALSE /obj/machinery/computer/security/Destroy() - if(watchers.len) - for(var/mob/M in watchers) - M.unset_machine() //to properly reset the view of the users if the console is deleted. + qdel(cam_screen) + qdel(cam_plane_master) + qdel(cam_background) return ..() -/obj/machinery/computer/security/can_interact(mob/user) - if((!hasSiliconAccessInArea(user) && !Adjacent(user)) || is_blind(user) || !in_view_range(user, src)) - return FALSE - return ..() +/obj/machinery/computer/security/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) + for(var/i in network) + network -= i + network += "[idnum][i]" -/obj/machinery/computer/security/interact(mob/user, special_state) +/obj/machinery/computer/security/ui_interact(\ + mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + // Update UI + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + // Show static if can't use the camera + if(!active_camera?.can_use()) + show_camera_static() + if(!ui) + var/user_ref = REF(user) + var/is_living = isliving(user) + // Ghosts shouldn't count towards concurrent users, which produces + // an audible terminal_on click. + if(is_living) + concurrent_users += user_ref + // Turn on the console + if(length(concurrent_users) == 1 && is_living) + playsound(src, 'sound/machines/terminal_on.ogg', 25, FALSE) + use_power(active_power_usage) + // Register map objects + user.client.register_map_obj(cam_screen) + user.client.register_map_obj(cam_plane_master) + user.client.register_map_obj(cam_background) + // Open UI + ui = new(user, src, ui_key, "CameraConsole", name, ui_x, ui_y, master_ui, state) + ui.open() + +/obj/machinery/computer/security/ui_data() + var/list/data = list() + data["network"] = network + data["activeCamera"] = null + if(active_camera) + data["activeCamera"] = list( + name = active_camera.c_tag, + status = active_camera.status, + ) + return data + +/obj/machinery/computer/security/ui_static_data() + var/list/data = list() + data["mapRef"] = map_name + var/list/cameras = get_available_cameras() + data["cameras"] = list() + for(var/i in cameras) + var/obj/machinery/camera/C = cameras[i] + data["cameras"] += list(list( + name = C.c_tag, + )) + return data + +/obj/machinery/computer/security/ui_act(action, params) . = ..() - if (ismob(user) && !isliving(user)) // ghosts don't need cameras - return - if (!network) - stack_trace("No camera network") - user.unset_machine() - return FALSE - if (!(islist(network))) - stack_trace("Camera network is not a list") - user.unset_machine() - return FALSE - - var/list/camera_list = get_available_cameras() - if(!(user in watchers)) - for(var/Num in camera_list) - var/obj/machinery/camera/CAM = camera_list[Num] - if(istype(CAM) && CAM.can_use()) - watchers[user] = CAM //let's give the user the first usable camera, and then let him change to the camera he wants. - break - if(!(user in watchers)) - user.unset_machine() // no usable camera on the network, we disconnect the user from the computer. - return FALSE - playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0) - use_camera_console(user) - -/obj/machinery/computer/security/proc/use_camera_console(mob/user) - var/list/camera_list = get_available_cameras() - var/t = input(user, "Which camera should you change to?") as null|anything in camera_list - if(!src || user.machine != src) //while we were choosing we got disconnected from our computer or are using another machine. - return - if(!t || t == "Cancel") - user.unset_machine() - playsound(src, 'sound/machines/terminal_off.ogg', 25, 0) + if(.) return - var/obj/machinery/camera/C = camera_list[t] + if(action == "switch_camera") + var/c_tag = params["name"] + var/list/cameras = get_available_cameras() + var/obj/machinery/camera/C = cameras[c_tag] + active_camera = C + playsound(src, get_sfx("terminal_type"), 25, FALSE) - if(!C || !C.can_use() || !can_interact(user)) - user.unset_machine() - return FALSE + // Show static if can't use the camera + if(!active_camera?.can_use()) + show_camera_static() + return TRUE - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25, 0) - if(isAI(user)) - var/mob/living/silicon/ai/A = user - A.eyeobj.setLoc(get_turf(C)) - A.client.eye = A.eyeobj - else - user.reset_perspective(C) - user.overlay_fullscreen("flash", /obj/screen/fullscreen/flash/static) - user.clear_fullscreen("flash", 5) - watchers[user] = C - use_power(50) - addtimer(CALLBACK(src, .proc/use_camera_console, user), 5) + var/list/visible_turfs = list() + for(var/turf/T in (C.isXRay() \ + ? range(C.view_range, C) \ + : view(C.view_range, C))) + visible_turfs += T -//returns the list of cameras accessible from this computer + var/list/bbox = get_bbox_of_atoms(visible_turfs) + var/size_x = bbox[3] - bbox[1] + 1 + var/size_y = bbox[4] - bbox[2] + 1 + + cam_screen.vis_contents = visible_turfs + cam_background.icon_state = "clear" + cam_background.fill_rect(1, 1, size_x, size_y) + + return TRUE + +/obj/machinery/computer/security/ui_close(mob/user) + var/user_ref = REF(user) + var/is_living = isliving(user) + // Living creature or not, we remove you anyway. + concurrent_users -= user_ref + // Unregister map objects + user.client.clear_map(map_name) + // Turn off the console + if(length(concurrent_users) == 0 && is_living) + active_camera = null + playsound(src, 'sound/machines/terminal_off.ogg', 25, FALSE) + use_power(0) + +/obj/machinery/computer/security/proc/show_camera_static() + cam_screen.vis_contents.Cut() + cam_background.icon_state = "scanline2" + cam_background.fill_rect(1, 1, default_map_size, default_map_size) + +// Returns the list of cameras accessible from this computer /obj/machinery/computer/security/proc/get_available_cameras() var/list/L = list() for (var/obj/machinery/camera/C in GLOB.cameranet.cameras) if((is_away_level(z) || is_away_level(C.z)) && (C.z != z))//if on away mission, can only receive feed from same z_level cameras continue L.Add(C) - - camera_sort(L) - var/list/D = list() - D["Cancel"] = "Cancel" for(var/obj/machinery/camera/C in L) if(!C.network) stack_trace("Camera in a cameranet has no camera network") @@ -114,9 +171,9 @@ if(!(islist(C.network))) stack_trace("Camera in a cameranet has a non-list camera network") continue - var/list/tempnetwork = C.network&network + var/list/tempnetwork = C.network & network if(tempnetwork.len) - D["[C.c_tag][(C.status ? null : " (Deactivated)")]"] = C + D["[C.c_tag]"] = C return D // SECURITY MONITORS @@ -127,7 +184,6 @@ icon_state = "television" icon_keyboard = null icon_screen = "detective_tv" - clockwork = TRUE //it'd look weird pass_flags = PASSTABLE /obj/machinery/computer/security/mining @@ -145,7 +201,7 @@ circuit = /obj/item/circuitboard/computer/research /obj/machinery/computer/security/hos - name = "Head of Security's camera console" + name = "\improper Head of Security's camera console" desc = "A custom security console with added access to the labor camp network." network = list("ss13", "labor") circuit = null @@ -157,7 +213,7 @@ circuit = null /obj/machinery/computer/security/qm - name = "Quartermaster's camera console" + name = "\improper Quartermaster's camera console" desc = "A console with access to the mining, auxillary base and vault camera networks." network = list("mine", "auxbase", "vault") circuit = null @@ -172,7 +228,6 @@ network = list("thunder") density = FALSE circuit = null - clockwork = TRUE //it'd look very weird light_power = 0 /obj/machinery/computer/security/telescreen/Initialize() @@ -190,11 +245,35 @@ name = "entertainment monitor" desc = "Damn, they better have the /tg/ channel on these things." icon = 'icons/obj/status_display.dmi' - icon_state = "entertainment" + icon_state = "entertainment_blank" network = list("thunder") + density = FALSE + circuit = null + interaction_flags_atom = NONE // interact() is called by BigClick() + var/icon_state_off = "entertainment_blank" + var/icon_state_on = "entertainment" + +/obj/machinery/computer/security/telescreen/entertainment/Initialize() + . = ..() + RegisterSignal(src, COMSIG_CLICK, .proc/BigClick) + +// Bypass clickchain to allow humans to use the telescreen from a distance +/obj/machinery/computer/security/telescreen/entertainment/proc/BigClick() + interact(usr) + +/obj/machinery/computer/security/telescreen/entertainment/proc/notify(on) + if(on && icon_state == icon_state_off) + say(pick( + "Feats of bravery live now at the thunderdome!", + "Two enter, one leaves! Tune in now!", + "Violence like you've never seen it before!", + "Spears! Camera! Action! LIVE NOW!")) + icon_state = icon_state_on + else + icon_state = icon_state_off /obj/machinery/computer/security/telescreen/rd - name = "Research Director's telescreen" + name = "\improper Research Director's telescreen" desc = "Used for watching the AI and the RD's goons from the safety of his office." network = list("rd", "aicore", "aiupload", "minisat", "xeno", "test") @@ -202,26 +281,26 @@ name = "circuitry telescreen" desc = "Used for watching the other eggheads from the safety of the circuitry lab." network = list("rd") - + /obj/machinery/computer/security/telescreen/ce - name = "Chief Engineer's telescreen" + name = "\improper Chief Engineer's telescreen" desc = "Used for watching the engine, telecommunications and the minisat." network = list("engine", "singularity", "tcomms", "minisat") /obj/machinery/computer/security/telescreen/cmo - name = "Chief Medical Officer's telescreen" + name = "\improper Chief Medical Officer's telescreen" desc = "A telescreen with access to the medbay's camera network." network = list("medbay") /obj/machinery/computer/security/telescreen/vault - name = "Vault monitor" + name = "vault monitor" desc = "A telescreen that connects to the vault's camera network." network = list("vault") /obj/machinery/computer/security/telescreen/toxins - name = "Bomb test site monitor" + name = "bomb test site monitor" desc = "A telescreen that connects to the bomb test site's camera." - network = list("toxin") + network = list("toxins") /obj/machinery/computer/security/telescreen/engine name = "engine monitor" @@ -254,7 +333,7 @@ network = list("minisat") /obj/machinery/computer/security/telescreen/aiupload - name = "AI upload monitor" + name = "\improper AI upload monitor" desc = "A telescreen that connects to the AI upload's camera network." network = list("aiupload") diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm index 5fe62ebb76..9f1390c69b 100644 --- a/code/game/machinery/computer/camera_advanced.dm +++ b/code/game/machinery/computer/camera_advanced.dm @@ -29,9 +29,17 @@ if(lock_override & CAMERA_LOCK_REEBE) z_lock |= SSmapping.levels_by_trait(ZTRAIT_REEBE) +/obj/machinery/computer/camera_advanced/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) + for(var/i in networks) + networks -= i + networks += "[idnum][i]" + /obj/machinery/computer/camera_advanced/syndie icon_keyboard = "syndie_key" +/obj/machinery/computer/camera_advanced/syndie/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) + return //For syndie nuke shuttle, to spy for station. + /obj/machinery/computer/camera_advanced/proc/CreateEye() eyeobj = new() eyeobj.origin = src @@ -95,7 +103,7 @@ return FALSE return ..() -/obj/machinery/computer/camera_advanced/attack_hand(mob/user) +/obj/machinery/computer/camera_advanced/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 22bea14381..6a99b248e3 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -61,7 +61,7 @@ // main interface if("main") state = STATE_DEFAULT - playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) if("login") var/mob/M = usr @@ -73,19 +73,19 @@ auth_id = "[I.registered_name] ([I.assignment])" if((ACCESS_CAPTAIN in I.access)) authenticated = 2 - playsound(src, 'sound/machines/terminal_on.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) if(obj_flags & EMAGGED) authenticated = 2 auth_id = "Unknown" to_chat(M, "[src] lets out a quiet alarm as its login is overridden.") - playsound(src, 'sound/machines/terminal_on.ogg', 50, 0) - playsound(src, 'sound/machines/terminal_alert.ogg', 25, 0) + playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) + playsound(src, 'sound/machines/terminal_alert.ogg', 25, FALSE) if(prob(25)) for(var/mob/living/silicon/ai/AI in active_ais()) SEND_SOUND(AI, sound('sound/machines/terminal_alert.ogg', volume = 10)) //Very quiet for balance reasons if("logout") authenticated = 0 - playsound(src, 'sound/machines/terminal_off.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE) if("swipeidseclevel") var/mob/M = usr @@ -109,7 +109,7 @@ security_level_cd = world.time + 15 SECONDS if(GLOB.security_level != old_level) to_chat(usr, "Authorization confirmed. Modifying security level.") - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) //Only notify people if an actual change happened var/security_level = NUM2SECLEVEL(GLOB.security_level) log_game("[key_name(usr)] has changed the security level to [security_level] with [src] at [AREACOORD(usr)].") @@ -118,28 +118,28 @@ tmp_alertlevel = 0 else to_chat(usr, "You are not authorized to do this!") - playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) tmp_alertlevel = 0 state = STATE_DEFAULT else to_chat(usr, "You need to swipe your ID!") - playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) if("announce") if(authenticated==2) - playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE) make_announcement(usr) if("crossserver") if(authenticated==2) if(!checkCCcooldown()) - to_chat(usr, "Arrays recycling. Please stand by.") - playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) + 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.", "") 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) send2otherserver("[station_name()]", input,"Comms_Console") minor_announce(input, title = "Outgoing message to allied station") usr.log_talk(input, LOG_SAY, tag="message to the other server") @@ -168,22 +168,18 @@ if(D) points_to_check = D.account_balance if(points_to_check >= S.credit_cost) - var/obj/machinery/shuttle_manipulator/M = locate() in GLOB.machines - if(M) - SSshuttle.shuttle_purchased = TRUE - D.adjust_money(-S.credit_cost) - minor_announce("[usr.real_name] has purchased [S.name] for [S.credit_cost] credits." , "Shuttle Purchase") - message_admins("[ADMIN_LOOKUPFLW(usr)] purchased [S.name].") - SSblackbox.record_feedback("text", "shuttle_purchase", 1, "[S.name]") - M.unload_preview() - M.load_template(S) - M.existing_shuttle = SSshuttle.emergency - M.action_load(S) - message_admins("[S.name] loaded, purchased by [usr]") - else - to_chat(usr, "Something went wrong! The shuttle exchange system seems to be down.") + SSshuttle.shuttle_purchased = TRUE + SSshuttle.unload_preview() + SSshuttle.load_template(S) + SSshuttle.existing_shuttle = SSshuttle.emergency + SSshuttle.action_load(S) + D.adjust_money(-S.credit_cost) + minor_announce("[usr.real_name] has purchased [S.name] for [S.credit_cost] credits." , "Shuttle Purchase") + message_admins("[ADMIN_LOOKUPFLW(usr)] purchased [S.name].") + log_shuttle("[key_name(usr)] has purchased [S.name].") + SSblackbox.record_feedback("text", "shuttle_purchase", 1, "[S.name]") else - to_chat(usr, "Not enough credits.") + to_chat(usr, "Insufficient credits.") if("callshuttle") state = STATE_DEFAULT @@ -268,7 +264,7 @@ // Status display stuff if("setstat") - playsound(src, "terminal_type", 50, 0) + playsound(src, "terminal_type", 50, FALSE) switch(href_list["statdisp"]) if("message") post_status("message", stat_msg1, stat_msg2) @@ -308,13 +304,13 @@ if("MessageSyndicate") if((authenticated==2) && (obj_flags & EMAGGED)) if(!checkCCcooldown()) - to_chat(usr, "Arrays recycling. Please stand by.") - playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) + to_chat(usr, "Arrays recycling. Please stand by.") + playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) return var/input = stripped_input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING COORDINATES\] 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 /??????/.", "") 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) Syndicate_announce(input, usr) to_chat(usr, "SYSERR @l(19833)of(transmit.dm): !@$ MESSAGE TRANSMITTED TO SYNDICATE COMMAND.") for(var/client/X in GLOB.admins) @@ -327,7 +323,7 @@ if("RestoreBackup") to_chat(usr, "Backup routing data restored!") - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) obj_flags &= ~EMAGGED updateDialog() @@ -341,7 +337,7 @@ return Nuke_request(input, usr) to_chat(usr, "Request sent.") - usr.log_message("has requested the nuclear codes from CentCom", LOG_SAY) + usr.log_message("has requested the nuclear codes from CentCom with reason \"[input]\"", LOG_SAY) priority_announce("The codes for the on-station nuclear self-destruct have been requested by [usr]. Confirmation or denial of this request will be sent shortly.", "Nuclear Self Destruct Codes Requested","commandreport") CM.lastTimeUsed = world.time @@ -448,7 +444,7 @@ if(authenticated == 1) authenticated = 2 to_chat(user, "You scramble the communication routing circuits!") - playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_alert.ogg', 50, FALSE) return TRUE /obj/machinery/computer/communications/ui_interact(mob/user) @@ -514,16 +510,16 @@ dat += "
    \[ Log In \]" if(STATE_CALLSHUTTLE) dat += get_call_shuttle_form() - playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE) if(STATE_CANCELSHUTTLE) dat += get_cancel_shuttle_form() - playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE) if(STATE_MESSAGELIST) dat += "Messages:" for(var/i in 1 to messages.len) var/datum/comm_message/M = messages[i] dat += "
    [M.title]" - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) if(STATE_VIEWMESSAGE) if (currmsg) dat += "[currmsg.title]

    [currmsg.content]" @@ -557,7 +553,7 @@ dat += " Red Alert |" dat += " Lockdown |" dat += " Biohazard \]

    " - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) if(STATE_ALERT_LEVEL) dat += "Current alert level: [NUM2SECLEVEL(GLOB.security_level)]
    " if(GLOB.security_level == SEC_LEVEL_DELTA) @@ -571,7 +567,7 @@ dat += "Confirm the change to: [NUM2SECLEVEL(tmp_alertlevel)]
    " dat += "Swipe ID to confirm change.
    " if(STATE_TOGGLE_EMERGENCY) - playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0) + playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE) if(GLOB.emergency_access == 1) dat += "Emergency Maintenance Access is currently ENABLED" dat += "
    Restore maintenance access restrictions?
    \[ OK | Cancel \]" @@ -722,7 +718,7 @@ /obj/machinery/computer/communications/proc/make_announcement(mob/living/user, is_silicon) if(!SScommunications.can_announce(user, is_silicon)) - to_chat(user, "Intercomms recharging. Please stand by.") + 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)) diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm index 01a1d043a2..cd8b5c1c59 100644 --- a/code/game/machinery/computer/crew.dm +++ b/code/game/machinery/computer/crew.dm @@ -80,7 +80,7 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if (!ui) - ui = new(user, src, ui_key, "crew", "crew monitor", 800, 600 , master_ui, state) + ui = new(user, src, ui_key, "CrewConsole", "crew monitor", 800, 600 , master_ui, state) ui.open() /datum/crewmonitor/proc/show(mob/M, source) diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm index d465ff2022..2dce50aa88 100644 --- a/code/game/machinery/computer/dna_console.dm +++ b/code/game/machinery/computer/dna_console.dm @@ -1,25 +1,41 @@ +/// Base timeout for creating mutation activators and other injectors #define INJECTOR_TIMEOUT 100 +/// Maximum number of genetic makeup storage slots in DNA Console #define NUMBER_OF_BUFFERS 3 +/// Timeout for DNA Scramble in DNA Consoles #define SCRAMBLE_TIMEOUT 600 -#define JOKER_TIMEOUT 12000 //20 minutes -#define JOKER_UPGRADE 1800 +/// Timeout for using the Joker feature to solve a gene in DNA Console +#define JOKER_TIMEOUT 12000 +/// How much time DNA Scanner upgrade tiers remove from JOKER_TIMEOUT +#define JOKER_UPGRADE 3000 +/// Maximum value for radiaton strength when pulsing enzymes #define RADIATION_STRENGTH_MAX 15 -#define RADIATION_STRENGTH_MULTIPLIER 1 //larger has more range +/// Larger multipliers will affect the range of values when pulsing enzymes +#define RADIATION_STRENGTH_MULTIPLIER 1 +/// Maximum value for the radiation pulse duration when pulsing enzymes #define RADIATION_DURATION_MAX 30 -#define RADIATION_ACCURACY_MULTIPLIER 3 //larger is less accurate +/// Large values reduce pulse accuracy and may pulse other enzymes than selected +#define RADIATION_ACCURACY_MULTIPLIER 3 +/// Special status indicating a scanner occupant is transforming eg. from monkey to human +#define STATUS_TRANSFORMING 4 -#define RADIATION_IRRADIATION_MULTIPLIER 1 //multiplier for how much radiation a test subject receives +/// Multiplier for how much radiation received from DNA Console functionality +#define RADIATION_IRRADIATION_MULTIPLIER 1 -#define SCANNER_ACTION_SE 1 -#define SCANNER_ACTION_UI 2 -#define SCANNER_ACTION_UE 3 -#define SCANNER_ACTION_MIXED 4 +/// Flag for the mutation ref search system. Search will include scanner occupant +#define SEARCH_OCCUPANT 1 +/// Flag for the mutation ref search system. Search will include console storage +#define SEARCH_STORED 2 +/// Flag for the mutation ref search system. Search will include diskette storage +#define SEARCH_DISKETTE 4 +/// Flag for the mutation ref search system. Search will include advanced injector mutations +#define SEARCH_ADV_INJ 8 /obj/machinery/computer/scan_consolenew - name = "\improper DNA scanner access console" + name = "DNA Console" desc = "Scan DNA." icon_screen = "dna" icon_keyboard = "med_key" @@ -31,47 +47,103 @@ active_power_usage = 400 light_color = LIGHT_COLOR_BLUE + /// Link to the techweb's stored research. Used to retrieve stored mutations var/datum/techweb/stored_research + /// Maximum number of mutations that DNA Consoles are able to store var/max_storage = 6 - var/combine + /// Duration for enzyme radiation pulses var/radduration = 2 + /// Strength for enzyme radiation pulses var/radstrength = 1 + /// Maximum number of chromosomes that DNA Consoles are able to store. var/max_chromosomes = 6 - - ///Amount of mutations we can store - var/list/buffer[NUMBER_OF_BUFFERS] - ///mutations we have stored + /// Maximum number of enzymes we can store + var/list/genetic_makeup_buffer[NUMBER_OF_BUFFERS] + /// List of all mutations stored on the DNA Console var/list/stored_mutations = list() - ///chromosomes we have stored + /// List of all chromosomes stored in the DNA Console var/list/stored_chromosomes = list() - ///combinations of injectors for the 'injector selection'. format is list("Elsa" = list(Cryokinesis, Geladikinesis), "The Hulk" = list(Hulk, Gigantism), etc) Glowy and the gang being an initialized datum - var/list/injector_selection = list() - ///max amount of selections you can make + /// Assoc list of all advanced injectors. Keys are injector names. Values are lists of mutations. + var/list/list/injector_selection = list() + /// Maximum number of advanced injectors that DNA Consoles store var/max_injector_selections = 2 - ///hard-cap on the advanced dna injector + /// Maximum number of mutation that an advanced injector can store var/max_injector_mutations = 10 - ///the max instability of the advanced injector. + /// Maximum total instability of all combined mutations allowed on an advanced injector var/max_injector_instability = 50 - var/injectorready = 0 //world timer cooldown var + /// World time when injectors are ready to be printed + var/injectorready = 0 + /// World time when JOKER algorithm can be used in DNA Consoles var/jokerready = 0 + /// World time when Scramble can be used in DNA Consoles var/scrambleready = 0 - var/current_screen = "mainmenu" - var/current_mutation //what block are we inspecting? only used when screen = "info" - var/current_storage //what storage block are we looking at? - var/obj/machinery/dna_scannernew/connected = null + + /// Currently stored genetic data diskette var/obj/item/disk/data/diskette = null + + /// Current delayed action, used for delayed enzyme transfer on scanner door close var/list/delayed_action = null + /// Index of the enzyme being modified during delayed enzyme pulse operations + var/rad_pulse_index = 0 + /// World time when the enzyme pulse should complete + var/rad_pulse_timer = 0 + + /// Used for setting tgui data - Whether the connected DNA Scanner is usable + var/can_use_scanner = FALSE + /// Used for setting tgui data - Whether the current DNA Scanner occupant is viable for genetic modification + var/is_viable_occupant = FALSE + /// Used for setting tgui data - Whether Scramble DNA is ready + var/is_scramble_ready = FALSE + /// Used for setting tgui data - Whether JOKER algorithm is ready + var/is_joker_ready = FALSE + /// Used for setting tgui data - Whether injectors are ready to be printed + var/is_injector_ready = FALSE + /// Used for setting tgui data - Wheher an enzyme pulse operation is ongoing + var/is_pulsing_rads = FALSE + /// Used for setting tgui data - Time until scramble is ready + var/time_to_scramble = 0 + /// Used for setting tgui data - Time until joker is ready + var/time_to_joker = 0 + /// Used for setting tgui data - Time until injectors are ready + var/time_to_injector = 0 + /// Used for setting tgui data - Time until the enzyme pulse is complete + var/time_to_pulse = 0 + + /// Currently connected DNA Scanner + var/obj/machinery/dna_scannernew/connected_scanner = null + /// Current DNA Scanner occupant + var/mob/living/carbon/scanner_occupant = null + + /// Used for setting tgui data - List of occupant mutations + var/list/tgui_occupant_mutations = list() + /// Used for setting tgui data - List of DNA Console stored mutations + var/list/tgui_console_mutations = list() + /// Used for setting tgui data - List of diskette stored mutations + var/list/tgui_diskette_mutations = list() + /// Used for setting tgui data - List of DNA Console chromosomes + var/list/tgui_console_chromosomes = list() + /// Used for setting tgui data - List of occupant mutations + var/list/tgui_genetic_makeup = list() + /// Used for setting tgui data - List of occupant mutations + var/list/tgui_advinjector_mutations = list() + + + /// State of tgui view, i.e. which tab is currently active, or which genome we're currently looking at. + var/list/list/tgui_view_state = list() + +/obj/machinery/computer/scan_consolenew/process() + . = ..() + + // This is for pulsing the UI element with radiation as part of genetic makeup + // If rad_pulse_index > 0 then it means we're attempting a rad pulse + if((rad_pulse_index > 0) && (rad_pulse_timer <= world.time)) + rad_pulse() + return + /obj/machinery/computer/scan_consolenew/attackby(obj/item/I, mob/user, params) - if (istype(I, /obj/item/disk/data)) //INSERT SOME DISKETTES - if (!src.diskette) - if (!user.transferItemToLoc(I,src)) - return - src.diskette = I - to_chat(user, "You insert [I].") - src.updateUsrDialog() - return + // Store chromosomes in the console if there's room if (istype(I, /obj/item/chromosome)) if(LAZYLEN(stored_chromosomes) < max_chromosomes) I.forceMove(src) @@ -80,856 +152,1797 @@ else to_chat(user, "You cannot store any more chromosomes!") return + + // Insert data disk if console disk slot is empty + // Swap data disk if there is one already a disk in the console + if (istype(I, /obj/item/disk/data)) //INSERT SOME DISKETTES + // Insert disk into DNA Console + if (!user.transferItemToLoc(I,src)) + return + // If insertion was successful and there's already a diskette in the console, eject the old one. + if(diskette) + eject_disk(user) + // Set the new diskette. + diskette = I + to_chat(user, "You insert [I].") + return + + // Recycle non-activator used injectors + // Turn activator used injectors (aka research injectors) to chromosomes if(istype(I, /obj/item/dnainjector/activator)) var/obj/item/dnainjector/activator/A = I if(A.used) to_chat(user,"Recycled [I].") if(A.research) - var/c_typepath = generate_chromosome() - var/obj/item/chromosome/CM = new c_typepath (drop_location()) - to_chat(user,"Recycled [I].") - if((LAZYLEN(stored_chromosomes) < max_chromosomes) && prob(60)) - CM.forceMove(src) - stored_chromosomes += CM - to_chat(user,"[capitalize(CM.name)] added to storage.") + if(prob(60)) + var/c_typepath = generate_chromosome() + var/obj/item/chromosome/CM = new c_typepath (drop_location()) + if(LAZYLEN(stored_chromosomes) < max_chromosomes) + CM.forceMove(src) + stored_chromosomes += CM + to_chat(user,"[capitalize(CM.name)] added to storage.") + else + to_chat(user, "You cannot store any more chromosomes!") + to_chat(user, "[capitalize(CM.name)] added on top of the console.") + else + to_chat(user, "There was not enough genetic data to extract a viable chromosome.") qdel(I) return - else - return ..() + + return ..() + + +/obj/machinery/computer/scan_consolenew/AltClick(mob/user) + // Make sure the user can interact with the machine. + if(!user.canUseTopic(src, !issilicon(user))) + return + + eject_disk(user) /obj/machinery/computer/scan_consolenew/Initialize() . = ..() - for(var/direction in GLOB.cardinals) - connected = locate(/obj/machinery/dna_scannernew, get_step(src, direction)) - if(!isnull(connected)) - break + + // Connect with a nearby DNA Scanner on init + connect_to_scanner() + + // Set appropriate ready timers and limits for machines functions injectorready = world.time + INJECTOR_TIMEOUT scrambleready = world.time + SCRAMBLE_TIMEOUT jokerready = world.time + JOKER_TIMEOUT + // Set the default tgui state + set_default_state() + + // Link machine with research techweb. Used for discovering and accessing + // already discovered mutations stored_research = SSresearch.science_tech /obj/machinery/computer/scan_consolenew/examine(mob/user) . = ..() - if(jokerready < world.time) - . += "JOKER algorithm available." - else - . += "JOKER algorithm available in about [round(0.00166666667 * (jokerready - world.time))] minutes." -/obj/machinery/computer/scan_consolenew/ui_interact(mob/user, last_change) +/obj/machinery/computer/scan_consolenew/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) . = ..() - if(!user) - return - var/datum/browser/popup = new(user, "scannernew", "DNA Modifier Console", 800, 630) // Set up the popup browser window - if(user.client) - var/datum/asset/simple/assets = get_asset_datum(/datum/asset/simple/genetics) - assets.send(user.client) - if(!(in_range(src, user) || hasSiliconAccessInArea(user))) - popup.close() - return - popup.add_stylesheet("scannernew", 'html/browser/scannernew.css') - var/mob/living/carbon/viable_occupant - var/list/occupant_status = list("
    Subject Status:
    ") - var/scanner_status - var/list/temp_html = list() - if(connected && connected.is_operational()) - if(connected.occupant) //set occupant_status message - viable_occupant = connected.occupant - if(viable_occupant.has_dna() && !HAS_TRAIT_NOT_FROM(viable_occupant, TRAIT_RADIMMUNE,BLOODSUCKER_TRAIT) && !HAS_TRAIT(viable_occupant, TRAIT_NOCLONE) || (connected.scan_level == 3)) //occupant is viable for dna modification - occupant_status += "[viable_occupant.name] => " - switch(viable_occupant.stat) - if(CONSCIOUS) - occupant_status += "Conscious" - if(UNCONSCIOUS) - occupant_status += "Unconscious" - else - occupant_status += "DEAD" - occupant_status += "
    " - occupant_status += "
    Health:
    [viable_occupant.health] %
    " - occupant_status += "
    Radiation Level:
    [viable_occupant.radiation/(RAD_MOB_SAFE/100)] %
    " - occupant_status += "
    Unique Enzymes :
    [viable_occupant.dna.unique_enzymes]
    " - occupant_status += "
    Last Operation:
    [last_change ? last_change : "----"]
    " + // Most of ui_interact is spent setting variables for passing to the tgui + // interface. + // We can also do some general state processing here too as it's a good + // indication that a player is using the console. + + var/scanner_op = scanner_operational() + var/can_modify_occ = can_modify_occupant() + + // Check for connected AND operational scanner. + if(scanner_op) + can_use_scanner = TRUE + else + can_use_scanner = FALSE + connected_scanner = null + is_viable_occupant = FALSE + + // Check for a viable occupant in the scanner. + if(can_modify_occ) + is_viable_occupant = TRUE + else + is_viable_occupant = FALSE + + + // Populates various buffers for passing to tgui + build_mutation_list(can_modify_occ) + build_genetic_makeup_list() + + // Populate variables for passing to tgui interface + is_scramble_ready = (scrambleready < world.time) + time_to_scramble = round((scrambleready - world.time)/10) + + is_joker_ready = (jokerready < world.time) + time_to_joker = round((jokerready - world.time)/10) + + is_injector_ready = (injectorready < world.time) + time_to_injector = round((injectorready - world.time)/10) + + is_pulsing_rads = ((rad_pulse_index > 0) && (rad_pulse_timer > world.time)) + time_to_pulse = round((rad_pulse_timer - world.time)/10) + + // Attempt to update tgui ui, open and update if needed. + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + + if(!ui) + ui = new(user, src, ui_key, "DnaConsole", name, 539, 710, master_ui, state) + ui.open() + +/obj/machinery/computer/scan_consolenew/ui_data(mob/user) + var/list/data = list() + + data["view"] = tgui_view_state + data["storage"] = list() + + // This block of code generates the huge data structure passed to the tgui + // interface for displaying all the various bits of console/scanner data + // Should all be very self-explanatory + data["isScannerConnected"] = can_use_scanner + if(can_use_scanner) + data["scannerOpen"] = connected_scanner.state_open + data["scannerLocked"] = connected_scanner.locked + data["radStrength"] = radstrength + data["radDuration"] = radduration + data["stdDevStr"] = radstrength * RADIATION_STRENGTH_MULTIPLIER + switch(RADIATION_ACCURACY_MULTIPLIER / (radduration + (connected_scanner.precision_coeff ** 2))) //hardcoded values from a z-table for a normal distribution + if(0 to 0.25) + data["stdDevAcc"] = ">95 %" + if(0.25 to 0.5) + data["stdDevAcc"] = "68-95 %" + if(0.5 to 0.75) + data["stdDevAcc"] = "55-68 %" else - viable_occupant = null - occupant_status += "Invalid DNA structure" + data["stdDevAcc"] = "<38 %" + + data["isViableSubject"] = is_viable_occupant + if(is_viable_occupant) + data["subjectName"] = scanner_occupant.name + if(scanner_occupant.transformation_timer) + data["subjectStatus"] = STATUS_TRANSFORMING else - occupant_status += "No subject detected" - - if(connected.state_open) - scanner_status = "Open" - else - scanner_status = "Closed" - if(connected.locked) - scanner_status += "(Locked)" - else - scanner_status += "(Unlocked)" - - + data["subjectStatus"] = scanner_occupant.stat + data["subjectHealth"] = scanner_occupant.health + data["subjectRads"] = scanner_occupant.radiation/(RAD_MOB_SAFE/100) + data["subjectEnzymes"] = scanner_occupant.dna.unique_enzymes + data["isMonkey"] = ismonkey(scanner_occupant) + data["subjectUNI"] = scanner_occupant.dna.uni_identity + data["storage"]["occupant"] = tgui_occupant_mutations + //data["subjectMutations"] = tgui_occupant_mutations else - occupant_status += "----" - scanner_status += "Error: No scanner detected" + data["subjectName"] = null + data["subjectStatus"] = null + data["subjectHealth"] = null + data["subjectRads"] = null + data["subjectEnzymes"] = null + //data["subjectMutations"] = null + data["storage"]["occupant"] = null - var/list/status = list("
    ") - status += "
    Scanner:
    [scanner_status]
    " - status += occupant_status + data["hasDelayedAction"] = (delayed_action != null) + data["isScrambleReady"] = is_scramble_ready + data["isJokerReady"] = is_joker_ready + data["isInjectorReady"] = is_injector_ready + data["scrambleSeconds"] = time_to_scramble + data["jokerSeconds"] = time_to_joker + data["injectorSeconds"] = time_to_injector + data["isPulsingRads"] = is_pulsing_rads + data["radPulseSeconds"] = time_to_pulse + if(diskette != null) + data["hasDisk"] = TRUE + data["diskCapacity"] = diskette.max_mutations - LAZYLEN(diskette.mutations) + data["diskReadOnly"] = diskette.read_only + //data["diskMutations"] = tgui_diskette_mutations + data["storage"]["disk"] = tgui_diskette_mutations + data["diskHasMakeup"] = (LAZYLEN(diskette.genetic_makeup_buffer) > 0) + data["diskMakeupBuffer"] = diskette.genetic_makeup_buffer.Copy() + else + data["hasDisk"] = FALSE + data["diskCapacity"] = 0 + data["diskReadOnly"] = TRUE + //data["diskMutations"] = null + data["storage"]["disk"] = null + data["diskHasMakeup"] = FALSE + data["diskMakeupBuffer"] = null - status += "

    Radiation Emitter Status

    " - var/stddev = radstrength*RADIATION_STRENGTH_MULTIPLIER - status += "
    Output Level:
    [radstrength]
    " - status += "
      \> Mutation:
    (-[stddev] to +[stddev] = 68 %) (-[2*stddev] to +[2*stddev] = 95 %)
    " - if(connected) - stddev = RADIATION_ACCURACY_MULTIPLIER/(radduration + (connected.precision_coeff ** 2)) - else - stddev = RADIATION_ACCURACY_MULTIPLIER/radduration - var/chance_to_hit - switch(stddev) //hardcoded values from a z-table for a normal distribution - if(0 to 0.25) - chance_to_hit = ">95 %" - if(0.25 to 0.5) - chance_to_hit = "68-95 %" - if(0.5 to 0.75) - chance_to_hit = "55-68 %" - else - chance_to_hit = "<38 %" - status += "
    Pulse Duration:
    [radduration]
    " - status += "
      \> Accuracy:
    [chance_to_hit]
    " - status += "
    " // Close statusDisplay div - var/list/buttons = list("Scan") - if(connected) - buttons += "[connected.state_open ? "Close" : "Open"] Scanner" - if (connected.state_open) - buttons += "[connected.locked ? "Unlock" : "Lock"] Scanner" - else - buttons += "[connected.locked ? "Unlock" : "Lock"] Scanner" - else - buttons += "Open Scanner Lock Scanner" - if(viable_occupant && (scrambleready < world.time)) - buttons += "Scramble DNA" - else - buttons += "Scramble DNA" - if(diskette) - buttons += "Disk" - else - buttons += "Disk" - if(current_screen == "mutations") - buttons += "Mutations" - else - buttons += "Mutations" - if((current_screen == "mainmenu") || !current_screen) - buttons += "Genetic Sequencer" - else - buttons += "Genetic Sequencer" - if(current_screen == "ui") - buttons += "Unique Identifiers" - else - buttons += "Unique Identifiers" - if(current_screen == "advinjector") - buttons += "Adv. Injectors" - else - buttons += "Adv. Injectors" - switch(current_screen) - if("working") - temp_html += status - temp_html += "

    System Busy

    " - temp_html += "Working ... Please wait ([DisplayTimeText(radduration*10)])" - if("ui") - temp_html += status - temp_html += buttons - temp_html += "

    Unique Identifiers

    " - temp_html += "-- Output Level ++" - temp_html += "
    -- Pulse Duration ++" - temp_html += "

    Irradiate Subject

    " - temp_html += "
    Unique Identifier:
    " - var/max_line_len = 7*DNA_BLOCK_SIZE - if(viable_occupant) - temp_html += "
    1
    " - var/char = "" - var/ui_text = viable_occupant.dna.uni_identity - var/len_byte = length(ui_text) - var/char_it = 0 - for(var/byte_it = 1, byte_it <= len_byte, byte_it += length(char)) - char_it++ - char = ui_text[byte_it] - temp_html += "[char]" - if((char_it % max_line_len) == 0) - temp_html += "
    " - if((char_it % DNA_BLOCK_SIZE) == 0 && byte_it < len_byte) - temp_html += "
    [(char_it / DNA_BLOCK_SIZE) + 1]
    " - else - temp_html += "---------" - temp_html += "

    Buffer Menu

    " + data["mutationCapacity"] = max_storage - LAZYLEN(stored_mutations) + //data["mutationStorage"] = tgui_console_mutations + data["storage"]["console"] = tgui_console_mutations + data["chromoCapacity"] = max_chromosomes - LAZYLEN(stored_chromosomes) + data["chromoStorage"] = tgui_console_chromosomes + data["makeupCapacity"] = NUMBER_OF_BUFFERS + data["makeupStorage"] = tgui_genetic_makeup - if(istype(buffer)) - for(var/i=1, i<=buffer.len, i++) - temp_html += "
    Slot [i]: " - var/list/buffer_slot = buffer[i] - if( !buffer_slot || !buffer_slot.len || !buffer_slot["name"] || !((buffer_slot["UI"] && buffer_slot["UE"]) || buffer_slot["SE"]) ) - temp_html += "
    \tNo Data" - if(viable_occupant) - temp_html += "
    Save to Buffer" - else - temp_html += "
    Save to Buffer" - temp_html += "Clear Buffer" - if(diskette) - temp_html += "Load from Disk" - else - temp_html += "Load from Disk" - temp_html += "Save to Disk" - else - var/ui = buffer_slot["UI"] - var/ue = buffer_slot["UE"] - var/name = buffer_slot["name"] - var/label = buffer_slot["label"] - var/blood_type = buffer_slot["blood_type"] - temp_html += "
    \tLabel: [label ? label : name]" - temp_html += "
    \tSubject: [name]" - if(ue && name && blood_type) - temp_html += "
    \tBlood Type: [blood_type]" - temp_html += "
    \tUE: [ue] " - if(viable_occupant) - temp_html += "Occupant" - else - temp_html += "Occupant" - temp_html += "Occupant:Delayed" - if(injectorready < world.time) - temp_html += "Injector" - else - temp_html += "Injector" - else - temp_html += "
    \tBlood Type: No Data" - temp_html += "
    \tUE: No Data" - if(ui) - temp_html += "
    \tUI: [ui] " - if(viable_occupant) - temp_html += "Occupant" - else - temp_html += "Occupant" - temp_html += "Occupant:Delayed" - if(injectorready < world.time) - temp_html += "Injector" - else - temp_html += "Injector" - else - temp_html += "
    \tUI: No Data" - if(ue && name && blood_type && ui) - temp_html += "
    \tUI+UE: [ui]/[ue] " - if(viable_occupant) - temp_html += "Occupant" - else - temp_html += "Occupant" - temp_html += "Occupant:Delayed" - if(injectorready < world.time) - temp_html += "UI+UE Injector" - else - temp_html += "UI+UE Injector" - if(viable_occupant) - temp_html += "
    Save to Buffer" - else - temp_html += "
    Save to Buffer" - temp_html += "Clear Buffer" - if(diskette) - temp_html += "Load from Disk" - else - temp_html += "Load from Disk" - if(diskette && !diskette.read_only) - temp_html += "Save to Disk" - else - temp_html += "Save to Disk" - if("disk") - temp_html += status - temp_html += buttons - if(diskette) - temp_html += "

    [diskette.name]


    " - temp_html += "Eject Disk
    " - if(LAZYLEN(diskette.mutations)) - temp_html += "" - for(var/datum/mutation/human/A in diskette.mutations) - temp_html += "" - temp_html += "" - if(LAZYLEN(stored_mutations) < max_storage) - temp_html += "" - else - temp_html += "" - temp_html += "" - temp_html += "
    [A.name]DeleteImportImport
    " - else - temp_html += "
    Load diskette to start ----------" - if("info") - if(LAZYLEN(stored_mutations)) - if(LAZYLEN(stored_mutations) >= current_storage) - var/datum/mutation/human/HM = stored_mutations[current_storage] - if(HM) - temp_html += display_sequence(HM.type, current_storage) - else - current_screen = "mainmenu" - if("mutations") - temp_html += status - temp_html += buttons - temp_html += "

    Mutation Storage:

    " - temp_html += "" - for(var/datum/mutation/human/HM in stored_mutations) - var/i = stored_mutations.Find(HM) - temp_html += "" - temp_html += "" - temp_html += "" - if(combine == HM.type) - temp_html += "" - else - temp_html += "" - temp_html += "
    [HM.name]ExportDeleteCombine
    Combine

    " - temp_html += "

    Chromosome Storage:

    " - temp_html += "" - for(var/i in 1 to stored_chromosomes.len) - var/obj/item/chromosome/CM = stored_chromosomes[i] - temp_html += "
    " - temp_html += "
    [CM.name]
    " - if("advinjector") - temp_html += status - temp_html += buttons - temp_html += "
    Advanced Injectors:

    " - temp_html += "" - for(var/A in injector_selection) - temp_html += "
    [A]" - var/list/true_selection = injector_selection[A] - temp_html += "
    " - for(var/B in true_selection) - var/datum/mutation/human/HM = B - var/mutcolor - switch(HM.quality) - if(POSITIVE) - mutcolor = "good" - if(MINOR_NEGATIVE) - mutcolor = "average" - if(NEGATIVE) - mutcolor = "bad" - temp_html += "
    [HM.name] " - temp_html += "Remove
    " - if (injectorready < world.time) - temp_html += "
    Print Advanced Injector" - else - temp_html += "
    Print Advanced Injector" - temp_html += "Remove Injector
    " - temp_html += "
    " - else - temp_html += status - temp_html += buttons - temp_html += "
    Genetic Sequence:

    " - if(viable_occupant) - if(viable_occupant) - for(var/A in get_mutation_list()) - temp_html += display_inactive_sequence(A) - temp_html += "
    " - else - temp_html += "----" - if(viable_occupant && (current_mutation in get_mutation_list(viable_occupant))) - temp_html += display_sequence(current_mutation) - temp_html += "

    " - else - temp_html += "----------" + //data["advInjectors"] = tgui_advinjector_mutations + data["storage"]["injector"] = tgui_advinjector_mutations + data["maxAdvInjectors"] = max_injector_selections - popup.set_content(temp_html.Join()) - popup.open() + return data -/obj/machinery/computer/scan_consolenew/proc/display_inactive_sequence(mutation) - var/temp_html = "" - var/class = "unselected" - var/mob/living/carbon/viable_occupant = get_viable_occupant() - if(!viable_occupant) - return - - var/location = viable_occupant.dna.mutation_index.Find(mutation) //We do this because we dont want people using sysexp or similair tools to just read the mutations. - - if(!location) //Do this only when needed, dont make a list with mutations for every iteration if you dont need to - var/list/mutations = get_mutation_list(TRUE) - if(mutation in mutations) - location = mutations.Find(mutation) - if(mutation == current_mutation) - class = "selected" - if(location > DNA_MUTATION_BLOCKS) - temp_html += "Extra Mutation" - else if(mutation in stored_research.discovered_mutations) - temp_html += "Discovered Mutation" - else - temp_html += "Undiscovered" - return temp_html - -/obj/machinery/computer/scan_consolenew/proc/display_sequence(mutation, storage_slot) //Storage slot is for when viewing from the stored mutations - var/temp_html = "" - if(!mutation) - temp_html += "ERR-" - return - var/mut_name = "Unknown gene" - var/mut_desc = "No information available." - var/alias - var/discovered = FALSE - var/active = FALSE - var/scrambled = FALSE - var/instability - var/mob/living/carbon/viable_occupant = get_viable_occupant() - var/datum/mutation/human/HM = get_valid_mutation(mutation) - - if(viable_occupant) - var/datum/mutation/human/M = viable_occupant.dna.get_mutation(mutation) - if(M) - scrambled = M.scrambled - active = TRUE - var/datum/mutation/human/A = GET_INITIALIZED_MUTATION(mutation) - alias = A.alias - if(active && !scrambled) - discover(mutation) - if(stored_research && (mutation in stored_research.discovered_mutations)) - mut_name = A.name - mut_desc = A.desc - discovered = TRUE - instability = A.instability - var/extra - if(viable_occupant && !(storage_slot || viable_occupant.dna.mutation_in_sequence(mutation))) - extra = TRUE - - if(discovered && !scrambled) - var/mutcolor - switch(A.quality) - if(POSITIVE) - mutcolor = "good" - if(MINOR_NEGATIVE) - mutcolor = "average" - if(NEGATIVE) - mutcolor = "bad" - if(HM) - instability *= GET_MUTATION_STABILIZER(HM) - temp_html += "
    [mut_name] ([alias])
    " - temp_html += "
    Instability : [round(instability)]
    " - else - temp_html += "
    [alias]
    " - temp_html += "
    [mut_desc]
    " - if(active && !storage_slot) - if(HM?.can_chromosome && (HM in viable_occupant.dna.mutations)) - var/i = viable_occupant.dna.mutations.Find(HM) - var/chromosome_name = "----" - if(HM.chromosome_name) - chromosome_name = HM.chromosome_name - temp_html += "
    Chromosome status: [chromosome_name]
    " - temp_html += "
    Sequence:

    " - if(!scrambled) - for(var/block in 1 to A.blocks) - var/whole_sequence = get_valid_gene_string(mutation) - var/sequence = copytext(whole_sequence, 1+(block-1)*(DNA_SEQUENCE_LENGTH*2),(DNA_SEQUENCE_LENGTH*2*block+1)) - temp_html += "
    " - for(var/i in 1 to DNA_SEQUENCE_LENGTH) - var/num = 1+(i-1)*2 - var/genenum = num+(DNA_SEQUENCE_LENGTH*2*(block-1)) - temp_html += "" - temp_html += "" - for(var/i in 1 to DNA_SEQUENCE_LENGTH) - temp_html += "" - temp_html += "" - for(var/i in 1 to DNA_SEQUENCE_LENGTH) - var/num = i*2 - var/genenum = num+(DNA_SEQUENCE_LENGTH*2*(block-1)) - temp_html += "" - temp_html += "
    |
    " - temp_html += "




    " - else - temp_html = "
    Sequence unreadable due to unpredictable mutation.
    " - if((active || storage_slot) && (injectorready < world.time) && !scrambled) - temp_html += "Print Activator" - temp_html += "Print Mutator" - else - temp_html += "Print Activator" - temp_html += "Print Mutator" - temp_html += "
    " - if(storage_slot) - temp_html += "Delete" - if((LAZYLEN(stored_mutations) < max_storage) && diskette && !diskette.read_only) - temp_html += "Export" - else - temp_html += "Export" - temp_html += "Back" - else if(active && !scrambled) - temp_html += "Store" - temp_html += "Adv. Injector" - if(extra || scrambled) - temp_html += "Nullify" - else - temp_html += "Nullify" - temp_html += "
    " - return temp_html - -/obj/machinery/computer/scan_consolenew/Topic(href, href_list) +/obj/machinery/computer/scan_consolenew/ui_act(action, var/list/params) if(..()) - return - if(!isturf(usr.loc)) - return - if(!((isturf(loc) && in_range(src, usr)) || hasSiliconAccessInArea(usr))) - return - if(current_screen == "working") - return + return TRUE + + . = TRUE add_fingerprint(usr) usr.set_machine(src) - var/mob/living/carbon/viable_occupant = get_viable_occupant() + switch(action) + // Connect this DNA Console to a nearby DNA Scanner + // Usually only activate as an option if there is no connected scanner + if("connect_scanner") + connect_to_scanner() + return - //Basic Tasks/////////////////////////////////////////// - var/num = round(text2num(href_list["num"])) - var/last_change - switch(href_list["task"]) - if("togglelock") - if(connected) - connected.locked = !connected.locked - if("toggleopen") - if(connected) - connected.toggle_open(usr) - if("setduration") - if(!num) - num = round(input(usr, "Choose pulse duration:", "Input an Integer", null) as num|null) - if(num) - radduration = WRAP(num, 1, RADIATION_DURATION_MAX+1) - if("setstrength") - if(!num) - num = round(input(usr, "Choose pulse strength:", "Input an Integer", null) as num|null) - if(num) - radstrength = WRAP(num, 1, RADIATION_STRENGTH_MAX+1) - if("screen") - current_screen = href_list["text"] - if("scramble") - if(viable_occupant && (scrambleready < world.time)) - viable_occupant.dna.remove_all_mutations(list(MUT_NORMAL, MUT_EXTRA)) - viable_occupant.dna.generate_dna_blocks() - scrambleready = world.time + SCRAMBLE_TIMEOUT - to_chat(usr,"DNA scrambled.") - viable_occupant.radiation += RADIATION_STRENGTH_MULTIPLIER*50/(connected.damage_coeff ** 2) - if("setbufferlabel") - var/text = sanitize(input(usr, "Input a new label:", "Input a Text", null) as text|null) - if(num && text) - num = clamp(num, 1, NUMBER_OF_BUFFERS) - var/list/buffer_slot = buffer[num] - if(istype(buffer_slot)) - buffer_slot["label"] = text - if("setbuffer") - if(num && viable_occupant) - num = clamp(num, 1, NUMBER_OF_BUFFERS) - buffer[num] = list( - "label"="Buffer[num]:[viable_occupant.real_name]", - "UI"=viable_occupant.dna.uni_identity, - "UE"=viable_occupant.dna.unique_enzymes, - "name"=viable_occupant.real_name, - "blood_type"=viable_occupant.dna.blood_type - ) - if("clearbuffer") - if(num) - num = clamp(num, 1, NUMBER_OF_BUFFERS) - var/list/buffer_slot = buffer[num] - if(istype(buffer_slot)) - buffer_slot.Cut() - if("transferbuffer") - if(num && viable_occupant) - switch(href_list["text"]) //Numbers are this high because other way upgrading laser is just not worth the hassle, and i cant think of anything better to inmrove - if("ui") - apply_buffer(SCANNER_ACTION_UI,num) - if("ue") - apply_buffer(SCANNER_ACTION_UE,num) - if("mixed") - apply_buffer(SCANNER_ACTION_MIXED,num) - if("injector") - if(num && injectorready < world.time) - num = clamp(num, 1, NUMBER_OF_BUFFERS) - var/list/buffer_slot = buffer[num] - if(istype(buffer_slot)) - var/obj/item/dnainjector/timed/I - switch(href_list["text"]) - if("ui") - if(buffer_slot["UI"]) - I = new /obj/item/dnainjector/timed(loc) - I.fields = list("UI"=buffer_slot["UI"]) - if(connected) - I.damage_coeff = connected.damage_coeff - if("ue") - if(buffer_slot["name"] && buffer_slot["UE"] && buffer_slot["blood_type"]) - I = new /obj/item/dnainjector/timed(loc) - I.fields = list("name"=buffer_slot["name"], "UE"=buffer_slot["UE"], "blood_type"=buffer_slot["blood_type"]) - if(connected) - I.damage_coeff = connected.damage_coeff - if("mixed") - if(buffer_slot["UI"] && buffer_slot["name"] && buffer_slot["UE"] && buffer_slot["blood_type"]) - I = new /obj/item/dnainjector/timed(loc) - I.fields = list("UI"=buffer_slot["UI"],"name"=buffer_slot["name"], "UE"=buffer_slot["UE"], "blood_type"=buffer_slot["blood_type"]) - if(connected) - I.damage_coeff = connected.damage_coeff - if(I) - injectorready = world.time + INJECTOR_TIMEOUT - if("loaddisk") - if(num && diskette && diskette.fields) - num = clamp(num, 1, NUMBER_OF_BUFFERS) - buffer[num] = diskette.fields.Copy() - if("savedisk") - if(num && diskette && !diskette.read_only) - num = clamp(num, 1, NUMBER_OF_BUFFERS) - var/list/buffer_slot = buffer[num] - if(istype(buffer_slot)) - diskette.name = "data disk \[[buffer_slot["label"]]\]" - diskette.fields = buffer_slot.Copy() - if("ejectdisk") - if(diskette) - diskette.forceMove(drop_location()) - diskette = null - if("setdelayed") - if(num) - delayed_action = list("action"=text2num(href_list["delayaction"]),"buffer"=num) - if("pulseui") - if(num && viable_occupant && connected) - radduration = WRAP(radduration, 1, RADIATION_DURATION_MAX+1) - radstrength = WRAP(radstrength, 1, RADIATION_STRENGTH_MAX+1) + // Toggle the door open/closed status on attached DNA Scanner + if("toggle_door") + // GUARD CHECK - Scanner still connected and operational? + if(!scanner_operational()) + return - var/locked_state = connected.locked - connected.locked = TRUE + connected_scanner.toggle_open(usr) + return - current_screen = "working" - ui_interact(usr) + // Toggle the door bolts on the attached DNA Scanner + if("toggle_lock") + // GUARD CHECK - Scanner still connected and operational? + if(!scanner_operational()) + return - sleep(radduration*10) - current_screen = "ui" + connected_scanner.locked = !connected_scanner.locked + return - if(viable_occupant && connected && connected.occupant==viable_occupant) - viable_occupant.radiation += (RADIATION_IRRADIATION_MULTIPLIER*radduration*radstrength)/(connected.damage_coeff ** 2) //Read comment in "transferbuffer" section above for explanation - switch(href_list["task"]) //Same thing as there but values are even lower, on best part they are about 0.0*, effectively no damage - if("pulseui") - var/len = length_char(viable_occupant.dna.uni_identity) - num = WRAP(num, 1, len+1) - num = randomize_radiation_accuracy(num, radduration + (connected.precision_coeff ** 2), len) //Each manipulator level above 1 makes randomization as accurate as selected time + manipulator lvl^2 - //Value is this high for the same reason as with laser - not worth the hassle of upgrading if the bonus is low - var/block = round((num-1)/DNA_BLOCK_SIZE)+1 - var/subblock = num - block*DNA_BLOCK_SIZE - last_change = "UI #[block]-[subblock]; " + // Scramble scanner occupant's DNA + if("scramble_dna") + // GUARD CHECK - Can we genetically modify the occupant? Includes scanner + // operational guard checks. + // GUARD CHECK - Is scramble DNA actually ready? + if(!can_modify_occupant() || !(scrambleready < world.time)) + return - var/hex = copytext_char(viable_occupant.dna.uni_identity, num, num+1) - last_change += "[hex]" - hex = scramble(hex, radstrength, radduration) - last_change += "->[hex]" + scanner_occupant.dna.remove_all_mutations(list(MUT_NORMAL, MUT_EXTRA)) + scanner_occupant.dna.generate_dna_blocks() + scrambleready = world.time + SCRAMBLE_TIMEOUT + to_chat(usr,"DNA scrambled.") + scanner_occupant.radiation += RADIATION_STRENGTH_MULTIPLIER*50/(connected_scanner.damage_coeff ** 2) + return - viable_occupant.dna.uni_identity = copytext_char(viable_occupant.dna.uni_identity, 1, num) + hex + copytext_char(viable_occupant.dna.uni_identity, num + 1) - viable_occupant.updateappearance(mutations_overlay_update=1) + // Check whether a specific mutation is eligible for discovery within the + // scanner occupant + // This is additionally done when a mutation's tab is selected in the tgui + // interface. This is because some mutations, such as Monkified on monkeys, + // are infact completed by default but not yet discovered. Likewise, all + // mutations can have their sequence completed while Monkified is still an + // active mutation and thus won't immediately be discovered but could be + // discovered when Monkified is removed + // ---------------------------------------------------------------------- // + // params["alias"] - Alias of a mutation. The alias is the "hidden" name of + // the mutation, for example "Mutation 5" or "Mutation 33" + if("check_discovery") + // GUARD CHECK - Can we genetically modify the occupant? Includes scanner + // operational guard checks. + if(!can_modify_occupant()) + return + + // GUARD CHECK - Have we somehow cheekily swapped occupants? This is + // unexpected. + if(!(scanner_occupant == connected_scanner.occupant)) + return + + check_discovery(params["alias"]) + return + + // Check all mutations of the occupant and check if any are discovered. + // This is called when the Genetic Sequencer is selected. It'll do things + // like immediately discover Monkified without needing to click through + // the mutation tabs and handle cases where mutations are solved but not + // discovered due to the Monkified mutation being active then removed. + if("all_check_discovery") + // GUARD CHECK - Can we genetically modify the occupant? Includes scanner + // operational guard checks. + if(!can_modify_occupant()) + return + + // GUARD CHECK - Have we somehow cheekily swapped occupants? This is + // unexpected. + if(!(scanner_occupant == connected_scanner.occupant)) + return + + // Go over all standard mutations and check if they've been discovered. + for(var/mutation_type in scanner_occupant.dna.mutation_index) + var/datum/mutation/human/HM = GET_INITIALIZED_MUTATION(mutation_type) + check_discovery(HM.alias) + + return + + // Set a gene in a mutation's genetic sequence. Will also check for mutations + // discovery as part of the process. + // ---------------------------------------------------------------------- // + // params["alias"] - Alias of a mutation. The alias is the "hidden" name of + // the mutation, for example "Mutation 5" or "Mutation 33" + // params["gene"] - The letter of the new gene + // params["pos"] - The BYOND index of the letter in the gene sequence to be + // changed. Expects a text string from TGUI and will convert to a number + if("pulse_gene") + // GUARD CHECK - Can we genetically modify the occupant? Includes scanner + // operational guard checks. + if(!can_modify_occupant()) + return + + // GUARD CHECK - Have we somehow cheekily swapped occupants? This is + // unexpected. + if(!(scanner_occupant == connected_scanner.occupant)) + return + + // GUARD CHECK - Is the occupant currently undergoing some form of + // transformation? If so, we don't want to be pulsing genes. + if(scanner_occupant.transformation_timer) + to_chat(usr,"Gene pulse failed: The scanner occupant undergoing a transformation.") + return + + // 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 + + // Resolve BYOND path to genome sequence of scanner occupant + var/sequence = GET_GENE_STRING(path, scanner_occupant.dna) + + var/newgene = params["gene"] + var/genepos = text2num(params["pos"]) + + // If the new gene is J, this means we're dealing with a JOKER + // GUARD CHECK - Is JOKER actually ready? + if((newgene == "J") && (jokerready < world.time)) + var/truegenes = GET_SEQUENCE(path) + newgene = truegenes[genepos] + jokerready = world.time + JOKER_TIMEOUT - (JOKER_UPGRADE * (connected_scanner.precision_coeff-1)) + + // If the gene is an X, we want to update the default genes with the new + // X to allow highlighting logic to work on the tgui interface. + if(newgene == "X") + var/defaultseq = scanner_occupant.dna.default_mutation_genes[path] + defaultseq = copytext_char(defaultseq, 1, genepos) + newgene + copytext_char(defaultseq, genepos + 1) + scanner_occupant.dna.default_mutation_genes[path] = defaultseq + + // Copy genome to scanner occupant and do some basic mutation checks as + // we've increased the occupant rads + sequence = copytext_char(sequence, 1, genepos) + newgene + copytext_char(sequence, genepos + 1) + scanner_occupant.dna.mutation_index[path] = sequence + scanner_occupant.radiation += RADIATION_STRENGTH_MULTIPLIER/connected_scanner.damage_coeff + scanner_occupant.domutcheck() + + // GUARD CHECK - Modifying genetics can lead to edge cases where the + // scanner occupant is qdel'd and replaced with a different entity. + // Examples of this include adding/removing the Monkified mutation which + // qdels the previous entity and creates a brand new one in its place. + // We should redo all of our occupant modification checks again, although + // it is less than ideal. + if(!can_modify_occupant()) + return + + // Check if we cracked a mutation + check_discovery(alias) + + return + + // Apply a chromosome to a specific mutation. + // ---------------------------------------------------------------------- // + // params["mutref"] - ATOM Ref of specific mutation to apply the chromo to + // params["chromo"] - Name of the chromosome to apply to the mutation + if("apply_chromo") + // GUARD CHECK - Can we genetically modify the occupant? Includes scanner + // operational guard checks. + if(!can_modify_occupant()) + return + + // GUARD CHECK - Have we somehow cheekily swapped occupants? This is + // unexpected. + if(!(scanner_occupant == connected_scanner.occupant)) + return + + var/bref = params["mutref"] + + // GUARD CHECK - Only search occupant for this specific ref, since your + // can only apply chromosomes to mutations occupants. + var/datum/mutation/human/HM = get_mut_by_ref(bref, SEARCH_OCCUPANT) + + // GUARD CHECK - This should not be possible. Unexpected result + if(!HM) + return + + // Look through our stored chromos and compare names to find a + // stored chromo we can apply. + for(var/obj/item/chromosome/CM in stored_chromosomes) + if(CM.can_apply(HM) && (CM.name == params["chromo"])) + stored_chromosomes -= CM + CM.apply(HM) + + return + + // Print any type of standard injector, limited right now to activators that + // activate a dormant mutation and mutators that forcibly create a new + // MUT_EXTRA mutation + // ---------------------------------------------------------------------- // + // params["mutref"] - ATOM Ref of specific mutation to create an injector of + // params["is_activator"] - Is this an "Activator" style injector, also + // referred to as a "Research" type. Expects a string with 0 or 1, which + // then gets converted to a number. + // params["source"] - The source the request came from. + // Expected results: + // "occupant" - From genetic sequencer + // "console" - From DNA Console storage + // "disk" - From inserted diskette + if("print_injector") + // Because printing mutators and activators share a bunch of code, + // it makes sense to keep them both together and set unique vars + // later in the code + + // As a side note, because mutations can contain unique metadata, + // this system uses BYOND Atom Refs to safely and accurately + // identify mutations from big ol' lists + + // GUARD CHECK - Is the injector actually ready? + if(world.time < injectorready) + return + + var/search_flags = 0 + + switch(params["source"]) + if("occupant") + // GUARD CHECK - Make sure we can modify the occupant before we + // attempt to search them for any given mutation refs. This could + // lead to no search flags being passed to get_mut_by_ref and this + // is intended functionality to prevent any cheese or abuse + if(can_modify_occupant()) + search_flags |= SEARCH_OCCUPANT + if("console") + search_flags |= SEARCH_STORED + if("disk") + search_flags |= SEARCH_DISKETTE + + var/bref = params["mutref"] + var/datum/mutation/human/HM = get_mut_by_ref(bref, search_flags) + + // GUARD CHECK - This should not be possible. Unexpected result + if(!HM) + return + + // Create a new DNA Injector and add the appropriate mutations to it + var/obj/item/dnainjector/activator/I = new /obj/item/dnainjector/activator(loc) + I.add_mutations += new HM.type(copymut = HM) + + var/is_activator = text2num(params["is_activator"]) + + // Activators are also called "research" injectors and are used to create + // chromosomes by recycling at the DNA Console + if(is_activator) + I.name = "[HM.name] activator" + I.research = TRUE + // If there's an operational connected scanner, we can use its upgrades + // to improve our injector's radiation generation + if(scanner_operational()) + I.damage_coeff = connected_scanner.damage_coeff*4 + injectorready = world.time + INJECTOR_TIMEOUT * (1 - 0.1 * connected_scanner.precision_coeff) else - current_screen = "mainmenu" - - if(connected) - connected.locked = locked_state - if("inspect") - if(viable_occupant) - var/list/mutations = get_mutation_list(TRUE) - if(current_mutation == mutations[num]) - current_mutation = null + injectorready = world.time + INJECTOR_TIMEOUT + else + I.name = "[HM.name] mutator" + I.doitanyway = TRUE + // If there's an operational connected scanner, we can use its upgrades + // to improve our injector's radiation generation + if(scanner_operational()) + I.damage_coeff = connected_scanner.damage_coeff + injectorready = world.time + INJECTOR_TIMEOUT * 5 * (1 - 0.1 * connected_scanner.precision_coeff) else - current_mutation = mutations[num] + injectorready = world.time + INJECTOR_TIMEOUT * 5 + + return + + // Save a mutation to the console's storage buffer. + // ---------------------------------------------------------------------- // + // params["mutref"] - ATOM Ref of specific mutation to store + // params["source"] - The source the request came from. + // Expected results: + // "occupant" - From genetic sequencer + // "disk" - From inserted diskette + if("save_console") + var/search_flags = 0 + + switch(params["source"]) + if("occupant") + // GUARD CHECK - Make sure we can modify the occupant before we + // attempt to search them for any given mutation refs. This could + // lead to no search flags being passed to get_mut_by_ref and this + // is intended functionality to prevent any cheese or abuse + if(can_modify_occupant()) + search_flags |= SEARCH_OCCUPANT + if("disk") + search_flags |= SEARCH_DISKETTE + + // GUARD CHECK - Is mutation storage full? + if(LAZYLEN(stored_mutations) >= max_storage) + to_chat(usr,"Mutation storage is full.") + return + + var/bref = params["mutref"] + var/datum/mutation/human/HM = get_mut_by_ref(bref, search_flags) + + // GUARD CHECK - This should not be possible. Unexpected result + if(!HM) + return + + var/datum/mutation/human/A = new HM.type() + A.copy_mutation(HM) + stored_mutations += A + to_chat(usr,"Mutation successfully stored.") + return + + // Save a mutation to the diskette's storage buffer. + // ---------------------------------------------------------------------- // + // params["mutref"] - ATOM Ref of specific mutation to store + // params["source"] - The source the request came from + // Expected results: + // "occupant" - From genetic sequencer + // "console" - From DNA Console storage + if("save_disk") + // GUARD CHECK - This code shouldn't even be callable without a diskette + // inserted. Unexpected result + if(!diskette) + return + + // GUARD CHECK - Make sure the disk is not full + if(LAZYLEN(diskette.mutations) >= diskette.max_mutations) + to_chat(usr,"Disk storage is full.") + return + + // GUARD CHECK - Make sure the disk isn't set to read only, as we're + // attempting to write to it + if(diskette.read_only) + to_chat(usr,"Disk is set to read only mode.") + return + + var/search_flags = 0 + + switch(params["source"]) + if("occupant") + // GUARD CHECK - Make sure we can modify the occupant before we + // attempt to search them for any given mutation refs. This could + // lead to no search flags being passed to get_mut_by_ref and this + // is intended functionality to prevent any cheese or abuse + if(can_modify_occupant()) + search_flags |= SEARCH_OCCUPANT + if("console") + search_flags |= SEARCH_STORED + + var/bref = params["mutref"] + var/datum/mutation/human/HM = get_mut_by_ref(bref, search_flags) + + // GUARD CHECK - This should not be possible. Unexpected result + if(!HM) + return + + var/datum/mutation/human/A = new HM.type() + A.copy_mutation(HM) + diskette.mutations += A + to_chat(usr,"Mutation successfully stored to disk.") + return + + // Completely removes a MUT_EXTRA mutation or mutation with corrupt gene + // sequence from the scanner occupant + // ---------------------------------------------------------------------- // + // params["mutref"] - ATOM Ref of specific mutation to nullify + if("nullify") + // GUARD CHECK - Can we genetically modify the occupant? Includes scanner + // operational guard checks. + if(!can_modify_occupant()) + return + + var/bref = params["mutref"] + var/datum/mutation/human/HM = get_mut_by_ref(bref, SEARCH_OCCUPANT) + + // GUARD CHECK - This should not be possible. Unexpected result + if(!HM) + return + + // GUARD CHECK - Nullify should only be used on scrambled or "extra" + // mutations. + if(!HM.scrambled && !(HM.class == MUT_EXTRA)) + return + + scanner_occupant.dna.remove_mutation(HM.type) + return + + // Deletes saved mutation from console buffer. + // ---------------------------------------------------------------------- // + // params["mutref"] - ATOM Ref of specific mutation to delete + if("delete_console_mut") + var/bref = params["mutref"] + var/datum/mutation/human/HM = get_mut_by_ref(bref, SEARCH_STORED) - if("inspectstorage") - current_storage = num - current_screen = "info" - if("savemut") - if(viable_occupant) - var/succes - if(LAZYLEN(stored_mutations) < max_storage) - var/mutation = text2path(href_list["path"]) - if(ispath(mutation, /datum/mutation/human)) //sanity checks - var/datum/mutation/human/HM = viable_occupant.dna.get_mutation(mutation) - if(HM) - var/datum/mutation/human/A = new HM.type() - A.copy_mutation(HM) - succes = TRUE - stored_mutations += A - to_chat(usr,"Mutation succesfully stored.") - if(!succes) //we can exactly return here - to_chat(usr,"Mutation storage is full.") - if("deletemut") - var/datum/mutation/human/HM = stored_mutations[num] if(HM) stored_mutations.Remove(HM) qdel(HM) - current_screen = "mutations" - if("activator") - if(injectorready < world.time) - var/mutation = text2path(href_list["path"]) - if(ispath(mutation, /datum/mutation/human)) - var/datum/mutation/human/HM = get_valid_mutation(mutation) - if(HM) - var/obj/item/dnainjector/activator/I = new /obj/item/dnainjector/activator(loc) - I.add_mutations += new HM.type (copymut = HM) - I.name = "[HM.name] activator" - I.research = TRUE - if(connected) - I.damage_coeff = connected.damage_coeff*4 - injectorready = world.time + INJECTOR_TIMEOUT * (1 - 0.1 * connected.precision_coeff) //precision_coeff being the matter bin rating - else - injectorready = world.time + INJECTOR_TIMEOUT - if("mutator") - if(injectorready < world.time) - var/mutation = text2path(href_list["path"]) - if(ispath(mutation, /datum/mutation/human)) - var/datum/mutation/human/HM = get_valid_mutation(mutation) - if(HM) - var/obj/item/dnainjector/activator/I = new /obj/item/dnainjector/activator(loc) - I.add_mutations += new HM.type (copymut = HM) - I.doitanyway = TRUE - I.name = "[HM.name] injector" - if(connected) - I.damage_coeff = connected.damage_coeff - injectorready = world.time + INJECTOR_TIMEOUT * 5 * (1 - 0.1 * connected.precision_coeff) - else - injectorready = world.time + INJECTOR_TIMEOUT * 5 - if("advinjector") - var/selection = href_list["injector"] - if(injectorready < world.time) - if(injector_selection.Find(selection)) - var/list/true_selection = injector_selection[selection] - if(LAZYLEN(injector_selection)) - var/obj/item/dnainjector/activator/I = new /obj/item/dnainjector/activator(loc) - for(var/A in true_selection) - var/datum/mutation/human/HM = A - I.add_mutations += new HM.type (copymut = HM) - I.doitanyway = TRUE - I.name = "Advanced [selection] injector" - if(connected) - I.damage_coeff = connected.damage_coeff - injectorready = world.time + INJECTOR_TIMEOUT * 8 * (1 - 0.1 * connected.precision_coeff) - else - injectorready = world.time + INJECTOR_TIMEOUT * 8 - if("nullify") - if(viable_occupant) - var/datum/mutation/human/A = viable_occupant.dna.get_mutation(current_mutation) - if(A && (!viable_occupant.dna.mutation_in_sequence(current_mutation) || A.scrambled)) - viable_occupant.dna.remove_mutation(current_mutation) - current_screen = "mainmenu" - current_mutation = null - if("pulsegene") - if(current_screen != "info") - var/path = text2path(href_list["path"]) - if(viable_occupant && num && (path in viable_occupant.dna.mutation_index)) - var/list/genes = list("A","T","G","C","X") - if(jokerready < world.time) - genes += "JOKER" - var/sequence = GET_GENE_STRING(path, viable_occupant.dna) - var/original = sequence[num] - var/new_gene = input("From [original] to-", "New block", original) as null|anything in genes - if(!new_gene) - new_gene = original - if(viable_occupant == get_viable_occupant()) //No cheesing - if((new_gene == "JOKER") && (jokerready < world.time)) - var/true_genes = GET_SEQUENCE(current_mutation) - new_gene = true_genes[num] - jokerready = world.time + JOKER_TIMEOUT - (JOKER_UPGRADE * (connected.precision_coeff-1)) - sequence = copytext(sequence, 1, num) + new_gene + copytext(sequence, num+1, length(sequence)+1) - viable_occupant.dna.mutation_index[path] = sequence - viable_occupant.radiation += RADIATION_STRENGTH_MULTIPLIER/connected.damage_coeff - viable_occupant.domutcheck() - if("exportdiskmut") - if(diskette && !diskette.read_only) - var/path = text2path(href_list["path"]) - if(ispath(path, /datum/mutation/human)) - var/datum/mutation/human/A = get_valid_mutation(path) - if(A && diskette && (LAZYLEN(diskette.mutations) < diskette.max_mutations)) - var/datum/mutation/human/HM = new A.type() - diskette.mutations += HM - HM.copy_mutation(A) - to_chat(usr, "Succesfully written [A.name] to [diskette.name].") - if("deletediskmut") - if(diskette && !diskette.read_only) - if(num && (LAZYLEN(diskette.mutations) >= num)) - var/datum/mutation/human/A = diskette.mutations[num] - diskette.mutations.Remove(A) - qdel(A) - if("importdiskmut") - if(diskette && (LAZYLEN(diskette.mutations) >= num)) - if(LAZYLEN(stored_mutations) < max_storage) - var/datum/mutation/human/A = diskette.mutations[num] - var/datum/mutation/human/HM = new A.type() - HM.copy_mutation(A) - stored_mutations += HM - to_chat(usr,"Succesfully written [A.name] to storage.") - if("combine") - if(num && (LAZYLEN(stored_mutations) >= num)) - if(LAZYLEN(stored_mutations) < max_storage) - var/datum/mutation/human/A = stored_mutations[num] - var/path = A.type - if(combine) - var/result_path = get_mixed_mutation(combine, path) - if(result_path) - stored_mutations += new result_path() - to_chat(usr, "Succes! New mutation has been added to storage") - discover(result_path) - combine = null - else - to_chat(usr, "Failed. No mutation could be created.") - combine = null - else - combine = path - to_chat(usr,"Selected [A.name] for combining") - else - to_chat(usr, "Not enough space to store potential mutation.") - if("ejectchromosome") - if(LAZYLEN(stored_chromosomes) <= num) - var/obj/item/chromosome/CM = stored_chromosomes[num] - CM.forceMove(drop_location()) - adjust_item_drop_location(CM) - stored_chromosomes -= CM - if("applychromosome") - if(viable_occupant && (LAZYLEN(viable_occupant.dna.mutations) <= num)) - var/datum/mutation/human/HM = viable_occupant.dna.mutations[num] - var/list/chromosomes = list() - for(var/obj/item/chromosome/CM in stored_chromosomes) - if(CM.can_apply(HM)) - chromosomes += CM - if(chromosomes.len) - var/obj/item/chromosome/CM = input("Select a chromosome to apply", "Apply Chromosome") as null|anything in sortNames(chromosomes) - if(CM) - to_chat(usr, "You apply [CM] to [HM.name].") - stored_chromosomes -= CM - CM.apply(HM) - if("expand_advinjector") - var/mutation = text2path(href_list["path"]) - var/datum/mutation/human/HM = get_valid_mutation(mutation) - if(HM && LAZYLEN(injector_selection)) - var/which_injector = input(usr, "Select Adv. Injector", "Advanced Injectors") as null|anything in injector_selection - if(injector_selection.Find(which_injector)) - var/list/true_selection = injector_selection[which_injector] - var/total_instability - for(var/B in true_selection) - var/datum/mutation/human/mootacion = B - total_instability += mootacion.instability - total_instability += HM.instability - if((total_instability > max_injector_instability) || (true_selection.len + 1) > max_injector_mutations) - to_chat(usr, "Adding more mutations would make the advanced injector too unstable!") - else - true_selection += HM //reminder that this works. because I keep forgetting this works - if("remove_from_advinjector") - var/mutation = text2path(href_list["path"]) - var/selection = href_list["injector"] - if(injector_selection.Find(selection)) - var/list/true_selection = injector_selection[selection] - for(var/B in true_selection) - var/datum/mutation/human/HM = B - if(HM.type == mutation) - true_selection -= HM - break + return - if("remove_advinjector") - var/selection = href_list["injector"] - for(selection in injector_selection) - if(selection == selection) - injector_selection.Remove(selection) + // Deletes saved mutation from disk buffer. + // ---------------------------------------------------------------------- // + // params["mutref"] - ATOM Ref of specific mutation to delete + if("delete_disk_mut") + // GUARD CHECK - This code shouldn't even be callable without a diskette + // inserted. Unexpected result + if(!diskette) + return - if("add_advinjector") - if(LAZYLEN(injector_selection) < max_injector_selections) - var/new_selection = input(usr, "Enter Adv. Injector name", "Advanced Injectors") as text|null - if(new_selection && !(new_selection in injector_selection)) - injector_selection[new_selection] = list() + // GUARD CHECK - Make sure the disk isn't set to read only, as we're + // attempting to write to it (via deletion) + if(diskette.read_only) + to_chat(usr,"Disk is set to read only mode.") + return + var/bref = params["mutref"] + var/datum/mutation/human/HM = get_mut_by_ref(bref, SEARCH_DISKETTE) - ui_interact(usr,last_change) + if(HM) + diskette.mutations.Remove(HM) + qdel(HM) -/obj/machinery/computer/scan_consolenew/proc/scramble(input,rs,rd) //hexadecimal genetics. dont confuse with scramble button + return + + // Ejects a stored chromosome from the DNA Console + // ---------------------------------------------------------------------- // + // params["chromo"] - Text string of the chromosome name + if("eject_chromo") + var/chromname = params["chromo"] + + for(var/obj/item/chromosome/CM in stored_chromosomes) + if(chromname == CM.name) + CM.forceMove(drop_location()) + adjust_item_drop_location(CM) + stored_chromosomes -= CM + return + + return + + // Combines two mutations from the console to try and create a new mutation + // ---------------------------------------------------------------------- // + // params["firstref"] - ATOM Ref of first mutation for combination + // params["secondref"] - ATOM Ref of second mutation for combination + // mutation + if("combine_console") + // GUaRD CHECK - Make sure mutation storage isn't full. If it is, we won't + // be able to store the new combo mutation + if(LAZYLEN(stored_mutations) >= max_storage) + to_chat(usr,"Mutation storage is full.") + return + + // GUARD CHECK - We're running a research-type operation. If, for some + // reason, somehow the DNA Console has been disconnected from the research + // network - Or was never in it to begin with - don't proceed + if(!stored_research) + return + + var/first_bref = params["firstref"] + var/second_bref = params["secondref"] + + // GUARD CHECK - Find the source and destination mutations on the console + // and make sure they actually exist. + var/datum/mutation/human/source_mut = get_mut_by_ref(first_bref, SEARCH_STORED | SEARCH_DISKETTE) + if(!source_mut) + return + + var/datum/mutation/human/dest_mut = get_mut_by_ref(second_bref, SEARCH_STORED | SEARCH_DISKETTE) + if(!dest_mut) + return + + // Attempt to mix the two mutations to get a new type + var/result_path = get_mixed_mutation(source_mut.type, dest_mut.type) + + if(!result_path) + return + + // If we got a new type, add it to our storage + stored_mutations += new result_path() + to_chat(usr, "Success! New mutation has been added to console storage.") + + // If it's already discovered, end here. Otherwise, add it to the list of + // discovered mutations. + // We've already checked for stored_research earlier + if(result_path in stored_research.discovered_mutations) + return + + var/datum/mutation/human/HM = GET_INITIALIZED_MUTATION(result_path) + stored_research.discovered_mutations += result_path + say("Successfully mutated [HM.name].") + return + + // Combines two mutations from the disk to try and create a new mutation + // ---------------------------------------------------------------------- // + // params["firstref"] - ATOM Ref of first mutation for combination + // params["secondref"] - ATOM Ref of second mutation for combination + // mutation + if("combine_disk") + // GUARD CHECK - This code shouldn't even be callable without a diskette + // inserted. Unexpected result + if(!diskette) + return + + // GUARD CHECK - Make sure the disk is not full. + if(LAZYLEN(diskette.mutations) >= diskette.max_mutations) + to_chat(usr,"Disk storage is full.") + return + + // GUARD CHECK - Make sure the disk isn't set to read only, as we're + // attempting to write to it + if(diskette.read_only) + to_chat(usr,"Disk is set to read only mode.") + return + + // GUARD CHECK - We're running a research-type operation. If, for some + // reason, somehow the DNA Console has been disconnected from the research + // network - Or was never in it to begin with - don't proceed + if(!stored_research) + return + + var/first_bref = params["firstref"] + var/second_bref = params["secondref"] + + // GUARD CHECK - Find the source and destination mutations on the console + // and make sure they actually exist. + var/datum/mutation/human/source_mut = get_mut_by_ref(first_bref, SEARCH_STORED | SEARCH_DISKETTE) + if(!source_mut) + return + + var/datum/mutation/human/dest_mut = get_mut_by_ref(second_bref, SEARCH_STORED | SEARCH_DISKETTE) + if(!dest_mut) + return + + // Attempt to mix the two mutations to get a new type + var/result_path = get_mixed_mutation(source_mut.type, dest_mut.type) + + if(!result_path) + return + + // If we got a new type, add it to our storage + diskette.mutations += new result_path() + to_chat(usr, "Success! New mutation has been added to the disk.") + + // If it's already discovered, end here. Otherwise, add it to the list of + // discovered mutations + // We've already checked for stored_research earlier + if(result_path in stored_research.discovered_mutations) + return + + var/datum/mutation/human/HM = GET_INITIALIZED_MUTATION(result_path) + stored_research.discovered_mutations += result_path + say("Successfully mutated [HM.name].") + return + + // Sets the Genetic Makeup pulse strength. + // ---------------------------------------------------------------------- // + // params["val"] - New strength value as text string, converted to number + // later on in code + if("set_pulse_strength") + var/value = round(text2num(params["val"])) + radstrength = WRAP(value, 1, RADIATION_STRENGTH_MAX+1) + return + + // Sets the Genetic Makeup pulse duration + // ---------------------------------------------------------------------- // + // params["val"] - New strength value as text string, converted to number + // later on in code + if("set_pulse_duration") + var/value = round(text2num(params["val"])) + radduration = WRAP(value, 1, RADIATION_DURATION_MAX+1) + return + + // Saves Genetic Makeup information to disk + // ---------------------------------------------------------------------- // + // params["index"] - The BYOND index of the console genetic makeup buffer to + // copy to disk + if("save_makeup_disk") + // GUARD CHECK - This code shouldn't even be callable without a diskette + // inserted. Unexpected result + if(!diskette) + return + + // GUARD CHECK - Make sure the disk isn't set to read only, as we're + // attempting to write to it + if(diskette.read_only) + to_chat(usr,"Disk is set to read only mode.") + return + + // Convert the index to a number and clamp within the array range + var/buffer_index = text2num(params["index"]) + buffer_index = clamp(buffer_index, 1, NUMBER_OF_BUFFERS) + + var/list/buffer_slot = genetic_makeup_buffer[buffer_index] + + // GUARD CHECK - This should not be possible to activate on a buffer slot + // that doesn't have any genetic data. Unexpected result + if(!istype(buffer_slot)) + return + + diskette.genetic_makeup_buffer = buffer_slot.Copy() + return + + // Loads Genetic Makeup from disk to a console buffer + // ---------------------------------------------------------------------- // + // params["index"] - The BYOND index of the console genetic makeup buffer to + // copy to. Expected as text string, converted to number later + if("load_makeup_disk") + // GUARD CHECK - This code shouldn't even be callable without a diskette + // inserted. Unexpected result + if(!diskette) + return + + // GUARD CHECK - This should not be possible to activate on a diskette + // that doesn't have any genetic data. Unexpected result + if(LAZYLEN(diskette.genetic_makeup_buffer) == 0) + return + + // Convert the index to a number and clamp within the array range, then + // copy the data from the disk to that buffer + var/buffer_index = text2num(params["index"]) + buffer_index = clamp(buffer_index, 1, NUMBER_OF_BUFFERS) + genetic_makeup_buffer[buffer_index] = diskette.genetic_makeup_buffer.Copy() + return + + // Deletes genetic makeup buffer from the inserted diskette + if("del_makeup_disk") + // GUARD CHECK - This code shouldn't even be callable without a diskette + // inserted. Unexpected result + if(!diskette) + return + + // GUARD CHECK - Make sure the disk isn't set to read only, as we're + // attempting to write (via deletion) to it + if(diskette.read_only) + to_chat(usr,"Disk is set to read only mode.") + return + + diskette.genetic_makeup_buffer.Cut() + return + + // Saves the scanner occupant's genetic makeup to a given console buffer + // ---------------------------------------------------------------------- // + // params["index"] - The BYOND index of the console genetic makeup buffer to + // save the new genetic data to. Expected as text string, converted to + // number later + if("save_makeup_console") + // GUARD CHECK - Can we genetically modify the occupant? Includes scanner + // operational guard checks. + if(!can_modify_occupant()) + return + + // Convert the index to a number and clamp within the array range, then + // copy the data from the disk to that buffer + var/buffer_index = text2num(params["index"]) + buffer_index = clamp(buffer_index, 1, NUMBER_OF_BUFFERS) + + // Set the new information + genetic_makeup_buffer[buffer_index] = list( + "label"="Slot [buffer_index]:[scanner_occupant.real_name]", + "UI"=scanner_occupant.dna.uni_identity, + "UE"=scanner_occupant.dna.unique_enzymes, + "name"=scanner_occupant.real_name, + "blood_type"=scanner_occupant.dna.blood_type) + + return + + // Deleted genetic makeup data from a console buffer slot + // ---------------------------------------------------------------------- // + // params["index"] - The BYOND index of the console genetic makeup buffer to + // delete the genetic data from. Expected as text string, converted to + // number later + if("del_makeup_console") + // Convert the index to a number and clamp within the array range, then + // copy the data from the disk to that buffer + var/buffer_index = text2num(params["index"]) + buffer_index = clamp(buffer_index, 1, NUMBER_OF_BUFFERS) + var/list/buffer_slot = genetic_makeup_buffer[buffer_index] + + // GUARD CHECK - This shouldn't be possible to execute this on a null + // buffer. Unexpected resut + if(!istype(buffer_slot)) + return + + genetic_makeup_buffer[buffer_index] = null + return + + // Eject stored diskette from console + if("eject_disk") + eject_disk(usr) + return + + // Create a Genetic Makeup injector. These injectors are timed and thus are + // only temporary + // ---------------------------------------------------------------------- // + // params["index"] - The BYOND index of the console genetic makeup buffer to + // create the makeup injector from. Expected as text string, converted to + // number later + // params["type"] - Type of injector to create + // Expected results: + // "ue" - Unique Enzyme, changes name and blood type + // "ui" - Unique Identity, changes looks + // "mixed" - Combination of both ue and ui + if("makeup_injector") + // Convert the index to a number and clamp within the array range, then + // copy the data from the disk to that buffer + var/buffer_index = text2num(params["index"]) + buffer_index = clamp(buffer_index, 1, NUMBER_OF_BUFFERS) + var/list/buffer_slot = genetic_makeup_buffer[buffer_index] + + // GUARD CHECK - This shouldn't be possible to execute this on a null + // buffer. Unexpected resut + if(!istype(buffer_slot)) + return + + var/type = params["type"] + var/obj/item/dnainjector/timed/I + + switch(type) + if("ui") + // GUARD CHECK - There's currently no way to save partial genetic data. + // However, if this is the case, we can't make a complete injector and + // this catches that edge case + if(!buffer_slot["UI"]) + to_chat(usr,"Genetic data corrupted, unable to create injector.") + return + + I = new /obj/item/dnainjector/timed(loc) + I.fields = list("UI"=buffer_slot["UI"]) + + // If there is a connected scanner, we can use its upgrades to reduce + // the radiation generated by this injector + if(scanner_operational()) + I.damage_coeff = connected_scanner.damage_coeff + if("ue") + // GUARD CHECK - There's currently no way to save partial genetic data. + // However, if this is the case, we can't make a complete injector and + // this catches that edge case + if(!buffer_slot["name"] || !buffer_slot["UE"] || !buffer_slot["blood_type"]) + to_chat(usr,"Genetic data corrupted, unable to create injector.") + return + + I = new /obj/item/dnainjector/timed(loc) + I.fields = list("name"=buffer_slot["name"], "UE"=buffer_slot["UE"], "blood_type"=buffer_slot["blood_type"]) + + // If there is a connected scanner, we can use its upgrades to reduce + // the radiation generated by this injector + if(scanner_operational()) + I.damage_coeff = connected_scanner.damage_coeff + if("mixed") + // GUARD CHECK - There's currently no way to save partial genetic data. + // However, if this is the case, we can't make a complete injector and + // this catches that edge case + if(!buffer_slot["UI"] || !buffer_slot["name"] || !buffer_slot["UE"] || !buffer_slot["blood_type"]) + to_chat(usr,"Genetic data corrupted, unable to create injector.") + return + + I = new /obj/item/dnainjector/timed(loc) + I.fields = list("UI"=buffer_slot["UI"],"name"=buffer_slot["name"], "UE"=buffer_slot["UE"], "blood_type"=buffer_slot["blood_type"]) + + // If there is a connected scanner, we can use its upgrades to reduce + // the radiation generated by this injector + if(scanner_operational()) + I.damage_coeff = connected_scanner.damage_coeff + + // If we successfully created an injector, don't forget to set the new + // ready timer. + if(I) + injectorready = world.time + INJECTOR_TIMEOUT + + return + + // Applies a genetic makeup buffer to the scanner occupant + // ---------------------------------------------------------------------- // + // params["index"] - The BYOND index of the console genetic makeup buffer to + // apply to the scanner occupant. Expected as text string, converted to + // number later + // params["type"] - Type of genetic makeup copy to implement + // Expected results: + // "ue" - Unique Enzyme, changes name and blood type + // "ui" - Unique Identity, changes looks + // "mixed" - Combination of both ue and ui + if("makeup_apply") + // GUARD CHECK - Can we genetically modify the occupant? Includes scanner + // operational guard checks. + if(!can_modify_occupant()) + return + + // Convert the index to a number and clamp within the array range, then + // copy the data from the disk to that buffer + var/buffer_index = text2num(params["index"]) + buffer_index = clamp(buffer_index, 1, NUMBER_OF_BUFFERS) + var/list/buffer_slot = genetic_makeup_buffer[buffer_index] + + // GUARD CHECK - This shouldn't be possible to execute this on a null + // buffer. Unexpected resut + if(!istype(buffer_slot)) + return + + var/type = params["type"] + + apply_genetic_makeup(type, buffer_slot) + return + + // Applies a genetic makeup buffer to the next scanner occupant. This sets + // some code that will run when the connected DNA Scanner door is next + // closed + // This allows people to self-modify their genetic makeup, as tgui + // interfaces can not be accessed while inside the DNA Scanner and genetic + // makeup injectors are only temporary + // ---------------------------------------------------------------------- // + // params["index"] - The BYOND index of the console genetic makeup buffer to + // apply to the scanner occupant. Expected as text string, converted to + // number later + // params["type"] - Type of genetic makeup copy to implement + // Expected results: + // "ue" - Unique Enzyme, changes name and blood type + // "ui" - Unique Identity, changes looks + // "mixed" - Combination of both ue and ui + if("makeup_delay") + // Convert the index to a number and clamp within the array range, then + // copy the data from the disk to that buffer + var/buffer_index = text2num(params["index"]) + buffer_index = clamp(buffer_index, 1, NUMBER_OF_BUFFERS) + var/list/buffer_slot = genetic_makeup_buffer[buffer_index] + + // GUARD CHECK - This shouldn't be possible to execute this on a null + // buffer. Unexpected resut + if(!istype(buffer_slot)) + return + + var/type = params["type"] + + // Set the delayed action. The next time the scanner door is closed, + // unless this is cancelled in the UI, the action will happen + delayed_action = list("type" = type, "buffer_slot" = buffer_slot) + return + + // Attempts to modify the indexed element of the Unique Identity string + // This is a time delayed action that is handled in process() + // ---------------------------------------------------------------------- // + // params["index"] - The BYOND index of the Unique Identity string to + // attempt to modify + if("makeup_pulse") + // GUARD CHECK - Can we genetically modify the occupant? Includes scanner + // operational guard checks. + if(!can_modify_occupant()) + return + + // Set the appropriate timer and index to pulse. This is then managed + // later on in process() + var/len = length_char(scanner_occupant.dna.uni_identity) + rad_pulse_timer = world.time + (radduration*10) + rad_pulse_index = WRAP(text2num(params["index"]), 1, len+1) + START_PROCESSING(SSobj, src) + return + + // Cancels the delayed action - In this context it is not the radiation + // pulse from "makeup_pulse", which can not be cancelled. It is instead + // the delayed genetic transfer from "makeup_delay" + if("cancel_delay") + delayed_action = null + return + + // Creates a new advanced injector storage buffer in the console + // ---------------------------------------------------------------------- // + // params["name"] - The name to apply to the new injector + if("new_adv_inj") + // GUARD CHECK - Make sure we can make a new injector. This code should + // not be called if we're already maxed out and this is an Unexpected + // result + if(!(LAZYLEN(injector_selection) < max_injector_selections)) + return + + // GUARD CHECK - Sanitise and trim the proposed name. This prevents HTML + // injection and equivalent as tgui input is not stripped + var/inj_name = params["name"] + inj_name = trim(sanitize(inj_name)) + + // GUARD CHECK - If the name is null or blank, or the name is already in + // the list of advanced injectors, we want to reject it as we can't have + // duplicate named advanced injectors + if(!inj_name || (inj_name in injector_selection)) + return + + injector_selection[inj_name] = list() + return + + // Deleted an advanced injector storage buffer from the console + // ---------------------------------------------------------------------- // + // params["name"] - The name of the injector to delete + if("del_adv_inj") + var/inj_name = params["name"] + + // GUARD CHECK - If the name is null or blank, reject. + // GUARD CHECK - If the name isn't in the list of advanced injectors, we + // want to reject this as it shouldn't be possible ever do this. + // Unexpected result + if(!inj_name || !(inj_name in injector_selection)) + return + + injector_selection.Remove(inj_name) + return + + // Creates an injector from an advanced injector buffer + // ---------------------------------------------------------------------- // + // params["name"] - The name of the injector to print + if("print_adv_inj") + // As a side note, because mutations can contain unique metadata, + // this system uses BYOND Atom Refs to safely and accurately + // identify mutations from big ol' lists. + + // GUARD CHECK - Is the injector actually ready? + if(world.time < injectorready) + return + + var/inj_name = params["name"] + + // GUARD CHECK - If the name is null or blank, reject. + // GUARD CHECK - If the name isn't in the list of advanced injectors, we + // want to reject this as it shouldn't be possible ever do this. + // Unexpected result + if(!inj_name || !(inj_name in injector_selection)) + return + + var/list/injector = injector_selection[inj_name] + var/obj/item/dnainjector/activator/I = new /obj/item/dnainjector/activator(loc) + + // Run through each mutation in our Advanced Injector and add them to a + // new injector + for(var/A in injector) + var/datum/mutation/human/HM = A + I.add_mutations += new HM.type(copymut=HM) + + // Force apply any mutations, this is functionality similar to mutators + I.doitanyway = TRUE + I.name = "Advanced [inj_name] injector" + + // If there's an operational connected scanner, we can use its upgrades + // to improve our injector's radiation generation + if(scanner_operational()) + I.damage_coeff = connected_scanner.damage_coeff + injectorready = world.time + INJECTOR_TIMEOUT * 8 * (1 - 0.1 * connected_scanner.precision_coeff) + else + injectorready = world.time + INJECTOR_TIMEOUT * 8 + + return + + // Adds a mutation to an advanced injector + // ---------------------------------------------------------------------- // + // params["mutref"] - ATOM Ref of specific mutation to add to the injector + // params["advinj"] - Name of the advanced injector to add the mutation to + if("add_advinj_mut") + // GUARD CHECK - Can we genetically modify the occupant? Includes scanner + // operational guard checks. + // This is needed because this operation can only be completed from the + // genetic sequencer. + if(!can_modify_occupant()) + return + + var/adv_inj = params["advinj"] + + // GUARD CHECK - Make sure our advanced injector actually exists. This + // should not be possible. Unexpected result + if(!(adv_inj in injector_selection)) + return + + // GUARD CHECK - Make sure we limit the number of mutations appropriately + if(LAZYLEN(injector_selection[adv_inj]) >= max_injector_mutations) + to_chat(usr,"Advanced injector mutation storage is full.") + return + + var/mut_source = params["source"] + var/search_flag = 0 + + switch(mut_source) + if("disk") + search_flag = SEARCH_DISKETTE + if("occupant") + search_flag = SEARCH_OCCUPANT + if("console") + search_flag = SEARCH_STORED + + if(!search_flag) + return + + var/bref = params["mutref"] + // We've already made sure we can modify the occupant, so this is safe to + // call + var/datum/mutation/human/HM = get_mut_by_ref(bref, search_flag) + + // GUARD CHECK - This should not be possible. Unexpected result + if(!HM) + return + + // We want to make sure we stick within the instability limit. + // We start with the instability of the mutation we're intending to add. + var/instability_total = HM.instability + + // We then add the instabilities of all other mutations in the injector, + // remembering to apply the Stabilizer chromosome modifiers + for(var/datum/mutation/human/I in injector_selection[adv_inj]) + instability_total += I.instability * GET_MUTATION_STABILIZER(I) + + // If this would take us over the max instability, we inform the user. + if(instability_total > max_injector_instability) + to_chat(usr,"Extra mutation would make the advanced injector too instable.") + return + + // If we've got here, all our checks are passed and we can successfully + // add the mutation to the advanced injector. + var/datum/mutation/human/A = new HM.type() + A.copy_mutation(HM) + injector_selection[adv_inj] += A + to_chat(usr,"Mutation successfully added to advanced injector.") + return + + // Deletes a mutation from an advanced injector + // ---------------------------------------------------------------------- // + // params["mutref"] - ATOM Ref of specific mutation to del from the injector + if("delete_injector_mut") + var/bref = params["mutref"] + + var/datum/mutation/human/HM = get_mut_by_ref(bref, SEARCH_ADV_INJ) + + // GUARD CHECK - This should not be possible. Unexpected result + if(!HM) + return + + // Check Advanced Injectors to find and remove the mutation + for(var/I in injector_selection) + if(injector_selection["[I]"].Remove(HM)) + qdel(HM) + return + + return + + // Sets a new tgui view state + // ---------------------------------------------------------------------- // + // params["id"] - Key for the state to set + // params[...] - Every other element is used to set state variables + if("set_view") + for (var/key in params) + if(key == "src") + continue + tgui_view_state[key] = params[key] + return TRUE + return FALSE + +/** + * Applies the enzyme buffer to the current scanner occupant + * + * Applies the type of a specific genetic makeup buffer to the current scanner + * occupant + * + * Arguments: + * * type - "ui"/"ue"/"mixed" - Which part of the enzyme buffer to apply + * * buffer_slot - Index of the enzyme buffer to apply + */ +/obj/machinery/computer/scan_consolenew/proc/apply_genetic_makeup(type, buffer_slot) + // Note - This proc is only called from code that has already performed the + // necessary occupant guard checks. If you call this code yourself, please + // apply can_modify_occupant() or equivalent checks first. + + // Pre-calc the rad increase since we'll be using it in all the possible + // operations + var/rad_increase = rand(100/(connected_scanner.damage_coeff ** 2),250/(connected_scanner.damage_coeff ** 2)) + + switch(type) + if("ui") + // GUARD CHECK - There's currently no way to save partial genetic data. + // However, if this is the case, we can't make a complete injector and + // this catches that edge case + if(!buffer_slot["UI"]) + to_chat(usr,"Genetic data corrupted, unable to apply genetic data.") + return FALSE + scanner_occupant.dna.uni_identity = buffer_slot["UI"] + scanner_occupant.updateappearance(mutations_overlay_update=1) + scanner_occupant.radiation += rad_increase + scanner_occupant.domutcheck() + return TRUE + if("ue") + // GUARD CHECK - There's currently no way to save partial genetic data. + // However, if this is the case, we can't make a complete injector and + // this catches that edge case + if(!buffer_slot["name"] || !buffer_slot["UE"] || !buffer_slot["blood_type"]) + to_chat(usr,"Genetic data corrupted, unable to apply genetic data.") + return FALSE + scanner_occupant.real_name = buffer_slot["name"] + scanner_occupant.name = buffer_slot["name"] + scanner_occupant.dna.unique_enzymes = buffer_slot["UE"] + scanner_occupant.dna.blood_type = buffer_slot["blood_type"] + scanner_occupant.radiation += rad_increase + scanner_occupant.domutcheck() + return TRUE + if("mixed") + // GUARD CHECK - There's currently no way to save partial genetic data. + // However, if this is the case, we can't make a complete injector and + // this catches that edge case + if(!buffer_slot["UI"] || !buffer_slot["name"] || !buffer_slot["UE"] || !buffer_slot["blood_type"]) + to_chat(usr,"Genetic data corrupted, unable to apply genetic data.") + return FALSE + scanner_occupant.dna.uni_identity = buffer_slot["UI"] + scanner_occupant.updateappearance(mutations_overlay_update=1) + scanner_occupant.real_name = buffer_slot["name"] + scanner_occupant.name = buffer_slot["name"] + scanner_occupant.dna.unique_enzymes = buffer_slot["UE"] + scanner_occupant.dna.blood_type = buffer_slot["blood_type"] + scanner_occupant.radiation += rad_increase + scanner_occupant.domutcheck() + return TRUE + + return FALSE +/** + * Checks if there is a connected DNA Scanner that is operational + */ +/obj/machinery/computer/scan_consolenew/proc/scanner_operational() + if(!connected_scanner) + return FALSE + + return (connected_scanner && connected_scanner.is_operational()) + +/** + * Checks if there is a valid DNA Scanner occupant for genetic modification + * + * Checks if there is a valid subject in the DNA Scanner that can be genetically + * modified. Will set the scanner occupant var as part of this check. + * Requires that the scanner can be operated and will return early if it can't + */ +/obj/machinery/computer/scan_consolenew/proc/can_modify_occupant() + // GUARD CHECK - We always want to perform the scanner operational check as + // part of checking if we can modify the occupant. + // We can never modify the occupant of a broken scanner. + if(!scanner_operational()) + return FALSE + + if(!connected_scanner.occupant) + return FALSE + + scanner_occupant = connected_scanner.occupant + + // Check validity of occupent for DNA Modification + // DNA Modification: + // requires DNA + // this DNA can not be bad + // is done via radiation bursts, so radiation immune carbons are not viable + // And the DNA Scanner itself must have a valid scan level + if(scanner_occupant.has_dna() && !HAS_TRAIT(scanner_occupant, TRAIT_RADIMMUNE) && !HAS_TRAIT(scanner_occupant, TRAIT_NOCLONE) || (connected_scanner.scan_level == 3)) + return TRUE + + return FALSE + +/** + * Checks for adjacent DNA scanners and connects when it finds a viable one + * + * Seearches cardinal directions in order. Stops when it finds a viable DNA Scanner. + * Will connect to a broken scanner if no functional scanner is available. + * Links itself to the DNA Scanner to receive door open and close events. + */ +/obj/machinery/computer/scan_consolenew/proc/connect_to_scanner() + var/obj/machinery/dna_scannernew/test_scanner = null + var/obj/machinery/dna_scannernew/broken_scanner = null + + // Look in each cardinal direction and try and find a DNA Scanner + // If you find a DNA Scanner, check to see if it broken or working + // If it's working, set the current scanner and return early + // If it's not working, remember it anyway as a broken scanner + for(var/direction in GLOB.cardinals) + test_scanner = locate(/obj/machinery/dna_scannernew, get_step(src, direction)) + if(!isnull(test_scanner)) + if(test_scanner.is_operational()) + connected_scanner = test_scanner + connected_scanner.linked_console = src + return + else + broken_scanner = test_scanner + + // Ultimately, if we have a broken scanner, we'll attempt to connect to it as + // a fallback case, but the code above will prefer a working scanner + if(!isnull(broken_scanner)) + connected_scanner = broken_scanner + connected_scanner.linked_console = src + +/** + * Called by connected DNA Scanners when their doors close. + * + * Sets the new scanner occupant and completes delayed enzyme transfer if one + * is queued. + */ +/obj/machinery/computer/scan_consolenew/proc/on_scanner_close() + // Set the appropriate occupant now the scanner is closed + if(connected_scanner.occupant) + scanner_occupant = connected_scanner.occupant + else + scanner_occupant = null + + // If we have a delayed action - In this case the only delayed action is + // applying a genetic makeup buffer the next time the DNA Scanner is closed - + // we want to perform it. + // GUARD CHECK - Make sure we can modify the occupant, apply_genetic_makeup() + // assumes we've already done this. + if(delayed_action && can_modify_occupant()) + var/type = delayed_action["type"] + var/buffer_slot = delayed_action["buffer_slot"] + if(apply_genetic_makeup(type, buffer_slot)) + to_chat(connected_scanner.occupant, "[src] activates!") + delayed_action = null + +/** + * Called by connected DNA Scanners when their doors open. + * + * Clears enzyme pulse operations, stops processing and nulls the current + * scanner occupant var. + */ +/obj/machinery/computer/scan_consolenew/proc/on_scanner_open() + // If we had a radiation pulse action ongoing, we want to stop this. + // Imagine it being like a microwave stopping when you open the door. + rad_pulse_index = 0 + rad_pulse_timer = 0 + STOP_PROCESSING(SSobj, src) + scanner_occupant = null + +/** + * Builds the genetic makeup list which will be sent to tgui interface. + */ +/obj/machinery/computer/scan_consolenew/proc/build_genetic_makeup_list() + // No code will ever null this list, we can safely Cut it. + tgui_genetic_makeup.Cut() + + for(var/i=1, i <= NUMBER_OF_BUFFERS, i++) + if(genetic_makeup_buffer[i]) + tgui_genetic_makeup["[i]"] = genetic_makeup_buffer[i].Copy() + else + tgui_genetic_makeup["[i]"] = null + +/** + * Builds the genetic makeup list which will be sent to tgui interface. + * + * Will iterate over the connected scanner occupant, DNA Console, inserted + * diskette and chromosomes and any advanced injectors, building the main data + * structures which get passed to the tgui interface. + */ +/obj/machinery/computer/scan_consolenew/proc/build_mutation_list(can_modify_occ) + // No code will ever null these lists. We can safely Cut them. + tgui_occupant_mutations.Cut() + tgui_diskette_mutations.Cut() + tgui_console_mutations.Cut() + tgui_console_chromosomes.Cut() + tgui_advinjector_mutations.Cut() + + // ------------------------------------------------------------------------ // + // GUARD CHECK - Can we genetically modify the occupant? This check will have + // previously included checks to make sure the DNA Scanner is still + // operational + if(can_modify_occ) + // ---------------------------------------------------------------------- // + // Start cataloguing all mutations that the occupant has by default + for(var/mutation_type in scanner_occupant.dna.mutation_index) + var/datum/mutation/human/HM = GET_INITIALIZED_MUTATION(mutation_type) + + var/list/mutation_data = list() + var/text_sequence = scanner_occupant.dna.mutation_index[mutation_type] + var/default_sequence = scanner_occupant.dna.default_mutation_genes[mutation_type] + var/discovered = (stored_research && (mutation_type in stored_research.discovered_mutations)) + + mutation_data["Alias"] = HM.alias + mutation_data["Sequence"] = text_sequence + mutation_data["DefaultSeq"] = default_sequence + mutation_data["Discovered"] = discovered + mutation_data["Source"] = "occupant" + + // We only want to pass this information along to the tgui interface if + // the mutation has been discovered. Prevents people being able to cheese + // or "hack" their way to figuring out what undiscovered mutations are + if(discovered) + mutation_data["Name"] = HM.name + mutation_data["Description"] = HM.desc + mutation_data["Instability"] = HM.instability * GET_MUTATION_STABILIZER(HM) + mutation_data["Quality"] = HM.quality + + // Assume the mutation is normal unless assigned otherwise. + var/mut_class = MUT_NORMAL + + // Check if the mutation is currently activated. If it is, we can add even + // MORE information to send to tgui. + var/datum/mutation/human/A = scanner_occupant.dna.get_mutation(mutation_type) + if(A) + mutation_data["Active"] = TRUE + mutation_data["Scrambled"] = A.scrambled + mutation_data["Class"] = A.class + mut_class = A.class + mutation_data["CanChromo"] = A.can_chromosome + mutation_data["ByondRef"] = REF(A) + mutation_data["Type"] = A.type + if(A.can_chromosome) + mutation_data["ValidChromos"] = jointext(A.valid_chrom_list, ", ") + mutation_data["AppliedChromo"] = A.chromosome_name + mutation_data["ValidStoredChromos"] = build_chrom_list(A) + else + mutation_data["Active"] = FALSE + mutation_data["Scrambled"] = FALSE + mutation_data["Class"] = MUT_NORMAL + + // Technically NONE of these mutations should be MUT_EXTRA but this will + // catch any weird edge cases + // Assign icons by priority - MUT_EXTRA will ALSO be discovered, so it + // has a higher priority for icon/image assignment + if (mut_class == MUT_EXTRA) + mutation_data["Image"] = "dna_extra.gif" + else if(discovered) + mutation_data["Image"] = "dna_discovered.gif" + else + mutation_data["Image"] = "dna_undiscovered.gif" + + tgui_occupant_mutations += list(mutation_data) + + // ---------------------------------------------------------------------- // + // Now get additional/"extra" mutations that they shouldn't have by default + for(var/datum/mutation/human/HM in scanner_occupant.dna.mutations) + // If it's in the mutation index array, we've already catalogued this + // mutation and can safely skip over it. It really shouldn't be, but this + // will catch any weird edge cases + if(HM.type in scanner_occupant.dna.mutation_index) + continue + + var/list/mutation_data = list() + var/text_sequence = GET_SEQUENCE(HM.type) + + // These will all be active mutations. They're added by injector and their + // sequencing code can't be changed. They can only be nullified, which + // completely removes them. + var/datum/mutation/human/A = GET_INITIALIZED_MUTATION(HM.type) + + mutation_data["Alias"] = A.alias + mutation_data["Sequence"] = text_sequence + mutation_data["Discovered"] = TRUE + mutation_data["Quality"] = HM.quality + mutation_data["Source"] = "occupant" + + mutation_data["Name"] = HM.name + mutation_data["Description"] = HM.desc + mutation_data["Instability"] = HM.instability * GET_MUTATION_STABILIZER(HM) + + mutation_data["Active"] = TRUE + mutation_data["Scrambled"] = HM.scrambled + mutation_data["Class"] = HM.class + mutation_data["CanChromo"] = HM.can_chromosome + mutation_data["ByondRef"] = REF(HM) + mutation_data["Type"] = HM.type + + if(HM.can_chromosome) + mutation_data["ValidChromos"] = jointext(HM.valid_chrom_list, ", ") + mutation_data["AppliedChromo"] = HM.chromosome_name + mutation_data["ValidStoredChromos"] = build_chrom_list(HM) + + // Nothing in this list should be undiscovered. Technically nothing + // should be anything but EXTRA. But we're just handling some edge cases. + if (HM.class == MUT_EXTRA) + mutation_data["Image"] = "dna_extra.gif" + else + mutation_data["Image"] = "dna_discovered.gif" + + tgui_occupant_mutations += list(mutation_data) + + // ------------------------------------------------------------------------ // + // Build the list of mutations stored within the DNA Console + for(var/datum/mutation/human/HM in stored_mutations) + var/list/mutation_data = list() + + var/datum/mutation/human/A = GET_INITIALIZED_MUTATION(HM.type) + + mutation_data["Alias"] = A.alias + mutation_data["Name"] = HM.name + mutation_data["Source"] = "console" + mutation_data["Active"] = TRUE + mutation_data["Description"] = HM.desc + mutation_data["Instability"] = HM.instability * GET_MUTATION_STABILIZER(HM) + mutation_data["ByondRef"] = REF(HM) + mutation_data["Type"] = HM.type + + mutation_data["CanChromo"] = HM.can_chromosome + if(HM.can_chromosome) + mutation_data["ValidChromos"] = jointext(HM.valid_chrom_list, ", ") + mutation_data["AppliedChromo"] = HM.chromosome_name + mutation_data["ValidStoredChromos"] = build_chrom_list(HM) + + tgui_console_mutations += list(mutation_data) + + // ------------------------------------------------------------------------ // + // Build the list of chromosomes stored within the DNA Console + var/chrom_index = 1 + for(var/obj/item/chromosome/CM in stored_chromosomes) + var/list/chromo_data = list() + + chromo_data["Name"] = CM.name + chromo_data["Description"] = CM.desc + chromo_data["Index"] = chrom_index + + tgui_console_chromosomes += list(chromo_data) + ++chrom_index + + // ------------------------------------------------------------------------ // + // Build the list of mutations stored on any inserted diskettes + if(diskette) + for(var/datum/mutation/human/HM in diskette.mutations) + var/list/mutation_data = list() + + var/datum/mutation/human/A = GET_INITIALIZED_MUTATION(HM.type) + + mutation_data["Alias"] = A.alias + mutation_data["Name"] = HM.name + mutation_data["Active"] = TRUE + //mutation_data["Sequence"] = GET_SEQUENCE(HM.type) + mutation_data["Source"] = "disk" + mutation_data["Description"] = HM.desc + mutation_data["Instability"] = HM.instability * GET_MUTATION_STABILIZER(HM) + mutation_data["ByondRef"] = REF(HM) + mutation_data["Type"] = HM.type + + mutation_data["CanChromo"] = HM.can_chromosome + if(HM.can_chromosome) + mutation_data["ValidChromos"] = jointext(HM.valid_chrom_list, ", ") + mutation_data["AppliedChromo"] = HM.chromosome_name + mutation_data["ValidStoredChromos"] = build_chrom_list(HM) + + tgui_diskette_mutations += list(mutation_data) + + // ------------------------------------------------------------------------ // + // Build the list of mutations stored within any Advanced Injectors + if(LAZYLEN(injector_selection)) + for(var/I in injector_selection) + var/list/mutations = list() + for(var/datum/mutation/human/HM in injector_selection[I]) + var/list/mutation_data = list() + + var/datum/mutation/human/A = GET_INITIALIZED_MUTATION(HM.type) + + mutation_data["Alias"] = A.alias + mutation_data["Name"] = HM.name + mutation_data["Active"] = TRUE + //mutation_data["Sequence"] = GET_SEQUENCE(HM.type) + mutation_data["Source"] = "injector" + mutation_data["Description"] = HM.desc + mutation_data["Instability"] = HM.instability * GET_MUTATION_STABILIZER(HM) + mutation_data["ByondRef"] = REF(HM) + mutation_data["Type"] = HM.type + + if(HM.can_chromosome) + mutation_data["AppliedChromo"] = HM.chromosome_name + + mutations += list(mutation_data) + tgui_advinjector_mutations += list(list( + "name" = "[I]", + "mutations" = mutations, + )) + +/** + * Takes any given chromosome and calculates chromosome compatibility + * + * Will iterate over the stored chromosomes in the DNA Console and will check + * whether it can be applied to the supplied mutation. Then returns a list of + * names of chromosomes that were compatible. + * + * Arguments: + * * mutation - The mutation to check chromosome compatibility with + */ +/obj/machinery/computer/scan_consolenew/proc/build_chrom_list(mutation) + var/list/chromosomes = list() + + for(var/obj/item/chromosome/CM in stored_chromosomes) + if(CM.can_apply(mutation)) + chromosomes += CM.name + + return chromosomes + +/** + * Checks whether a mutation alias has been discovered + * + * Checks whether a given mutation's genetic sequence has been completed and + * discovers it if appropriate + * + * Arguments: + * * alias - Alias of the mutation to check (ie "Mutation 51" or "Mutation 12") + */ +/obj/machinery/computer/scan_consolenew/proc/check_discovery(alias) + // Note - All code paths that call this have already done checks on the + // current occupant to prevent cheese and other abuses. If you call this + // proc please also do the following checks first: + // if(!can_modify_occupant()) + // return + // if(!(scanner_occupant == connected_scanner.occupant)) + // return + + // Turn the alias ("Mutation 1", "Mutation 35") into a mutation path + var/path = GET_MUTATION_TYPE_FROM_ALIAS(alias) + + // Check to see if this mutation is in the active mutation list. If it isn't, + // then the mutation isn't eligible for discovery. If it is but is scrambled, + // then the mutation isn't eligible for discovery. Finally, check if the + // mutation is in discovered mutations - If it isn't, add it to discover. + var/datum/mutation/human/M = scanner_occupant.dna.get_mutation(path) + if(!M) + return FALSE + if(M.scrambled) + return FALSE + if(stored_research && !(path in stored_research.discovered_mutations)) + var/datum/mutation/human/HM = GET_INITIALIZED_MUTATION(path) + stored_research.discovered_mutations += path + say("Successfully discovered [HM.name].") + return TRUE + + return FALSE + +/** + * Find a mutation from various storage locations via ATOM ref + * + * Takes an ATOM Ref and searches the appropriate mutation buffers and storage + * vars to try and find the associated mutation. + * + * Arguments: + * * ref - ATOM ref of the mutation to locate + * * target_flags - Flags for storage mediums to search, see #defines + */ +/obj/machinery/computer/scan_consolenew/proc/get_mut_by_ref(ref, target_flags) + var/mutation + + // Assume the occupant is valid and the check has been carried out before + // calling this proc with the relevant flags. + if(target_flags & SEARCH_OCCUPANT) + mutation = (locate(ref) in scanner_occupant.dna.mutations) + if(mutation) + return mutation + + if(target_flags & SEARCH_STORED) + mutation = (locate(ref) in stored_mutations) + if(mutation) + return mutation + + if(diskette && (target_flags & SEARCH_DISKETTE)) + mutation = (locate(ref) in diskette.mutations) + if(mutation) + return mutation + + if(injector_selection && (target_flags & SEARCH_ADV_INJ)) + for(var/I in injector_selection) + mutation = (locate(ref) in injector_selection["[I]"]) + if(mutation) + return mutation + + return null + +/** + * Creates a randomised accuracy value for the enzyme pulse functionality. + * + * Donor code from previous DNA Console iteration. + * + * Arguments: + * * position - Index of the intended enzyme element to pulse + * * radduration - Duration of intended radiation pulse + * * number_of_blocks - Number of individual data blocks in the pulsed enzyme + */ +/obj/machinery/computer/scan_consolenew/proc/randomize_radiation_accuracy(position, radduration, number_of_blocks) + var/val = round(gaussian(0, RADIATION_ACCURACY_MULTIPLIER/radduration) + position, 1) + return WRAP(val, 1, number_of_blocks+1) + +/** + * Scrambles an enzyme element value for the enzyme pulse functionality. + * + * Donor code from previous DNA Console iteration. + * + * Arguments: + * * input - Enzyme identity element to scramble, expected hex value + * * rs - Strength of radiation pulse, increases the range of possible outcomes + */ +/obj/machinery/computer/scan_consolenew/proc/scramble(input,rs) var/length = length(input) var/ran = gaussian(0, rs*RADIATION_STRENGTH_MULTIPLIER) if(ran == 0) @@ -940,98 +1953,71 @@ ran = -round(-ran) //positive, so ceiling it return num2hex(WRAP(hex2num(input)+ran, 0, 16**length), length) -/obj/machinery/computer/scan_consolenew/proc/randomize_radiation_accuracy(position, radduration, number_of_blocks) - var/val = round(gaussian(0, RADIATION_ACCURACY_MULTIPLIER/radduration) + position, 1) - return WRAP(val, 1, number_of_blocks+1) + /** + * Performs the enzyme radiation pulse. + * + * Donor code from previous DNA Console iteration. Called from process() when + * there is a radiation pulse in progress. Ends processing. + */ +/obj/machinery/computer/scan_consolenew/proc/rad_pulse() + // GUARD CHECK - Can we genetically modify the occupant? Includes scanner + // operational guard checks. + // If we can't, abort the procedure. + if(!can_modify_occupant()) + rad_pulse_index = 0 + STOP_PROCESSING(SSobj, src) + return -/obj/machinery/computer/scan_consolenew/proc/get_viable_occupant() - var/mob/living/carbon/viable_occupant = null - if(connected) - viable_occupant = connected.occupant - if(!istype(viable_occupant) || !viable_occupant.dna || HAS_TRAIT_NOT_FROM(viable_occupant, TRAIT_RADIMMUNE,BLOODSUCKER_TRAIT) || HAS_TRAIT(viable_occupant, TRAIT_NOCLONE)) - viable_occupant = null - return viable_occupant + var/len = length_char(scanner_occupant.dna.uni_identity) + var/num = randomize_radiation_accuracy(rad_pulse_index, radduration + (connected_scanner.precision_coeff ** 2), len) //Each manipulator level above 1 makes randomization as accurate as selected time + manipulator lvl^2 //Value is this high for the same reason as with laser - not worth the hassle of upgrading if the bonus is low + var/hex = copytext_char(scanner_occupant.dna.uni_identity, num, num+1) + hex = scramble(hex, radstrength, radduration) -/obj/machinery/computer/scan_consolenew/proc/apply_buffer(action,buffer_num) - buffer_num = clamp(buffer_num, 1, NUMBER_OF_BUFFERS) - var/list/buffer_slot = buffer[buffer_num] - var/mob/living/carbon/viable_occupant = get_viable_occupant() - if(istype(buffer_slot)) - viable_occupant.radiation += rand(100/(connected.damage_coeff ** 2),250/(connected.damage_coeff ** 2)) - //15 and 40 are just magic numbers that were here before so i didnt touch them, they are initial boundaries of damage - //Each laser level reduces damage by lvl^2, so no effect on 1 lvl, 4 times less damage on 2 and 9 times less damage on 3 - //Numbers are this high because other way upgrading laser is just not worth the hassle, and i cant think of anything better to inmrove - switch(action) - if(SCANNER_ACTION_UI) - if(buffer_slot["UI"]) - viable_occupant.dna.uni_identity = buffer_slot["UI"] - viable_occupant.updateappearance(mutations_overlay_update=1) - if(SCANNER_ACTION_UE) - if(buffer_slot["name"] && buffer_slot["UE"] && buffer_slot["blood_type"]) - viable_occupant.real_name = buffer_slot["name"] - viable_occupant.name = buffer_slot["name"] - viable_occupant.dna.unique_enzymes = buffer_slot["UE"] - viable_occupant.dna.blood_type = buffer_slot["blood_type"] - if(SCANNER_ACTION_MIXED) - if(buffer_slot["UI"]) - viable_occupant.dna.uni_identity = buffer_slot["UI"] - viable_occupant.updateappearance(mutations_overlay_update=1) - if(buffer_slot["name"] && buffer_slot["UE"] && buffer_slot["blood_type"]) - viable_occupant.real_name = buffer_slot["name"] - viable_occupant.name = buffer_slot["name"] - viable_occupant.dna.unique_enzymes = buffer_slot["UE"] - viable_occupant.dna.blood_type = buffer_slot["blood_type"] + scanner_occupant.dna.uni_identity = copytext_char(scanner_occupant.dna.uni_identity, 1, num) + hex + copytext_char(scanner_occupant.dna.uni_identity, num + 1) + scanner_occupant.updateappearance(mutations_overlay_update=1) -/obj/machinery/computer/scan_consolenew/proc/on_scanner_close() - if(delayed_action && get_viable_occupant()) - to_chat(connected.occupant, "[src] activates!") - apply_buffer(delayed_action["action"],delayed_action["buffer"]) - delayed_action = null //or make it stick + reset button ? + rad_pulse_index = 0 + STOP_PROCESSING(SSobj, src) + return -/obj/machinery/computer/scan_consolenew/proc/get_valid_mutation(mutation) - var/mob/living/carbon/C = get_viable_occupant() - if(C) - var/datum/mutation/human/HM = C.dna.get_mutation(mutation) - if(HM) - return HM - for(var/datum/mutation/human/A in stored_mutations) - if(A.type == mutation) - return A +/** + * Sets the default state for the tgui interface. + */ +/obj/machinery/computer/scan_consolenew/proc/set_default_state() + tgui_view_state["consoleMode"] = "storage" + tgui_view_state["storageMode"] = "console" + tgui_view_state["storageConsSubMode"] = "mutations" + tgui_view_state["storageDiskSubMode"] = "mutations" +/** + * Ejects the DNA Disk from the console. + * + * Will insert into the user's hand if possible, otherwise will drop it at the + * console's location. + * + * Arguments: + * * user - The mob that is attempting to eject the diskette. + */ +/obj/machinery/computer/scan_consolenew/proc/eject_disk(mob/user) + // Check for diskette. + if(!diskette) + return -/obj/machinery/computer/scan_consolenew/proc/get_mutation_list(include_storage) //Returns a list of the mutation index types and any extra mutations - var/mob/living/carbon/viable_occupant = get_viable_occupant() - var/list/paths = list() - if(viable_occupant) - for(var/A in viable_occupant.dna.mutation_index) - paths += A - for(var/datum/mutation/human/A in viable_occupant.dna.mutations) - if(A.class == MUT_EXTRA) - paths += A.type - if(include_storage) - for(var/datum/mutation/human/A in stored_mutations) - paths += A.type - return paths + to_chat(user, "You eject [diskette] from [src].") -/obj/machinery/computer/scan_consolenew/proc/get_valid_gene_string(mutation) - var/mob/living/carbon/C = get_viable_occupant() - if(C && (mutation in C.dna.mutation_index)) - return GET_GENE_STRING(mutation, C.dna) - else if(C && (LAZYLEN(C.dna.mutations))) - for(var/datum/mutation/human/A in C.dna.mutations) - if(A.type == mutation) - return GET_SEQUENCE(mutation) - for(var/datum/mutation/human/A in stored_mutations) - if(A.type == mutation) - return GET_SEQUENCE(mutation) + // Reset the state to console storage. + tgui_view_state["storageMode"] = "console" + + // If the disk shouldn't pop into the user's hand for any reason, drop it on the console instead. + if(!istype(user) || !Adjacent(user) || !user.put_in_active_hand(diskette)) + diskette.forceMove(drop_location()) + diskette = null -/obj/machinery/computer/scan_consolenew/proc/discover(mutation) - if(stored_research && !(mutation in stored_research.discovered_mutations)) - stored_research.discovered_mutations += mutation - return TRUE -/////////////////////////// DNA MACHINES #undef INJECTOR_TIMEOUT #undef NUMBER_OF_BUFFERS +#undef SCRAMBLE_TIMEOUT +#undef JOKER_TIMEOUT +#undef JOKER_UPGRADE #undef RADIATION_STRENGTH_MAX #undef RADIATION_STRENGTH_MULTIPLIER @@ -1041,11 +2027,9 @@ #undef RADIATION_IRRADIATION_MULTIPLIER -#undef SCANNER_ACTION_SE -#undef SCANNER_ACTION_UI -#undef SCANNER_ACTION_UE -#undef SCANNER_ACTION_MIXED +#undef STATUS_TRANSFORMING -//#undef BAD_MUTATION_DIFFICULTY -//#undef GOOD_MUTATION_DIFFICULTY -//#undef OP_MUTATION_DIFFICULTY +#undef SEARCH_OCCUPANT +#undef SEARCH_STORED +#undef SEARCH_DISKETTE +#undef SEARCH_ADV_INJ diff --git a/code/game/machinery/computer/launchpad_control.dm b/code/game/machinery/computer/launchpad_control.dm index 1924cd9f23..fdbe2f1060 100644 --- a/code/game/machinery/computer/launchpad_control.dm +++ b/code/game/machinery/computer/launchpad_control.dm @@ -56,7 +56,7 @@ /obj/machinery/computer/launchpad/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "launchpad_console", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "LaunchpadConsole", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/computer/launchpad/ui_data(mob/user) diff --git a/code/game/machinery/computer/prisoner/gulag_teleporter.dm b/code/game/machinery/computer/prisoner/gulag_teleporter.dm index ca75ff1dd0..dd925fbe3b 100644 --- a/code/game/machinery/computer/prisoner/gulag_teleporter.dm +++ b/code/game/machinery/computer/prisoner/gulag_teleporter.dm @@ -25,7 +25,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "gulag_console", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "GulagTeleporterConsole", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_data(mob/user) diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index 2621616759..4fd9665b1d 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -5,163 +5,123 @@ icon_keyboard = "rd_key" req_access = list(ACCESS_ROBOTICS) circuit = /obj/item/circuitboard/computer/robotics - var/temp = null - light_color = LIGHT_COLOR_PINK + ui_x = 500 + ui_y = 460 /obj/machinery/computer/robotics/proc/can_control(mob/user, mob/living/silicon/robot/R) + . = FALSE if(!istype(R)) - return FALSE + return if(isAI(user)) - if (R.connected_ai != user) - return FALSE + if(R.connected_ai != user) + return if(iscyborg(user)) - if (R != user) - return FALSE + if(R != user) + return if(R.scrambledcodes) - return FALSE - if (hasSiliconAccessInArea(user) && !issilicon(user)) - if (!Adjacent(user)) - return FALSE + return return TRUE -/obj/machinery/computer/robotics/ui_interact(mob/user) - . = ..() - if (src.z > 6) - to_chat(user, "Unable to establish a connection: \black You're too far away from the station!") - return - user.set_machine(src) - var/dat - var/robots = 0 +/obj/machinery/computer/robotics/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "RoboticsControlConsole", name, ui_x, ui_y, master_ui, state) + ui.open() + +/obj/machinery/computer/robotics/ui_data(mob/user) + var/list/data = list() + + data["can_hack"] = FALSE + if(issilicon(user)) + var/mob/living/silicon/S = user + if(S.hack_software) + data["can_hack"] = TRUE + else if(IsAdminGhost(user)) + data["can_hack"] = TRUE + + data["cyborgs"] = list() for(var/mob/living/silicon/robot/R in GLOB.silicon_mobs) if(!can_control(user, R)) continue - robots++ - dat += "[R.name] |" - if(R.stat) - dat += " Not Responding |" - else if(R.locked_down) - dat += " Locked Down |" - else - dat += " Operating Normally |" - if(R.cell) - dat += " Battery Installed ([R.cell.charge]/[R.cell.maxcharge]) |" - else - dat += " No Cell Installed |" - if(R.module) - dat += " Module Installed ([R.module.name]) |" - else - dat += " No Module Installed |" - if(R.connected_ai) - dat += " Slaved to [R.connected_ai.name] |" - else - dat += " Independent from AI |" - if(issilicon(user) && user != R) - var/mob/living/silicon/S = user - if(is_servant_of_ratvar(S)) - dat += "(Convert) " - else if(S.hack_software && !R.emagged) - dat += "(Hack) " - else if(IsAdminGhost(user) && !R.emagged) - dat += "(Hack) " - dat += "([R.locked_down? "Lockdown" : "Release"]) " - dat += "(Destroy)" - dat += "
    " + if(z != (get_turf(R)).z) + continue + var/list/cyborg_data = list( + name = R.name, + locked_down = R.locked_down, + status = R.stat, + charge = R.cell ? round(R.cell.percent()) : null, + module = R.module ? "[R.module.name] Module" : "No Module Detected", + synchronization = R.connected_ai, + emagged = R.emagged, + ref = REF(R) + ) + data["cyborgs"] += list(cyborg_data) - if(!robots) - dat += "No Cyborg Units detected within access parameters." - dat += "
    " - - var/drones = 0 + data["drones"] = list() for(var/mob/living/simple_animal/drone/D in GLOB.drones_list) if(D.hacked) continue - drones++ - dat += "[D.name] |" - if(D.stat) - dat += " Not Responding |" - dat += "(Destroy)" - dat += "
    " + if(z != (get_turf(D)).z) + continue + var/list/drone_data = list( + name = D.name, + status = D.stat, + ref = REF(D) + ) + data["drones"] += list(drone_data) - if(!drones) - dat += "No Drone Units detected within access parameters." + return data - var/datum/browser/popup = new(user, "computer", "Cyborg Control Console", 400, 500) - popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) - popup.open() - return - -/obj/machinery/computer/robotics/Topic(href, href_list) +/obj/machinery/computer/robotics/ui_act(action, params) if(..()) return - if (href_list["temp"]) - src.temp = null - - else if (href_list["killbot"]) - if(src.allowed(usr)) - var/mob/living/silicon/robot/R = locate(href_list["killbot"]) in GLOB.silicon_mobs - if(can_control(usr, R)) - var/choice = input("Are you certain you wish to detonate [R.name]?") in list("Confirm", "Abort") - if(choice == "Confirm" && can_control(usr, R) && !..()) + switch(action) + if("killbot") + if(allowed(usr)) + var/mob/living/silicon/robot/R = locate(params["ref"]) in GLOB.silicon_mobs + if(can_control(usr, R) && !..()) var/turf/T = get_turf(R) message_admins("[ADMIN_LOOKUPFLW(usr)] detonated [key_name_admin(R, R.client)] at [ADMIN_VERBOSEJMP(T)]!") log_game("\[key_name(usr)] detonated [key_name(R)]!") if(R.connected_ai) to_chat(R.connected_ai, "

    ALERT - Cyborg detonation detected: [R.name]
    ") R.self_destruct() - else - to_chat(usr, "Access Denied.") - - else if (href_list["stopbot"]) - if(src.allowed(usr)) - var/mob/living/silicon/robot/R = locate(href_list["stopbot"]) in GLOB.silicon_mobs - if(can_control(usr, R)) - var/choice = input("Are you certain you wish to [!R.locked_down ? "lock down" : "release"] [R.name]?") in list("Confirm", "Abort") - if(choice == "Confirm" && can_control(usr, R) && !..()) - message_admins("[ADMIN_LOOKUPFLW(usr)] [!R.locked_down ? "locked down" : "released"] [key_name(R, R.client)][ADMIN_LOOKUPFLW(R)]!") + else + to_chat(usr, "Access Denied.") + if("stopbot") + if(allowed(usr)) + var/mob/living/silicon/robot/R = locate(params["ref"]) in GLOB.silicon_mobs + if(can_control(usr, R) && !..()) + message_admins("[ADMIN_LOOKUPFLW(usr)] [!R.locked_down ? "locked down" : "released"] [ADMIN_LOOKUPFLW(R)]!") log_game("[key_name(usr)] [!R.locked_down ? "locked down" : "released"] [key_name(R)]!") R.SetLockdown(!R.locked_down) to_chat(R, "[!R.locked_down ? "Your lockdown has been lifted!" : "You have been locked down!"]") if(R.connected_ai) to_chat(R.connected_ai, "[!R.locked_down ? "NOTICE - Cyborg lockdown lifted" : "ALERT - Cyborg lockdown detected"]: [R.name]
    ") - - else - to_chat(usr, "Access Denied.") - - else if (href_list["magbot"]) - var/mob/living/silicon/S = usr - if((istype(S) && S.hack_software) || IsAdminGhost(usr)) - var/mob/living/silicon/robot/R = locate(href_list["magbot"]) in GLOB.silicon_mobs - if(istype(R) && !R.emagged && (R.connected_ai == usr || IsAdminGhost(usr)) && !R.scrambledcodes && can_control(usr, R)) - log_game("[key_name(usr)] emagged [key_name(R)] using robotic console!") - message_admins("[ADMIN_LOOKUPFLW(usr)] emagged cyborg [key_name_admin(R)] using robotic console!") - R.SetEmagged(1) - - else if(href_list["convert"]) - if(isAI(usr) && is_servant_of_ratvar(usr)) - var/mob/living/silicon/robot/R = locate(href_list["convert"]) in GLOB.silicon_mobs - if(istype(R) && !is_servant_of_ratvar(R) && R.connected_ai == usr) - log_game("[key_name(usr)] converted [key_name(R)] using robotic console!") - message_admins("[ADMIN_LOOKUPFLW(usr)] converted cyborg [key_name_admin(R)] using robotic console!") - add_servant_of_ratvar(R) - - else if (href_list["killdrone"]) - if(src.allowed(usr)) - var/mob/living/simple_animal/drone/D = locate(href_list["killdrone"]) in GLOB.mob_list - if(D.hacked) - to_chat(usr, "ERROR: [D] is not responding to external commands.") else - var/turf/T = get_turf(D) - message_admins("[ADMIN_LOOKUPFLW(usr)] detonated [key_name_admin(D)] at [ADMIN_VERBOSEJMP(T)]!") - log_game("[key_name(usr)] detonated [key_name(D)]!") - var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread - s.set_up(3, 1, D) - s.start() - D.visible_message("\the [D] self destructs!") - D.gib() - - - src.updateUsrDialog() - return + to_chat(usr, "Access Denied.") + if("magbot") + var/mob/living/silicon/S = usr + if((istype(S) && S.hack_software) || IsAdminGhost(usr)) + var/mob/living/silicon/robot/R = locate(params["ref"]) in GLOB.silicon_mobs + if(istype(R) && !R.emagged && (R.connected_ai == usr || IsAdminGhost(usr)) && !R.scrambledcodes && can_control(usr, R)) + log_game("[key_name(usr)] emagged [key_name(R)] using robotic console!") + message_admins("[ADMIN_LOOKUPFLW(usr)] emagged cyborg [key_name_admin(R)] using robotic console!") + R.SetEmagged(TRUE) + if("killdrone") + if(allowed(usr)) + var/mob/living/simple_animal/drone/D = locate(params["ref"]) in GLOB.mob_list + if(D.hacked) + to_chat(usr, "ERROR: [D] is not responding to external commands.") + else + var/turf/T = get_turf(D) + message_admins("[ADMIN_LOOKUPFLW(usr)] detonated [key_name_admin(D)] at [ADMIN_VERBOSEJMP(T)]!") + log_game("[key_name(usr)] detonated [key_name(D)]!") + var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread + s.set_up(3, TRUE, D) + s.start() + D.visible_message("\the [D] self destructs!") + D.gib() diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index 25f4237439..5c280eeace 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -662,7 +662,7 @@ What a mess.*/ GLOB.data_core.removeMajorCrime(active1.fields["id"], href_list["cdataid"]) if("notes") if(istype(active2, /datum/data/record)) - var/t1 = stripped_input(usr, "Please summarize notes:", "Secure. records", active2.fields["notes"], null) + var/t1 = stripped_multiline_input(usr, "Please summarize notes:", "Secure records", active2.fields["notes"], 8192) if(!canUseSecurityRecordsConsole(usr, t1, null, a2)) return active2.fields["notes"] = t1 diff --git a/code/game/machinery/computer/station_alert.dm b/code/game/machinery/computer/station_alert.dm index fcb18b4dff..b4340b9350 100644 --- a/code/game/machinery/computer/station_alert.dm +++ b/code/game/machinery/computer/station_alert.dm @@ -20,7 +20,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "station_alert", name, 325, 500, master_ui, state) + ui = new(user, src, ui_key, "StationAlertConsole", name, 325, 500, master_ui, state) ui.open() /obj/machinery/computer/station_alert/ui_data(mob/user) diff --git a/code/game/machinery/computer/teleporter.dm b/code/game/machinery/computer/teleporter.dm index 6710258626..e7957a5b75 100644 --- a/code/game/machinery/computer/teleporter.dm +++ b/code/game/machinery/computer/teleporter.dm @@ -38,7 +38,7 @@ obj/machinery/computer/teleporter/ui_interact(mob/user, ui_key = "main", datum/t datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "teleporter", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "Teleporter", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/computer/teleporter/ui_data(mob/user) diff --git a/code/game/machinery/defibrillator_mount.dm b/code/game/machinery/defibrillator_mount.dm index 5c13bfdf5d..f91fd66fb5 100644 --- a/code/game/machinery/defibrillator_mount.dm +++ b/code/game/machinery/defibrillator_mount.dm @@ -59,7 +59,7 @@ return defib.get_cell() //defib interaction -/obj/machinery/defibrillator_mount/attack_hand(mob/living/user) +/obj/machinery/defibrillator_mount/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) if(!defib) to_chat(user, "There's no defibrillator unit loaded!") return diff --git a/code/game/machinery/dish_drive.dm b/code/game/machinery/dish_drive.dm index 31e6a3cfeb..5bf16d4638 100644 --- a/code/game/machinery/dish_drive.dm +++ b/code/game/machinery/dish_drive.dm @@ -31,7 +31,7 @@ if(user.Adjacent(src)) . += "Alt-click it to beam its contents to any nearby disposal bins." -/obj/machinery/dish_drive/attack_hand(mob/living/user) +/obj/machinery/dish_drive/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) if(!contents.len) to_chat(user, "There's nothing in [src]!") return diff --git a/code/game/machinery/dna_scanner.dm b/code/game/machinery/dna_scanner.dm index 6c5ea7d518..e721e986d2 100644 --- a/code/game/machinery/dna_scanner.dm +++ b/code/game/machinery/dna_scanner.dm @@ -15,6 +15,7 @@ var/precision_coeff var/message_cooldown var/breakout_time = 1200 + var/obj/machinery/computer/scan_consolenew/linked_console = null /obj/machinery/dna_scannernew/RefreshParts() scan_level = 0 @@ -22,8 +23,8 @@ precision_coeff = 0 for(var/obj/item/stock_parts/scanning_module/P in component_parts) scan_level += P.rating - for(var/obj/item/stock_parts/matter_bin/P in component_parts) - precision_coeff = P.rating + for(var/obj/item/stock_parts/matter_bin/M in component_parts) + precision_coeff = M.rating for(var/obj/item/stock_parts/micro_laser/P in component_parts) damage_coeff = P.rating @@ -31,11 +32,8 @@ . = ..() if(in_range(user, src) || isobserver(user)) . += "The status display reads: Radiation pulse accuracy increased by factor [precision_coeff**2].
    Radiation pulse damage decreased by factor [damage_coeff**2].
    " - if(scan_level >= 3) - . += "Scanner has been upgraded to support autoprocessing." /obj/machinery/dna_scannernew/update_icon_state() - //no power or maintenance if(stat & (NOPOWER|BROKEN)) icon_state = initial(icon_state)+ (state_open ? "_open" : "") + "_unpowered" @@ -53,10 +51,6 @@ //running icon_state = initial(icon_state)+ (state_open ? "_open" : "") -/obj/machinery/dna_scannernew/power_change() - ..() - update_icon() - /obj/machinery/dna_scannernew/proc/toggle_open(mob/user) if(panel_open) to_chat(user, "Close the maintenance panel first.") @@ -78,7 +72,7 @@ return user.visible_message("You see [user] kicking against the door of [src]!", \ "You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)", \ - "You hear a metallic creaking from [src].") + "You hear a metallic creaking from [src].") if(do_after(user,(breakout_time), target = src)) if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked) return @@ -94,33 +88,28 @@ return C return null -/obj/machinery/dna_scannernew/close_machine(atom/movable/target) +/obj/machinery/dna_scannernew/close_machine(mob/living/carbon/user) if(!state_open) return FALSE - ..(target) - - // search for ghosts, if the corpse is empty and the scanner is connected to a cloner - var/mob/living/mob_occupant = get_mob_or_brainmob(occupant) - if(istype(mob_occupant)) - if(locate_computer(/obj/machinery/computer/cloning)) - if(!mob_occupant.suiciding && !(HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && !mob_occupant.hellbound) - mob_occupant.notify_ghost_cloning("Your corpse has been placed into a cloning scanner. Re-enter your corpse if you want to be cloned!", source = src) + ..(user) // DNA manipulators cannot operate on severed heads or brains - if(isliving(occupant)) - var/obj/machinery/computer/scan_consolenew/console = locate_computer(/obj/machinery/computer/scan_consolenew) - if(console) - console.on_scanner_close() + if(iscarbon(occupant)) + if(linked_console) + linked_console.on_scanner_close() return TRUE /obj/machinery/dna_scannernew/open_machine() - if(state_open || panel_open) + if(state_open) return FALSE ..() + if(linked_console) + linked_console.on_scanner_open() + return TRUE /obj/machinery/dna_scannernew/relaymove(mob/user as mob) @@ -131,51 +120,49 @@ return open_machine() -/obj/machinery/dna_scannernew/screwdriver_act(mob/living/user, obj/item/I) - . = TRUE - if(..()) - return - if(occupant) - to_chat(user, "[src] is currently occupied!") - return - if(state_open) - to_chat(user, "[src] must be closed to [panel_open ? "close" : "open"] its maintenance hatch!") - return - if(default_deconstruction_screwdriver(user, icon_state, icon_state, I)) //sent icon_state is irrelevant... - update_icon() //..since we're updating the icon here, since the scanner can be unpowered when opened/closed - return - return FALSE +/obj/machinery/dna_scannernew/attackby(obj/item/I, mob/user, params) -/obj/machinery/dna_scannernew/wrench_act(mob/living/user, obj/item/I) - . = ..() - if(default_change_direction_wrench(user, I)) - return TRUE + if(!occupant && default_deconstruction_screwdriver(user, icon_state, icon_state, I))//sent icon_state is irrelevant... + update_icon()//..since we're updating the icon here, since the scanner can be unpowered when opened/closed + return -/obj/machinery/dna_scannernew/crowbar_act(mob/living/user, obj/item/I) - . = ..() if(default_pry_open(I)) - return TRUE - if(default_deconstruction_crowbar(I)) - return TRUE + return -/obj/machinery/dna_scannernew/default_pry_open(obj/item/I) //wew - . = !(state_open || panel_open || (flags_1 & NODECONSTRUCT_1)) && I.tool_behaviour == TOOL_CROWBAR - if(.) - I.play_tool_sound(src, 50) - visible_message("[usr] pries open [src].", "You pry open [src].") - open_machine() + if(default_deconstruction_crowbar(I)) + return + + return ..() /obj/machinery/dna_scannernew/interact(mob/user) toggle_open(user) -/obj/machinery/dna_scannernew/AltClick(mob/user) - . = ..() - if(!user.canUseTopic(src, !hasSiliconAccessInArea(user))) - return - interact(user) - return TRUE - /obj/machinery/dna_scannernew/MouseDrop_T(mob/target, mob/user) - if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser()) + var/mob/living/L = user + if(user.stat || (isliving(user) && (!(L.mobility_flags & MOBILITY_STAND) || !(L.mobility_flags & MOBILITY_UI))) || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser()) return close_machine(target) + + +//Just for transferring between genetics machines. +/obj/item/disk/data + name = "DNA data disk" + icon_state = "datadisk0" //Gosh I hope syndies don't mistake them for the nuke disk. + var/list/genetic_makeup_buffer = list() + var/list/fields = list() + var/list/mutations = list() + var/max_mutations = 6 + var/read_only = FALSE //Well,it's still a floppy disk + +/obj/item/disk/data/Initialize() + . = ..() + icon_state = "datadisk[rand(0,6)]" + add_overlay("datadisk_gene") + +/obj/item/disk/data/attack_self(mob/user) + read_only = !read_only + to_chat(user, "You flip the write-protect tab to [read_only ? "protected" : "unprotected"].") + +/obj/item/disk/data/examine(mob/user) + . = ..() + . += "The write-protect tab is set to [read_only ? "protected" : "unprotected"]." diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 8959cd8cc9..a950cb7e7d 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -157,6 +157,10 @@ . = ..() AddComponent(/datum/component/ntnet_interface) +/obj/machinery/door/airlock/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) + if(id_tag) + id_tag = "[idnum][id_tag]" + /obj/machinery/door/airlock/proc/update_other_id() for(var/obj/machinery/door/airlock/A in GLOB.airlocks) if(A.closeOtherId == closeOtherId && A != src) @@ -188,7 +192,7 @@ /obj/machinery/door/airlock/vv_edit_var(var_name) . = ..() switch (var_name) - if ("cyclelinkeddir") + if (NAMEOF(src, cyclelinkeddir)) cyclelinkairlock() /obj/machinery/door/airlock/check_access_ntnet(datum/netdata/data) @@ -759,7 +763,7 @@ /obj/machinery/door/airlock/attack_paw(mob/user) return attack_hand(user) -/obj/machinery/door/airlock/attack_hand(mob/user) +/obj/machinery/door/airlock/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -1440,7 +1444,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "ai_airlock", name, 500, 390, master_ui, state) + ui = new(user, src, ui_key, "AiAirlock", name, 500, 390, master_ui, state) ui.open() return TRUE diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock_electronics.dm index ae6930f5fb..a0ce3954c3 100644 --- a/code/game/machinery/doors/airlock_electronics.dm +++ b/code/game/machinery/doors/airlock_electronics.dm @@ -2,10 +2,14 @@ name = "airlock electronics" req_access = list(ACCESS_MAINT_TUNNELS) custom_price = PRICE_CHEAP - + /// A list of all granted accesses var/list/accesses = list() + /// If the airlock should require ALL or only ONE of the listed accesses var/one_access = 0 - var/unres_sides = 0 //unrestricted sides, or sides of the airlock that will open regardless of access + /// Unrestricted sides, or sides of the airlock that will open regardless of access + var/unres_sides = 0 + /// A holder of the electronics, in case of them working as an integrated part + var/holder /obj/item/electronics/airlock/examine(mob/user) . = ..() @@ -13,31 +17,37 @@ /obj/item/electronics/airlock/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) - SStgui.try_update_ui(user, src, ui_key, ui, force_open) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "airlock_electronics", name, 420, 485, master_ui, state) + ui = new(user, src, ui_key, "AirlockElectronics", name, 420, 485, master_ui, state) ui.open() +/obj/item/electronics/airlock/ui_static_data(mob/user) + var/list/data = list() + var/list/regions = list() + for(var/i in 1 to 7) + var/list/accesses = list() + for(var/access in get_region_accesses(i)) + if (get_access_desc(access)) + accesses += list(list( + "desc" = replacetext(get_access_desc(access), " ", " "), + "ref" = access, + )) + + regions += list(list( + "name" = get_region_accesses_name(i), + "regid" = i, + "accesses" = accesses + )) + + data["regions"] = regions + return data + /obj/item/electronics/airlock/ui_data() var/list/data = list() - var/list/regions = list() - - for(var/i in 1 to 7) - var/list/region = list() - var/list/accesses = list() - for(var/j in get_region_accesses(i)) - var/list/access = list() - access["name"] = get_access_desc(j) - access["id"] = j - access["req"] = (j in src.accesses) - accesses[++accesses.len] = access - region["name"] = get_region_accesses_name(i) - region["accesses"] = accesses - regions[++regions.len] = region - data["regions"] = regions + data["accesses"] = accesses data["oneAccess"] = one_access data["unres_direction"] = unres_sides - return data /obj/item/electronics/airlock/ui_act(action, params) @@ -48,12 +58,12 @@ accesses = list() one_access = 0 . = TRUE - if("one_access") - one_access = !one_access - . = TRUE if("grant_all") accesses = get_all_accesses() . = TRUE + if("one_access") + one_access = !one_access + . = TRUE if("set") var/access = text2num(params["access"]) if (!(access in accesses)) @@ -65,3 +75,20 @@ var/unres_direction = text2num(params["unres_direction"]) unres_sides ^= unres_direction //XOR, toggles only the bit that was clicked . = TRUE + if("grant_region") + var/region = text2num(params["region"]) + if(isnull(region)) + return + accesses |= get_region_accesses(region) + . = TRUE + if("deny_region") + var/region = text2num(params["region"]) + if(isnull(region)) + return + accesses -= get_region_accesses(region) + . = TRUE + +/obj/item/electronics/airlock/ui_host() + if(holder) + return holder + return src diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index 1d39372dec..5a1ed7dd19 100644 --- a/code/game/machinery/doors/brigdoors.dm +++ b/code/game/machinery/doors/brigdoors.dm @@ -144,7 +144,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "brig_timer", name, 300, 138, master_ui, state) + ui = new(user, src, ui_key, "BrigTimer", name, 300, 138, master_ui, state) ui.open() //icon update function diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index b73e6a57ff..baf8c35f46 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -140,7 +140,7 @@ do_animate("deny") return -/obj/machinery/door/attack_hand(mob/user) +/obj/machinery/door/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index e359c6331f..4855280b86 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -88,7 +88,7 @@ else stat |= NOPOWER -/obj/machinery/door/firedoor/attack_hand(mob/user) +/obj/machinery/door/firedoor/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/machinery/doors/poddoor.dm b/code/game/machinery/doors/poddoor.dm index c032ded6b0..4226d8a439 100644 --- a/code/game/machinery/doors/poddoor.dm +++ b/code/game/machinery/doors/poddoor.dm @@ -16,6 +16,9 @@ damage_deflection = 70 poddoor = TRUE +/obj/machinery/door/poddoor/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) + id = "[idnum][id]" + /obj/machinery/door/poddoor/preopen icon_state = "open" density = FALSE diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index 0b23e650d7..4c68d0b0b5 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -141,7 +141,7 @@ if(user) log_game("[user] reset a fire alarm at [COORD(src)]") -/obj/machinery/firealarm/attack_hand(mob/user) +/obj/machinery/firealarm/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(buildstage != 2) return ..() add_fingerprint(user) diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index f4f1aa0637..c0e1122140 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -36,6 +36,9 @@ else bulb = new(src) +/obj/machinery/flasher/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) + id = "[idnum][id]" + /obj/machinery/flasher/Destroy() QDEL_NULL(bulb) return ..() diff --git a/code/game/machinery/gulag_item_reclaimer.dm b/code/game/machinery/gulag_item_reclaimer.dm index 55b1e34022..45484caa77 100644 --- a/code/game/machinery/gulag_item_reclaimer.dm +++ b/code/game/machinery/gulag_item_reclaimer.dm @@ -31,7 +31,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "gulag_item_reclaimer", name, 300, 400, master_ui, state) + ui = new(user, src, ui_key, "GulagItemReclaimer", name, 300, 400, master_ui, state) ui.open() /obj/machinery/gulag_item_reclaimer/ui_data(mob/user) diff --git a/code/game/machinery/harvester.dm b/code/game/machinery/harvester.dm index 141f261688..8cb7ca1e8d 100644 --- a/code/game/machinery/harvester.dm +++ b/code/game/machinery/harvester.dm @@ -50,7 +50,7 @@ harvesting = FALSE warming_up = FALSE -/obj/machinery/harvester/attack_hand(mob/user) +/obj/machinery/harvester/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(state_open) close_machine() else if(!harvesting) diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 621e486e90..f43114f7cb 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -78,7 +78,7 @@ GLOBAL_LIST_EMPTY(network_holopads) new_disk.forceMove(src) disk = new_disk -/obj/machinery/holopad/tutorial/attack_hand(mob/user) +/obj/machinery/holopad/tutorial/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(!istype(user)) return if(user.incapacitated() || !is_operational()) diff --git a/code/game/machinery/hypnochair.dm b/code/game/machinery/hypnochair.dm index 64d60ac778..16b464ced6 100644 --- a/code/game/machinery/hypnochair.dm +++ b/code/game/machinery/hypnochair.dm @@ -37,7 +37,7 @@ /obj/machinery/hypnochair/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "hypnochair", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "HypnoChair", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/hypnochair/ui_data() diff --git a/code/game/machinery/igniter.dm b/code/game/machinery/igniter.dm index 099b51db82..7cf21ed767 100644 --- a/code/game/machinery/igniter.dm +++ b/code/game/machinery/igniter.dm @@ -26,7 +26,7 @@ on = TRUE icon_state = "igniter1" -/obj/machinery/igniter/attack_hand(mob/user) +/obj/machinery/igniter/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -53,6 +53,9 @@ else icon_state = "igniter0" +/obj/machinery/igniter/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) + id = "[idnum][id]" + // Wall mounted remote-control igniter. /obj/machinery/sparker diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index cd9e9dc83f..5eb3de3e3b 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -158,7 +158,7 @@ attached.transfer_blood_to(beaker, amount) update_icon() -/obj/machinery/iv_drip/attack_hand(mob/user) +/obj/machinery/iv_drip/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/machinery/launch_pad.dm b/code/game/machinery/launch_pad.dm index c8219e9ebf..63ef40e045 100644 --- a/code/game/machinery/launch_pad.dm +++ b/code/game/machinery/launch_pad.dm @@ -285,8 +285,7 @@ /obj/item/launchpad_remote/ui_interact(mob/user, ui_key = "launchpad_remote", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "launchpad_remote", "Briefcase Launchpad Remote", 300, 240, master_ui, state) //width, height - ui.set_style("syndicate") + ui = new(user, src, ui_key, "LaunchpadRemote", "Briefcase Launchpad Remote", 300, 240, master_ui, state) //width, height ui.open() ui.set_autoupdate(TRUE) diff --git a/code/game/machinery/mass_driver.dm b/code/game/machinery/mass_driver.dm index ab0a0534ab..a8fa31d5fb 100644 --- a/code/game/machinery/mass_driver.dm +++ b/code/game/machinery/mass_driver.dm @@ -11,6 +11,8 @@ var/id = 1 var/drive_range = 50 //this is mostly irrelevant since current mass drivers throw into space, but you could make a lower-range mass driver for interstation transport or something I guess. +/obj/machinery/mass_driver/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) + id = "[idnum][id]" /obj/machinery/mass_driver/proc/drive(amount) if(stat & (BROKEN|NOPOWER)) diff --git a/code/game/machinery/porta_turret/portable_turret_construct.dm b/code/game/machinery/porta_turret/portable_turret_construct.dm index 9d86e3792d..bf70ee8a9d 100644 --- a/code/game/machinery/porta_turret/portable_turret_construct.dm +++ b/code/game/machinery/porta_turret/portable_turret_construct.dm @@ -168,7 +168,7 @@ return ..() -/obj/machinery/porta_turret_construct/attack_hand(mob/user) +/obj/machinery/porta_turret_construct/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/machinery/porta_turret/portable_turret_cover.dm b/code/game/machinery/porta_turret/portable_turret_cover.dm index 7fdb9b38be..3899f07685 100644 --- a/code/game/machinery/porta_turret/portable_turret_cover.dm +++ b/code/game/machinery/porta_turret/portable_turret_cover.dm @@ -31,7 +31,7 @@ return parent_turret.attack_ai(user) -/obj/machinery/porta_turret_cover/attack_hand(mob/user) +/obj/machinery/porta_turret_cover/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index 426c818ccb..5d0d39e3a4 100755 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -108,7 +108,7 @@ return ..() -/obj/machinery/recharger/attack_hand(mob/user) +/obj/machinery/recharger/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index 8680aa69e6..706d2bb9bf 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -225,6 +225,6 @@ /obj/item/paper/guides/recycler name = "paper - 'garbage duty instructions'" - info = "

    New Assignment

    You have been assigned to collect garbage from trash bins, located around the station. The crewmembers will put their trash into it and you will collect the said trash.

    There is a recycling machine near your closet, inside maintenance; use it to recycle the trash for a small chance to get useful minerals. Then deliver these minerals to cargo or engineering. You are our last hope for a clean station, do not screw this up!" + info = "_New Assignment_\n\n You have been assigned to collect garbage from trash bins, located around the station. The crewmembers will put their trash into it and you will collect the said trash.

    There is a recycling machine near your closet, inside maintenance; use it to recycle the trash for a small chance to get useful minerals. Then deliver these minerals to cargo or engineering. You are our last hope for a clean station, do not screw this up!" #undef SAFETY_COOLDOWN diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm index ffabee1606..e6137c08c2 100644 --- a/code/game/machinery/spaceheater.dm +++ b/code/game/machinery/spaceheater.dm @@ -175,7 +175,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "space_heater", name, 400, 305, master_ui, state) + ui = new(user, src, ui_key, "SpaceHeater", name, 400, 305, master_ui, state) ui.open() /obj/machinery/space_heater/ui_data() diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 3bb67e2a1c..8937106601 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -287,7 +287,7 @@ if(!.) return switch(var_name) - if("shuttle_id") + if(NAMEOF(src, shuttle_id)) update() /obj/machinery/status_display/shuttle/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 97b4b0eaef..75772786fc 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -381,7 +381,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "suit_storage_unit", name, 400, 305, master_ui, state) + ui = new(user, src, ui_key, "SuitStorageUnit", name, 400, 305, master_ui, state) ui.open() /obj/machinery/suit_storage_unit/ui_data() diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm index e300afe6b9..8b9aa64c58 100644 --- a/code/game/machinery/syndicatebeacon.dm +++ b/code/game/machinery/syndicatebeacon.dm @@ -68,7 +68,7 @@ GLOBAL_VAR_INIT(singularity_counter, 0) /obj/machinery/power/singularity_beacon/attack_ai(mob/user) return -/obj/machinery/power/singularity_beacon/attack_hand(mob/user) +/obj/machinery/power/singularity_beacon/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/machinery/telecomms/computers/logbrowser.dm b/code/game/machinery/telecomms/computers/logbrowser.dm index fdf6ba121c..9867a1c133 100644 --- a/code/game/machinery/telecomms/computers/logbrowser.dm +++ b/code/game/machinery/telecomms/computers/logbrowser.dm @@ -21,7 +21,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "tcommsserver", "Telecomms Server Monitor", 575, 400, master_ui, state) + ui = new(user, src, ui_key, "TelecommsLogBrowser", "Telecomms Server Monitor", 575, 400, master_ui, state) ui.open() /obj/machinery/computer/telecomms/server/ui_data(mob/user) diff --git a/code/game/machinery/telecomms/computers/message.dm b/code/game/machinery/telecomms/computers/message.dm index 41d417967b..11d50a2858 100644 --- a/code/game/machinery/telecomms/computers/message.dm +++ b/code/game/machinery/telecomms/computers/message.dm @@ -41,7 +41,7 @@ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "telepdalog", name, 727, 510, master_ui, state) + ui = new(user, src, ui_key, "TelecommsPDALog", name, 727, 510, master_ui, state) ui.open() /obj/machinery/computer/message_monitor/ui_static_data(mob/user) @@ -389,7 +389,6 @@ /obj/item/paper/monitorkey/proc/print(obj/machinery/telecomms/message_server/server) info = "

    Daily Key Reset


    The new message monitor key is '[server.decryptkey]'.
    Please keep this a secret and away from the clown.
    If necessary, change the password to a more secure one." - info_links = info add_overlay("paper_words") /obj/item/paper/monitorkey/LateInitialize() diff --git a/code/game/machinery/telecomms/computers/telemonitor.dm b/code/game/machinery/telecomms/computers/telemonitor.dm index bca16a0de4..11312fcfaf 100644 --- a/code/game/machinery/telecomms/computers/telemonitor.dm +++ b/code/game/machinery/telecomms/computers/telemonitor.dm @@ -22,7 +22,7 @@ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "telemonitor", name, 575, 400, master_ui, state) + ui = new(user, src, ui_key, "TelecommsMonitor", name, 575, 400, master_ui, state) ui.open() /obj/machinery/computer/telecomms/monitor/ui_data(mob/user) diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm index 6d299f4413..86aa7905d5 100644 --- a/code/game/machinery/telecomms/machine_interactions.dm +++ b/code/game/machinery/telecomms/machine_interactions.dm @@ -36,7 +36,7 @@ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "teleinteract", "[name] Access", 520, 500, master_ui, state) + ui = new(user, src, ui_key, "TelecommsInteraction", "[name] Access", 520, 500, master_ui, state) ui.open() /obj/machinery/telecomms/ui_data(mob/user) diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm index 26220d4d89..9e277b9d8e 100644 --- a/code/game/machinery/washing_machine.dm +++ b/code/game/machinery/washing_machine.dm @@ -297,7 +297,7 @@ GLOBAL_LIST_INIT(dye_registry, list( else return ..() -/obj/machinery/washing_machine/attack_hand(mob/user) +/obj/machinery/washing_machine/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/mecha/mech_bay.dm b/code/game/mecha/mech_bay.dm index bcf1b948e2..dcd8a12b38 100644 --- a/code/game/mecha/mech_bay.dm +++ b/code/game/mecha/mech_bay.dm @@ -84,7 +84,7 @@ /obj/machinery/computer/mech_bay_power_console/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "mech_bay_power_console", "Mech Bay Power Control Console", 400, 200, master_ui, state) + ui = new(user, src, ui_key, "MechBayPowerConsole", "Mech Bay Power Control Console", 400, 200, master_ui, state) ui.open() /obj/machinery/computer/mech_bay_power_console/ui_act(action, params) diff --git a/code/game/mecha/mecha_control_console.dm b/code/game/mecha/mecha_control_console.dm index 91c97ff14a..c7db051331 100644 --- a/code/game/mecha/mecha_control_console.dm +++ b/code/game/mecha/mecha_control_console.dm @@ -5,62 +5,74 @@ icon_keyboard = "tech_key" req_access = list(ACCESS_ROBOTICS) circuit = /obj/item/circuitboard/computer/mecha_control - var/list/located = list() - var/screen = 0 - var/stored_data + ui_x = 500 + ui_y = 500 -/obj/machinery/computer/mecha/ui_interact(mob/user) - . = ..() - var/dat = "[src.name]" - if(screen == 0) - dat += "

    Tracking beacons data

    " - var/list/trackerlist = list() - for(var/obj/mecha/MC in GLOB.mechas_list) - trackerlist += MC.trackers - for(var/obj/item/mecha_parts/mecha_tracking/TR in trackerlist) - var/answer = TR.get_mecha_info() - if(answer) - dat += {"
    [answer]
    - Send message
    - Show exosuit log
    - [TR.recharging?"Recharging EMP Pulse...
    ":"(EMP Pulse)
    "]"} +/obj/machinery/computer/mecha/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "ExosuitControlConsole", name, ui_x, ui_y, master_ui, state) + ui.open() - if(screen==1) - dat += "

    Log contents

    " - dat += "Return
    " - dat += "[stored_data]" +/obj/machinery/computer/mecha/ui_data(mob/user) + var/list/data = list() - dat += "(Refresh)
    " - dat += "" + var/list/trackerlist = list() + for(var/obj/mecha/MC in GLOB.mechas_list) + trackerlist += MC.trackers - user << browse(dat, "window=computer;size=400x500") - onclose(user, "computer") + data["mechs"] = list() + for(var/obj/item/mecha_parts/mecha_tracking/MT in trackerlist) + if(!MT.chassis) + continue + var/obj/mecha/M = MT.chassis + var/list/mech_data = list( + name = M.name, + integrity = round((M.obj_integrity / M.max_integrity) * 100), + charge = M.cell ? round(M.cell.percent()) : null, + airtank = M.internal_tank ? M.return_pressure() : null, + pilot = M.occupant, + location = get_area_name(M, TRUE), + active_equipment = M.selected, + emp_recharging = MT.recharging, + tracker_ref = REF(MT) + ) + if(istype(M, /obj/mecha/working/ripley)) + var/obj/mecha/working/ripley/RM = M + mech_data += list( + cargo_space = round((RM.cargo.len / RM.cargo_capacity) * 100) + ) -/obj/machinery/computer/mecha/Topic(href, href_list) + data["mechs"] += list(mech_data) + + return data + +/obj/machinery/computer/mecha/ui_act(action, params) if(..()) return - if(href_list["send_message"]) - var/obj/item/mecha_parts/mecha_tracking/MT = locate(href_list["send_message"]) - if (!istype(MT)) - return - var/message = stripped_input(usr,"Input message","Transmit message") - var/obj/mecha/M = MT.in_mecha() - if(trim(message) && M) - M.occupant_message(message) - return - if(href_list["shock"]) - var/obj/item/mecha_parts/mecha_tracking/MT = locate(href_list["shock"]) - if (istype(MT)) - MT.shock() - if(href_list["get_log"]) - var/obj/item/mecha_parts/mecha_tracking/MT = locate(href_list["get_log"]) - if(istype(MT)) - stored_data = MT.get_mecha_log() - screen = 1 - if(href_list["return"]) - screen = 0 - updateUsrDialog() - return + + switch(action) + if("send_message") + var/obj/item/mecha_parts/mecha_tracking/MT = locate(params["tracker_ref"]) + if(!istype(MT)) + return + var/message = stripped_input(usr, "Input message", "Transmit message") + var/obj/mecha/M = MT.chassis + if(trim(message) && M) + M.occupant_message(message) + to_chat(usr, "Message sent.") + . = TRUE + if("shock") + var/obj/item/mecha_parts/mecha_tracking/MT = locate(params["tracker_ref"]) + if(!istype(MT)) + return + var/obj/mecha/M = MT.chassis + if(M) + MT.shock() + log_game("[key_name(usr)] has activated remote EMP on exosuit [M], located at [loc_name(M)], which is currently [M.occupant? "being piloted by [key_name(M.occupant)]." : "without a pilot."] ") + message_admins("[key_name_admin(usr)][ADMIN_FLW(usr)] has activated remote EMP on exosuit [M][ADMIN_JMP(M)], which is currently [M.occupant ? "being piloted by [key_name_admin(M.occupant)][ADMIN_FLW(M.occupant)]." : "without a pilot."] ") + . = TRUE /obj/item/mecha_parts/mecha_tracking name = "exosuit tracking beacon" @@ -68,24 +80,31 @@ icon = 'icons/obj/device.dmi' icon_state = "motion2" w_class = WEIGHT_CLASS_SMALL - var/ai_beacon = FALSE //If this beacon allows for AI control. Exists to avoid using istype() on checking. - var/recharging = 0 + /// If this beacon allows for AI control. Exists to avoid using istype() on checking + var/ai_beacon = FALSE + /// Cooldown variable for EMP pulsing + var/recharging = FALSE + /// The Mecha that this tracking beacon is attached to + var/obj/mecha/chassis +/** + * Returns a html formatted string describing attached mech status + */ /obj/item/mecha_parts/mecha_tracking/proc/get_mecha_info() - if(!in_mecha()) - return 0 - var/obj/mecha/M = src.loc - var/cell_charge = M.get_charge() - var/answer = {"Name: [M.name] -Integrity: [M.obj_integrity/M.max_integrity*100]% -Cell charge: [isnull(cell_charge)?"Not found":"[M.cell.percent()]%"] -Airtank: [M.return_pressure()]kPa -Pilot: [M.occupant||"None"] -Location: [get_area(M)||"Unknown"] -Active equipment: [M.selected||"None"] "} - if(istype(M, /obj/mecha/working/ripley)) - var/obj/mecha/working/ripley/RM = M - answer += "Used cargo space: [RM.cargo.len/RM.cargo_capacity*100]%
    " + if(!chassis) + return FALSE + + var/cell_charge = chassis.get_charge() + var/answer = {"Name: [chassis.name]
    + Integrity: [round((chassis.obj_integrity/chassis.max_integrity * 100), 0.01)]%
    + Cell Charge: [isnull(cell_charge) ? "Not Found":"[chassis.cell.percent()]%"]
    + Airtank: [chassis.internal_tank ? "[round(chassis.return_pressure(), 0.01)]" : "Not Equipped"] kPa
    + Pilot: [chassis.occupant || "None"]
    + Location: [get_area_name(chassis, TRUE) || "Unknown"]
    + Active Equipment: [chassis.selected || "None"]"} + if(istype(chassis, /obj/mecha/working/ripley)) + var/obj/mecha/working/ripley/RM = chassis + answer += "
    Used Cargo Space: [round((RM.cargo.len / RM.cargo_capacity * 100), 0.01)]%" return answer @@ -95,42 +114,41 @@ qdel(src) /obj/item/mecha_parts/mecha_tracking/Destroy() - if(ismecha(loc)) - var/obj/mecha/M = loc - if(src in M.trackers) - M.trackers -= src + if(chassis) + if(src in chassis.trackers) + chassis.trackers -= src + chassis = null return ..() -/obj/item/mecha_parts/mecha_tracking/proc/in_mecha() - if(ismecha(loc)) - return loc - return 0 +/obj/item/mecha_parts/mecha_tracking/try_attach_part(mob/user, obj/mecha/M) + if(!..()) + return + M.trackers += src + M.diag_hud_set_mechtracking() + chassis = M +/** + * Attempts to EMP mech that the tracker is attached to, if there is one and tracker is not on cooldown + */ /obj/item/mecha_parts/mecha_tracking/proc/shock() if(recharging) return - var/obj/mecha/M = in_mecha() - if(M) - M.emp_act(EMP_HEAVY) - addtimer(CALLBACK(src, /obj/item/mecha_parts/mecha_tracking/proc/recharge), 15 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) - recharging = 1 + if(chassis) + chassis.emp_act(EMP_HEAVY) + addtimer(CALLBACK(src, /obj/item/mecha_parts/mecha_tracking/proc/recharge), 5 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE) + recharging = TRUE +/** + * Resets recharge variable, allowing tracker to be EMP pulsed again + */ /obj/item/mecha_parts/mecha_tracking/proc/recharge() - recharging = 0 - -/obj/item/mecha_parts/mecha_tracking/proc/get_mecha_log() - if(!ismecha(loc)) - return 0 - var/obj/mecha/M = src.loc - return M.get_log_html() - + recharging = FALSE /obj/item/mecha_parts/mecha_tracking/ai_control name = "exosuit AI control beacon" desc = "A device used to transmit exosuit data. Also allows active AI units to take control of said exosuit." ai_beacon = TRUE - /obj/item/storage/box/mechabeacons name = "exosuit tracking beacons" diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm index 395ac810f4..dedbef1906 100644 --- a/code/game/mecha/mecha_defense.dm +++ b/code/game/mecha/mecha_defense.dm @@ -54,7 +54,7 @@ . *= booster_damage_modifier -/obj/mecha/attack_hand(mob/living/user) +/obj/mecha/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/mecha/mecha_parts.dm b/code/game/mecha/mecha_parts.dm index 14df70438f..8a9e4e641f 100644 --- a/code/game/mecha/mecha_parts.dm +++ b/code/game/mecha/mecha_parts.dm @@ -9,6 +9,13 @@ w_class = WEIGHT_CLASS_GIGANTIC flags_1 = CONDUCT_1 +/obj/item/mecha_parts/proc/try_attach_part(mob/user, obj/mecha/M) //For attaching parts to a finished mech + if(!user.transferItemToLoc(src, M)) + to_chat(user, "\The [src] is stuck to your hand, you cannot put it in \the [M]!") + return FALSE + user.visible_message("[user] attaches [src] to [M].", "You attach [src] to [M].") + return TRUE + /obj/item/mecha_parts/chassis name = "Mecha Chassis" icon_state = "backbone" diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index bacb8c6669..eabbdfad88 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -9,7 +9,7 @@ var/buckle_prevents_pull = FALSE //Interaction -/atom/movable/attack_hand(mob/living/user) +/atom/movable/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/effects/contraband.dm b/code/game/objects/effects/contraband.dm index faab0df6e9..e4f1c854d0 100644 --- a/code/game/objects/effects/contraband.dm +++ b/code/game/objects/effects/contraband.dm @@ -101,7 +101,7 @@ to_chat(user, "You carefully remove the poster from the wall.") roll_and_drop(user.loc) -/obj/structure/sign/poster/attack_hand(mob/user) +/obj/structure/sign/poster/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm index 2e45bbfca5..01f0b6f957 100644 --- a/code/game/objects/effects/decals/cleanable/misc.dm +++ b/code/game/objects/effects/decals/cleanable/misc.dm @@ -137,7 +137,7 @@ random_icon_states = list("vomit_1", "vomit_2", "vomit_3", "vomit_4") beauty = -150 -/obj/effect/decal/cleanable/vomit/attack_hand(mob/user) +/obj/effect/decal/cleanable/vomit/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm index 23c5822727..0cf95ea263 100644 --- a/code/game/objects/effects/effect_system/effects_foam.dm +++ b/code/game/objects/effects/effect_system/effects_foam.dm @@ -284,7 +284,7 @@ /obj/structure/foamedmetal/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1) -/obj/structure/foamedmetal/attack_hand(mob/user) +/obj/structure/foamedmetal/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index 504b931685..e363529c46 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -60,7 +60,7 @@ /obj/effect/portal/attack_tk(mob/user) return -/obj/effect/portal/attack_hand(mob/user) +/obj/effect/portal/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index a23e6811f5..00d6d31ad0 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -152,7 +152,7 @@ else ..() -/obj/structure/spider/spiderling/attack_hand(mob/user) +/obj/structure/spider/spiderling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(user.a_intent != INTENT_HELP) user.changeNext_move(CLICK_CD_MELEE) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 75115795c6..7bda35ebe9 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -304,7 +304,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb add_fingerprint(usr) return ..() -/obj/item/attack_hand(mob/user) +/obj/item/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/items/RPD.dm b/code/game/objects/items/RPD.dm index 665082d1d2..93d73b2b5f 100644 --- a/code/game/objects/items/RPD.dm +++ b/code/game/objects/items/RPD.dm @@ -249,7 +249,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/pipes) assets.send(user) - ui = new(user, src, ui_key, "rpd", name, 425, 472, master_ui, state) + ui = new(user, src, ui_key, "RapidPipeDispenser", name, 425, 515, master_ui, state) ui.open() /obj/item/pipe_dispenser/ui_data(mob/user) diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm index 6648db46c4..3d444b7eca 100644 --- a/code/game/objects/items/cardboard_cutouts.dm +++ b/code/game/objects/items/cardboard_cutouts.dm @@ -44,7 +44,7 @@ )) //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/cardboard_cutout/attack_hand(mob/living/user) +/obj/item/cardboard_cutout/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) if(user.a_intent == INTENT_HELP || pushed_over) return ..() user.visible_message("[user] pushes over [src]!", "You push over [src]!") diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index 60e869815b..5b1b86b9e4 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -224,7 +224,7 @@ . = ..() if(.) switch(var_name) - if("assignment","registered_name") + if(NAMEOF(src, assignment),NAMEOF(src, registered_name)) //,NAMEOF(src, registered_age)) update_label() /obj/item/card/id/attack_self(mob/user) @@ -250,15 +250,13 @@ return ..() /obj/item/card/id/proc/insert_money(obj/item/I, mob/user, physical_currency) + if(!registered_account) + to_chat(user, "[src] doesn't have a linked account to deposit [I] into!") + return var/cash_money = I.get_item_credit_value() if(!cash_money) to_chat(user, "[I] doesn't seem to be worth anything!") return - - if(!registered_account) - to_chat(user, "[src] doesn't have a linked account to deposit [I] into!") - return - registered_account.adjust_money(cash_money) if(physical_currency) to_chat(user, "You stuff [I] into [src]. It disappears in a small puff of bluespace smoke, adding [cash_money] credits to the linked account.") @@ -269,17 +267,20 @@ qdel(I) /obj/item/card/id/proc/mass_insert_money(list/money, mob/user) + if(!registered_account) + to_chat(user, "[src] doesn't have a linked account to deposit into!") + return FALSE + if (!money || !money.len) return FALSE var/total = 0 for (var/obj/item/physical_money in money) - var/cash_money = physical_money.get_item_credit_value() + total += physical_money.get_item_credit_value() + CHECK_TICK - total += cash_money - - registered_account.adjust_money(cash_money) + registered_account.adjust_money(total) QDEL_LIST(money) diff --git a/code/game/objects/items/chromosome.dm b/code/game/objects/items/chromosome.dm index 1340e7f35b..8330a8e202 100644 --- a/code/game/objects/items/chromosome.dm +++ b/code/game/objects/items/chromosome.dm @@ -53,32 +53,32 @@ /obj/item/chromosome/stabilizer name = "stabilizer chromosome" - desc = "A chromosome that adjusts to the body to reduce genetic damage by 20%." + desc = "A chromosome that reduces mutation instability by 20%." icon_state = "stabilizer" stabilizer_coeff = 0.8 weight = 1 /obj/item/chromosome/synchronizer name = "synchronizer chromosome" - desc = "A chromosome that gives the mind more controle over the mutation, reducing knockback and downsides by 50%." + desc = "A chromosome that reduces mutation knockback and downsides by 50%." icon_state = "synchronizer" synchronizer_coeff = 0.5 /obj/item/chromosome/power name = "power chromosome" - desc = "A power chromosome for boosting certain mutation's power by 50%." + desc = "A chromosome that increases mutation power by 50%." icon_state = "power" power_coeff = 1.5 /obj/item/chromosome/energy name = "energetic chromosome" - desc = "A chromosome that reduces cooldown on action based mutations by 50%." + desc = "A chromosome that reduces action based mutation cooldowns by by 50%." icon_state = "energy" energy_coeff = 0.5 /obj/item/chromosome/reinforcer name = "reinforcement chromosome" - desc = "Renders the mutation immune to mutadone." + desc = "A chromosome that renders mutations immune to mutadone." icon_state = "reinforcer" weight = 3 diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index fc98da2c0d..620fbbf100 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -152,7 +152,7 @@ SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "crayon", name, 600, 600, + ui = new(user, src, ui_key, "Crayon", name, 600, 600, master_ui, state) ui.open() diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index bcae1d750f..e15dc72838 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -78,7 +78,7 @@ toggle_paddles() //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/defibrillator/attack_hand(mob/user) +/obj/item/defibrillator/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(loc == user) if(slot_flags == ITEM_SLOT_BACK) if(user.get_item_by_slot(SLOT_BACK) == src) diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm index 38b117b132..bfb9348d97 100644 --- a/code/game/objects/items/devices/aicard.dm +++ b/code/game/objects/items/devices/aicard.dm @@ -58,7 +58,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "intellicard", name, 500, 500, master_ui, state) + ui = new(user, src, ui_key, "Intellicard", name, 500, 500, master_ui, state) ui.open() /obj/item/aicard/ui_data() diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm index 981a811bc3..ee26d81a0d 100644 --- a/code/game/objects/items/devices/gps.dm +++ b/code/game/objects/items/devices/gps.dm @@ -76,7 +76,7 @@ GLOBAL_LIST_EMPTY(GPS_list) // Variable window height, depending on how many GPS units there are // to show, clamped to relatively safe range. var/gps_window_height = clamp(325 + GLOB.GPS_list.len * 14, 325, 700) - ui = new(user, src, ui_key, "gps", "Global Positioning System", 470, gps_window_height, master_ui, state) //width, height + ui = new(user, src, ui_key, "Gps", "Global Positioning System", 470, gps_window_height, master_ui, state) //width, height ui.open() ui.set_autoupdate(state = updating) diff --git a/code/game/objects/items/devices/polycircuit.dm b/code/game/objects/items/devices/polycircuit.dm index fb15ce45dc..a9f7cd46c8 100644 --- a/code/game/objects/items/devices/polycircuit.dm +++ b/code/game/objects/items/devices/polycircuit.dm @@ -11,7 +11,7 @@ /obj/item/stack/circuit_stack/attack_self(mob/user)// Prevents the crafting menu, and tells you how to use it. to_chat(user, "You can't use [src] by itself, you'll have to try and remove one of these circuits by hand... carefully.") -/obj/item/stack/circuit_stack/attack_hand(mob/user) +/obj/item/stack/circuit_stack/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) var/mob/living/carbon/human/H = user if(!user.get_inactive_held_item() == src) return ..() diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm index 5802909201..ec59009794 100644 --- a/code/game/objects/items/devices/powersink.dm +++ b/code/game/objects/items/devices/powersink.dm @@ -97,7 +97,7 @@ GLOBAL_LIST_EMPTY(power_sinks) /obj/item/powersink/attack_ai() return -/obj/item/powersink/attack_hand(mob/user) +/obj/item/powersink/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm index e94d14a57d..cdb8c09527 100644 --- a/code/game/objects/items/devices/radio/electropack.dm +++ b/code/game/objects/items/devices/radio/electropack.dm @@ -16,6 +16,9 @@ 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) @@ -29,7 +32,7 @@ . = ..() //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/electropack/attack_hand(mob/user) +/obj/item/electropack/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(iscarbon(user)) var/mob/living/carbon/C = user if(src == C.back) @@ -128,22 +131,12 @@ if(!ishuman(user)) return - user.set_machine(src) - var/dat = {" - -Turned [on ? "On" : "Off"] - Toggle
    -Frequency/Code for electropack:
    -Frequency: -[format_frequency(src.frequency)] -Set
    - -Code: -[src.code] -Set
    -
    "} - user << browse(dat, "window=radio") - onclose(user, "radio") - return +/obj/item/electropack/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "Electropack", name, ui_x, ui_y, master_ui, state) + ui.open() /obj/item/electropack/shockcollar name = "shock collar" @@ -169,7 +162,7 @@ Code: materials = list(/datum/material/iron = 5000, /datum/material/glass =2000) category = list("hacked", "Misc") -/obj/item/electropack/shockcollar/attack_hand(mob/user) +/obj/item/electropack/shockcollar/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(loc == user && user.get_item_by_slot(SLOT_NECK)) to_chat(user, "The collar is fastened tight! You'll need help taking this off!") return diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index f4c317c8ba..ec19c0c05e 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -86,7 +86,7 @@ /obj/item/radio/intercom/attack_ai(mob/user) interact(user) -/obj/item/radio/intercom/attack_hand(mob/user) +/obj/item/radio/intercom/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 5fe9de75aa..e26b29289a 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -119,7 +119,7 @@ ui_height += 6 + channels.len * 21 else ui_height += 24 - ui = new(user, src, ui_key, "radio", name, ui_width, ui_height, master_ui, state) + ui = new(user, src, ui_key, "Radio", name, ui_width, ui_height, master_ui, state) ui.open() /obj/item/radio/ui_data(mob/user) diff --git a/code/game/objects/items/devices/reverse_bear_trap.dm b/code/game/objects/items/devices/reverse_bear_trap.dm index 20107373d3..46b9547e9d 100644 --- a/code/game/objects/items/devices/reverse_bear_trap.dm +++ b/code/game/objects/items/devices/reverse_bear_trap.dm @@ -45,7 +45,7 @@ to_chat(loc, "*ding*") addtimer(CALLBACK(src, .proc/snap), 2) -/obj/item/reverse_bear_trap/attack_hand(mob/user) +/obj/item/reverse_bear_trap/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(iscarbon(user)) var/mob/living/carbon/C = user if(C.get_item_by_slot(SLOT_HEAD) == src) diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm index 78a1a3bfda..5765ac71f1 100644 --- a/code/game/objects/items/devices/taperecorder.dm +++ b/code/game/objects/items/devices/taperecorder.dm @@ -55,7 +55,7 @@ ..() //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/taperecorder/attack_hand(mob/user) +/obj/item/taperecorder/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(loc == user) if(mytape) if(!user.is_holding(src)) diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index b6261b9060..4d255fd339 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -76,6 +76,9 @@ effective or pretty fucking useless. var/used = 0 // is it cooling down? var/stealth = FALSE + var/ui_x = 320 + var/ui_y = 335 + /obj/item/healthanalyzer/rad_laser/attack(mob/living/M, mob/living/user) if(!stealth || !irradiate) ..() @@ -111,7 +114,12 @@ effective or pretty fucking useless. ui_interact(user) /obj/item/healthanalyzer/rad_laser/ui_interact(mob/user) - . = ..() +/obj/item/healthanalyzer/rad_laser/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "RadioactiveMicrolaser", "Radioactive Microlaser", ui_x, ui_y, master_ui, state) + ui.open() var/dat = "Irradiation: [irradiate ? "On" : "Off"]
    " dat += "Stealth Mode (NOTE: Deactivates automatically while Irradiation is off): [stealth ? "On" : "Off"]
    " diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm index 9d5b6d5b6c..ccf9dcd253 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -13,6 +13,8 @@ var/mob/attacher = null var/valve_open = FALSE var/toggle = 1 + var/ui_x = 310 + var/ui_y = 320 /obj/item/transfer_valve/IsAssemblyHolder() return TRUE @@ -235,3 +237,52 @@ // eventually maybe have it update icon to show state (timer, prox etc.) like old bombs /obj/item/transfer_valve/proc/c_state() return + +/obj/item/transfer_valve/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "TransferValve", name, ui_x, ui_y, master_ui, state) + ui.open() + +/obj/item/transfer_valve/ui_data(mob/user) + var/list/data = list() + data["tank_one"] = tank_one + data["tank_two"] = tank_two + data["attached_device"] = attached_device + data["valve"] = valve_open + return data + +/obj/item/transfer_valve/ui_act(action, params) + if(..()) + return + + switch(action) + if("tankone") + if(tank_one) + split_gases() + valve_open = FALSE + tank_one.forceMove(drop_location()) + tank_one = null + . = TRUE + if("tanktwo") + if(tank_two) + split_gases() + valve_open = FALSE + tank_two.forceMove(drop_location()) + tank_two = null + . = TRUE + if("toggle") + toggle_valve() + . = TRUE + if("device") + if(attached_device) + attached_device.attack_self(usr) + . = TRUE + if("remove_device") + if(attached_device) + attached_device.on_detach() + attached_device = null + . = TRUE + + update_icon() diff --git a/code/game/objects/items/eightball.dm b/code/game/objects/items/eightball.dm index c4a15a1871..837f57ceb5 100644 --- a/code/game/objects/items/eightball.dm +++ b/code/game/objects/items/eightball.dm @@ -196,7 +196,7 @@ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "eightball", name, 400, 600, master_ui, state) + ui = new(user, src, ui_key, "EightBallVote", name, 400, 600, master_ui, state) ui.open() /obj/item/toy/eightball/haunted/ui_data(mob/user) diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index c7c9fa37a9..e3388b12eb 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -320,7 +320,7 @@ do_sparks(1, TRUE, src) qdel(src) -/obj/item/restraints/legcuffs/beartrap/energy/attack_hand(mob/user) +/obj/item/restraints/legcuffs/beartrap/energy/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) Crossed(user) //honk . = ..() diff --git a/code/game/objects/items/kitchen.dm b/code/game/objects/items/kitchen.dm index dda41494ff..2c00265ce8 100644 --- a/code/game/objects/items/kitchen.dm +++ b/code/game/objects/items/kitchen.dm @@ -54,6 +54,14 @@ else return ..() +/obj/item/kitchen/fork/throwing + name = "throwing fork" + desc = "A fork, sharpened to perfection, making it a great weapon for throwing." + throwforce = 15 + throw_speed = 4 + throw_range = 6 + embedding = list("pain_mult" = 2, "embed_chance" = 100, "fall_chance" = 0, "embed_chance_turf_mod" = 15) + sharpness = IS_SHARP /obj/item/kitchen/knife name = "kitchen knife" diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index c6aa9f7bf4..b2e463e89e 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -621,7 +621,7 @@ to_chat(user, "[target] doesn't seem to want to get on [src]!") update_icon() -/obj/item/melee/roastingstick/attack_hand(mob/user) +/obj/item/melee/roastingstick/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) ..() if (held_sausage) user.put_in_hands(held_sausage) diff --git a/code/game/objects/items/miscellaneous.dm b/code/game/objects/items/miscellaneous.dm index 7237a1788f..a7f7e3152c 100644 --- a/code/game/objects/items/miscellaneous.dm +++ b/code/game/objects/items/miscellaneous.dm @@ -18,6 +18,8 @@ icon = 'icons/obj/device.dmi' icon_state = "gangtool-blue" item_state = "radio" + var/list/stored_options + var/force_refresh = FALSE //if set to true, the beacon will recalculate its display options whenever opened /obj/item/choice_beacon/attack_self(mob/user) if(canUseBeacon(user)) @@ -34,14 +36,15 @@ return FALSE /obj/item/choice_beacon/proc/generate_options(mob/living/M) - var/list/display_names = generate_display_names() - if(!display_names.len) + if(!stored_options || force_refresh) + stored_options = generate_display_names() + if(!stored_options.len) return - var/choice = input(M,"Which item would you like to order?","Select an Item") as null|anything in display_names + var/choice = input(M,"Which item would you like to order?","Select an Item") as null|anything in stored_options if(!choice || !M.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) return - spawn_option(display_names[choice],M) + spawn_option(stored_options[choice],M) qdel(src) /obj/item/choice_beacon/proc/spawn_option(obj/choice,mob/living/M) @@ -153,6 +156,51 @@ new choice(get_turf(M)) to_chat(M, "You hear something crackle from the beacon for a moment before a voice speaks. \"Please stand by for a message from S.E.L.F. Message as follows: Item request received. Your package has been transported, use the autosurgeon supplied to apply the upgrade. Message ends.\"") +/obj/item/choice_beacon/box + name = "choice box (default)" + desc = "Think really hard about what you want, and then rip it open!" + icon = 'icons/obj/storage.dmi' + icon_state = "deliverypackage3" + item_state = "deliverypackage3" + +/obj/item/choice_beacon/box/spawn_option(obj/choice,mob/living/M) + to_chat(M, "The box opens, revealing the [choice]!") + playsound(src.loc, 'sound/items/poster_ripped.ogg', 50, 1) + M.temporarilyRemoveItemFromInventory(src, TRUE) + M.put_in_hands(new choice) + qdel(src) + +/obj/item/choice_beacon/box/plushie + name = "choice box (plushie)" + desc = "Using the power of quantum entanglement, this box contains every plush, until the moment it is opened!" + icon = 'icons/obj/plushes.dmi' + icon_state = "box" + item_state = "box" + +/obj/item/choice_beacon/box/spawn_option(choice,mob/living/M) + if(ispath(choice, /obj/item/toy/plush)) + ..() //regular plush, spawn it naturally + else + //snowflake plush + var/obj/item/toy/plush/snowflake_plushie = new(get_turf(M)) + snowflake_plushie.set_snowflake_from_config(choice) + M.temporarilyRemoveItemFromInventory(src, TRUE) + M.put_in_hands(new choice) + qdel(src) + +/obj/item/choice_beacon/box/plushie/generate_display_names() + var/list/plushie_list = list() + //plushie set 1: just subtypes of /obj/item/toy/plush + var/list/plushies_set_one = subtypesof(/obj/item/toy/plush) - list(/obj/item/toy/plush/narplush, /obj/item/toy/plush/awakenedplushie, /obj/item/toy/plush/random_snowflake, /obj/item/toy/plush/random) //don't allow these special ones (you can still get narplush/hugbox) + for(var/V in plushies_set_one) + var/atom/A = V + plushie_list[initial(A.name)] = A + //plushie set 2: snowflake plushies + var/list/plushies_set_two = CONFIG_GET(keyed_list/snowflake_plushies) + for(var/V in plushies_set_two) + plushie_list[V] = V //easiest way to do this which works with how selecting options works, despite being snowflakey to have the key equal the value + return plushie_list + /obj/item/skub desc = "It's skub." name = "skub" diff --git a/code/game/objects/items/pet_carrier.dm b/code/game/objects/items/pet_carrier.dm index f2994c0b97..caf41b7a78 100644 --- a/code/game/objects/items/pet_carrier.dm +++ b/code/game/objects/items/pet_carrier.dm @@ -106,7 +106,7 @@ if(user == target) to_chat(user, "Why would you ever do that?") return - if(ishostile(target) && !allows_hostiles && target.move_resist < MOVE_FORCE_VERY_STRONG) //don't allow goliaths into pet carriers + if(ishostile(target) && (!allows_hostiles || istype(target, /mob/living/simple_animal/hostile/carp/cayenne)) || target.move_resist < MOVE_FORCE_VERY_STRONG) //don't allow goliaths into pet carriers, but let cayenne in! to_chat(user, "You have a feeling you shouldn't keep this as a pet.") load_occupant(user, target) @@ -251,7 +251,8 @@ occupant_gas_supply = new if(isanimal(occupant)) var/mob/living/simple_animal/animal = occupant - occupant_gas_supply.set_temperature(animal.minbodytemp) //simple animals only care about temperature when their turf isnt a location + occupant_gas_supply[/datum/gas/oxygen] = 0.0064 //make sure it has some gas in so it isn't depressurized + occupant_gas_supply.set_temperature(animal.minbodytemp) //simple animals only care about temperature/pressure when their turf isnt a location else if(ishuman(occupant)) //humans require resistance to cold/heat and living in no air while inside, and lose this when outside ADD_TRAIT(occupant, TRAIT_RESISTCOLD, "bluespace_container_cold_resist") diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm index 1f69cdae2e..4b2e022da7 100644 --- a/code/game/objects/items/robot/robot_items.dm +++ b/code/game/objects/items/robot/robot_items.dm @@ -746,8 +746,8 @@ ***********************************************************************/ /obj/item/weapon/gripper - name = "circuit gripper" - desc = "A simple grasping tool for inserting circuitboards into machinary." + name = "engineering gripper" + desc = "A simple grasping tool for interacting with various engineering related items, such as circuits, gas tanks and conveyer belts. Alt click to drop instead of use." icon = 'icons/obj/device.dmi' icon_state = "gripper" @@ -755,18 +755,36 @@ //Has a list of items that it can hold. var/list/can_hold = list( - /obj/item/circuitboard + /obj/item/circuitboard, + /obj/item/light, + /obj/item/electronics, + /obj/item/tank, + /obj/item/conveyor_switch_construct, + /obj/item/stack/conveyor, + /obj/item/wallframe, + /obj/item/vending_refill, + /obj/item/stack/sheet, + /obj/item/stack/tile, + /obj/item/stack/rods, + /obj/item/stock_parts + ) + //Basically a blacklist for any subtypes above we dont want + var/list/cannot_hold = list( + /obj/item/stack/sheet/mineral/plasma, + /obj/item/stack/sheet/plasteel ) var/obj/item/wrapped = null // Item currently being held. -/obj/item/weapon/gripper/attack_self() +//Used to interact with UI's of held items, such as gas tanks and airlock electronics. +/obj/item/weapon/gripper/AltClick(mob/user) if(wrapped) wrapped.forceMove(get_turf(wrapped)) + to_chat(user, "You drop the [wrapped].") wrapped = null return ..() -/obj/item/weapon/gripper/afterattack(var/atom/target, var/mob/living/user, proximity, params) +/obj/item/weapon/gripper/afterattack(var/atom/target, var/mob/living/silicon/robot/user, proximity, params) if(!proximity) return @@ -792,18 +810,21 @@ return else if(istype(target,/obj/item)) - var/obj/item/I = target - var/grab = 0 + for(var/typepath in can_hold) if(istype(I,typepath)) grab = 1 - break + for(var/badpath in cannot_hold) + if(istype(I,badpath)) + if(!user.emagged) + grab = 0 + continue //We can grab the item, finally. if(grab) - to_chat(user, "You collect \the [I].") + to_chat(user, "You collect \the [I].") I.loc = src wrapped = I return @@ -812,19 +833,12 @@ /obj/item/weapon/gripper/mining name = "shelter capsule deployer" - desc = "A simple grasping tool for carrying and deploying shelter capsules." + desc = "A simple grasping tool for carrying and deploying shelter capsules. Alt click to drop instead of use." icon_state = "gripper_mining" can_hold = list( /obj/item/survivalcapsule ) -/obj/item/weapon/gripper/mining/attack_self() - if(wrapped) - wrapped.forceMove(get_turf(wrapped)) - wrapped.attack_self() - wrapped = null - return - /obj/item/gun/energy/plasmacutter/cyborg name = "cyborg plasma cutter" desc = "A basic variation of the plasma cutter, compressed into a cyborg chassis. Less effective than normal plasma cutters." diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index d33ecedf0a..9fbedb33cd 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -566,7 +566,7 @@ /obj/item/borg/upgrade/expand/deactivate(mob/living/silicon/robot/R, user = usr) . = ..() - if (.) + if (. && R.hasExpanded) R.resize = 0.5 R.hasExpanded = FALSE R.update_transform() diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm index 2f40604719..7fd37053b1 100644 --- a/code/game/objects/items/shooting_range.dm +++ b/code/game/objects/items/shooting_range.dm @@ -31,7 +31,7 @@ to_chat(user, "You slice off [src]'s uneven chunks of aluminium and scorch marks.") return TRUE -/obj/item/target/attack_hand(mob/user) +/obj/item/target/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm index 00e48fd12a..c142db6530 100644 --- a/code/game/objects/items/stacks/bscrystal.dm +++ b/code/game/objects/items/stacks/bscrystal.dm @@ -75,7 +75,7 @@ to_chat(user, "You cannot crush the polycrystal in-hand, try breaking one off.") //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/stack/sheet/bluespace_crystal/attack_hand(mob/user) +/obj/item/stack/sheet/bluespace_crystal/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(user.get_inactive_held_item() == src) if(zero_amount()) return diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index e6403e83cc..866f067b69 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -280,7 +280,7 @@ return . = ..() -/obj/item/stack/medical/mesh/attack_hand(mob/user) +/obj/item/stack/medical/mesh/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(!is_open & user.get_inactive_held_item() == src) to_chat(user, "You need to open [src] first.") return diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 3ca7137548..1306ad7610 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -244,6 +244,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \ new/datum/stack_recipe("rifle stock", /obj/item/weaponcrafting/stock, 10, time = 20), \ new/datum/stack_recipe("rolling pin", /obj/item/kitchen/rollingpin, 2, time = 30), \ new/datum/stack_recipe("wooden bucket", /obj/item/reagent_containers/glass/bucket/wood, 2, time = 30), \ + new/datum/stack_recipe("painting frame", /obj/item/wallframe/painting, 1, time = 10),\ new/datum/stack_recipe("wooden buckler", /obj/item/shield/riot/buckler, 20, time = 40), \ new/datum/stack_recipe("baseball bat", /obj/item/melee/baseball_bat, 5, time = 15),\ null, \ diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 16b46567c7..df9807b524 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -390,7 +390,7 @@ . = ..() //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/stack/attack_hand(mob/user) +/obj/item/stack/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(user.get_inactive_held_item() == src) if(zero_amount()) return diff --git a/code/game/objects/items/stacks/tape.dm b/code/game/objects/items/stacks/tape.dm index 177260febb..d33d106d11 100644 --- a/code/game/objects/items/stacks/tape.dm +++ b/code/game/objects/items/stacks/tape.dm @@ -15,6 +15,9 @@ var/list/conferred_embed = EMBED_HARMLESS var/overwrite_existing = FALSE + var/endless = FALSE + var/apply_time = 30 + /obj/item/stack/sticky_tape/afterattack(obj/item/I, mob/living/user) if(!istype(I)) return @@ -25,17 +28,24 @@ user.visible_message("[user] begins wrapping [I] with [src].", "You begin wrapping [I] with [src].") - if(do_after(user, 30, target=I)) + if(do_after(user, apply_time, target=I)) I.embedding = conferred_embed I.updateEmbedding() to_chat(user, "You finish wrapping [I] with [src].") - use(1) + if(!endless) + use(1) I.name = "[prefix] [I.name]" if(istype(I, /obj/item/grenade)) var/obj/item/grenade/sticky_bomb = I sticky_bomb.sticky = TRUE +/obj/item/stack/sticky_tape/infinite //endless tape that applies far faster, for maximum honks + name = "endless sticky tape" + desc = "This roll of sticky tape somehow has no end." + endless = TRUE + apply_time = 10 + /obj/item/stack/sticky_tape/super name = "super sticky tape" singular_name = "super sticky tape" diff --git a/code/game/objects/items/stacks/tickets.dm b/code/game/objects/items/stacks/tickets.dm new file mode 100644 index 0000000000..22cb895277 --- /dev/null +++ b/code/game/objects/items/stacks/tickets.dm @@ -0,0 +1,31 @@ +/obj/item/stack/arcadeticket + name = "arcade tickets" + desc = "Wow! With enough of these, you could buy a bike! ...Pssh, yeah right." + singular_name = "arcade ticket" + icon_state = "arcade-ticket" + item_state = "tickets" + w_class = WEIGHT_CLASS_TINY + max_amount = 30 + +/obj/item/stack/arcadeticket/Initialize(mapload, new_amount, merge = TRUE) + . = ..() + update_icon() + +/obj/item/stack/arcadeticket/update_icon() + var/amount = get_amount() + if((amount >= 12) && (amount > 0)) + icon_state = "arcade-ticket_4" + else if((amount >= 6) && (amount > 0)) + icon_state = "arcade-ticket_3" + else if((amount >= 2) && (amount > 0)) + icon_state = "arcade-ticket_2" + else + icon_state = "arcade-ticket" + +/obj/item/stack/arcadeticket/proc/pay_tickets() + amount -= 2 + if (amount == 0) + qdel(src) + +/obj/item/stack/arcadeticket/thirty + amount = 30 diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index 3d5f0dc924..b989398e53 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -648,3 +648,9 @@ obj/item/storage/backpack/duffelbag/syndie/shredderbundle new /obj/item/gun/ballistic/automatic/flechette/shredder(src) new /obj/item/storage/belt/military(src) new /obj/item/clothing/suit/space/hardsuit/syndi/elite(src) + +/obj/item/storage/backpack/snail + name = "snail shell" + desc = "Worn by snails as armor and storage compartment." + icon_state = "snailshell" + item_state = "snailshell" diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index 2831311eff..b64aa60cac 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -48,7 +48,8 @@ STR.max_w_class = WEIGHT_CLASS_SMALL STR.max_combined_w_class = 30 STR.max_items = 30 - STR.cant_hold = typecacheof(list(/obj/item/disk/nuclear)) + STR.can_hold_extra = typecacheof(list(/obj/item/organ/lungs, /obj/item/organ/liver, /obj/item/organ/stomach, /obj/item/clothing/shoes)) - typesof(/obj/item/clothing/shoes/magboots, /obj/item/clothing/shoes/clown_shoes, /obj/item/clothing/shoes/jackboots, /obj/item/clothing/shoes/workboots) + STR.cant_hold = typecacheof(list(/obj/item/disk/nuclear, /obj/item/storage/wallet, /obj/item/organ/brain)) STR.limited_random_access = TRUE STR.limited_random_access_stack_position = 3 diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm index cdd3781748..02ae867240 100644 --- a/code/game/objects/items/storage/boxes.dm +++ b/code/game/objects/items/storage/boxes.dm @@ -1418,3 +1418,9 @@ obj/item/storage/box/stingbangs new /obj/item/reagent_containers/glass/beaker/meta(src) new /obj/item/reagent_containers/glass/beaker/noreact(src) new /obj/item/reagent_containers/glass/beaker/bluespace(src) + +/obj/item/storage/box/strange_seeds_5pack + +/obj/item/storage/box/strange_seeds_5pack/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/seeds/random(src) \ No newline at end of file diff --git a/code/game/objects/items/storage/secure.dm b/code/game/objects/items/storage/secure.dm index 0e9a9fda61..6061feb893 100644 --- a/code/game/objects/items/storage/secure.dm +++ b/code/game/objects/items/storage/secure.dm @@ -205,7 +205,7 @@ new /obj/item/paper(src) new /obj/item/pen(src) -/obj/item/storage/secure/safe/attack_hand(mob/user) +/obj/item/storage/secure/safe/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm index e69b2b6272..b601e4310e 100644 --- a/code/game/objects/items/tanks/tanks.dm +++ b/code/game/objects/items/tanks/tanks.dm @@ -168,7 +168,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "tanks", name, 400, 120, master_ui, state) + ui = new(user, src, ui_key, "Tank", name, 400, 120, master_ui, state) ui.open() /obj/item/tank/ui_data(mob/user) diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm index b1c0d3dfbb..0a7eefb786 100644 --- a/code/game/objects/items/tanks/watertank.dm +++ b/code/game/objects/items/tanks/watertank.dm @@ -72,7 +72,7 @@ QDEL_NULL(noz) return ..() -/obj/item/watertank/attack_hand(mob/user) +/obj/item/watertank/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if (user.get_item_by_slot(user.getBackSlot()) == src) toggle_mister(user) else diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index bf1eca01f9..fe2e0df2eb 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -574,7 +574,7 @@ else . = ..() -/obj/item/toy/prize/attack_hand(mob/user) +/obj/item/toy/prize/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -813,7 +813,7 @@ //ATTACK HAND IGNORING PARENT RETURN VALUE //ATTACK HAND NOT CALLING PARENT -/obj/item/toy/cards/deck/attack_hand(mob/user) +/obj/item/toy/cards/deck/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) draw_card(user) /obj/item/toy/cards/deck/proc/draw_card(mob/user) diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 7524bb93e1..7170ba8be7 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -706,6 +706,92 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 item_flags = DROPDEL | ABSTRACT attack_verb = list("bopped") +/obj/item/circlegame/Initialize() + . = ..() + var/mob/living/owner = loc + if(!istype(owner)) + return + RegisterSignal(owner, COMSIG_PARENT_EXAMINE, .proc/ownerExamined) + +/obj/item/circlegame/Destroy() + var/mob/owner = loc + if(istype(owner)) + UnregisterSignal(owner, COMSIG_PARENT_EXAMINE) + return ..() + +/obj/item/circlegame/dropped(mob/user) + UnregisterSignal(user, COMSIG_PARENT_EXAMINE) //loc will have changed by the time this is called, so Destroy() can't catch it + // this is a dropdel item. + return ..() + +/// Stage 1: The mistake is made +/obj/item/circlegame/proc/ownerExamined(mob/living/owner, mob/living/sucker) + if(!istype(sucker) || !in_range(owner, sucker)) + return + addtimer(CALLBACK(src, .proc/waitASecond, owner, sucker), 4) + +/// Stage 2: Fear sets in +/obj/item/circlegame/proc/waitASecond(mob/living/owner, mob/living/sucker) + if(QDELETED(sucker) || QDELETED(src) || QDELETED(owner)) + return + + if(owner == sucker) // big mood + to_chat(owner, "Wait a second... you just looked at your own [src.name]!") + addtimer(CALLBACK(src, .proc/selfGottem, owner), 10) + else + to_chat(sucker, "Wait a second... was that a-") + addtimer(CALLBACK(src, .proc/GOTTEM, owner, sucker), 6) + +/// Stage 3A: We face our own failures +/obj/item/circlegame/proc/selfGottem(mob/living/owner) + if(QDELETED(src) || QDELETED(owner)) + return + + playsound(get_turf(owner), 'sound/effects/hit_punch.ogg', 50, TRUE, -1) + owner.visible_message("[owner] shamefully bops [owner.p_them()]self with [owner.p_their()] [src.name].", "You shamefully bop yourself with your [src.name].", \ + "You hear a dull thud!") + log_combat(owner, owner, "bopped", src.name, "(self)") + owner.do_attack_animation(owner) + owner.apply_damage(100, STAMINA) + owner.Knockdown(10) + qdel(src) + +/// Stage 3B: We face our reckoning (unless we moved away or they're incapacitated) +/obj/item/circlegame/proc/GOTTEM(mob/living/owner, mob/living/sucker) + if(QDELETED(sucker)) + return + + if(QDELETED(src) || QDELETED(owner)) + to_chat(sucker, "Nevermind... must've been your imagination...") + return + + if(!in_range(owner, sucker) || !(owner.mobility_flags & MOBILITY_USE)) + to_chat(sucker, "Phew... you moved away before [owner] noticed you saw [owner.p_their()] [src.name]...") + return + + to_chat(owner, "[sucker] looks down at your [src.name] before trying to avert [sucker.p_their()] eyes, but it's too late!") + to_chat(sucker, "[owner] sees the fear in your eyes as you try to look away from [owner.p_their()] [src.name]!") + + playsound(get_turf(owner), 'sound/effects/hit_punch.ogg', 50, TRUE, -1) + owner.do_attack_animation(sucker) + + if(HAS_TRAIT(owner, TRAIT_HULK)) + owner.visible_message("[owner] bops [sucker] with [owner.p_their()] [src.name] much harder than intended, sending [sucker.p_them()] flying!", \ + "You bop [sucker] with your [src.name] much harder than intended, sending [sucker.p_them()] flying!", "You hear a sickening sound of flesh hitting flesh!", ignored_mobs=list(sucker)) + to_chat(sucker, "[owner] bops you incredibly hard with [owner.p_their()] [src.name], sending you flying!") + sucker.apply_damage(50, STAMINA) + sucker.Knockdown(50) + log_combat(owner, sucker, "bopped", src.name, "(setup- Hulk)") + var/atom/throw_target = get_edge_target_turf(sucker, owner.dir) + sucker.throw_at(throw_target, 6, 3, owner) + else + owner.visible_message("[owner] bops [sucker] with [owner.p_their()] [src.name]!", "You bop [sucker] with your [src.name]!", \ + "You hear a dull thud!", ignored_mobs=list(sucker)) + sucker.apply_damage(15, STAMINA) + log_combat(owner, sucker, "bopped", src.name, "(setup)") + to_chat(sucker, "[owner] bops you with [owner.p_their()] [src.name]!") + qdel(src) + /obj/item/slapper name = "slapper" desc = "This is how real men fight." diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index ba3eba9bd3..fb3b1535ed 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -37,13 +37,9 @@ if("anchored") setAnchored(vval) return TRUE - if("obj_flags") + if(NAMEOF(src, obj_flags)) if ((obj_flags & DANGEROUS_POSSESSION) && !(vval & DANGEROUS_POSSESSION)) return FALSE - if("control_object") - var/obj/O = vval - if(istype(O) && (O.obj_flags & DANGEROUS_POSSESSION)) - return FALSE return ..() /obj/Initialize() diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index d30f617919..cce4955210 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -28,7 +28,7 @@ queue_smooth_neighbors(src) return ..() -/obj/structure/attack_hand(mob/user) +/obj/structure/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm index a793459c5d..a6cd8df746 100644 --- a/code/game/objects/structures/aliens.dm +++ b/code/game/objects/structures/aliens.dm @@ -249,7 +249,7 @@ /obj/structure/alien/egg/attack_alien(mob/living/carbon/alien/user) return attack_hand(user) -/obj/structure/alien/egg/attack_hand(mob/living/user) +/obj/structure/alien/egg/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/artstuff.dm b/code/game/objects/structures/artstuff.dm index fcc26d1313..827e9a7b0a 100644 --- a/code/game/objects/structures/artstuff.dm +++ b/code/game/objects/structures/artstuff.dm @@ -80,7 +80,7 @@ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "canvas", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "Canvas", name, ui_x, ui_y, master_ui, state) ui.set_autoupdate(FALSE) ui.open() diff --git a/code/game/objects/structures/barsigns.dm b/code/game/objects/structures/barsigns.dm index 821409c26b..7ea678cae4 100644 --- a/code/game/objects/structures/barsigns.dm +++ b/code/game/objects/structures/barsigns.dm @@ -52,7 +52,7 @@ /obj/structure/sign/barsign/attack_ai(mob/user) return attack_hand(user) -/obj/structure/sign/barsign/attack_hand(mob/user) +/obj/structure/sign/barsign/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index a4ee2f16e2..e45ddf650c 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -311,7 +311,7 @@ LINEN BINS /obj/structure/bedsheetbin/attack_paw(mob/user) return attack_hand(user) -/obj/structure/bedsheetbin/attack_hand(mob/user) +/obj/structure/bedsheetbin/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 732b4db14f..672bd49632 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -458,7 +458,7 @@ return container_resist(user) -/obj/structure/closet/attack_hand(mob/user) +/obj/structure/closet/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/crates_lockers/closets/genpop.dm b/code/game/objects/structures/crates_lockers/closets/genpop.dm index 2b263bb1ed..04c2f37b0f 100644 --- a/code/game/objects/structures/crates_lockers/closets/genpop.dm +++ b/code/game/objects/structures/crates_lockers/closets/genpop.dm @@ -91,7 +91,7 @@ locked = TRUE return ..() -/obj/structure/closet/secure_closet/genpop/attack_hand(mob/user) +/obj/structure/closet/secure_closet/genpop/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(user.lying && get_dist(src, user) > 0) return @@ -114,4 +114,4 @@ return - ..() \ No newline at end of file + ..() diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 2c977a34d6..99bce305f8 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -41,7 +41,7 @@ if(manifest) . += "manifest" -/obj/structure/closet/crate/attack_hand(mob/user) +/obj/structure/closet/crate/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/crates_lockers/crates/large.dm b/code/game/objects/structures/crates_lockers/crates/large.dm index 880460a23c..d8c2f7f91c 100644 --- a/code/game/objects/structures/crates_lockers/crates/large.dm +++ b/code/game/objects/structures/crates_lockers/crates/large.dm @@ -8,7 +8,7 @@ delivery_icon = "deliverybox" integrity_failure = 0 //Makes the crate break when integrity reaches 0, instead of opening and becoming an invisible sprite. -/obj/structure/closet/crate/large/attack_hand(mob/user) +/obj/structure/closet/crate/large/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) add_fingerprint(user) if(manifest) tear_manifest(user) @@ -40,4 +40,4 @@ else to_chat(user, "You need a crowbar to pry this open!") return FALSE //Just stop. Do nothing. Don't turn into an invisible sprite. Don't open like a locker. - //The large crate has no non-attack interactions other than the crowbar, anyway. \ No newline at end of file + //The large crate has no non-attack interactions other than the crowbar, anyway. diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index c332a07edf..4db889b392 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -157,7 +157,7 @@ /obj/structure/displaycase/attack_paw(mob/user) return attack_hand(user) -/obj/structure/displaycase/attack_hand(mob/user) +/obj/structure/displaycase/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/divine.dm b/code/game/objects/structures/divine.dm index bca96e67d1..5afe97f669 100644 --- a/code/game/objects/structures/divine.dm +++ b/code/game/objects/structures/divine.dm @@ -7,7 +7,7 @@ density = FALSE can_buckle = 1 -/obj/structure/sacrificealtar/attack_hand(mob/living/user) +/obj/structure/sacrificealtar/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -30,7 +30,7 @@ var/time_between_uses = 1800 var/last_process = 0 -/obj/structure/healingfountain/attack_hand(mob/living/user) +/obj/structure/healingfountain/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -48,4 +48,4 @@ if(last_process + time_between_uses > world.time) icon_state = "fountain" else - icon_state = "fountain-red" \ No newline at end of file + icon_state = "fountain-red" diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm index 528153324d..bacb6fc92b 100644 --- a/code/game/objects/structures/dresser.dm +++ b/code/game/objects/structures/dresser.dm @@ -19,7 +19,7 @@ new /obj/item/stack/sheet/mineral/wood(drop_location(), 10) qdel(src) -/obj/structure/dresser/attack_hand(mob/user) +/obj/structure/dresser/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(. || !ishuman(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) return diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm index 3bc84deb4d..a279070e69 100644 --- a/code/game/objects/structures/extinguisher.dm +++ b/code/game/objects/structures/extinguisher.dm @@ -69,7 +69,7 @@ return ..() -/obj/structure/extinguisher_cabinet/attack_hand(mob/user) +/obj/structure/extinguisher_cabinet/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm index 679a755321..eaa6e574cd 100644 --- a/code/game/objects/structures/false_walls.dm +++ b/code/game/objects/structures/false_walls.dm @@ -41,7 +41,7 @@ new /obj/structure/falsewall/brass(loc) qdel(src) -/obj/structure/falsewall/attack_hand(mob/user) +/obj/structure/falsewall/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(opening) return . = ..() @@ -180,7 +180,7 @@ radiate() return ..() -/obj/structure/falsewall/uranium/attack_hand(mob/user) +/obj/structure/falsewall/uranium/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) radiate() . = ..() diff --git a/code/game/objects/structures/femur_breaker.dm b/code/game/objects/structures/femur_breaker.dm index 7331285161..1fa21d119e 100644 --- a/code/game/objects/structures/femur_breaker.dm +++ b/code/game/objects/structures/femur_breaker.dm @@ -32,7 +32,7 @@ if (LAZYLEN(buckled_mobs)) . += "Someone appears to be strapped in. You can help them unbuckle, or activate the femur breaker." -/obj/structure/femur_breaker/attack_hand(mob/user) +/obj/structure/femur_breaker/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) add_fingerprint(user) // Currently being used diff --git a/code/game/objects/structures/fence.dm b/code/game/objects/structures/fence.dm index 35891fa607..5803fb1306 100644 --- a/code/game/objects/structures/fence.dm +++ b/code/game/objects/structures/fence.dm @@ -120,7 +120,7 @@ open = TRUE density = TRUE -/obj/structure/fence/door/attack_hand(mob/user) +/obj/structure/fence/door/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(can_open(user)) toggle(user) @@ -156,4 +156,4 @@ #undef NO_HOLE #undef MEDIUM_HOLE #undef LARGE_HOLE -#undef MAX_HOLE_SIZE \ No newline at end of file +#undef MAX_HOLE_SIZE diff --git a/code/game/objects/structures/fireaxe.dm b/code/game/objects/structures/fireaxe.dm index bcf1016c1e..de88372b1e 100644 --- a/code/game/objects/structures/fireaxe.dm +++ b/code/game/objects/structures/fireaxe.dm @@ -105,7 +105,7 @@ fireaxe = null qdel(src) -/obj/structure/fireaxecabinet/attack_hand(mob/user) +/obj/structure/fireaxecabinet/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm index ce78b92f38..6d72bb58b2 100644 --- a/code/game/objects/structures/flora.dm +++ b/code/game/objects/structures/flora.dm @@ -65,7 +65,7 @@ var/gift_type = /obj/item/a_gift/anything var/list/ckeys_that_took = list() -/obj/structure/flora/tree/pine/xmas/presents/attack_hand(mob/living/user) +/obj/structure/flora/tree/pine/xmas/presents/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/fluff.dm b/code/game/objects/structures/fluff.dm index 736e58143e..1dcda6eb50 100644 --- a/code/game/objects/structures/fluff.dm +++ b/code/game/objects/structures/fluff.dm @@ -110,7 +110,7 @@ desc = "Space Jesus is my copilot." icon_state = "driverseat" -/obj/structure/fluff/bus/passable/seat/driver/attack_hand(mob/user) +/obj/structure/fluff/bus/passable/seat/driver/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) playsound(src, 'sound/items/carhorn.ogg', 50, 1) . = ..() diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm index 4455c8820d..03bcdde57c 100644 --- a/code/game/objects/structures/ghost_role_spawners.dm +++ b/code/game/objects/structures/ghost_role_spawners.dm @@ -186,7 +186,7 @@ else new_spawn.mind.assigned_role = "Free Golem" -/obj/effect/mob_spawn/human/golem/attack_hand(mob/user) +/obj/effect/mob_spawn/human/golem/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 936b9248e8..19a52f5a56 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -99,7 +99,7 @@ ..(user, 1) return TRUE -/obj/structure/grille/attack_hand(mob/living/user) +/obj/structure/grille/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/guillotine.dm b/code/game/objects/structures/guillotine.dm index 0a5ba6a68c..a335906744 100644 --- a/code/game/objects/structures/guillotine.dm +++ b/code/game/objects/structures/guillotine.dm @@ -51,7 +51,7 @@ if (LAZYLEN(buckled_mobs)) . += "Someone appears to be strapped in. You can help them out, or you can harm them by activating the guillotine." -/obj/structure/guillotine/attack_hand(mob/user) +/obj/structure/guillotine/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) add_fingerprint(user) // Currently being used by something @@ -256,4 +256,4 @@ #undef GUILLOTINE_ACTIVATE_DELAY #undef GUILLOTINE_WRENCH_DELAY #undef GUILLOTINE_ACTION_INUSE -#undef GUILLOTINE_ACTION_WRENCH \ No newline at end of file +#undef GUILLOTINE_ACTION_WRENCH diff --git a/code/game/objects/structures/guncase.dm b/code/game/objects/structures/guncase.dm index ede7e31e0d..1cab600fb1 100644 --- a/code/game/objects/structures/guncase.dm +++ b/code/game/objects/structures/guncase.dm @@ -53,7 +53,7 @@ else return ..() -/obj/structure/guncase/attack_hand(mob/user) +/obj/structure/guncase/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/headpike.dm b/code/game/objects/structures/headpike.dm index 65d930e08b..7a67387a8e 100644 --- a/code/game/objects/structures/headpike.dm +++ b/code/game/objects/structures/headpike.dm @@ -37,7 +37,7 @@ MA.pixel_y = 12 . += H -/obj/structure/headpike/attack_hand(mob/user) +/obj/structure/headpike/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -47,4 +47,4 @@ victim = null spear.forceMove(drop_location()) spear = null - qdel(src) \ No newline at end of file + qdel(src) diff --git a/code/game/objects/structures/holosign.dm b/code/game/objects/structures/holosign.dm index 8d2f7bcbf7..41ecd721ed 100644 --- a/code/game/objects/structures/holosign.dm +++ b/code/game/objects/structures/holosign.dm @@ -25,7 +25,7 @@ projector = null return ..() -/obj/structure/holosign/attack_hand(mob/living/user) +/obj/structure/holosign/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -162,7 +162,7 @@ return TRUE //nice or benign diseases! return TRUE -/obj/structure/holosign/barrier/medical/attack_hand(mob/living/user) +/obj/structure/holosign/barrier/medical/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) if(CanPass(user) && user.a_intent == INTENT_HELP) force_allaccess = !force_allaccess to_chat(user, "You [force_allaccess ? "deactivate" : "activate"] the biometric scanners.") //warning spans because you can make the station sick! @@ -182,7 +182,7 @@ /obj/structure/holosign/barrier/cyborg/hacked/proc/cooldown() shockcd = FALSE -/obj/structure/holosign/barrier/cyborg/hacked/attack_hand(mob/living/user) +/obj/structure/holosign/barrier/cyborg/hacked/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm index dc4a741b8b..72487ddc16 100644 --- a/code/game/objects/structures/janicart.dm +++ b/code/game/objects/structures/janicart.dm @@ -91,7 +91,7 @@ else return ..() -/obj/structure/janitorialcart/attack_hand(mob/user) +/obj/structure/janitorialcart/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm index 05a7e1c958..5706f79192 100644 --- a/code/game/objects/structures/kitchen_spike.dm +++ b/code/game/objects/structures/kitchen_spike.dm @@ -61,7 +61,7 @@ return TRUE //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/structure/kitchenspike/attack_hand(mob/user) +/obj/structure/kitchenspike/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(VIABLE_MOB_CHECK(user.pulling) && user.a_intent == INTENT_GRAB && !has_buckled_mobs()) var/mob/living/L = user.pulling if(HAS_TRAIT(user, TRAIT_PACIFISM) && L.stat != DEAD) diff --git a/code/game/objects/structures/ladders.dm b/code/game/objects/structures/ladders.dm index f321498bfd..6037183cc9 100644 --- a/code/game/objects/structures/ladders.dm +++ b/code/game/objects/structures/ladders.dm @@ -122,7 +122,7 @@ return FALSE return TRUE -/obj/structure/ladder/attack_hand(mob/user) +/obj/structure/ladder/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/life_candle.dm b/code/game/objects/structures/life_candle.dm index a64dc6c6a9..ddd334a9e4 100644 --- a/code/game/objects/structures/life_candle.dm +++ b/code/game/objects/structures/life_candle.dm @@ -24,7 +24,7 @@ var/respawn_time = 50 var/respawn_sound = 'sound/magic/staff_animation.ogg' -/obj/structure/life_candle/attack_hand(mob/user) +/obj/structure/life_candle/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index f52fa0576a..cca41b4e11 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -50,7 +50,7 @@ /obj/structure/mineral_door/attack_paw(mob/user) return attack_hand(user) -/obj/structure/mineral_door/attack_hand(mob/user) +/obj/structure/mineral_door/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 65e1b7dd9a..b1829054ce 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -15,7 +15,7 @@ if(icon_state == "mirror_broke" && !broken) obj_break(null, mapload) -/obj/structure/mirror/attack_hand(mob/user) +/obj/structure/mirror/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -118,7 +118,7 @@ choosable_races += S.id ..() -/obj/structure/mirror/magic/attack_hand(mob/user) +/obj/structure/mirror/magic/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 3c2f5ef49e..ce8323d399 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -58,7 +58,7 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an /obj/structure/bodycontainer/attack_paw(mob/user) return attack_hand(user) -/obj/structure/bodycontainer/attack_hand(mob/user) +/obj/structure/bodycontainer/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -223,7 +223,15 @@ GLOBAL_LIST_EMPTY(crematoriums) GLOB.crematoriums.Add(src) ..() -/obj/structure/bodycontainer/crematorium/update_icon_state() +/obj/structure/bodycontainer/crematorium/Initialize() + . = ..() + connected = new /obj/structure/tray/c_tray(src) + connected.connected = src + +/obj/structure/bodycontainer/crematorium/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) + id = "[idnum][id]" + +/obj/structure/bodycontainer/crematorium/update_icon() if(!connected || connected.loc != src) icon_state = "crema0" else @@ -320,7 +328,7 @@ GLOBAL_LIST_EMPTY(crematoriums) /obj/structure/tray/attack_paw(mob/user) return attack_hand(user) -/obj/structure/tray/attack_hand(mob/user) +/obj/structure/tray/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/spirit_board.dm b/code/game/objects/structures/spirit_board.dm index 4a9a1bdce6..3a415b84a9 100644 --- a/code/game/objects/structures/spirit_board.dm +++ b/code/game/objects/structures/spirit_board.dm @@ -14,7 +14,7 @@ desc = "[initial(desc)] The planchette is sitting at \"[planchette]\"." return ..() -/obj/structure/spirit_board/attack_hand(mob/user) +/obj/structure/spirit_board/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -76,4 +76,4 @@ to_chat(M, "There aren't enough people to use the [src.name]!") return 0 - return 1 \ No newline at end of file + return 1 diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm index 466912f93e..1d7ba1d993 100644 --- a/code/game/objects/structures/statues.dm +++ b/code/game/objects/structures/statues.dm @@ -74,7 +74,7 @@ radiate() ..() -/obj/structure/statue/uranium/attack_hand(mob/user) +/obj/structure/statue/uranium/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) radiate() . = ..() @@ -240,7 +240,7 @@ honk() return ..() -/obj/structure/statue/bananium/attack_hand(mob/user) +/obj/structure/statue/bananium/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) honk() . = ..() diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 15e1bb7030..7569b10fdd 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -60,7 +60,7 @@ /obj/structure/table/attack_paw(mob/user) return attack_hand(user) -/obj/structure/table/attack_hand(mob/living/user) +/obj/structure/table/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) if(Adjacent(user) && user.pulling) if(isliving(user.pulling)) var/mob/living/pushed_mob = user.pulling @@ -678,7 +678,7 @@ /obj/structure/rack/attack_paw(mob/living/user) attack_hand(user) -/obj/structure/rack/attack_hand(mob/living/user) +/obj/structure/rack/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm index 6a8175b921..e2298ac6c5 100644 --- a/code/game/objects/structures/tank_dispenser.dm +++ b/code/game/objects/structures/tank_dispenser.dm @@ -71,9 +71,12 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "tank_dispenser", name, 275, 103, master_ui, state) + ui = new(user, src, ui_key, "TankDispenser", name, 275, 103, master_ui, state) ui.open() +/obj/structure/tank_dispenser/attack_robot(mob/user) + ui_interact(user) + /obj/structure/tank_dispenser/ui_data(mob/user) var/list/data = list() data["oxygen"] = oxygentanks diff --git a/code/game/objects/structures/target_stake.dm b/code/game/objects/structures/target_stake.dm index 9dcfec43bf..a08d5c95c1 100644 --- a/code/game/objects/structures/target_stake.dm +++ b/code/game/objects/structures/target_stake.dm @@ -48,7 +48,7 @@ handle_density() to_chat(user, "You slide the target into the stake.") -/obj/structure/target_stake/attack_hand(mob/user) +/obj/structure/target_stake/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/transit_tubes/station.dm b/code/game/objects/structures/transit_tubes/station.dm index ba23878168..7f597857d9 100644 --- a/code/game/objects/structures/transit_tubes/station.dm +++ b/code/game/objects/structures/transit_tubes/station.dm @@ -58,7 +58,7 @@ qdel(R) -/obj/structure/transit_tube/station/attack_hand(mob/user) +/obj/structure/transit_tube/station/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 30c4696af3..6e39bee927 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -28,7 +28,7 @@ AM.forceMove(loc) return ..() -/obj/structure/toilet/attack_hand(mob/living/user) +/obj/structure/toilet/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -174,7 +174,7 @@ ..() hiddenitem = new /obj/item/reagent_containers/food/urinalcake -/obj/structure/urinal/attack_hand(mob/user) +/obj/structure/urinal/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -492,7 +492,7 @@ var/buildstacktype = /obj/item/stack/sheet/metal var/buildstackamount = 1 -/obj/structure/sink/attack_hand(mob/living/user) +/obj/structure/sink/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -784,7 +784,7 @@ return TRUE -/obj/structure/curtain/attack_hand(mob/user) +/obj/structure/curtain/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 31f6df009d..8a27604e97 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -169,7 +169,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) return 1 . = ..() -/obj/structure/window/attack_hand(mob/user) +/obj/structure/window/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -837,7 +837,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) for (var/i in 1 to rand(1,4)) . += new /obj/item/paper/natural(location) -/obj/structure/window/paperframe/attack_hand(mob/user) +/obj/structure/window/paperframe/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/turfs/closed.dm b/code/game/turfs/closed.dm index 65b487bd05..b78826b23b 100644 --- a/code/game/turfs/closed.dm +++ b/code/game/turfs/closed.dm @@ -83,7 +83,7 @@ . = ..() if(.) switch(var_name) - if("icon") + if(NAMEOF(src, icon)) SStitle.icon = icon /turf/closed/indestructible/riveted diff --git a/code/game/turfs/simulated/floor/light_floor.dm b/code/game/turfs/simulated/floor/light_floor.dm index f9376c0672..4f7aa9e492 100644 --- a/code/game/turfs/simulated/floor/light_floor.dm +++ b/code/game/turfs/simulated/floor/light_floor.dm @@ -52,7 +52,7 @@ set_light(0) return ..() -/turf/open/floor/light/attack_hand(mob/user) +/turf/open/floor/light/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/turfs/simulated/floor/mineral_floor.dm b/code/game/turfs/simulated/floor/mineral_floor.dm index f0ac0053ce..9a227d2594 100644 --- a/code/game/turfs/simulated/floor/mineral_floor.dm +++ b/code/game/turfs/simulated/floor/mineral_floor.dm @@ -149,7 +149,7 @@ if(!.) honk() -/turf/open/floor/mineral/bananium/attack_hand(mob/user) +/turf/open/floor/mineral/bananium/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) .=..() if(!.) honk() @@ -202,7 +202,7 @@ if(!.) radiate() -/turf/open/floor/mineral/uranium/attack_hand(mob/user) +/turf/open/floor/mineral/uranium/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) .=..() if(!.) radiate() diff --git a/code/game/turfs/simulated/floor/reinf_floor.dm b/code/game/turfs/simulated/floor/reinf_floor.dm index 7816341a0a..b050d8fb89 100644 --- a/code/game/turfs/simulated/floor/reinf_floor.dm +++ b/code/game/turfs/simulated/floor/reinf_floor.dm @@ -89,7 +89,7 @@ /turf/open/floor/engine/attack_paw(mob/user) return attack_hand(user) -/turf/open/floor/engine/attack_hand(mob/user) +/turf/open/floor/engine/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/turfs/simulated/wall/mineral_walls.dm b/code/game/turfs/simulated/wall/mineral_walls.dm index a5f0d5e824..c8afe628db 100644 --- a/code/game/turfs/simulated/wall/mineral_walls.dm +++ b/code/game/turfs/simulated/wall/mineral_walls.dm @@ -72,7 +72,7 @@ return return -/turf/closed/wall/mineral/uranium/attack_hand(mob/user) +/turf/closed/wall/mineral/uranium/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) radiate() . = ..() diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 6ac3ca086b..03f2c504c2 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -136,7 +136,7 @@ to_chat(user, text("You punch the wall.")) return TRUE -/turf/closed/wall/attack_hand(mob/user) +/turf/closed/wall/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index b1a10c72ce..02c12a9744 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -122,7 +122,7 @@ requires_activation = FALSE ..() -/turf/attack_hand(mob/user) +/turf/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/game/world.dm b/code/game/world.dm index db193f31b0..55333fb3e6 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -131,11 +131,13 @@ GLOBAL_LIST(topic_status_cache) GLOB.world_runtime_log = "[GLOB.log_directory]/runtime.log" GLOB.query_debug_log = "[GLOB.log_directory]/query_debug.log" GLOB.world_job_debug_log = "[GLOB.log_directory]/job_debug.log" + GLOB.world_paper_log = "[GLOB.log_directory]/paper.log" GLOB.tgui_log = "[GLOB.log_directory]/tgui.log" GLOB.subsystem_log = "[GLOB.log_directory]/subsystem.log" GLOB.reagent_log = "[GLOB.log_directory]/reagents.log" GLOB.world_crafting_log = "[GLOB.log_directory]/crafting.log" GLOB.click_log = "[GLOB.log_directory]/click.log" + GLOB.world_asset_log = "[GLOB.log_directory]/asset.log" #ifdef UNIT_TESTS diff --git a/code/modules/NTNet/relays.dm b/code/modules/NTNet/relays.dm index 0d855f15bb..2101a72960 100644 --- a/code/modules/NTNet/relays.dm +++ b/code/modules/NTNet/relays.dm @@ -69,7 +69,7 @@ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "ntnet_relay", "NTNet Quantum Relay", ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "NtnetRelay", "NTNet Quantum Relay", ui_x, ui_y, master_ui, state) ui.open() diff --git a/code/modules/VR/vr_sleeper.dm b/code/modules/VR/vr_sleeper.dm index 26ae200990..9953fe4bc5 100644 --- a/code/modules/VR/vr_sleeper.dm +++ b/code/modules/VR/vr_sleeper.dm @@ -71,22 +71,17 @@ /obj/machinery/vr_sleeper/update_icon_state() icon_state = "[initial(icon_state)][state_open ? "-open" : ""]" -/obj/machinery/vr_sleeper/open_machine() - if(state_open) - return - if(occupant) - SStgui.close_user_uis(occupant, src) - return ..() /obj/machinery/vr_sleeper/MouseDrop_T(mob/target, mob/user) if(user.lying || !iscarbon(target) || !Adjacent(target) || !user.canUseTopic(src, BE_CLOSE, TRUE, NO_TK)) return close_machine(target) + ui_interact(user) -/obj/machinery/vr_sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) +/obj/machinery/vr_sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_contained_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "vr_sleeper", "VR Sleeper", 475, 340, master_ui, state) + ui = new(user, src, ui_key, "VrSleeper", "VR Sleeper", 475, 340, master_ui, state) ui.open() /obj/machinery/vr_sleeper/ui_act(action, params) @@ -130,11 +125,13 @@ /obj/machinery/vr_sleeper/ui_data(mob/user) var/list/data = list() + var/is_living if(vr_mob && !QDELETED(vr_mob)) + is_living = isliving(vr_mob) data["can_delete_avatar"] = TRUE data["vr_avatar"] = list("name" = vr_mob.name) - data["isliving"] = istype(vr_mob) - if(data["isliving"]) + data["isliving"] = is_living + if(is_living) var/status switch(vr_mob.stat) if(CONSCIOUS) @@ -146,6 +143,11 @@ if(SOFT_CRIT) status = "Barely Conscious" data["vr_avatar"] += list("status" = status, "health" = vr_mob.health, "maxhealth" = vr_mob.maxHealth) + else + data["can_delete_avatar"] = FALSE + data["vr_avatar"] = FALSE + data["isliving"] = FALSE + data["toggle_open"] = state_open data["emagged"] = you_die_in_the_game_you_die_for_real data["isoccupant"] = (user == occupant) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 289abbe250..718f9d4246 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -62,7 +62,7 @@ GLOBAL_PROTECT(admin_verbs_admin) /client/proc/cmd_admin_check_player_exp, /* shows players by playtime */ /client/proc/toggle_combo_hud, // toggle display of the combination pizza antag and taco sci/med/eng hud /client/proc/toggle_AI_interact, /*toggle admin ability to interact with machines as an AI*/ - /client/proc/open_shuttle_manipulator, /* Opens shuttle manipulator UI */ + /datum/admins/proc/open_shuttlepanel, /* Opens shuttle manipulator UI */ /client/proc/respawn_character, /client/proc/secrets, /client/proc/toggle_hear_radio, /*allows admins to hide all radio output*/ diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index bbd6b55e4f..68b9a8e341 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -55,7 +55,7 @@ if(AH) message_admins("[key_name_admin(src)] has started replying to [key_name(C, 0, 0)]'s admin help.") - var/msg = input(src,"Message:", "Private message to [key_name(C, 0, 0)]") as message|null + var/msg = stripped_multiline_input(src,"Message:", "Private message to [key_name(C, 0, 0)]") if (!msg) message_admins("[key_name_admin(src)] has cancelled their reply to [key_name(C, 0, 0)]'s admin help.") return @@ -87,10 +87,10 @@ if(irc) - if(!ircreplyamount) //to prevent people from spamming irc + if(!ircreplyamount) //to prevent people from spamming irc/discord return if(!msg) - msg = input(src,"Message:", "Private message to Administrator") as text|null + msg = stripped_multiline_input(src,"Message:", "Private message to Administrator") if(!msg) return @@ -112,7 +112,7 @@ //get message text, limit it's length.and clean/escape html if(!msg) - msg = input(src,"Message:", "Private message to [key_name(recipient, 0, 0)]") as message|null + msg = stripped_multiline_input(src,"Message:", "Private message to [key_name(recipient, 0, 0)]") msg = trim(msg) if(!msg) return @@ -191,7 +191,7 @@ spawn() //so we don't hold the caller proc up var/sender = src var/sendername = key - var/reply = input(recipient, msg,"Admin PM from-[sendername]", "") as text|null //show message and await a reply + var/reply = stripped_multiline_input(recipient, msg,"Admin PM from-[sendername]", "") //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 diff --git a/code/modules/admin/verbs/borgpanel.dm b/code/modules/admin/verbs/borgpanel.dm index 869e44e4f5..35f4ddb3e5 100644 --- a/code/modules/admin/verbs/borgpanel.dm +++ b/code/modules/admin/verbs/borgpanel.dm @@ -36,7 +36,7 @@ /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) if(!ui) - ui = new(user, src, ui_key, "borgopanel", "Borg Panel", 700, 700, master_ui, state) + ui = new(user, src, ui_key, "BorgPanel", "Borg Panel", 700, 700, master_ui, state) ui.open() /datum/borgpanel/ui_data(mob/user) diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index d335cfb171..9b36fd7a2a 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -421,7 +421,7 @@ Traitors and the like can also be revived with the previous role mostly intact. new_character.real_name = record_found.fields["name"] new_character.gender = record_found.fields["gender"] new_character.age = record_found.fields["age"] - new_character.hardset_dna(record_found.fields["identity"], record_found.fields["enzymes"], record_found.fields["name"], record_found.fields["blood_type"], new record_found.fields["species"], record_found.fields["features"]) + new_character.hardset_dna(record_found.fields["identity"], record_found.fields["enzymes"], null, record_found.fields["name"], record_found.fields["blood_type"], new record_found.fields["species"], record_found.fields["features"]) else var/datum/preferences/A = new() A.copy_to(new_character) @@ -1058,13 +1058,6 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits var/datum/atom_hud/A = GLOB.huds[ANTAG_HUD_TRAITOR] return A.hudusers[mob] -/client/proc/open_shuttle_manipulator() - set category = "Admin" - set name = "Shuttle Manipulator" - set desc = "Opens the shuttle manipulator UI." - - for(var/obj/machinery/shuttle_manipulator/M in GLOB.machines) - M.ui_interact(usr) /client/proc/run_weather() set category = "Fun" @@ -1276,7 +1269,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits if(!check_rights(R_ADMIN) || !check_rights(R_FUN)) return - var/list/punishment_list = list(ADMIN_PUNISHMENT_PIE, ADMIN_PUNISHMENT_CUSTOM_PIE, ADMIN_PUNISHMENT_FIREBALL, ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_BSA, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_SUPPLYPOD_QUICK, ADMIN_PUNISHMENT_SUPPLYPOD, ADMIN_PUNISHMENT_MAZING, ADMIN_PUNISHMENT_ROD) + var/list/punishment_list = list(ADMIN_PUNISHMENT_PIE, ADMIN_PUNISHMENT_CUSTOM_PIE, ADMIN_PUNISHMENT_FIREBALL, ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_BSA, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_SUPPLYPOD_QUICK, ADMIN_PUNISHMENT_SUPPLYPOD, ADMIN_PUNISHMENT_MAZING, ADMIN_PUNISHMENT_ROD, ADMIN_PUNISHMENT_PICKLE) var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in punishment_list @@ -1341,7 +1334,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits if(ADMIN_PUNISHMENT_PIE) var/obj/item/reagent_containers/food/snacks/pie/cream/nostun/creamy = new(get_turf(target)) creamy.splat(target) - if (ADMIN_PUNISHMENT_CUSTOM_PIE) + if(ADMIN_PUNISHMENT_CUSTOM_PIE) var/obj/item/reagent_containers/food/snacks/pie/cream/nostun/A = new() if(!A.reagents) var/amount = input(usr, "Specify the reagent size of [A]", "Set Reagent Size", 50) as num|null @@ -1354,6 +1347,8 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits if(amount) A.reagents.add_reagent(chosen_id, amount) A.splat(target) + if(ADMIN_PUNISHMENT_PICKLE) + target.turn_into_pickle() punish_log(target, punishment) diff --git a/code/modules/admin/verbs/shuttlepanel.dm b/code/modules/admin/verbs/shuttlepanel.dm new file mode 100644 index 0000000000..a80eafae02 --- /dev/null +++ b/code/modules/admin/verbs/shuttlepanel.dm @@ -0,0 +1,76 @@ +/datum/admins/proc/open_shuttlepanel() + set category = "Admin" + set name = "Shuttle Manipulator" + set desc = "Opens the shuttle manipulator UI." + + if(!check_rights(R_ADMIN)) + return + + SSshuttle.ui_interact(usr) + + +/obj/docking_port/mobile/proc/admin_fly_shuttle(mob/user) + var/list/options = list() + + for(var/port in SSshuttle.stationary) + if (istype(port, /obj/docking_port/stationary/transit)) + continue // please don't do this + var/obj/docking_port/stationary/S = port + if (canDock(S) == SHUTTLE_CAN_DOCK) + options[S.name || S.id] = S + + options += "--------" + options += "Infinite Transit" + options += "Delete Shuttle" + options += "Into The Sunset (delete & greentext 'escape')" + + var/selection = input(user, "Select where to fly [name || id]:", "Fly Shuttle") as null|anything in options + if(!selection) + return + + switch(selection) + if("Infinite Transit") + destination = null + mode = SHUTTLE_IGNITING + setTimer(ignitionTime) + + if("Delete Shuttle") + if(alert(user, "Really delete [name || id]?", "Delete Shuttle", "Cancel", "Really!") != "Really!") + return + jumpToNullSpace() + + if("Into The Sunset (delete & greentext 'escape')") + if(alert(user, "Really delete [name || id] and greentext escape objectives?", "Delete Shuttle", "Cancel", "Really!") != "Really!") + return + intoTheSunset() + + else + if(options[selection]) + request(options[selection]) + +/obj/docking_port/mobile/emergency/admin_fly_shuttle(mob/user) + return // use the existing verbs for this + +/obj/docking_port/mobile/arrivals/admin_fly_shuttle(mob/user) + switch(alert(user, "Would you like to fly the arrivals shuttle once or change its destination?", "Fly Shuttle", "Fly", "Retarget", "Cancel")) + if("Cancel") + return + if("Fly") + return ..() + + var/list/options = list() + + for(var/port in SSshuttle.stationary) + if (istype(port, /obj/docking_port/stationary/transit)) + continue // please don't do this + var/obj/docking_port/stationary/S = port + if (canDock(S) == SHUTTLE_CAN_DOCK) + options[S.name || S.id] = S + + var/selection = input(user, "Select the new arrivals destination:", "Fly Shuttle") as null|anything in options + if(!selection) + return + target_dock = options[selection] + if(!QDELETED(target_dock)) + destination = target_dock + diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index 9fa8145339..8bff37ab03 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -23,6 +23,7 @@ GLOBAL_LIST_EMPTY(antagonists) var/show_name_in_check_antagonists = FALSE //Will append antagonist name in admin listings - use for categories that share more than one antag type var/list/blacklisted_quirks = list(/datum/quirk/nonviolent,/datum/quirk/mute) // Quirks that will be removed upon gaining this antag. Pacifist and mute are default. var/threat = 0 // Amount of threat this antag poses, for dynamic mode + var/show_to_ghosts = FALSE // Should this antagonist be shown as antag to ghosts? Shouldn't be used for stealthy antagonists like traitors var/list/skill_modifiers diff --git a/code/modules/antagonists/abductor/abductor.dm b/code/modules/antagonists/abductor/abductor.dm index 9132288415..b4fc5b5948 100644 --- a/code/modules/antagonists/abductor/abductor.dm +++ b/code/modules/antagonists/abductor/abductor.dm @@ -7,6 +7,7 @@ job_rank = ROLE_ABDUCTOR show_in_antagpanel = FALSE //should only show subtypes threat = 5 + show_to_ghosts = TRUE var/datum/team/abductor_team/team var/sub_role var/outfit diff --git a/code/modules/antagonists/abductor/machinery/console.dm b/code/modules/antagonists/abductor/machinery/console.dm index b8d5b1bf6d..9c9715ee43 100644 --- a/code/modules/antagonists/abductor/machinery/console.dm +++ b/code/modules/antagonists/abductor/machinery/console.dm @@ -24,7 +24,7 @@ var/obj/machinery/computer/camera_advanced/abductor/camera var/list/datum/icon_snapshot/disguises = list() -/obj/machinery/abductor/console/attack_hand(mob/user) +/obj/machinery/abductor/console/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/antagonists/abductor/machinery/dispenser.dm b/code/modules/antagonists/abductor/machinery/dispenser.dm index 17fa311c8f..ef423b6379 100644 --- a/code/modules/antagonists/abductor/machinery/dispenser.dm +++ b/code/modules/antagonists/abductor/machinery/dispenser.dm @@ -22,7 +22,7 @@ gland_colors[i] = random_color() amounts[i] = rand(1,5) -/obj/machinery/abductor/gland_dispenser/attack_hand(mob/user) +/obj/machinery/abductor/gland_dispenser/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/antagonists/abductor/machinery/experiment.dm b/code/modules/antagonists/abductor/machinery/experiment.dm index de350db8ab..c84dc722e4 100644 --- a/code/modules/antagonists/abductor/machinery/experiment.dm +++ b/code/modules/antagonists/abductor/machinery/experiment.dm @@ -21,7 +21,7 @@ return close_machine(target) -/obj/machinery/abductor/experiment/attack_hand(mob/user) +/obj/machinery/abductor/experiment/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/antagonists/blob/blob.dm b/code/modules/antagonists/blob/blob.dm index 1b076c9302..9a82bb546b 100644 --- a/code/modules/antagonists/blob/blob.dm +++ b/code/modules/antagonists/blob/blob.dm @@ -2,6 +2,7 @@ name = "Blob" roundend_category = "blobs" antagpanel_category = "Blob" + show_to_ghosts = TRUE job_rank = ROLE_BLOB threat = 20 var/datum/action/innate/blobpop/pop_action diff --git a/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm b/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm index 090ef45d89..9301d0c239 100644 --- a/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm +++ b/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm @@ -217,7 +217,7 @@ return FALSE return ..() -/obj/structure/bloodsucker/vassalrack/attack_hand(mob/user) +/obj/structure/bloodsucker/vassalrack/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) //. = ..() // Taken from sacrificial altar in divine.dm //if(.) // return @@ -469,7 +469,7 @@ . += {"This is a magical candle which drains at the sanity of the fools who havent yet accepted your master, as long as it is active.\n You can turn it on and off by clicking on it while you are next to it"} */ -/obj/structure/bloodsucker/candelabrum/attack_hand(mob/user) +/obj/structure/bloodsucker/candelabrum/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) var/datum/antagonist/vassal/T = user.mind.has_antag_datum(ANTAG_DATUM_VASSAL) if(AmBloodsucker(user) || istype(T)) toggle() diff --git a/code/modules/antagonists/changeling/cellular_emporium.dm b/code/modules/antagonists/changeling/cellular_emporium.dm index b2c1a52a4a..6abefeefe7 100644 --- a/code/modules/antagonists/changeling/cellular_emporium.dm +++ b/code/modules/antagonists/changeling/cellular_emporium.dm @@ -16,7 +16,7 @@ /datum/cellular_emporium/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "cellular_emporium", name, 900, 480, master_ui, state) + ui = new(user, src, ui_key, "CellularEmporium", name, 900, 480, master_ui, state) ui.open() /datum/cellular_emporium/ui_data(mob/user) diff --git a/code/modules/antagonists/changeling/powers/transform.dm b/code/modules/antagonists/changeling/powers/transform.dm index 795ba772d6..c0979b6936 100644 --- a/code/modules/antagonists/changeling/powers/transform.dm +++ b/code/modules/antagonists/changeling/powers/transform.dm @@ -18,7 +18,7 @@ //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/clothing/glasses/changeling/attack_hand(mob/user) +/obj/item/clothing/glasses/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling)) to_chat(user, "You reabsorb [src] into your body.") qdel(src) @@ -34,7 +34,7 @@ //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/clothing/under/changeling/attack_hand(mob/user) +/obj/item/clothing/under/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling)) to_chat(user, "You reabsorb [src] into your body.") qdel(src) @@ -51,7 +51,7 @@ //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/clothing/suit/changeling/attack_hand(mob/user) +/obj/item/clothing/suit/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling)) to_chat(user, "You reabsorb [src] into your body.") qdel(src) @@ -66,7 +66,7 @@ ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT) //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/clothing/head/changeling/attack_hand(mob/user) +/obj/item/clothing/head/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling)) to_chat(user, "You reabsorb [src] into your body.") qdel(src) @@ -82,7 +82,7 @@ //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/clothing/shoes/changeling/attack_hand(mob/user) +/obj/item/clothing/shoes/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling)) to_chat(user, "You reabsorb [src] into your body.") qdel(src) @@ -98,7 +98,7 @@ //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/clothing/gloves/changeling/attack_hand(mob/user) +/obj/item/clothing/gloves/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling)) to_chat(user, "You reabsorb [src] into your body.") qdel(src) @@ -114,7 +114,7 @@ //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/clothing/mask/changeling/attack_hand(mob/user) +/obj/item/clothing/mask/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling)) to_chat(user, "You reabsorb [src] into your body.") qdel(src) @@ -132,7 +132,7 @@ //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/changeling/attack_hand(mob/user) +/obj/item/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling)) to_chat(user, "You reabsorb [src] into your body.") qdel(src) diff --git a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm index 036ea37ada..90c4bdf8de 100644 --- a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm +++ b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm @@ -28,7 +28,7 @@ return //you can't tk stomp sigils, but you can hit them with something //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/effect/clockwork/sigil/attack_hand(mob/user) +/obj/effect/clockwork/sigil/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(iscarbon(user) && !user.stat) if(is_servant_of_ratvar(user) && user.a_intent != INTENT_HARM) return ..() diff --git a/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm b/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm index 36aaa27716..9106015c0a 100644 --- a/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm +++ b/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm @@ -64,7 +64,7 @@ ..() //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/effect/clockwork/spatial_gateway/attack_hand(mob/living/user) +/obj/effect/clockwork/spatial_gateway/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) if(!uses) return FALSE if(user.pulling && user.a_intent == INTENT_GRAB && isliving(user.pulling)) diff --git a/code/modules/antagonists/clockcult/clock_helpers/scripture_checks.dm b/code/modules/antagonists/clockcult/clock_helpers/scripture_checks.dm index e5497d7c9f..66e20b6e87 100644 --- a/code/modules/antagonists/clockcult/clock_helpers/scripture_checks.dm +++ b/code/modules/antagonists/clockcult/clock_helpers/scripture_checks.dm @@ -38,10 +38,11 @@ set_slab.update_quickbind() /proc/generate_all_scripture() - if(!GLOB.all_scripture.len) - for(var/V in sortList(subtypesof(/datum/clockwork_scripture), /proc/cmp_clockscripture_priority)) - var/datum/clockwork_scripture/S = new V - GLOB.all_scripture[S.type] = S + if(GLOB.all_scripture.len) + return + for(var/V in sortList(subtypesof(/datum/clockwork_scripture) - list(/datum/clockwork_scripture/channeled, /datum/clockwork_scripture/create_object, /datum/clockwork_scripture/create_object/construct), /proc/cmp_clockscripture_priority)) + var/datum/clockwork_scripture/S = new V + GLOB.all_scripture[S.type] = S //changes construction value /proc/change_construction_value(amount) diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm index 5837ac302d..d0d3bafe06 100644 --- a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm +++ b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm @@ -1,7 +1,7 @@ /obj/item/clockwork/slab //Clockwork slab: The most important tool in Ratvar's arsenal. Allows scripture recital, tutorials, and generates components. name = "clockwork slab" desc = "A strange metal tablet. A clock in the center turns around and around." - clockwork_desc = "A link between you and the Celestial Derelict. It contains information, recites scripture, and is your most vital tool as a Servant.
    \ + clockwork_desc = "A link between you and the Celestial Derelict. It contains information, recites scripture, and is your most vital tool as a Servant.\ It can be used to link traps and triggers by attacking them with the slab. Keep in mind that traps linked with one another will activate in tandem!" icon_state = "dread_ipad" @@ -15,16 +15,19 @@ var/busy //If the slab is currently being used by something var/no_cost = FALSE //If the slab is admin-only and needs no components and has no scripture locks var/speed_multiplier = 1 //multiples how fast this slab recites scripture - var/selected_scripture = SCRIPTURE_DRIVER + // var/selected_scripture = SCRIPTURE_DRIVER //handled UI side var/obj/effect/proc_holder/slab/slab_ability //the slab's current bound ability, for certain scripture - var/recollecting = FALSE //if we're looking at fancy recollection + var/recollecting = TRUE //if we're looking at fancy recollection. tutorial enabled by default var/recollection_category = "Default" var/list/quickbound = list(/datum/clockwork_scripture/abscond, \ /datum/clockwork_scripture/ranged_ability/kindle, /datum/clockwork_scripture/ranged_ability/hateful_manacles) //quickbound scripture, accessed by index var/maximum_quickbound = 5 //how many quickbound scriptures we can have + var/ui_x = 800 + var/ui_z = 420 + var/obj/structure/destructible/clockwork/trap/linking //If we're linking traps together, which ones we're doing /obj/item/clockwork/slab/internal //an internal motor for mobs running scripture @@ -55,7 +58,7 @@ return ..() //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/clockwork/slab/debug/attack_hand(mob/living/user) +/obj/item/clockwork/slab/debug/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) if(!is_servant_of_ratvar(user)) add_servant_of_ratvar(user) return ..() @@ -146,8 +149,8 @@ if(!quickbound[i]) continue var/datum/clockwork_scripture/quickbind_slot = quickbound[i] - . += "Quickbind button: [initial(quickbind_slot.name)]." - . += "Available power: [DisplayPower(get_clockwork_power())]." + . += "Quickbind button: [initial(quickbind_slot.name)]." + . += "Available power: [DisplayPower(get_clockwork_power())]." //Slab actions; Hierophant, Quickbind /obj/item/clockwork/slab/ui_action_click(mob/user, action) @@ -165,18 +168,19 @@ user.emote("scream") user.apply_damage(5, BURN, BODY_ZONE_L_ARM) user.apply_damage(5, BURN, BODY_ZONE_R_ARM) - return 0 + return FALSE if(!is_servant_of_ratvar(user)) to_chat(user, "The information on [src]'s display shifts rapidly. After a moment, your head begins to pound, and you tear your eyes away.") - user.confused += 5 - user.dizziness += 5 - return 0 + if(user.confused || user.dizziness) + user.confused += 5 + user.dizziness += 5 + return FALSE if(busy) to_chat(user, "[src] refuses to work, displaying the message: \"[busy]!\"") - return 0 + return FALSE if(!no_cost && !can_recite_scripture(user)) to_chat(user, "[src] hums fitfully in your hands, but doesn't seem to do anything...") - return 0 + return FALSE access_display(user) /obj/item/clockwork/slab/AltClick(mob/living/user) @@ -195,9 +199,7 @@ /obj/item/clockwork/slab/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "clockwork_slab", name, 800, 420, master_ui, state) - ui.set_autoupdate(FALSE) //we'll update this occasionally, but not as often as possible - ui.set_style("clockwork") + ui = new(user, src, ui_key, "ClockworkSlab", name, ui_x, ui_z, master_ui, state) ui.open() /obj/item/clockwork/slab/proc/recite_scripture(datum/clockwork_scripture/scripture, mob/living/user) @@ -207,10 +209,12 @@ to_chat(user, "You need to hold the slab in your active hand to recite scripture!") return FALSE var/initial_tier = initial(scripture.tier) - if(initial_tier != SCRIPTURE_PERIPHERAL) - if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier]) - to_chat(user, "That scripture is not unlocked, and cannot be recited!") - return FALSE + if(initial_tier == SCRIPTURE_PERIPHERAL) + to_chat(user, "Nice try using href exploits") + return + if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier]) + to_chat(user, "That scripture is not unlocked, and cannot be recited!") + return FALSE var/datum/clockwork_scripture/scripture_to_recite = new scripture scripture_to_recite.slab = src scripture_to_recite.invoker = user @@ -218,26 +222,6 @@ return TRUE -//Guide to Serving Ratvar -/obj/item/clockwork/slab/proc/recollection() - var/list/textlist = list("If you're seeing this, file a bug report.") - if(GLOB.ratvar_awakens) - textlist = list("") - for(var/i in 1 to 100) - textlist += "HONOR RATVAR " - textlist += "" - else - textlist = list("
    [text2ratvar("Purge all untruths and honor Engine.")]

    \ - \ - NOTICE: This information is out of date. Read the Ark & You primer in your backpack or read the wiki page for current info.
    \ -

    \ - These pages serve as the archives of Ratvar, the Clockwork Justiciar. This section of your slab has information on being as a Servant, advice for what to do next, and \ - pointers for serving the master well. You should recommended that you check this area for help if you get stuck or need guidance on what to do next.

    \ - \ - Disclaimer: Many objects, terms, and phrases, such as Servant, Cache, and Slab, are capitalized like proper nouns. This is a quirk of the Ratvarian language; \ - do not let it confuse you! You are free to use the names in pronoun form when speaking in normal languages.
    ") - return textlist.Join() - //Gets text for a certain section. "Default" is used for when you first open Recollection. //Current sections (make sure to update this if you add one: //- Basics @@ -246,255 +230,93 @@ //- Scripture //- Power //- Conversion -/obj/item/clockwork/slab/proc/get_recollection_text(section) - var/list/dat = list() - switch(section) - if("Default") - dat += "You can browse the above sections as you please. They're designed to be read in order, but feel free to pick and choose between them." - if("Getting Started") - dat += "Getting Started

    " - dat += "Welcome, Servant! This section houses the utmost basics of being a Servant of Ratvar, and is much more informal than the other sections. Being a Servant of \ - Ratvar is a very complex role, with many systems, objects, and resources to use effectively and creatively.

    " - dat += "This section of your clockwork slab covers everything that Servants have to be aware of, but is a long read because of how in-depth the systems are. Knowing \ - how to use the tools at your disposal makes all the difference between a clueless Servant and a great one.

    " - dat += "If this is your first time being a Servant, relax. It's very much possible that you'll fail, but it's impossible to learn without making mistakes. For the time \ - being, use the Hierophant Network button in the top left-hand corner of your screen to try and get in touch with your fellow Servants; ignore the others for now. This button \ - will let you send messages across space and time to all other Servants. This makes it great for coordinating, and you should use it often! Note: Using \ - this will cause you to whisper your message aloud, so doing so in a public place is very suspicious and you should try to restrict it to private use.

    " - dat += "If you aren't willing or don't have the time to read through every section, you can still help your teammates! Ask if they've set up a base. If they have, head there \ - and ask however you can help; chances are there's always something. If not, it's your job as a Servant to get one up and running! Try to find a secluded, low-traffic area, \ - like the auxiliary base or somewhere deep in maintenance. You'll want to go into the Drivers section of the slab and look for Tinkerer's Cache. Find a nice spot and \ - create one. This serves as a storage for components, the cult's primary resource. (Your slab's probably produced a few by now.) By attacking that cache with this \ - slab, you'll offload all your components into it, and all Servants will be able to use those components from any distance - all Tinkerer's Caches are linked!

    " - dat += "Once you have a base up and running, contact your fellows and let them know. You should come back here often to drop off the slab's components, and your fellows \ - should do the same, either in this cache or in ones of their own.

    " - dat += "If you think you're confident in taking further steps to help the cult, feel free to move onto the other sections. If not, let your allies know that you're new and \ - would appreciate the help they might offer you. Most experienced Servants would be happy to help; if everyone is inexperienced, then you'll have to step out of your comfort \ - zone and read onto the other sections. It's very likely that you might fail, but don't worry too much about it; you can't learn effectively without making mistakes.

    " - dat += "For now, welcome! If you're looking to learn, you should start with the Basics section, then move onto Components and Scripture. At the very \ - least, you should read the Conversion section, as it outlines the most important aspects of being a Servant. Good luck!

    " - dat += "-=-=-=-=-=-" - if("Basics") - dat += "Servant Basics

    " - dat += "The first thing any Servant should know is their slab, inside and out. The clockwork slab is by far your most important tool. It allows you to speak with your \ - fellow Servants, create components that fuel many of your abilities, use those abilities, and should be kept safe and hidden on your person at all times. If you have not \ - done so already, it's a good idea to check for any fellow Servants using the Hierophant Network button in the top-left corner of your screen; due to the cult's nature, \ - teamwork is an instrumental component of your success.

    " //get it? component? ha! - dat += "As a Servant of Ratvar, the tools you are given focus around building and maintaining bases and outposts. A great deal of your power comes from stationary \ - structures, and without constructing a base somewhere, it's essentially impossible to succeed. Finding a good spot to build a base can be difficult, and it's recommended \ - that you choose an area in low-traffic part of the station (such as the auxiliary base). Make sure to disconnect any cameras in the area beforehand.

    " - dat += "Because of how complex being a Servant is, it isn't possible to fit much information into this section. It's highly recommended that you read the Components \ - and Scripture sections next. Not knowing how these two systems work will cripple both you and your fellows, and lead to a frustrating experience for everyone.

    " - dat += "-=-=-=-=-=-" - if("Terminology") - dat += "Common Servant Terminology
    " - dat += "This isn't intended to be read all at once; you are advised to treat it moreso as a glossary.

    " - dat += "General
    " - dat += "Servant: A person or robot who serves Ratvar. You are one of these.
    " - dat += "Cache: A Tinkerer's Cache, which is a structure that stores and creates components.
    " - dat += "CV: Construction Value. All clockwork structures, floors, and walls increase this number.
    " - dat += "Vitality: Used for healing effects, produced by Ratvarian spear attacks and Vitality Matrices.
    " - dat += "Geis: An important scripture used to make normal crew and robots into Servants of Ratvar.
    " - dat += "Ark: The cult's win condition, a huge structure that needs to be defended.

    " - dat += "Items
    " - dat += "Slab: A clockwork slab, a Servant's most important tool. You're holding one! Keep it safe and hidden.
    " - dat += "Visor: A judicial visor, which is a pair of glasses that can smite an area for a brief stun and delayed explosion.
    " - dat += "Wraith Specs: Wraith spectacles, which provide true sight (X-ray, night vision) but damage the wearer's eyes.
    " - dat += "Spear: A Ratvarian spear, which is a very powerful melee weapon that produces Vitality.
    " - dat += "Fabricator: A replica fabricator, which converts objects into clockwork versions.

    " - dat += "Constructs
    " - dat += "Marauder: A clockwork marauder, which is a powerful bodyguard that hides in its owner.

    " - dat += "Structures (* = requires power)
    " - dat += "Warden: An ocular warden, which is a ranged turret that damages non-Servants that see it.
    " - dat += "Prism*: A prolonging prism, which delays the shuttle for two minutes at a huge power cost.

    " - dat += "Motor*: A mania motor, which serves as area-denial through negative effects and eventual conversion.
    " - dat += "Daemon*: A tinkerer's daemon, which quickly creates components.
    " - dat += "Obelisk*: A clockwork obelisk, which can broadcast large messages and allows limited teleportation.
    " - dat += "Sigils
    " - dat += "Note: Sigils can be stacked on top of one another, making certain sigils very effective when paired!
    " - dat += "Transgression: Stuns the first non-Servant to cross it for ten seconds and blinds others nearby. Disappears on use.
    " - dat += "Submission: Converts the first non-Servant to stand on the sigil for seven seconds. Disappears on use.
    " - dat += "Matrix: Drains health from non-Servants, producing Vitality. Can heal and revive Servants.
    " - dat += "Accession: Identical to the Sigil of Submission, but doesn't disappear on use. It can also convert a single mindshielded target, but will disappear after doing this.
    " - dat += "Transmission: Drains and stores power for clockwork structures. Feeding it brass sheets will create additional power.

    " - dat += "-=-=-=-=-=-" - if("Components") - dat += "Components & Their Uses

    " - dat += "Components are your primary resource as a Servant. There are five types of component, with each one being used in different roles:

    " - dat += "Although this is a good rule of thumb, their effects become much more nuanced when used together. For instance, a turret might have both belligerent eyes and \ - vanguard cogwheels as construction requirements, because it defends its allies by harming its enemies.

    " - dat += "Components' primary use is fueling scripture (covered in its own section), and they can be created through various ways. This clockwork slab, for instance, \ - will make a random component of every type - or a specific one, if you choose a target component from the interface - every remove me already. This number will increase \ - as the amount of Servants in the covenant increase; additionally, slabs can only produce components when held by a Servant, and holding more than one slab will cause both \ - of them to halt progress until one of them is removed from their person.

    " - dat += "Your slab has an internal storage of components, but it isn't meant to be the main one. Instead, there's a global storage of components that can be \ - added to through various ways. Anything that needs components will first draw them from the global storage before attempting to draw them from the slab. Most methods of \ - component production add to the global storage. You can also offload components from your slab into the global storage by using it on a Tinkerer's Cache, a structure whose \ - primary purpose is to do just that (although it will also slowly produce components when placed near a brass wall.)

    " - dat += "-=-=-=-=-=-" - if("Scripture") - dat += "The Ancient Scripture

    " - dat += "If you have experience with the Nar'Sian cult (or the \"blood cult\") then you will know of runes. They are the manifestations of the Geometer's power, and where most \ - of the cult's supernatural ability comes from. The Servant equivalent of runes is called scripture, and unlike runes, scripture is loaded into your clockwork slab.

    " - dat += "Each piece of scripture has widely-varying effects. Your most important scripture, Geis, is obvious and suspicious, but charges your slab with energy and allows \ - you to attack a non-Servant in melee range to restrain them and begin converting them into a Servant. This is just one example; each piece of scripture can be simple or \ - complex, be obvious or have hidden mechanics that can only be found through trial and error.

    " - dat += "Any given piece of scripture has a component cost listed in its \"Recite\" button. The acronyms for the components should be obvious if you've read about components \ - already; reciting this piece of scripture will consume the listed components, first from the global storage and then from your slab. Note that failing to recite a piece of \ - scripture will not consume the components required to recite it.

    " - dat += "It should also be noted that some scripture cannot be recited alone. Especially with more powerful scripture, you may need multiple Servants to recite a piece of \ - scripture; both of you will need to stand still until the recital completes. Only human and silicon Servants are valid for scripture recital! Constructs cannot help \ - in reciting scripture.

    " - dat += "Finally, scripture is separated into three \"tiers\" based on power: Drivers, Scripts, and Applications.[prob(1) ? " (The Revenant tier was removed a long time ago. \ - Get with the times.)" : ""] You can view the requirements to unlock each tier in its scripture list. Once a tier is unlocked, it's unlocked permanently; the cult only needs to fill the \ - requirement for unlocking a tier once!

    " - dat += "-=-=-=-=-=-" - if("Power") - dat += "Power! Unlimited Power!

    " - dat += "In the early stages of the cult, the only resource that must be actively worried about is components. However, as new scripture is unlocked, a new resource \ - becomes necessary: power. Almost all clockwork structures require power to function in some way. There is nothing special about this power; it's mere electricity, \ - and can be harnessed in several ways.

    " - dat += "To begin with, if there is no other source of power nearby, structures will draw from the area's APC, assuming it has one. This is inefficient and ill-advised as \ - anything but a last resort. Instead, it is recommended that a Sigil of Transmission is created. This sigil serves as both battery and power generator for nearby clockwork \ - structures, and those structures will happily draw power from the sigil before they resort to APCs.

    " - dat += "Generating power is less easy. The most reliable and efficient way is using brass sheets; attacking a sigil of transmission with brass sheets will convert them \ - to power, at a rate of [DisplayPower(POWER_FLOOR)] per sheet. (Brass sheets are created from replica fabricators, which are explained more in detail in the Conversion section.) \ - Activating a sigil of transmission will also cause it to drain power from the nearby area, which, while effective, serves as an obvious tell that there is something wrong.

    " - dat += "Without power, many structures will not function, making a base vulnerable to attack. For this reason, it is critical that you keep an eye on your power reserves and \ - ensure that they remain comfortably high.

    " - dat += "-=-=-=-=-=-" - if("Conversion") - dat += "Growing the Ranks

    " - dat += "Because the Servants of Ratvar are a cult, the main method to gain more power is to \"enlighten\" normal crew into new Servants. When a crewmember is converted, \ - they become a full-fledged Servant, ready and willing to serve the cause of Ratvar. It should also be noted that silicon crew, such as cyborgs and the AI, can be \ - converted just like normal crew and will gain special abilities; this is covered later. This section will also cover converting the station's structure itself; walls, \ - floors, windows, tables, and other objects can all be converted into clockwork versions, and serve an important purpose.

    " - dat += "A Note on Geis: There are several ways to convert humans and silicons. However, the most important tool to making them work is \ - Geis, a Driver-tier scripture. Using it whispers an invocation very quickly and charges your slab with power. In addition to making the slab visible in your hand, \ - you can now use it on a target within melee range to bind and mute them. It is by far your most reliable tool for capturing potential converts and targets, though it is incredibly \ - obvious. In addition, you are unable to take any actions other than moving while your target is bound. The binding will last for 25 seconds and mute for about 13 seconds, though \ - allies can use Geis to refresh these effects.

    " - dat += "Converting: The two methods of conversion are the sigil of submission, whose purpose is to do so, and the mania motor. \ - The sigil of submission is a sigil that, when stood on by a non-Servant for eight seconds, will convert that non-Servant. This is the only practical way to convert targets. \ - Sigils of submission are cheap, early, and permanent! Make sure sigils of submission are placed only in bases or otherwise hidden spots, or with a sigil of transgression on them. \ - The mania motor, however, is generally unreliable and unlocked later, only converting those who stand near it for an extended period.

    " - dat += "Converting Humans: For obvious reasons, humans are the most common conversion target. Because every crew member is different, and \ - may be armed with different equipment, you should take precautions to ensure that they aren't able to resist. If able, removing a headset is essential, as is restraining \ - them through handcuffs, cable ties, or other restraints. Some crew, like security, are also implanted with mindshield implants; these will prevent conversion and must be \ - surgically removed before they are an eligible convert. Note: The captain is never an eligible convert and should instead be killed or imprisoned. If security \ - begins administering mindshield implants, this will greatly inhibit conversion. Also note that mindshield implants can be broken by a sigil of accession automatically, but \ - the sigil will disappear.

    " - dat += "Converting Silicons: Due to their robotic nature, silicons are generally more predictable than humans in terms of conversion. \ - However, they are also much, much harder to subdue, especially cyborgs. The easiest way to convert a cyborg is by using Geis to restrain them, then dragging them to a sigil \ - of submission. If you stack a sigil of transgression and a sigil of submission, a crossing cyborg will be stunned and helpless to escape before they are converted.

    " - dat += "Converting AIs is very often the hardest task of the cult, and has been the downfall of countless successful Servants. Their omnipresence across the station, \ - coupled with their secure location and ability to lock themselves securely, makes them a powerful target. However, once the AI itself is reached, it is usually completely \ - helpless to resist its own conversion. A very common tactic is to take advantage of a converted cyborg to rush the AI before it is able to react.

    " - dat += "Even once an AI is converted, care must be taken to ensure that it remains hidden. Not only does the AI's core become brassy and thus obvious to an outside \ - observer, but the AI loses the ability to speak in anything but Ratvarian. For this reason, it has to remain completely silent over common radio channels if stealth \ - is at all a priority. This is suspicious and will rapidly lead to the crew checking on it, which usually results in the cult's outing. It is, however, necessary to convert \ - all AIs present on the station before the Ark becomes invokable, so this must be done at some point.

    " - dat += "Converting the Station: Converted objects all serve a purpose and are important to the cult's success. To convert objects, \ - a Servant needs to use a replica fabricator, a handheld tool that uses power to replace objects with clockwork versions. Different clockwork objects have different \ - effects and are often crucial. The most noteworthy are clockwork walls, which automatically \"link\" to any nearby Tinkerer's Caches, causing them to slowly \ - generate components. This is incredibly useful for obvious reasons, and creating a clockwork wall near every Tinkerer's Cache should be prioritized. Clockwork floors \ - will slowly heal any toxin damage suffered by Servants standing on them, and clockwork airlocks can only be opened by Servants.

    " - dat += "The replica fabricator itself is also worth noting. In addition to replacing objects, it can also create brass sheets at the cost of power by using the \ - fabricator in-hand. It can also be used to repair any damaged clockwork structures.

    " - dat += "Replacing objects is almost as, if not as important as, converting new Servants. A base is impossible to manage without clockwork walls at the very least, and \ - once the cult has been outed and the crew are actively searching, there is little reason not to use as many as possible.

    " - dat += "-=-=-=-=-=-" - else - dat += "404: [section ? section : "Section"] Not Found!

    \ - One of the cogscarabs must've misplaced this section, because the game wasn't able to find any info regarding it. Report this to the coders!" - return "

    [dat.Join()]

    " - -//Gets the quickbound scripture as a text block. -/obj/item/clockwork/slab/proc/get_recollection_quickbinds() - var/list/dat = list() - dat += "Quickbound Scripture
    \ - You can have up to five scriptures bound to action buttons for easy use.

    " - if(LAZYLEN(quickbound)) - for(var/i in 1 to maximum_quickbound) - if(LAZYLEN(quickbound) < i || !quickbound[i]) - dat += "A Quickbind slot, currently set to Nothing.
    " - else - var/datum/clockwork_scripture/quickbind_slot = quickbound[i] - dat += "A Quickbind slot, currently set to [initial(quickbind_slot.name)].
    " - return dat.Join() - /obj/item/clockwork/slab/ui_data(mob/user) //we display a lot of data via TGUI - var/list/data = list() - data["power"] = "[DisplayPower(get_clockwork_power())] power is available for scripture and other consumers." - - switch(selected_scripture) //display info based on selected scripture tier - if(SCRIPTURE_DRIVER) - data["tier_info"] = "These scriptures are permanently unlocked." - if(SCRIPTURE_SCRIPT) - if(SSticker.scripture_states[SCRIPTURE_SCRIPT]) - data["tier_info"] = "These scriptures are permanently unlocked." - else - data["tier_info"] = "These scriptures will automatically unlock when the Ark is halfway ready or if [DisplayPower(SCRIPT_UNLOCK_THRESHOLD)] of power is reached." - if(SCRIPTURE_APPLICATION) - if(SSticker.scripture_states[SCRIPTURE_APPLICATION]) - data["tier_info"] = "These scriptures are permanently unlocked." - else - data["tier_info"] = "Unlock these optional scriptures by converting another servant or if [DisplayPower(APPLICATION_UNLOCK_THRESHOLD)] of power is reached.." - - data["selected"] = selected_scripture - data["scripturecolors"] = "Scriptures in yellow are related to construction and building.
    \ - Scriptures in red are related to attacking and offense.
    \ - Scriptures in blue are related to healing and defense.
    \ - Scriptures in purple are niche but still important!
    \ - Scriptures with italicized names are important to success." - generate_all_scripture() - - data["scripture"] = list() + . = list() + .["recollection"] = recollecting + .["power"] = DisplayPower(get_clockwork_power()) + .["power_unformatted"] = get_clockwork_power() + // .["rec_text"] = recollection() handled TGUI side + .["HONOR_RATVAR"] = GLOB.ratvar_awakens + .["scripture"] = list() for(var/s in GLOB.all_scripture) var/datum/clockwork_scripture/S = GLOB.all_scripture[s] - if(S.tier == selected_scripture) //display only scriptures of the selected tier - var/scripture_color = get_component_color_bright(S.primary_component) - var/list/temp_info = list("name" = "[S.name]", - "descname" = "([S.descname])", - "tip" = "[S.desc]\n[S.usage_tip]", - "required" = "([DisplayPower(S.power_cost)][S.special_power_text ? "+ [replacetext(S.special_power_text, "POWERCOST", "[DisplayPower(S.special_power_cost)]")]" : ""])", - "type" = "[S.type]", - "quickbind" = S.quickbind) - if(S.important) - temp_info["name"] = "[temp_info["name"]]" - var/found = quickbound.Find(S.type) - if(found) - temp_info["bound"] = "[found]" - if(S.invokers_required > 1) - temp_info["invokers"] = "Invokers: [S.invokers_required]" - data["scripture"] += list(temp_info) - data["recollection"] = recollecting - if(recollecting) - data["recollection_categories"] = GLOB.ratvar_awakens ? list() : list(\ - list("name" = "Getting Started", "desc" = "First-time servant? Read this first."), \ - list("name" = "Basics", "desc" = "A primer on how to play as a servant."), \ - list("name" = "Terminology", "desc" = "Common acronyms, words, and terms."), \ - list("name" = "Components", "desc" = "Information on components, your primary resource."), \ - list("name" = "Scripture", "desc" = "Information on scripture, ancient tools used by the cult."), \ - list("name" = "Power", "desc" = "The power system that certain objects use to function."), \ - list("name" = "Conversion", "desc" = "Converting the crew, cyborgs, and very walls to your cause."), \ - ) - data["rec_text"] = recollection() - data["rec_section"] = GLOB.ratvar_awakens ? "" : get_recollection_text(recollection_category) - data["rec_binds"] = GLOB.ratvar_awakens ? "" : get_recollection_quickbinds() - return data + if(S.tier == SCRIPTURE_PERIPHERAL) //yes, tiers are the tabs. + continue + + var/list/data = list() + data["name"] = S.name + data["descname"] = S.descname + data["tip"] = "[S.desc]\n[S.usage_tip]" + data["required"] = "([DisplayPower(S.power_cost)][S.special_power_text ? "+ [replacetext(S.special_power_text, "POWERCOST", "[DisplayPower(S.special_power_cost)]")]" : ""])" + data["required_unformatted"] = S.power_cost + data["type"] = "[S.type]" + data["quickbind"] = S.quickbind //this is if it cant quickbind + data["fontcolor"] = get_component_color_bright(S.primary_component) + data["important"] = S.important //italic! + + var/found = quickbound.Find(S.type) + if(found) + data["bound"] = found //number (pos) on where is it on the list + if(S.invokers_required > 1) + data["invokers"] = "Invokers: [S.invokers_required]" + + .["rec_binds"] = list() + for(var/i in 1 to maximum_quickbound) + if(GLOB.ratvar_awakens) + return + if(LAZYLEN(quickbound) < i || !quickbound[i]) + .["rec_binds"] += list(list()) + else + var/datum/clockwork_scripture/quickbind_slot = quickbound[i] + .["rec_binds"] += list(list( + "name" = initial(quickbind_slot.name), + "color" = get_component_color_bright(initial(quickbind_slot.primary_component)) + )) + + .["scripture"][S.tier] += list(data) + +/obj/item/clockwork/slab/ui_static_data(mob/user) + . = list() + .["tier_infos"] = list() + .["tier_infos"][SCRIPTURE_DRIVER] = list( + "requirement" = "None, this is already unlocked", + "ready" = TRUE //to bold it on JS side, and to say "These scriptures are permanently unlocked." + ) + .["tier_infos"][SCRIPTURE_SCRIPT] = list( + "requirement" = "These scriptures will automatically unlock when the Ark is halfway ready or if [DisplayPower(SCRIPT_UNLOCK_THRESHOLD)] of power is reached.", + "ready" = SSticker.scripture_states[SCRIPTURE_SCRIPT] //huh, on the gamemode ticker? okay... + ) + .["tier_infos"][SCRIPTURE_APPLICATION] = list( + "requirement" = "Unlock these optional scriptures by converting another servant or if [DisplayPower(APPLICATION_UNLOCK_THRESHOLD)] of power is reached..", + "ready" = SSticker.scripture_states[SCRIPTURE_APPLICATION] + ) + + // .["selected"] = selected_scripture + generate_all_scripture() + .["recollection_categories"] = GLOB.ratvar_awakens ? list() : list( + list("name" = "Getting Started", "desc" = "First-time servant? Read this first."), + list("name" = "Basics", "desc" = "A primer on how to play as a servant."), + list("name" = "Terminology", "desc" = "Common acronyms, words, and terms."), + list("name" = "Components", "desc" = "Information on components, your primary resource."), + list("name" = "Scripture", "desc" = "Information on scripture, ancient tools used by the cult."), + list("name" = "Power", "desc" = "The power system that certain objects use to function."), + list("name" = "Conversion", "desc" = "Converting the crew, cyborgs, and very walls to your cause.") + ) + // .["rec_section"]["title"] //this is here if ever we decided to return these back. + // .["rec_section"]["info"]// wall of info for the thing /obj/item/clockwork/slab/ui_act(action, params) switch(action) if("toggle") recollecting = !recollecting if("recite") - INVOKE_ASYNC(src, .proc/recite_scripture, text2path(params["category"]), usr, FALSE) - if("select") - selected_scripture = params["category"] + INVOKE_ASYNC(src, .proc/recite_scripture, text2path(params["script"]), usr, FALSE) if("bind") - var/datum/clockwork_scripture/path = text2path(params["category"]) //we need a path and not a string + var/datum/clockwork_scripture/path = text2path(params["script"]) //we need a path and not a string + if(!ispath(path, /datum/clockwork_scripture) || !initial(path.quickbind) || initial(path.tier) == SCRIPTURE_PERIPHERAL) //fuck you href bus + to_chat(usr, "Nice try using href exploits") + return var/found_index = quickbound.Find(path) if(found_index) //hey, we already HAVE this bound if(LAZYLEN(quickbound) == found_index) //if it's the last scripture, remove it instead of leaving a null @@ -512,8 +334,8 @@ quickbind_to_slot(path, target_index) if("rec_category") recollection_category = params["category"] - ui_interact(usr) - return 1 + update_static_data() + return TRUE /obj/item/clockwork/slab/proc/quickbind_to_slot(datum/clockwork_scripture/scripture, index) //takes a typepath(typecast for initial()) and binds it to a slot if(!ispath(scripture) || !scripture || (scripture in quickbound)) diff --git a/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm b/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm index 43c05b8556..7578d41b15 100644 --- a/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm +++ b/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm @@ -32,7 +32,7 @@ clockwork_desc = initial(clockwork_desc) //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/clockwork/construct_chassis/attack_hand(mob/living/user) +/obj/item/clockwork/construct_chassis/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) if(w_class >= WEIGHT_CLASS_HUGE) to_chat(user, "[src] is too cumbersome to carry! Drag it around instead!") return diff --git a/code/modules/antagonists/clockcult/clock_structures/clockwork_obelisk.dm b/code/modules/antagonists/clockcult/clock_structures/clockwork_obelisk.dm index 058bd9d24e..8c529d43a6 100644 --- a/code/modules/antagonists/clockcult/clock_structures/clockwork_obelisk.dm +++ b/code/modules/antagonists/clockcult/clock_structures/clockwork_obelisk.dm @@ -41,7 +41,7 @@ affected += try_use_power(MIN_CLOCKCULT_POWER*4) return affected -/obj/structure/destructible/clockwork/powered/clockwork_obelisk/attack_hand(mob/living/user) +/obj/structure/destructible/clockwork/powered/clockwork_obelisk/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm b/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm index c01c7f0f57..2c84a5b332 100644 --- a/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm +++ b/code/modules/antagonists/clockcult/clock_structures/eminence_spire.dm @@ -11,7 +11,7 @@ var/selection_timer //Timer ID; this is canceled if the vote is canceled var/kingmaking -/obj/structure/destructible/clockwork/eminence_spire/attack_hand(mob/living/user) +/obj/structure/destructible/clockwork/eminence_spire/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm b/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm index 7d8b206f41..385b9a5431 100644 --- a/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm +++ b/code/modules/antagonists/clockcult/clock_structures/heralds_beacon.dm @@ -58,7 +58,7 @@ . += "There are [time_remaining] second[time_remaining != 1 ? "s" : ""] remaining to vote." . += "There are [voters.len]/[votes_needed] votes to activate the beacon!" -/obj/structure/destructible/clockwork/heralds_beacon/attack_hand(mob/living/user) +/obj/structure/destructible/clockwork/heralds_beacon/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/antagonists/clockcult/clock_structures/mania_motor.dm b/code/modules/antagonists/clockcult/clock_structures/mania_motor.dm index 5fbaf9fd57..24d0651444 100644 --- a/code/modules/antagonists/clockcult/clock_structures/mania_motor.dm +++ b/code/modules/antagonists/clockcult/clock_structures/mania_motor.dm @@ -30,7 +30,7 @@ toggle() return TRUE -/obj/structure/destructible/clockwork/powered/mania_motor/attack_hand(mob/living/user) +/obj/structure/destructible/clockwork/powered/mania_motor/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/lever.dm b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/lever.dm index 12e4b62a65..d4a02cc3e1 100644 --- a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/lever.dm +++ b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/lever.dm @@ -6,7 +6,7 @@ max_integrity = 75 icon_state = "lever" -/obj/structure/destructible/clockwork/trap/trigger/lever/attack_hand(mob/living/user) +/obj/structure/destructible/clockwork/trap/trigger/lever/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/repeater.dm b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/repeater.dm index f5ed91ac15..e7d4e18c43 100644 --- a/code/modules/antagonists/clockcult/clock_structures/trap_triggers/repeater.dm +++ b/code/modules/antagonists/clockcult/clock_structures/trap_triggers/repeater.dm @@ -6,7 +6,7 @@ max_integrity = 15 //Fragile! icon_state = "repeater" -/obj/structure/destructible/clockwork/trap/trigger/repeater/attack_hand(mob/living/user) +/obj/structure/destructible/clockwork/trap/trigger/repeater/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index b0538d6521..9b77e70a73 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -67,7 +67,7 @@ Runes can either be invoked by one's self or with many different cultists. Each to_chat(user, "You disrupt the magic of [src] with [I].") qdel(src) -/obj/effect/rune/attack_hand(mob/living/user) +/obj/effect/rune/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/antagonists/devil/devil.dm b/code/modules/antagonists/devil/devil.dm index c12259778e..3b6dc68986 100644 --- a/code/modules/antagonists/devil/devil.dm +++ b/code/modules/antagonists/devil/devil.dm @@ -92,6 +92,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master", //Don't delete upon mind destruction, otherwise soul re-selling will break. delete_on_mind_deletion = FALSE threat = 5 + show_to_ghosts = TRUE var/obligation var/ban var/bane diff --git a/code/modules/antagonists/disease/disease_datum.dm b/code/modules/antagonists/disease/disease_datum.dm index 7de0330ad6..b8e906064c 100644 --- a/code/modules/antagonists/disease/disease_datum.dm +++ b/code/modules/antagonists/disease/disease_datum.dm @@ -2,6 +2,7 @@ name = "Sentient Disease" roundend_category = "diseases" antagpanel_category = "Disease" + show_to_ghosts = TRUE var/disease_name = "" /datum/antagonist/disease/on_gain() diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm index 1d773627c7..295616d052 100644 --- a/code/modules/antagonists/ert/ert.dm +++ b/code/modules/antagonists/ert/ert.dm @@ -12,6 +12,7 @@ var/list/name_source threat = -5 show_in_antagpanel = FALSE + show_to_ghosts = TRUE antag_moodlet = /datum/mood_event/focused /datum/antagonist/ert/on_gain() diff --git a/code/modules/antagonists/monkey/monkey.dm b/code/modules/antagonists/monkey/monkey.dm index ebb39c814e..971532958f 100644 --- a/code/modules/antagonists/monkey/monkey.dm +++ b/code/modules/antagonists/monkey/monkey.dm @@ -9,6 +9,7 @@ roundend_category = "monkeys" antagpanel_category = "Monkey" threat = 3 + show_to_ghosts = TRUE var/datum/team/monkey/monkey_team var/monkey_only = TRUE diff --git a/code/modules/antagonists/nightmare/nightmare.dm b/code/modules/antagonists/nightmare/nightmare.dm index 837b6e4216..f5b10de5c2 100644 --- a/code/modules/antagonists/nightmare/nightmare.dm +++ b/code/modules/antagonists/nightmare/nightmare.dm @@ -3,3 +3,4 @@ show_in_antagpanel = FALSE show_name_in_check_antagonists = TRUE threat = 5 + show_to_ghosts = TRUE diff --git a/code/modules/antagonists/ninja/ninja.dm b/code/modules/antagonists/ninja/ninja.dm index 2615822dd8..414f7dd6b0 100644 --- a/code/modules/antagonists/ninja/ninja.dm +++ b/code/modules/antagonists/ninja/ninja.dm @@ -3,6 +3,7 @@ antagpanel_category = "Ninja" job_rank = ROLE_NINJA show_name_in_check_antagonists = TRUE + show_to_ghosts = TRUE antag_moodlet = /datum/mood_event/focused threat = 8 var/helping_station = FALSE diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index a11ecaa3df..5c011b6318 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -7,6 +7,9 @@ density = TRUE resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + ui_x = 350 + ui_y = 442 + var/timer_set = 90 var/default_timer_set = 90 var/minimum_timer_set = 90 @@ -262,8 +265,7 @@ /obj/machinery/nuclearbomb/ui_interact(mob/user, ui_key="main", datum/tgui/ui=null, force_open=0, datum/tgui/master_ui=null, datum/ui_state/state=GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "nuclear_bomb", name, 350, 442, master_ui, state) - ui.set_style(ui_style) + ui = new(user, src, ui_key, "NuclearBomb", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/nuclearbomb/ui_data(mob/user) diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm index 454cde6d72..652b19a8e7 100644 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ b/code/modules/antagonists/nukeop/nukeop.dm @@ -6,6 +6,7 @@ antag_moodlet = /datum/mood_event/focused threat = 10 skill_modifiers = list(/datum/skill_modifier/job/level/wiring) + show_to_ghosts = TRUE var/datum/team/nuclear/nuke_team var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team. var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint. diff --git a/code/modules/antagonists/official/official.dm b/code/modules/antagonists/official/official.dm index 1d340253c4..1ec64cb2b6 100644 --- a/code/modules/antagonists/official/official.dm +++ b/code/modules/antagonists/official/official.dm @@ -4,6 +4,7 @@ show_in_antagpanel = FALSE var/datum/objective/mission var/datum/team/ert/ert_team + show_to_ghosts = TRUE /datum/antagonist/official/greet() to_chat(owner, "You are a CentCom Official.") diff --git a/code/modules/antagonists/pirate/pirate.dm b/code/modules/antagonists/pirate/pirate.dm index 01f3c6068e..e6d350064d 100644 --- a/code/modules/antagonists/pirate/pirate.dm +++ b/code/modules/antagonists/pirate/pirate.dm @@ -4,6 +4,7 @@ roundend_category = "space pirates" antagpanel_category = "Pirate" threat = 5 + show_to_ghosts = TRUE var/datum/team/pirate/crew /datum/antagonist/pirate/greet() diff --git a/code/modules/antagonists/revenant/revenant_antag.dm b/code/modules/antagonists/revenant/revenant_antag.dm index 46c1176533..c93291797a 100644 --- a/code/modules/antagonists/revenant/revenant_antag.dm +++ b/code/modules/antagonists/revenant/revenant_antag.dm @@ -3,6 +3,7 @@ show_in_antagpanel = FALSE show_name_in_check_antagonists = TRUE threat = 5 + show_to_ghosts = TRUE /datum/antagonist/revenant/greet() owner.announce_objectives() diff --git a/code/modules/antagonists/santa/santa.dm b/code/modules/antagonists/santa/santa.dm index f58a21ba42..ff7dae98f6 100644 --- a/code/modules/antagonists/santa/santa.dm +++ b/code/modules/antagonists/santa/santa.dm @@ -1,6 +1,8 @@ /datum/antagonist/santa name = "Santa" show_in_antagpanel = FALSE + show_name_in_check_antagonists = TRUE + show_to_ghosts = TRUE /datum/antagonist/santa/on_gain() . = ..() diff --git a/code/modules/antagonists/slaughter/slaughter_antag.dm b/code/modules/antagonists/slaughter/slaughter_antag.dm index 04f7167fa5..87db9772b7 100644 --- a/code/modules/antagonists/slaughter/slaughter_antag.dm +++ b/code/modules/antagonists/slaughter/slaughter_antag.dm @@ -6,6 +6,7 @@ threat = 10 job_rank = ROLE_ALIEN show_in_antagpanel = FALSE + show_to_ghosts = TRUE /datum/antagonist/slaughter/on_gain() forge_objectives() diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm index cef4fb2d62..89352d81bd 100644 --- a/code/modules/antagonists/swarmer/swarmer.dm +++ b/code/modules/antagonists/swarmer/swarmer.dm @@ -36,7 +36,7 @@ if(A) notify_ghosts("A swarmer shell has been created in [A.name].", 'sound/effects/bin_close.ogg', source = src, action = NOTIFY_ATTACK, flashwindow = FALSE, ignore_dnr_observers = TRUE) -/obj/effect/mob_spawn/swarmer/attack_hand(mob/living/user) +/obj/effect/mob_spawn/swarmer/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -400,13 +400,13 @@ return FALSE /obj/structure/lattice/catwalk/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) - . = ..() var/turf/here = get_turf(src) for(var/A in here.contents) var/obj/structure/cable/C = A if(istype(C)) to_chat(S, "Disrupting the power grid would bring no benefit to us. Aborting.") return FALSE + return ..() /obj/item/deactivated_swarmer/IntegrateAmount() return 50 diff --git a/code/modules/antagonists/traitor/equipment/contractor.dm b/code/modules/antagonists/traitor/equipment/contractor.dm index 6c5d5766e4..94a3059b5f 100644 --- a/code/modules/antagonists/traitor/equipment/contractor.dm +++ b/code/modules/antagonists/traitor/equipment/contractor.dm @@ -1,4 +1,4 @@ -// Support unit gets it's own very basic antag datum for admin logging. +/// Support unit gets it's own very basic antag datum for admin logging. /datum/antagonist/traitor/contractor_support name = "Contractor Support Unit" antag_moodlet = /datum/mood_event/focused @@ -8,11 +8,13 @@ should_equip = FALSE /// Don't give them an uplink. var/datum/team/contractor_team/contractor_team -/datum/team/contractor_team // Team for storing both the contractor and their support unit - only really for the HUD and admin logging. +/// Team for storing both the contractor and their support unit - only really for the HUD and admin logging. +/datum/team/contractor_team show_roundend_report = FALSE /datum/antagonist/traitor/contractor_support/forge_traitor_objectives() var/datum/objective/generic_objective = new + generic_objective.name = "Follow Contractor's Orders" generic_objective.explanation_text = "Follow your orders. Assist agents in this mission area." generic_objective.completed = TRUE @@ -25,7 +27,9 @@ var/static/list/contractor_items = typecacheof(/datum/contractor_item/, TRUE) var/datum/syndicate_contract/current_contract var/list/datum/syndicate_contract/assigned_contracts = list() + var/list/assigned_targets = list() // used as a blacklist to make sure we're not assigning targets already assigned + var/contracts_completed = 0 var/contract_TC_payed_out = 0 // Keeping track for roundend reporting var/contract_TC_to_redeem = 0 // Used internally and roundend reporting - what TC we have available to cashout. @@ -34,7 +38,8 @@ var/datum/contractor_item/contractor_item = new path hub_items.Add(contractor_item) -/datum/contractor_hub/proc/create_contracts(datum/mind/owner) // 6 initial contracts +/datum/contractor_hub/proc/create_contracts(datum/mind/owner) + // 6 initial contracts var/list/to_generate = list( CONTRACT_PAYOUT_LARGE, CONTRACT_PAYOUT_MEDIUM, @@ -44,61 +49,74 @@ CONTRACT_PAYOUT_SMALL ) - var/lowest_TC_threshold = 30 // We don't want the sum of all the payouts to be under this amount + //What the fuck + if(length(to_generate) > length(GLOB.data_core.locked)) + to_generate.Cut(1, length(GLOB.data_core.locked)) + // We don't want the sum of all the payouts to be under this amount + var/lowest_TC_threshold = 30 + var/total = 0 var/lowest_paying_sum = 0 var/datum/syndicate_contract/lowest_paying_contract - to_generate = shuffle(to_generate) // Randomise order, so we don't have contracts always in payout order. - var/start_index = 1 // Support contract generation happening multiple times - if(assigned_contracts.len != 0) + // Randomise order, so we don't have contracts always in payout order. + to_generate = shuffle(to_generate) + // Support contract generation happening multiple times + var/start_index = 1 + if (assigned_contracts.len != 0) start_index = assigned_contracts.len + 1 - for(var/i = 1; i <= to_generate.len; i++) // Generate contracts, and find the lowest paying. + // Generate contracts, and find the lowest paying. + for (var/i = 1; i <= to_generate.len; i++) var/datum/syndicate_contract/contract_to_add = new(owner, assigned_targets, to_generate[i]) var/contract_payout_total = contract_to_add.contract.payout + contract_to_add.contract.payout_bonus assigned_targets.Add(contract_to_add.contract.target) - if(!lowest_paying_contract || (contract_payout_total < lowest_paying_sum)) + if (!lowest_paying_contract || (contract_payout_total < lowest_paying_sum)) lowest_paying_sum = contract_payout_total lowest_paying_contract = contract_to_add total += contract_payout_total contract_to_add.id = start_index assigned_contracts.Add(contract_to_add) start_index++ - if(total < lowest_TC_threshold) // If the threshold for TC payouts isn't reached, boost the lowest paying contract + + // If the threshold for TC payouts isn't reached, boost the lowest paying contract + if (total < lowest_TC_threshold) lowest_paying_contract.contract.payout_bonus += (lowest_TC_threshold - total) /datum/contractor_item var/name // Name of item var/desc // description of item var/item // item path, no item path means the purchase needs it's own handle_purchase() - var/item_icon = "fa-broadcast-tower" // fontawesome icon to use inside the hub - https://fontawesome.com/icons/ + var/item_icon = "broadcast-tower" // fontawesome icon to use inside the hub - https://fontawesome.com/icons/ var/limited = -1 // Any number above 0 for how many times it can be bought in a round for a single traitor. -1 is unlimited. var/cost // Cost of the item in contract rep. /datum/contractor_item/contract_reroll name = "Contract Reroll" desc = "Request a reroll of your current contract list. Will generate a new target, payment, and dropoff for the contracts you currently have available." - item_icon = "fa-dice" + item_icon = "dice" limited = 2 cost = 0 /datum/contractor_item/contract_reroll/handle_purchase(var/datum/contractor_hub/hub) . = ..() if (.) - var/list/new_target_list = list() // We're not regenerating already completed/aborted/extracting contracts, but we don't want to repeat their targets. + /// We're not regenerating already completed/aborted/extracting contracts, but we don't want to repeat their targets. + var/list/new_target_list = list() for(var/datum/syndicate_contract/contract_check in hub.assigned_contracts) if (contract_check.status != CONTRACT_STATUS_ACTIVE && contract_check.status != CONTRACT_STATUS_INACTIVE) if (contract_check.contract.target) new_target_list.Add(contract_check.contract.target) continue - for(var/datum/syndicate_contract/rerolling_contract in hub.assigned_contracts) // Reroll contracts without duplicates + /// Reroll contracts without duplicates + for(var/datum/syndicate_contract/rerolling_contract in hub.assigned_contracts) if (rerolling_contract.status != CONTRACT_STATUS_ACTIVE && rerolling_contract.status != CONTRACT_STATUS_INACTIVE) continue rerolling_contract.generate(new_target_list) new_target_list.Add(rerolling_contract.contract.target) - hub.assigned_targets = new_target_list // Set our target list with the new set we've generated. + /// Set our target list with the new set we've generated. + hub.assigned_targets = new_target_list /datum/contractor_item/contractor_pinpointer name = "Contractor Pinpointer" desc = "A pinpointer that finds targets even without active suit sensors. Due to taking advantage of an exploit within the system, it can't pinpoint to the same accuracy as the traditional models. Becomes permanently locked to the user that first activates it." @@ -125,20 +143,25 @@ /datum/contractor_item/contractor_partner/handle_purchase(var/datum/contractor_hub/hub, mob/living/user) . = ..() + if (.) to_chat(user, "The uplink vibrates quietly, connecting to nearby agents...") - var/list/mob/candidates = pollGhostCandidates("Do you want to play as the Contractor Support Unit for [user.real_name]?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_CONTRACTOR_SUPPORT) + + var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the Contractor Support Unit for [user.real_name]?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_CONTRACTOR_SUPPORT) + if(LAZYLEN(candidates)) var/mob/dead/observer/C = pick(candidates) spawn_contractor_partner(user, C.key) else to_chat(user, "No available agents at this time, please try again later.") - limited += 1 // refund and add the limit back. + // refund and add the limit back. + limited += 1 hub.contract_rep += cost hub.purchased_items -= src /datum/outfit/contractor_partner name = "Contractor Support Unit" + uniform = /obj/item/clothing/under/chameleon suit = /obj/item/clothing/suit/chameleon back = /obj/item/storage/backpack @@ -148,28 +171,35 @@ ears = /obj/item/radio/headset/chameleon id = /obj/item/card/id/syndicate r_hand = /obj/item/storage/toolbox/syndicate + backpack_contents = list(/obj/item/storage/box/survival, /obj/item/implanter/uplink, /obj/item/clothing/mask/chameleon, /obj/item/storage/fancy/cigarettes/cigpack_syndicate, /obj/item/lighter) /datum/outfit/contractor_partner/post_equip(mob/living/carbon/human/H, visualsOnly) . = ..() - var/obj/item/clothing/mask/cigarette/syndicate/cig = H.get_item_by_slot(SLOT_WEAR_MASK) - cig.light() // pre-light their cig for extra badass + var/obj/item/clothing/mask/cigarette/syndicate/cig = H.get_item_by_slot(ITEM_SLOT_MASK) + // pre-light their cig + cig.light() /datum/contractor_item/contractor_partner/proc/spawn_contractor_partner(mob/living/user, key) var/mob/living/carbon/human/partner = new() var/datum/outfit/contractor_partner/partner_outfit = new() + partner_outfit.equip(partner) + var/obj/structure/closet/supplypod/arrival_pod = new() + arrival_pod.style = STYLE_SYNDICATE arrival_pod.explosionSize = list(0,0,0,1) arrival_pod.bluespace = TRUE var/turf/free_location = find_obstruction_free_location(2, user) - if (!free_location) // We really want to send them - if we can't find a nice location just land it on top of them. + // We really want to send them - if we can't find a nice location just land it on top of them. + if (!free_location) free_location = get_turf(user) partner.forceMove(arrival_pod) partner.ckey = key - partner_mind = partner.mind // We give a reference to the mind that'll be the support unit + /// We give a reference to the mind that'll be the support unit + partner_mind = partner.mind partner_mind.make_Contractor_Support() to_chat(partner_mind.current, "\n[user.real_name] is your superior. Follow any, and all orders given by them. You're here to support their mission only.") to_chat(partner_mind.current, "Should they perish, or be otherwise unavailable, you're to assist other active agents in this mission area to the best of your ability.\n\n") @@ -186,7 +216,7 @@ . = ..() if (.) power_fail(35, 50) - priority_announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Critical Power Failure", "poweroff") + priority_announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Critical Power Failure", "poweroff.ogg") // Subtract cost, and spawn if it's an item. /datum/contractor_item/proc/handle_purchase(var/datum/contractor_hub/hub, mob/living/user) @@ -199,6 +229,7 @@ else if (limited == 0) return FALSE hub.purchased_items.Add(src) + user.playsound_local(user, 'sound/machines/uplinkpurchase.ogg', 100) if (item && ispath(item)) var/atom/item_to_create = new item(get_turf(user)) diff --git a/code/modules/antagonists/traitor/syndicate_contract.dm b/code/modules/antagonists/traitor/syndicate_contract.dm index 70ff59eee0..0f67616a32 100644 --- a/code/modules/antagonists/traitor/syndicate_contract.dm +++ b/code/modules/antagonists/traitor/syndicate_contract.dm @@ -4,47 +4,70 @@ var/datum/objective/contract/contract = new() var/target_rank var/ransom = 0 - var/payout_type = null + var/payout_type + var/wanted_message + var/list/victim_belongings = list() /datum/syndicate_contract/New(contract_owner, blacklist, type=CONTRACT_PAYOUT_SMALL) contract.owner = contract_owner payout_type = type + generate(blacklist) /datum/syndicate_contract/proc/generate(blacklist) contract.find_target(null, blacklist) - var/datum/data/record/record = find_record("name", contract.target.name, GLOB.data_core.general) - if(record) + + var/datum/data/record/record + if (contract.target) + record = find_record("name", contract.target.name, GLOB.data_core.general) + + if (record) target_rank = record.fields["rank"] else target_rank = "Unknown" + if (payout_type == CONTRACT_PAYOUT_LARGE) contract.payout_bonus = rand(9,13) - else if(payout_type == CONTRACT_PAYOUT_MEDIUM) + else if (payout_type == CONTRACT_PAYOUT_MEDIUM) contract.payout_bonus = rand(6,8) else contract.payout_bonus = rand(2,4) + contract.payout = rand(0, 2) contract.generate_dropoff() + ransom = 100 * rand(18, 45) + var/base = pick_list(WANTED_FILE, "basemessage") + var/verb_string = pick_list(WANTED_FILE, "verb") + var/noun = pick_list_weighted(WANTED_FILE, "noun") + var/location = pick_list_weighted(WANTED_FILE, "location") + wanted_message = "[base] [verb_string] [noun] [location]." + /datum/syndicate_contract/proc/handle_extraction(var/mob/living/user) if (contract.target && contract.dropoff_check(user, contract.target.current)) + var/turf/free_location = find_obstruction_free_location(3, user, contract.dropoff) - if(free_location) // We've got a valid location, launch. + + if (free_location) + // We've got a valid location, launch. launch_extraction_pod(free_location) return TRUE + return FALSE // Launch the pod to collect our victim. /datum/syndicate_contract/proc/launch_extraction_pod(turf/empty_pod_turf) var/obj/structure/closet/supplypod/extractionpod/empty_pod = new() + RegisterSignal(empty_pod, COMSIG_ATOM_ENTERED, .proc/enter_check) + empty_pod.stay_after_drop = TRUE empty_pod.reversing = TRUE empty_pod.explosionSize = list(0,0,0,1) empty_pod.leavingSound = 'sound/effects/podwoosh.ogg' + new /obj/effect/abstract/DPtarget(empty_pod_turf, empty_pod) /datum/syndicate_contract/proc/enter_check(datum/source, sent_mob) @@ -52,37 +75,55 @@ if(isliving(sent_mob)) var/mob/living/M = sent_mob var/datum/antagonist/traitor/traitor_data = contract.owner.has_antag_datum(/datum/antagonist/traitor) + if(M == contract.target.current) traitor_data.contractor_hub.contract_TC_to_redeem += contract.payout + traitor_data.contractor_hub.contracts_completed += 1 + if(M.stat != DEAD) traitor_data.contractor_hub.contract_TC_to_redeem += contract.payout_bonus + status = CONTRACT_STATUS_COMPLETE + if(traitor_data.contractor_hub.current_contract == src) traitor_data.contractor_hub.current_contract = null + traitor_data.contractor_hub.contract_rep += 2 else status = CONTRACT_STATUS_ABORTED // Sending a target that wasn't even yours is as good as just aborting it + if(traitor_data.contractor_hub.current_contract == src) traitor_data.contractor_hub.current_contract = null + if(iscarbon(M)) for(var/obj/item/W in M) if(ishuman(M)) var/mob/living/carbon/human/H = M - if(W == H.w_uniform || W == H.shoes) - continue //So all they're left with are shoes and uniform. + if(W == H.w_uniform) + continue //So all they're left with are shoes and uniform. + if(W == H.shoes) + continue + + M.transferItemToLoc(W) victim_belongings.Add(W) + var/obj/structure/closet/supplypod/extractionpod/pod = source - pod.send_up(pod) // Handle the pod returning + + // Handle the pod returning + pod.send_up(pod) + if(ishuman(M)) - var/mob/living/carbon/human/target = M // After we remove items, at least give them what they need to live. + var/mob/living/carbon/human/target = M + + // After we remove items, at least give them what they need to live. target.dna.species.give_important_for_life(target) handleVictimExperience(M) // After pod is sent we start the victim narrative/heal. var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR) var/points_to_check = min(D.account_balance, ransom) D.adjust_money(min(points_to_check, ransom)) priority_announce("One of your crew was captured by a rival organisation - we've needed to pay their ransom to bring them back. \ - As is policy we've taken a portion of the station's funds to offset the overall cost.", null, "attention", null, "Nanotrasen Asset Protection") + As is policy we've taken a portion of the station's funds to offset the overall cost.", null, "attention", null, "Nanotrasen Asset Protection") sleep(30) @@ -128,13 +169,18 @@ M.Dizzy(15) M.confused += 20 -/datum/syndicate_contract/proc/returnVictim(var/mob/living/M) // We're returning the victim +// We're returning the victim +/datum/syndicate_contract/proc/returnVictim(var/mob/living/M) var/list/possible_drop_loc = list() + for(var/turf/possible_drop in contract.dropoff.contents) - if(!is_blocked_turf(possible_drop)) - possible_drop_loc.Add(possible_drop) + if(!isspaceturf(possible_drop) && !isclosedturf(possible_drop)) + if(!is_blocked_turf(possible_drop)) + possible_drop_loc.Add(possible_drop) + if(possible_drop_loc.len > 0) var/pod_rand_loc = rand(1, possible_drop_loc.len) + var/obj/structure/closet/supplypod/return_pod = new() return_pod.bluespace = TRUE return_pod.explosionSize = list(0,0,0,0) @@ -144,8 +190,10 @@ for(var/obj/item/W in M) if(ishuman(M)) var/mob/living/carbon/human/H = M - if(W == H.w_uniform || W == H.shoes) + if(W == H.w_uniform) continue //So all they're left with are shoes and uniform. + if(W == H.shoes) + continue M.dropItemToGround(W) for(var/obj/item/W in victim_belongings) W.forceMove(return_pod) diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm index 70adafd3fb..7263793f7f 100644 --- a/code/modules/antagonists/wizard/wizard.dm +++ b/code/modules/antagonists/wizard/wizard.dm @@ -13,6 +13,7 @@ var/move_to_lair = TRUE var/outfit_type = /datum/outfit/wizard var/wiz_age = WIZARD_AGE_MIN /* Wizards by nature cannot be too young. */ + show_to_ghosts = TRUE /datum/antagonist/wizard/on_gain() register() diff --git a/code/modules/antagonists/xeno/xeno.dm b/code/modules/antagonists/xeno/xeno.dm index 7c4c5351df..2cc8e34b99 100644 --- a/code/modules/antagonists/xeno/xeno.dm +++ b/code/modules/antagonists/xeno/xeno.dm @@ -12,6 +12,7 @@ name = "Xenomorph" job_rank = ROLE_ALIEN show_in_antagpanel = FALSE + show_to_ghosts = TRUE var/datum/team/xeno/xeno_team threat = 3 diff --git a/code/modules/assembly/health.dm b/code/modules/assembly/health.dm index cddc4fb08f..0af6c85fb6 100644 --- a/code/modules/assembly/health.dm +++ b/code/modules/assembly/health.dm @@ -4,7 +4,6 @@ icon_state = "health" custom_materials = list(/datum/material/iron=800, /datum/material/glass=200) attachable = TRUE - secured = FALSE var/scanning = FALSE var/health_scan @@ -12,7 +11,8 @@ /obj/item/assembly/health/examine(mob/user) . = ..() - . += "Use a multitool to swap between \"detect death\" mode and \"detect critical state\" mode." + . += "Use it in hand to turn it off/on and Alt-click to swap between \"detect death\" mode and \"detect critical state\" mode." + . += "[src.scanning ? "The sensor is on and you can see [health_scan] displayed on the screen" : "The sensor is off"]." /obj/item/assembly/health/activate() if(!..()) @@ -30,14 +30,13 @@ update_icon() return secured -/obj/item/assembly/health/multitool_act(mob/living/user, obj/item/I) +/obj/item/assembly/health/AltClick(mob/living/user) if(alarm_health == HEALTH_THRESHOLD_CRIT) alarm_health = HEALTH_THRESHOLD_DEAD to_chat(user, "You toggle [src] to \"detect death\" mode.") else alarm_health = HEALTH_THRESHOLD_CRIT to_chat(user, "You toggle [src] to \"detect critical state\" mode.") - return TRUE /obj/item/assembly/health/process() if(!scanning || !secured) @@ -46,7 +45,6 @@ var/atom/A = src if(connected && connected.holder) A = connected.holder - for(A, A && !ismob(A), A=A.loc); // like get_turf(), but for mobs. var/mob/living/M = A @@ -71,36 +69,7 @@ STOP_PROCESSING(SSobj, src) return -/obj/item/assembly/health/ui_interact(mob/user as mob)//TODO: Change this to the wires thingy +/obj/item/assembly/health/attack_self(mob/user) . = ..() - if(!secured) - user.show_message("The [name] is unsecured!") - return FALSE - var/dat = "Health Sensor" - dat += "
    [scanning?"On":"Off"]" - if(scanning && health_scan) - dat += "
    Health: [health_scan]" - user << browse(dat, "window=hscan") - onclose(user, "hscan") - -/obj/item/assembly/health/Topic(href, href_list) - ..() - if(!ismob(usr)) - return - - var/mob/user = usr - - if(!user.canUseTopic(src)) - usr << browse(null, "window=hscan") - onclose(usr, "hscan") - return - - if(href_list["scanning"]) - toggle_scan() - - if(href_list["close"]) - usr << browse(null, "window=hscan") - return - - attack_self(user) - return + to_chat(user, "You toggle [src] [src.scanning ? "off" : "on"].") + toggle_scan() diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm index 33c6d46045..8cb6eb66fb 100644 --- a/code/modules/assembly/infrared.dm +++ b/code/modules/assembly/infrared.dm @@ -4,7 +4,8 @@ icon_state = "infrared" custom_materials = list(/datum/material/iron=1000, /datum/material/glass=500) is_position_sensitive = TRUE - + var/ui_x = 225 + var/ui_y = 110 var/on = FALSE var/visible = FALSE var/maxlength = 8 @@ -38,7 +39,7 @@ /obj/item/assembly/infra/activate() if(!..()) - return FALSE//Cooldown check + return FALSE //Cooldown check on = !on refreshBeam() update_icon() @@ -69,7 +70,7 @@ holder.update_icon() return -/obj/item/assembly/infra/dropped(mob/user) +/obj/item/assembly/infra/dropped() . = ..() if(holder) holder_movement() //sync the dir of the device as well if it's contained in a TTV or an assembly holder @@ -133,7 +134,7 @@ . = ..() setDir(t) -/obj/item/assembly/infra/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) +/obj/item/assembly/infra/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, gentle = FALSE) . = ..() olddir = dir @@ -176,55 +177,56 @@ return return refreshBeam() -/obj/item/assembly/infra/ui_interact(mob/user)//TODO: change this this to the wire control panel - . = ..() - if(is_secured(user)) - user.set_machine(src) - var/dat = "Infrared Laser" - dat += "
    Status: [on ? "On" : "Off"]" - dat += "
    Visibility: [visible ? "Visible" : "Invisible"]" - dat += "

    Refresh" - dat += "

    Close" - user << browse(dat, "window=infra") - onclose(user, "infra") - return - -/obj/item/assembly/infra/Topic(href, href_list) - ..() - if(usr.incapacitated() || !in_range(loc, usr)) - usr << browse(null, "window=infra") - onclose(usr, "infra") - return - if(href_list["state"]) - on = !(on) - update_icon() - refreshBeam() - if(href_list["visible"]) - visible = !(visible) - update_icon() - refreshBeam() - if(href_list["close"]) - usr << browse(null, "window=infra") - return - if(usr) - attack_self(usr) - /obj/item/assembly/infra/setDir() . = ..() refreshBeam() +/obj/item/assembly/infra/ui_status(mob/user) + if(is_secured(user)) + return ..() + return UI_CLOSE + +/obj/item/assembly/infra/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "InfraredEmitter", name, ui_x, ui_y, master_ui, state) + ui.open() + +/obj/item/assembly/infra/ui_data(mob/user) + var/list/data = list() + data["on"] = on + data["visible"] = visible + return data + +/obj/item/assembly/infra/ui_act(action, params) + if(..()) + return + + switch(action) + if("power") + on = !on + . = TRUE + if("visibility") + visible = !visible + . = TRUE + + update_icon() + refreshBeam() + /***************************IBeam*********************************/ /obj/effect/beam/i_beam name = "infrared beam" icon = 'icons/obj/projectiles.dmi' icon_state = "ibeam" - var/obj/item/assembly/infra/master anchored = TRUE density = FALSE pass_flags = PASSTABLE|PASSGLASS|PASSGRILLE|LETPASSTHROW + var/obj/item/assembly/infra/master /obj/effect/beam/i_beam/Crossed(atom/movable/AM as mob|obj) + . = ..() if(istype(AM, /obj/effect/beam)) return if (isitem(AM)) diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm index f1a4ce47cc..f0d8f28688 100644 --- a/code/modules/assembly/proximity.dm +++ b/code/modules/assembly/proximity.dm @@ -4,7 +4,8 @@ icon_state = "prox" custom_materials = list(/datum/material/iron=800, /datum/material/glass=200) attachable = TRUE - + var/ui_x = 250 + var/ui_y = 185 var/scanning = FALSE var/timing = FALSE var/time = 10 @@ -26,7 +27,7 @@ /obj/item/assembly/prox_sensor/activate() if(!..()) - return FALSE//Cooldown check + return FALSE //Cooldown check if(!scanning) timing = !timing else @@ -41,7 +42,6 @@ else proximity_monitor.SetHost(src,src) - /obj/item/assembly/prox_sensor/toggle_secure() secured = !secured if(!secured) @@ -56,8 +56,6 @@ update_icon() return secured - - /obj/item/assembly/prox_sensor/HasProximity(atom/movable/AM as mob|obj) if (istype(AM, /obj/effect/beam)) return @@ -75,7 +73,6 @@ next_activate = world.time + 30 return TRUE - /obj/item/assembly/prox_sensor/process() if(!timing) return @@ -111,50 +108,47 @@ holder.update_icon() return -/obj/item/assembly/prox_sensor/ui_interact(mob/user)//TODO: Change this to the wires thingy - . = ..() +/obj/item/assembly/prox_sensor/ui_status(mob/user) if(is_secured(user)) - var/second = time % 60 - var/minute = (time - second) / 60 - var/dat = "Proximity Sensor" - if(!scanning) - dat += "
    [(timing ? "Arming" : "Not Arming")] [minute]:[second]" - dat += "
    - - + +" - dat += "
    Armed":"1'>Unarmed (Movement sensor active when armed!)"]" - dat += "
    Detection range: - [sensitivity] +" - dat += "

    Refresh" - dat += "

    Close" - user << browse(dat, "window=prox") - onclose(user, "prox") + return ..() + return UI_CLOSE + +/obj/item/assembly/prox_sensor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "ProximitySensor", name, ui_x, ui_y, master_ui, state) + ui.open() + +/obj/item/assembly/prox_sensor/ui_data(mob/user) + var/list/data = list() + data["seconds"] = round(time % 60) + data["minutes"] = round((time - data["seconds"]) / 60) + data["timing"] = timing + data["scanning"] = scanning + data["sensitivity"] = sensitivity + return data + +/obj/item/assembly/prox_sensor/ui_act(action, params) + if(..()) return - -/obj/item/assembly/prox_sensor/Topic(href, href_list) - ..() - if(usr.incapacitated() || !in_range(loc, usr)) - usr << browse(null, "window=prox") - onclose(usr, "prox") - return - - if(href_list["sense"]) - sensitivity_change(((href_list["sense"] == "up") ? 1 : -1)) - - if(href_list["scanning"]) - toggle_scan(text2num(href_list["scanning"])) - - if(href_list["time"]) - timing = text2num(href_list["time"]) - update_icon() - - if(href_list["tp"]) - var/tp = text2num(href_list["tp"]) - time += tp - time = min(max(round(time), 0), 600) - - if(href_list["close"]) - usr << browse(null, "window=prox") - return - - if(usr) - attack_self(usr) - + switch(action) + if("scanning") + toggle_scan(!scanning) + . = TRUE + if("sense") + var/value = text2num(params["range"]) + if(value) + sensitivity_change(value) + . = TRUE + if("time") + timing = !timing + update_icon() + . = TRUE + if("input") + var/value = text2num(params["adjust"]) + if(value) + value = round(time + value) + time = clamp(value, 0, 600) + . = TRUE diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index e70b6e5c74..fe548d662d 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -8,7 +8,8 @@ custom_materials = list(/datum/material/iron=400, /datum/material/glass=120) wires = WIRE_RECEIVE | WIRE_PULSE | WIRE_RADIO_PULSE | WIRE_RADIO_RECEIVE attachable = TRUE - + var/ui_x = 280 + var/ui_y = 132 var/code = DEFAULT_SIGNALER_CODE var/frequency = FREQ_SIGNALER var/datum/radio_frequency/radio_connection @@ -47,14 +48,16 @@ holder.update_icon() return -/obj/item/assembly/signaler/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) - if(!is_secured(user)) - return +/obj/item/assembly/signaler/ui_status(mob/user) + if(is_secured(user)) + return ..() + return UI_CLOSE + +/obj/item/assembly/signaler/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - var/ui_width = 280 - var/ui_height = 132 - ui = new(user, src, ui_key, "signaler", name, ui_width, ui_height, master_ui, state) + ui = new(user, src, ui_key, "Signaler", name, ui_x, ui_y, master_ui, state) ui.open() /obj/item/assembly/signaler/ui_data(mob/user) @@ -231,4 +234,4 @@ /obj/item/assembly/signaler/cyborg/attackby(obj/item/W, mob/user, params) return /obj/item/assembly/signaler/cyborg/screwdriver_act(mob/living/user, obj/item/I) - return \ No newline at end of file + return diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm index bbcddbdb93..d0f0e1e593 100644 --- a/code/modules/assembly/timer.dm +++ b/code/modules/assembly/timer.dm @@ -4,7 +4,8 @@ icon_state = "timer" custom_materials = list(/datum/material/iron=500, /datum/material/glass=50) attachable = TRUE - + var/ui_x = 275 + var/ui_y = 115 var/timing = FALSE var/time = 5 var/saved_time = 5 @@ -41,7 +42,6 @@ update_icon() return TRUE - /obj/item/assembly/timer/toggle_secure() secured = !secured if(secured) @@ -52,7 +52,6 @@ update_icon() return secured - /obj/item/assembly/timer/proc/timer_end() if(!secured || next_activate > world.time) return FALSE @@ -66,7 +65,6 @@ timing = TRUE update_icon() - /obj/item/assembly/timer/process() if(!timing) return @@ -76,7 +74,6 @@ timer_end() time = saved_time - /obj/item/assembly/timer/update_icon() cut_overlays() attached_overlays = list() @@ -86,50 +83,44 @@ if(holder) holder.update_icon() - -/obj/item/assembly/timer/ui_interact(mob/user)//TODO: Have this use the wires - . = ..() +/obj/item/assembly/timer/ui_status(mob/user) if(is_secured(user)) - var/second = time % 60 - var/minute = (time - second) / 60 - var/dat = "Timing Unit" - dat += "
    [(timing ? "Timing" : "Not Timing")] [minute]:[second]" - dat += "
    - - + +" - dat += "

    Stop repeating" : "1'>Set to repeat")]" - dat += "

    Refresh" - dat += "

    Close" - var/datum/browser/popup = new(user, "timer", name) - popup.set_content(dat) - popup.open() + return ..() + return UI_CLOSE +/obj/item/assembly/timer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "Timer", name, ui_x, ui_y, master_ui, state) + ui.open() -/obj/item/assembly/timer/Topic(href, href_list) - ..() - if(!usr.canUseTopic(src, BE_CLOSE)) - usr << browse(null, "window=timer") - onclose(usr, "timer") +/obj/item/assembly/timer/ui_data(mob/user) + var/list/data = list() + data["seconds"] = round(time % 60) + data["minutes"] = round((time - data["seconds"]) / 60) + data["timing"] = timing + data["loop"] = loop + return data + +/obj/item/assembly/timer/ui_act(action, params) + if(..()) return - if(href_list["time"]) - timing = text2num(href_list["time"]) - if(timing && istype(holder, /obj/item/transfer_valve)) - var/timer_message = "[ADMIN_LOOKUPFLW(usr)] activated [src] attachment on [holder]." - message_admins(timer_message) - GLOB.bombers += timer_message - log_game("[key_name(usr)] activated [src] attachment on [holder]") - update_icon() - if(href_list["repeat"]) - loop = text2num(href_list["repeat"]) - - if(href_list["tp"]) - var/tp = text2num(href_list["tp"]) - time += tp - time = min(max(round(time), 1), 600) - saved_time = time - - if(href_list["close"]) - usr << browse(null, "window=timer") - return - - if(usr) - attack_self(usr) + switch(action) + if("time") + timing = !timing + if(timing && istype(holder, /obj/item/transfer_valve)) + log_game(usr, "activated a", src, "attachment on [holder]") + update_icon() + . = TRUE + if("repeat") + loop = !loop + . = TRUE + if("input") + var/value = text2num(params["adjust"]) + if(value) + value = round(time + value) + time = clamp(value, 1, 600) + saved_time = time + . = TRUE diff --git a/code/modules/asset_cache/asset_cache.dm b/code/modules/asset_cache/asset_cache.dm index 7a12e5e9f6..f702bf714e 100644 --- a/code/modules/asset_cache/asset_cache.dm +++ b/code/modules/asset_cache/asset_cache.dm @@ -1,10 +1,12 @@ /* Asset cache quick users guide: + Make a datum in asset_list_items.dm with your assets for your thing. Checkout asset_list.dm for the helper subclasses The simple subclass will most like be of use for most cases. Then call get_asset_datum() with the type of the datum you created and store the return Then call .send(client) on that stored return value. + Note: If your code uses output() with assets you will need to call asset_flush on the client and wait for it to return before calling output(). You only need do this if .send(client) returned TRUE */ @@ -98,3 +100,4 @@ Note: If your code uses output() with assets you will need to call asset_flush o //The same asset will always lead to the same asset name /proc/generate_asset_name(file) return "asset.[md5(fcopy_rsc(file))]" + diff --git a/code/modules/asset_cache/asset_list.dm b/code/modules/asset_cache/asset_list.dm index fe9859f238..2e5881c67f 100644 --- a/code/modules/asset_cache/asset_list.dm +++ b/code/modules/asset_cache/asset_list.dm @@ -226,3 +226,5 @@ GLOBAL_LIST_EMPTY(asset_datums) /datum/asset/simple/icon_states/multiple_icons/register() for(var/i in icons) ..(i) + + diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm index ba58769d3e..57d8e55e07 100644 --- a/code/modules/asset_cache/asset_list_items.dm +++ b/code/modules/asset_cache/asset_list_items.dm @@ -1,27 +1,10 @@ //DEFINITIONS FOR ASSET DATUMS START HERE. -/* uncomment this and delete the tgui def bellow this for the new tgui + /datum/asset/simple/tgui assets = list( "tgui.bundle.js" = 'tgui/packages/tgui/public/tgui.bundle.js', "tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css', ) -*/ -/datum/asset/simple/tgui - assets = list( - // Old TGUI - "tgui.css" = 'tgui/assets/tgui.css', - "tgui.js" = 'tgui/assets/tgui.js', - // tgui-next - "tgui-main.html" = 'tgui-next/packages/tgui/public/tgui-main.html', - "tgui.bundle.js" = 'tgui-next/packages/tgui/public/tgui.bundle.js', - "tgui.bundle.css" = 'tgui-next/packages/tgui/public/tgui.bundle.css', - // Old TGUI compatability - "tgui-fallback.html" = 'tgui-next/packages/tgui/public/tgui-fallback.html', - "shim-html5shiv.js" = 'tgui-next/packages/tgui/public/shim-html5shiv.js', - "shim-ie8.js" = 'tgui-next/packages/tgui/public/shim-ie8.js', - "shim-dom4.js" = 'tgui-next/packages/tgui/public/shim-dom4.js', - "shim-css-om.js" = 'tgui-next/packages/tgui/public/shim-css-om.js', - ) /datum/asset/group/tgui children = list( @@ -56,17 +39,17 @@ "smmon_3.gif" = 'icons/program_icons/smmon_3.gif', "smmon_4.gif" = 'icons/program_icons/smmon_4.gif', "smmon_5.gif" = 'icons/program_icons/smmon_5.gif', - "smmon_6.gif" = 'icons/program_icons/smmon_6.gif' - //"borg_mon.gif" = 'icons/program_icons/borg_mon.gif' + "smmon_6.gif" = 'icons/program_icons/smmon_6.gif', + "borg_mon.gif" = 'icons/program_icons/borg_mon.gif' ) -/* uncomment if you're porting the new ntnet app + /datum/asset/simple/radar_assets assets = list( "ntosradarbackground.png" = 'icons/UI_Icons/tgui/ntosradar_background.png', "ntosradarpointer.png" = 'icons/UI_Icons/tgui/ntosradar_pointer.png', "ntosradarpointerS.png" = 'icons/UI_Icons/tgui/ntosradar_pointer_S.png' ) -*/ + /datum/asset/spritesheet/simple/pda name = "pda" assets = list( @@ -95,7 +78,6 @@ "refresh" = 'icons/pda_icons/pda_refresh.png', "scanner" = 'icons/pda_icons/pda_scanner.png', "signaler" = 'icons/pda_icons/pda_signaler.png', - //"skills" = 'icons/pda_icons/pda_skills.png', "status" = 'icons/pda_icons/pda_status.png', "dronephone" = 'icons/pda_icons/pda_dronephone.png', "emoji" = 'icons/pda_icons/pda_emoji.png' @@ -115,12 +97,9 @@ "stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png', "stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png', "stamp-law" = 'icons/stamp_icons/large_stamp-law.png' - //"stamp-chap" = 'icons/stamp_icons/large_stamp-chap.png', - //"stamp-mime" = 'icons/stamp_icons/large_stamp-mime.png', - //"stamp-centcom" = 'icons/stamp_icons/large_stamp-centcom.png', - //"stamp-syndicate" = 'icons/stamp_icons/large_stamp-syndicate.png' ) + /datum/asset/simple/IRV assets = list( "jquery-ui.custom-core-widgit-mouse-sortable-min.js" = 'html/IRV/jquery-ui.custom-core-widgit-mouse-sortable-min.js', @@ -168,12 +147,13 @@ "jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js', ) + /datum/asset/simple/goonchat assets = list( "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js', "browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js', "browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css', - "browserOutput_dark.css" = 'code/modules/goonchat/browserassets/css/browserOutput_dark.css', //dark theme, cit specific + "browserOutput_dark.css" = 'code/modules/goonchat/browserassets/css/browserOutput_dark.css', "browserOutput_light.css" = 'code/modules/goonchat/browserassets/css/browserOutput_light.css' ) @@ -219,6 +199,16 @@ "none_button.png" = 'html/none_button.png', ) +/datum/asset/simple/arcade + assets = list( + "boss1.gif" = 'icons/UI_Icons/Arcade/boss1.gif', + "boss2.gif" = 'icons/UI_Icons/Arcade/boss2.gif', + "boss3.gif" = 'icons/UI_Icons/Arcade/boss3.gif', + "boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif', + "boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif', + "boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif', + ) + /datum/asset/spritesheet/simple/minesweeper name = "minesweeper" assets = list( @@ -237,45 +227,7 @@ "minehit" = 'icons/UI_Icons/minesweeper_tiles/minehit.png' ) -/* Port the app game thing -/datum/asset/simple/arcade - assets = list( - "boss1.gif" = 'icons/UI_Icons/Arcade/boss1.gif', - "boss2.gif" = 'icons/UI_Icons/Arcade/boss2.gif', - "boss3.gif" = 'icons/UI_Icons/Arcade/boss3.gif', - "boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif', - "boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif', - "boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif', - ) -*/ -/* -/datum/asset/spritesheet/simple/achievements - name ="achievements" - assets = list( - "default" = 'icons/UI_Icons/Achievements/default.png', - "basemisc" = 'icons/UI_Icons/Achievements/basemisc.png', - "baseboss" = 'icons/UI_Icons/Achievements/baseboss.png', - "baseskill" = 'icons/UI_Icons/Achievements/baseskill.png', - "bbgum" = 'icons/UI_Icons/Achievements/Boss/bbgum.png', - "colossus" = 'icons/UI_Icons/Achievements/Boss/colossus.png', - "hierophant" = 'icons/UI_Icons/Achievements/Boss/hierophant.png', - "legion" = 'icons/UI_Icons/Achievements/Boss/legion.png', - "miner" = 'icons/UI_Icons/Achievements/Boss/miner.png', - "swarmer" = 'icons/UI_Icons/Achievements/Boss/swarmer.png', - "tendril" = 'icons/UI_Icons/Achievements/Boss/tendril.png', - "featofstrength" = 'icons/UI_Icons/Achievements/Misc/featofstrength.png', - "helbital" = 'icons/UI_Icons/Achievements/Misc/helbital.png', - "jackpot" = 'icons/UI_Icons/Achievements/Misc/jackpot.png', - "meteors" = 'icons/UI_Icons/Achievements/Misc/meteors.png', - "timewaste" = 'icons/UI_Icons/Achievements/Misc/timewaste.png', - "upgrade" = 'icons/UI_Icons/Achievements/Misc/upgrade.png', - "clownking" = 'icons/UI_Icons/Achievements/Misc/clownking.png', - "clownthanks" = 'icons/UI_Icons/Achievements/Misc/clownthanks.png', - "rule8" = 'icons/UI_Icons/Achievements/Misc/rule8.png', - "snail" = 'icons/UI_Icons/Achievements/Misc/snail.png', - "mining" = 'icons/UI_Icons/Achievements/Skills/mining.png', - ) -*/ + /datum/asset/spritesheet/simple/pills name ="pills" assets = list( @@ -313,8 +265,8 @@ /datum/asset/spritesheet/pipes name = "pipes" -/datum/asset/spritesheet/pipes/register() //we do not have chempipes - for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi')) +/datum/asset/spritesheet/pipes/register() + for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi')) InsertAll("", each, GLOB.alldirs) ..() @@ -323,7 +275,7 @@ name = "design" /datum/asset/spritesheet/research_designs/register() - for(var/path in subtypesof(/datum/design)) + for (var/path in subtypesof(/datum/design)) var/datum/design/D = path var/icon_file @@ -381,9 +333,9 @@ name = "vending" /datum/asset/spritesheet/vending/register() - for(var/k in GLOB.vending_products) + for (var/k in GLOB.vending_products) var/atom/item = k - if(!ispath(item, /atom)) + if (!ispath(item, /atom)) continue var/icon_file = initial(item.icon) @@ -394,12 +346,12 @@ if(icon_state in icon_states_list) I = icon(icon_file, icon_state, SOUTH) var/c = initial(item.color) - if(!isnull(c) && c != "#FFFFFF") + if (!isnull(c) && c != "#FFFFFF") I.Blend(c, ICON_MULTIPLY) else var/icon_states_string - for(var/an_icon_state in icon_states_list) - if(!icon_states_string) + for (var/an_icon_state in icon_states_list) + if (!icon_states_string) icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])" else icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])" @@ -418,7 +370,12 @@ "dna_extra.gif" = 'html/dna_extra.gif' ) -/datum/asset/simple/vv +/datum/asset/simple/orbit assets = list( - "view_variables.css" = 'html/admin/view_variables.css' + "ghost.png" = 'html/ghost.png' ) + + assets = list( + "ghost.png" = 'html/ghost.png' + ) + diff --git a/code/modules/asset_cache/validate_assets.html b/code/modules/asset_cache/validate_assets.html index 205a7f4dad..b27a266c00 100644 --- a/code/modules/asset_cache/validate_assets.html +++ b/code/modules/asset_cache/validate_assets.html @@ -23,6 +23,7 @@ } }; xhr.send(null); - - - + + + + \ No newline at end of file diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm index 43e54dc2c7..7af823e8a9 100644 --- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm +++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm @@ -16,6 +16,8 @@ GLOBAL_LIST_INIT(meta_gas_dangers, meta_gas_danger_list()) GLOBAL_LIST_INIT(meta_gas_ids, meta_gas_id_list()) GLOBAL_LIST_INIT(meta_gas_fusions, meta_gas_fusion_list()) /datum/gas_mixture + /// Never ever set this variable, hooked into vv_get_var for view variables viewing. + var/gas_list_view_only var/initial_volume = CELL_VOLUME //liters var/list/reaction_results var/list/analyzer_results //used for analyzer feedback - not initialized until its used @@ -29,9 +31,75 @@ GLOBAL_LIST_INIT(meta_gas_fusions, meta_gas_fusion_list()) reaction_results = new /datum/gas_mixture/vv_edit_var(var_name, var_value) - if(var_name == "_extools_pointer_gasmixture") + if(var_name == NAMEOF(src, _extools_pointer_gasmixture)) return FALSE // please no. segfaults bad. + if(var_name == NAMEOF(src, gas_list_view_only)) + return FALSE return ..() + +/datum/gas_mixture/vv_get_var(var_name) + . = ..() + if(var_name == NAMEOF(src, gas_list_view_only)) + var/list/dummy = get_gases() + for(var/gas in dummy) + dummy[gas] = get_moles(gas) + return debug_variable("gases (READ ONLY)", dummy, 0, src) + +/datum/gas_mixture/vv_get_dropdown() + . = ..() + VV_DROPDOWN_OPTION("", "---") + VV_DROPDOWN_OPTION(VV_HK_PARSE_GASSTRING, "Parse Gas String") + VV_DROPDOWN_OPTION(VV_HK_EMPTY, "Empty") + VV_DROPDOWN_OPTION(VV_HK_SET_MOLES, "Set Moles") + VV_DROPDOWN_OPTION(VV_HK_SET_TEMPERATURE, "Set Temperature") + VV_DROPDOWN_OPTION(VV_HK_SET_VOLUME, "Set Volume") + +/datum/gas_mixture/vv_do_topic(list/href_list) + . = ..() + if(!.) + return + if(href_list[VV_HK_PARSE_GASSTRING]) + var/gasstring = input(usr, "Input Gas String (WARNING: Advanced. Don't use this unless you know how these work.", "Gas String Parse") as text|null + if(!istext(gasstring)) + return + log_admin("[key_name(usr)] modified gas mixture [REF(src)]: Set to gas string [gasstring].") + message_admins("[key_name(usr)] modified gas mixture [REF(src)]: Set to gas string [gasstring].") + parse_gas_string(gasstring) + if(href_list[VV_HK_EMPTY]) + log_admin("[key_name(usr)] emptied gas mixture [REF(src)].") + message_admins("[key_name(usr)] emptied gas mixture [REF(src)].") + clear() + if(href_list[VV_HK_SET_MOLES]) + var/list/gases = get_gases() + for(var/gas in gases) + gases[gas] = get_moles(gas) + var/gastype = input(usr, "What kind of gas?", "Set Gas") as null|anything in subtypesof(/datum/gas) + if(!ispath(gastype, /datum/gas)) + return + var/amount = input(usr, "Input amount", "Set Gas", gases[gastype] || 0) as num|null + if(!isnum(amount)) + return + amount = max(0, amount) + log_admin("[key_name(usr)] modified gas mixture [REF(src)]: Set gas type [gastype] to [amount] moles.") + message_admins("[key_name(usr)] modified gas mixture [REF(src)]: Set gas type [gastype] to [amount] moles.") + set_moles(gastype, amount) + if(href_list[VV_HK_SET_TEMPERATURE]) + var/temp = input(usr, "Set the temperature of this mixture to?", "Set Temperature", return_temperature()) as num|null + if(!isnum(temp)) + return + temp = max(2.7, temp) + log_admin("[key_name(usr)] modified gas mixture [REF(src)]: Changed temperature to [temp].") + message_admins("[key_name(usr)] modified gas mixture [REF(src)]: Changed temperature to [temp].") + set_temperature(temp) + if(href_list[VV_HK_SET_VOLUME]) + var/volume = input(usr, "Set the volume of this mixture to?", "Set Volume", return_volume()) as num|null + if(!isnum(volume)) + return + volume = max(0, volume) + log_admin("[key_name(usr)] modified gas mixture [REF(src)]: Changed volume to [volume].") + message_admins("[key_name(usr)] modified gas mixture [REF(src)]: Changed volume to [volume].") + set_volume(volume) + /* /datum/gas_mixture/Del() __gasmixture_unregister() @@ -169,7 +237,7 @@ GLOBAL_LIST_INIT(meta_gas_fusions, meta_gas_fusion_list()) set_moles(path, text2num(gas[id])) archive() return 1 - + /datum/gas_mixture/react(datum/holder) . = NO_REACTION if(!total_moles()) diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm index 20a2638dcf..6b89deeb80 100644 --- a/code/modules/atmospherics/machinery/airalarm.dm +++ b/code/modules/atmospherics/machinery/airalarm.dm @@ -241,7 +241,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "airalarm", name, 440, 650, master_ui, state) + ui = new(user, src, ui_key, "AirAlarm", name, 440, 650, master_ui, state) ui.open() /obj/machinery/airalarm/ui_data(mob/user) diff --git a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm index fc967608b3..9e1908a500 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm @@ -26,6 +26,21 @@ Passive gate is similar to the regular pump except: construction_type = /obj/item/pipe/directional pipe_state = "passivegate" + ui_x = 335 + ui_y = 115 + +/obj/machinery/atmospherics/components/binary/passive_gate/CtrlClick(mob/user) + if(can_interact(user)) + on = !on + update_icon() + return ..() + +/obj/machinery/atmospherics/components/binary/passive_gate/AltClick(mob/user) + if(can_interact(user)) + target_pressure = MAX_OUTPUT_PRESSURE + update_icon() + return ..() + /obj/machinery/atmospherics/components/binary/passive_gate/Destroy() SSradio.remove_object(src,frequency) return ..() @@ -91,7 +106,7 @@ Passive gate is similar to the regular pump except: datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "atmos_pump", name, 335, 115, master_ui, state) + ui = new(user, src, ui_key, "AtmosPump", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/atmospherics/components/binary/passive_gate/ui_data() diff --git a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm index ab6d02fe61..d41df83e12 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm @@ -111,7 +111,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "atmos_pump", name, 335, 115, master_ui, state) + ui = new(user, src, ui_key, "AtmosPump", name, 335, 115, master_ui, state) ui.open() /obj/machinery/atmospherics/components/binary/pump/ui_data() diff --git a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm index 87cbeb6edf..d95e4ec123 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm @@ -96,7 +96,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "atmos_pump", name, 310, 115, master_ui, state) + ui = new(user, src, ui_key, "AtmosPump", name, 310, 115, master_ui, state) ui.open() /obj/machinery/atmospherics/components/binary/volume_pump/ui_data() diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm index f49dee124e..dd6952dfc6 100644 --- a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm +++ b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm @@ -137,7 +137,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "atmos_filter", name, 475, 185, master_ui, state) + ui = new(user, src, ui_key, "AtmosFilter", name, 475, 185, master_ui, state) ui.open() /obj/machinery/atmospherics/components/trinary/filter/ui_data() diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm index a96a6efa4b..758d27ab61 100644 --- a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm +++ b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm @@ -131,7 +131,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "atmos_mixer", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "AtmosMixer", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/atmospherics/components/trinary/mixer/ui_data() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index ad47a111c5..e4f69df396 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -322,7 +322,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "cryo", name, 400, 550, master_ui, state) + ui = new(user, src, ui_key, "Cryo", name, 400, 550, master_ui, state) ui.open() /obj/machinery/atmospherics/components/unary/cryo_cell/ui_data() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm index 5b87c518b1..70672418a1 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm @@ -20,6 +20,21 @@ pipe_state = "injector" + ui_x = 310 + ui_y = 115 + +/obj/machinery/atmospherics/components/unary/outlet_injector/CtrlClick(mob/user) + if(can_interact(user)) + on = !on + update_icon() + return ..() + +/obj/machinery/atmospherics/components/unary/outlet_injector/AltClick(mob/user) + if(can_interact(user)) + volume_rate = MAX_TRANSFER_RATE + update_icon() + return ..() + /obj/machinery/atmospherics/components/unary/outlet_injector/Destroy() SSradio.remove_object(src,frequency) return ..() @@ -140,7 +155,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "atmos_pump", name, 310, 115, master_ui, state) + ui = new(user, src, ui_key, "AtmosPump", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/atmospherics/components/unary/outlet_injector/ui_data() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm index c57dcc6507..c6168a6c9c 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm @@ -129,7 +129,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "thermomachine", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "ThermoMachine", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/atmospherics/components/unary/thermomachine/ui_data(mob/user) diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm index d8430864a2..12ba7e79b9 100644 --- a/code/modules/atmospherics/machinery/portable/canister.dm +++ b/code/modules/atmospherics/machinery/portable/canister.dm @@ -5,6 +5,8 @@ desc = "A canister for the storage of gas." icon_state = "yellow" density = TRUE + ui_x = 300 + ui_y = 232 var/valve_open = FALSE var/obj/machinery/atmospherics/components/binary/passive_gate/pump @@ -34,6 +36,7 @@ var/restricted = FALSE req_access = list() + var/update = 0 var/static/list/label2types = list( "n2" = /obj/machinery/portable_atmospherics/canister/nitrogen, "o2" = /obj/machinery/portable_atmospherics/canister/oxygen, @@ -159,11 +162,11 @@ /obj/machinery/portable_atmospherics/canister/proto name = "prototype canister" + /obj/machinery/portable_atmospherics/canister/proto/default name = "prototype canister" desc = "The best way to fix an atmospheric emergency... or the best way to introduce one." icon_state = "proto" - icon_state = "proto" volume = 5000 max_integrity = 300 temperature_resistance = 2000 + T0C @@ -171,6 +174,7 @@ can_min_release_pressure = (ONE_ATMOSPHERE / 30) prototype = TRUE + /obj/machinery/portable_atmospherics/canister/proto/default/oxygen name = "prototype canister" desc = "A prototype canister for a prototype bike, what could go wrong?" @@ -192,6 +196,7 @@ update_icon() + /obj/machinery/portable_atmospherics/canister/Destroy() qdel(pump) pump = null @@ -215,7 +220,6 @@ /obj/machinery/portable_atmospherics/canister/update_overlays() . = ..() - if(holding) . += "can-open" if(connected_port) @@ -245,7 +249,8 @@ new /obj/item/stack/sheet/metal (loc, 5) qdel(src) -/obj/machinery/portable_atmospherics/canister/welder_act(mob/living/user, obj/item/I) +obj/machinery/portable_atmospherics/canister/welder_act(mob/living/user, obj/item/I) + ..() if(user.a_intent == INTENT_HARM) return FALSE @@ -273,10 +278,9 @@ T.assume_air(expelled_gas) air_update_turf() - stat |= BROKEN + obj_break() density = FALSE - playsound(src.loc, 'sound/effects/spray.ogg', 10, 1, -3) - update_icon() + playsound(src.loc, 'sound/effects/spray.ogg', 10, TRUE, -3) investigate_log("was destroyed.", INVESTIGATE_ATMOS) if(holding) @@ -319,7 +323,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "canister", name, 420, 405, master_ui, state) + ui = new(user, src, ui_key, "Canister", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/portable_atmospherics/canister/ui_data() @@ -354,7 +358,7 @@ return switch(action) if("relabel") - var/label = input("New canister label:", name) as null|anything in label2types + var/label = input("New canister label:", name) as null|anything in sortList(label2types) if(label && !..()) var/newtype = label2types[label] if(newtype) diff --git a/code/modules/atmospherics/machinery/portable/pump.dm b/code/modules/atmospherics/machinery/portable/pump.dm index 4ab934a1c8..7f1dc4d20f 100644 --- a/code/modules/atmospherics/machinery/portable/pump.dm +++ b/code/modules/atmospherics/machinery/portable/pump.dm @@ -8,6 +8,8 @@ name = "portable air pump" icon_state = "psiphon:0" density = TRUE + ui_x = 300 + ui_y = 315 var/on = FALSE var/direction = PUMP_OUT @@ -32,7 +34,6 @@ /obj/machinery/portable_atmospherics/pump/update_icon_state() icon_state = "psiphon:[on]" - /obj/machinery/portable_atmospherics/pump/update_overlays() . = ..() if(holding) @@ -79,14 +80,14 @@ on = FALSE update_icon() else if(on && holding && direction == PUMP_OUT) - investigate_log("[key_name(user)] started a transfer into [holding].
    ", INVESTIGATE_ATMOS) + investigate_log("[key_name(user)] started a transfer into [holding].", INVESTIGATE_ATMOS) /obj/machinery/portable_atmospherics/pump/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "portable_pump", name, 300, 315, master_ui, state) + ui = new(user, src, ui_key, "PortablePump", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/portable_atmospherics/pump/ui_data() @@ -121,14 +122,14 @@ message_admins("[ADMIN_LOOKUPFLW(usr)] turned on a pump that contains [n2o ? "N2O" : ""][n2o && plasma ? " & " : ""][plasma ? "Plasma" : ""] at [ADMIN_VERBOSEJMP(src)]") log_admin("[key_name(usr)] turned on a pump that contains [n2o ? "N2O" : ""][n2o && plasma ? " & " : ""][plasma ? "Plasma" : ""] at [AREACOORD(src)]") else if(on && direction == PUMP_OUT) - investigate_log("[key_name(usr)] started a transfer into [holding].
    ", INVESTIGATE_ATMOS) + investigate_log("[key_name(usr)] started a transfer into [holding].", INVESTIGATE_ATMOS) . = TRUE if("direction") if(direction == PUMP_OUT) direction = PUMP_IN else if(on && holding) - investigate_log("[key_name(usr)] started a transfer into [holding].
    ", INVESTIGATE_ATMOS) + investigate_log("[key_name(usr)] started a transfer into [holding].", INVESTIGATE_ATMOS) direction = PUMP_OUT . = TRUE if("pressure") @@ -142,10 +143,6 @@ else if(pressure == "max") pressure = PUMP_MAX_PRESSURE . = TRUE - else if(pressure == "input") - pressure = input("New release pressure ([PUMP_MIN_PRESSURE]-[PUMP_MAX_PRESSURE] kPa):", name, pump.target_pressure) as num|null - if(!isnull(pressure) && !..()) - . = TRUE else if(text2num(pressure) != null) pressure = text2num(pressure) . = TRUE @@ -154,7 +151,6 @@ investigate_log("was set to [pump.target_pressure] kPa by [key_name(usr)].", INVESTIGATE_ATMOS) if("eject") if(holding) - holding.forceMove(drop_location()) - holding = null + replace_tank(usr, FALSE) . = TRUE update_icon() diff --git a/code/modules/atmospherics/machinery/portable/scrubber.dm b/code/modules/atmospherics/machinery/portable/scrubber.dm index 6589e601a2..bc703b8bbd 100644 --- a/code/modules/atmospherics/machinery/portable/scrubber.dm +++ b/code/modules/atmospherics/machinery/portable/scrubber.dm @@ -2,6 +2,8 @@ name = "portable air scrubber" icon_state = "pscrubber:0" density = TRUE + ui_x = 320 + ui_y = 350 var/on = FALSE var/volume_rate = 1000 @@ -64,7 +66,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "portable_scrubber", name, 320, 335, master_ui, state) + ui = new(user, src, ui_key, "PortableScrubber", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/portable_atmospherics/scrubber/ui_data() diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm index fcdc564380..03c0f5178a 100644 --- a/code/modules/awaymissions/capture_the_flag.dm +++ b/code/modules/awaymissions/capture_the_flag.dm @@ -54,7 +54,7 @@ STOP_PROCESSING(SSobj, src) //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/ctf/attack_hand(mob/living/user) +/obj/item/ctf/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) if(!is_ctf_target(user) && !anyonecanpickup) to_chat(user, "Non players shouldn't be moving the flag!") return @@ -679,7 +679,7 @@ /obj/machinery/control_point/attackby(mob/user, params) capture(user) -/obj/machinery/control_point/attack_hand(mob/user) +/obj/machinery/control_point/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index e91dfee034..4b2f1e9962 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -595,7 +595,7 @@ job_description = "Space Bar Patron" //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/effect/mob_spawn/human/alive/space_bar_patron/attack_hand(mob/user) +/obj/effect/mob_spawn/human/alive/space_bar_patron/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) var/despawn = alert("Return to cryosleep? (Warning, Your mob will be deleted!)",,"Yes","No") if(despawn == "No" || !loc || !Adjacent(user)) return diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm index 4f155d4174..6ddda43bc8 100644 --- a/code/modules/awaymissions/gateway.dm +++ b/code/modules/awaymissions/gateway.dm @@ -1,246 +1,327 @@ +/// Station home gateway GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation) +/// List of possible gateway destinations. +GLOBAL_LIST_EMPTY(gateway_destinations) + +/** + * Corresponds to single entry in gateway control. + * + * Will NOT be added automatically to GLOB.gateway_destinations list. + */ +/datum/gateway_destination + var/name = "Unknown Destination" + var/wait = 0 /// How long after roundstart this destination becomes active + var/enabled = TRUE /// If disabled, the destination won't be availible + var/hidden = FALSE /// Will not show on gateway controls at all. + +/* Can a gateway link to this destination right now. */ +/datum/gateway_destination/proc/is_availible() + return enabled && (world.time - SSticker.round_start_time >= wait) + +/* Returns user-friendly description why you can't connect to this destination, displayed in UI */ +/datum/gateway_destination/proc/get_availible_reason() + . = "Unreachable" + if(world.time - SSticker.round_start_time < wait) + . = "Connection desynchronized. Recalibration in progress." + +/* Check if the movable is allowed to arrive at this destination (exile implants mostly) */ +/datum/gateway_destination/proc/incoming_pass_check(atom/movable/AM) + return TRUE + +/* Get the actual turf we'll arrive at */ +/datum/gateway_destination/proc/get_target_turf() + CRASH("get target turf not implemented for this destination type") + +/* Called after moving the movable to target turf */ +/datum/gateway_destination/proc/post_transfer(atom/movable/AM) + if (ismob(AM)) + var/mob/M = AM + if (M.client) + M.client.move_delay = max(world.time + 5, M.client.move_delay) + +/* Called when gateway activates with this destination. */ +/datum/gateway_destination/proc/activate(obj/machinery/gateway/activated) + return + +/* Called when gateway targeting this destination deactivates. */ +/datum/gateway_destination/proc/deactivate(obj/machinery/gateway/deactivated) + return + +/* Returns data used by gateway controller ui */ +/datum/gateway_destination/proc/get_ui_data() + . = list() + .["ref"] = REF(src) + .["name"] = name + .["availible"] = is_availible() + .["reason"] = get_availible_reason() + if(wait) + .["timeout"] = max(1 - (wait - (world.time - SSticker.round_start_time)) / wait, 0) + +/* Destination is another gateway */ +/datum/gateway_destination/gateway + /// The gateway this destination points at + var/obj/machinery/gateway/target_gateway + +/* We set the target gateway target to activator gateway */ +/datum/gateway_destination/gateway/activate(obj/machinery/gateway/activated) + if(!target_gateway.target) + target_gateway.activate(activated) + +/* We turn off the target gateway if it's linked with us */ +/datum/gateway_destination/gateway/deactivate(obj/machinery/gateway/deactivated) + if(target_gateway.target == deactivated.destination) + target_gateway.deactivate() + +/datum/gateway_destination/gateway/is_availible() + return ..() && target_gateway.calibrated && !target_gateway.target && target_gateway.powered() + +/datum/gateway_destination/gateway/get_availible_reason() + . = ..() + if(!target_gateway.calibrated) + . = "Exit gateway malfunction. Manual recalibration required." + if(target_gateway.target) + . = "Exit gateway in use." + if(!target_gateway.powered()) + . = "Exit gateway unpowered." + +/datum/gateway_destination/gateway/get_target_turf() + return get_step(target_gateway.portal,SOUTH) + +/datum/gateway_destination/gateway/post_transfer(atom/movable/AM) + . = ..() + addtimer(CALLBACK(AM,/atom/movable.proc/setDir,SOUTH),0) + +/* Special home destination, so we can check exile implants */ +/datum/gateway_destination/gateway/home + +/datum/gateway_destination/gateway/home/incoming_pass_check(atom/movable/AM) + if(isliving(AM)) + if(check_exile_implant(AM)) + return FALSE + else + for(var/mob/living/L in AM.contents) + if(check_exile_implant(L)) + target_gateway.say("Rejecting [AM]: Exile implant detected in contained lifeform.") + return FALSE + if(AM.has_buckled_mobs()) + for(var/mob/living/L in AM.buckled_mobs) + if(check_exile_implant(L)) + target_gateway.say("Rejecting [AM]: Exile implant detected in close proximity lifeform.") + return FALSE + return TRUE + +/datum/gateway_destination/gateway/home/proc/check_exile_implant(mob/living/L) + for(var/obj/item/implant/exile/E in L.implants)//Checking that there is an exile implant + to_chat(L, "The station gate has detected your exile implant and is blocking your entry.") + return TRUE + return FALSE + + +/* Destination is one ore more turfs - created by landmarks */ +/datum/gateway_destination/point + var/list/target_turfs = list() + /// Used by away landmarks + var/id + +/datum/gateway_destination/point/get_target_turf() + return pick(target_turfs) + +/* Dense invisible object starting the teleportation. Created by gateways on activation. */ +/obj/effect/gateway_portal_bumper + var/obj/machinery/gateway/gateway + density = TRUE + invisibility = INVISIBILITY_ABSTRACT + +/obj/effect/gateway_portal_bumper/Bumped(atom/movable/AM) + if(get_dir(src,AM) == SOUTH) + gateway.Transfer(AM) + +/obj/effect/gateway_portal_bumper/Destroy(force) + . = ..() + gateway = null /obj/machinery/gateway name = "gateway" desc = "A mysterious gateway built by unknown hands, it allows for faster than light travel to far-flung locations." icon = 'icons/obj/machines/gateway.dmi' icon_state = "off" - density = TRUE resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - var/active = 0 - var/checkparts = TRUE - var/list/obj/effect/landmark/randomspawns = list() + + // 3x2 offset by one row + pixel_x = -32 + pixel_y = -32 + bound_height = 64 + bound_width = 96 + bound_x = -32 + bound_y = 0 + density = TRUE + + use_power = IDLE_POWER_USE + idle_power_usage = 100 + active_power_usage = 5000 + var/calibrated = TRUE - var/list/linked = list() - var/can_link = FALSE //Is this the centerpiece? + /// Type of instanced gateway destination, needs to be subtype of /datum/gateway_destination/gateway + var/destination_type = /datum/gateway_destination/gateway + /// Name of the generated destination + var/destination_name = "Unknown Gateway" + /// This is our own destination, pointing at this gateway + var/datum/gateway_destination/gateway/destination + /// This is current active destination + var/datum/gateway_destination/target + /// bumper object, the thing that starts actual teleport + var/obj/effect/gateway_portal_bumper/portal /obj/machinery/gateway/Initialize() - randomspawns = GLOB.awaydestinations + generate_destination() update_icon() - if(!istype(src, /obj/machinery/gateway/centerstation) && !istype(src, /obj/machinery/gateway/centeraway)) - switch(dir) - if(SOUTH,SOUTHEAST,SOUTHWEST) - density = FALSE return ..() -/obj/machinery/gateway/proc/toggleoff() - for(var/obj/machinery/gateway/G in linked) - G.active = 0 - G.update_icon() - active = 0 +/obj/machinery/gateway/proc/generate_destination() + destination = new destination_type + destination.name = destination_name + destination.target_gateway = src + GLOB.gateway_destinations += destination + +/obj/machinery/gateway/proc/deactivate() + var/datum/gateway_destination/dest = target + target = null + dest.deactivate(src) + QDEL_NULL(portal) + use_power = IDLE_POWER_USE update_icon() -/obj/machinery/gateway/proc/detect() - if(!can_link) - return FALSE - linked = list() //clear the list - var/turf/T = loc - var/ready = FALSE - - for(var/i in GLOB.alldirs) - T = get_step(loc, i) - var/obj/machinery/gateway/G = locate(/obj/machinery/gateway) in T - if(G) - linked.Add(G) - continue - - //this is only done if we fail to find a part - ready = FALSE - toggleoff() - break - - if((linked.len == 8) || !checkparts) - ready = TRUE - return ready +/obj/machinery/gateway/process() + if((stat & (NOPOWER)) && use_power) + if(target) + deactivate() + return /obj/machinery/gateway/update_icon_state() - icon_state = active ? "on" : "off" + if(target) + icon_state = "on" + else + icon_state = "off" -/obj/machinery/gateway/attack_hand(mob/user) - . = ..() - if(.) - return - if(!detect()) - return - if(!active) - toggleon(user) - return - toggleoff() - -/obj/machinery/gateway/proc/toggleon(mob/user) - return FALSE - -/obj/machinery/gateway/safe_throw_at() +/obj/machinery/gateway/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, gentle = FALSE) return +/obj/machinery/gateway/proc/generate_bumper() + portal = new(get_turf(src)) + portal.gateway = src + +/obj/machinery/gateway/proc/activate(datum/gateway_destination/D) + if(!powered() || target) + return + target = D + target.activate(destination) + generate_bumper() + use_power = ACTIVE_POWER_USE + update_icon() + +/obj/machinery/gateway/proc/Transfer(atom/movable/AM) + if(!target || !target.incoming_pass_check(AM)) + return + AM.forceMove(target.get_target_turf()) + target.post_transfer(AM) + +/* Station's primary gateway */ +/obj/machinery/gateway/centerstation + destination_type = /datum/gateway_destination/gateway/home + destination_name = "Home Gateway" + /obj/machinery/gateway/centerstation/Initialize() . = ..() if(!GLOB.the_gateway) GLOB.the_gateway = src - update_icon() - wait = world.time + CONFIG_GET(number/gateway_delay) //+ thirty minutes default - awaygate = locate(/obj/machinery/gateway/centeraway) /obj/machinery/gateway/centerstation/Destroy() if(GLOB.the_gateway == src) GLOB.the_gateway = null return ..() -//this is da important part wot makes things go -/obj/machinery/gateway/centerstation - density = TRUE - icon_state = "offcenter" - use_power = IDLE_POWER_USE - - //warping vars - var/wait = 0 //this just grabs world.time at world start - var/obj/machinery/gateway/centeraway/awaygate = null - can_link = TRUE - -/obj/machinery/gateway/centerstation/update_icon_state() - icon_state = active ? "oncenter" : "offcenter" - -/obj/machinery/gateway/centerstation/process() - if((stat & (NOPOWER)) && use_power) - if(active) - toggleoff() - return - - if(active) - use_power(5000) - -/obj/machinery/gateway/centerstation/toggleon(mob/user) - if(!detect()) - return - if(!powered()) - return - if(!awaygate) - to_chat(user, "Error: No destination found.") - return - if(world.time < wait) - to_chat(user, "Error: Warpspace triangulation in progress. Estimated time to completion: [DisplayTimeText(wait - world.time)].") - return - - for(var/obj/machinery/gateway/G in linked) - G.active = 1 - G.update_icon() - active = 1 - update_icon() - -//okay, here's the good teleporting stuff -/obj/machinery/gateway/centerstation/Bumped(atom/movable/AM) - if(!active) - return - if(!detect()) - return - if(!awaygate || QDELETED(awaygate)) - return - - if(awaygate.calibrated) - AM.forceMove(get_step(awaygate.loc, SOUTH)) - AM.setDir(SOUTH) - if (ismob(AM)) - var/mob/M = AM - if (M.client) - M.client.move_delay = max(world.time + 5, M.client.move_delay) - return +/obj/machinery/gateway/multitool_act(mob/living/user, obj/item/I) + if(calibrated) + to_chat(user, "The gate is already calibrated, there is no work for you to do here.") else - var/obj/effect/landmark/dest = pick(randomspawns) - if(dest) - AM.forceMove(get_turf(dest)) - AM.setDir(SOUTH) - use_power(5000) - return - -/obj/machinery/gateway/centeraway/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/multitool)) - if(calibrated) - to_chat(user, "\black The gate is already calibrated, there is no work for you to do here.") - return - else - to_chat(user, "Recalibration successful!: \black This gate's systems have been fine tuned. Travel to this gate will now be on target.") - calibrated = TRUE - return - -/////////////////////////////////////Away//////////////////////// - - -/obj/machinery/gateway/centeraway - density = TRUE - icon_state = "offcenter" - use_power = NO_POWER_USE - var/obj/machinery/gateway/centerstation/stationgate = null - can_link = TRUE - - -/obj/machinery/gateway/centeraway/Initialize() - . = ..() - update_icon() - stationgate = locate(/obj/machinery/gateway/centerstation) - - -/obj/machinery/gateway/centeraway/update_icon_state() - icon_state = active ? "oncenter" : "offcenter" - -/obj/machinery/gateway/centeraway/toggleon(mob/user) - if(!detect()) - return - if(!stationgate) - to_chat(user, "Error: No destination found.") - return - - for(var/obj/machinery/gateway/G in linked) - G.active = 1 - G.update_icon() - active = 1 - update_icon() - -/obj/machinery/gateway/centeraway/proc/check_exile_implant(mob/living/L) - for(var/obj/item/implant/exile/E in L.implants)//Checking that there is an exile implant - to_chat(L, "\black The station gate has detected your exile implant and is blocking your entry.") - return TRUE - return FALSE - -/obj/machinery/gateway/centeraway/Bumped(atom/movable/AM) - if(!detect()) - return - if(!active) - return - if(!stationgate || QDELETED(stationgate)) - return - if(isliving(AM)) - if(check_exile_implant(AM)) - return - else - for(var/mob/living/L in AM.contents) - if(check_exile_implant(L)) - say("Rejecting [AM]: Exile implant detected in contained lifeform.") - return - if(AM.has_buckled_mobs()) - for(var/mob/living/L in AM.buckled_mobs) - if(check_exile_implant(L)) - say("Rejecting [AM]: Exile implant detected in close proximity lifeform.") - return - AM.forceMove(get_step(stationgate.loc, SOUTH)) - AM.setDir(SOUTH) - if (ismob(AM)) - var/mob/M = AM - if (M.client) - M.client.move_delay = max(world.time + 5, M.client.move_delay) - - -/obj/machinery/gateway/centeraway/admin - desc = "A mysterious gateway built by unknown hands, this one seems more compact." - -/obj/machinery/gateway/centeraway/admin/Initialize() - . = ..() - if(stationgate && !stationgate.awaygate) - stationgate.awaygate = src - -/obj/machinery/gateway/centeraway/admin/detect() + to_chat(user, "Recalibration successful!: \black This gate's systems have been fine tuned. Travel to this gate will now be on target.") + calibrated = TRUE return TRUE +/* Doesn't need control console or power, always links to home when interacting. */ +/obj/machinery/gateway/away + density = TRUE + use_power = NO_POWER_USE + +/obj/machinery/gateway/away/interact(mob/user, special_state) + . = ..() + if(!target) + if(!GLOB.the_gateway) + to_chat(user,"Home gateway is not responding!") + if(GLOB.the_gateway.target) + to_chat(user,"Home gateway already in use!") + return + activate(GLOB.the_gateway.destination) + else + deactivate() + +/* Gateway control computer */ +/obj/machinery/computer/gateway_control + name = "Gateway Control" + desc = "Human friendly interface to the mysterious gate next to it." + var/obj/machinery/gateway/G + +/obj/machinery/computer/gateway_control/Initialize(mapload, obj/item/circuitboard/C) + . = ..() + try_to_linkup() + +/obj/machinery/computer/gateway_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui, force_open, datum/tgui/master_ui, datum/ui_state/state = GLOB.default_state) + . = ..() + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "Gateway", name, ui_x, ui_y, master_ui, state) + ui.open() + +/obj/machinery/computer/gateway_control/ui_data(mob/user) + . = ..() + .["gateway_present"] = G + .["gateway_status"] = G ? G.powered() : FALSE + .["current_target"] = G?.target?.get_ui_data() + var/list/destinations = list() + if(G) + for(var/datum/gateway_destination/D in GLOB.gateway_destinations) + if(D == G.destination) + continue + destinations += list(D.get_ui_data()) + .["destinations"] = destinations + +/obj/machinery/computer/gateway_control/ui_act(action, list/params) + . = ..() + if(.) + return + switch(action) + if("linkup") + try_to_linkup() + return TRUE + if("activate") + var/datum/gateway_destination/D = locate(params["destination"]) in GLOB.gateway_destinations + try_to_connect(D) + return TRUE + if("deactivate") + if(G && G.target) + G.deactivate() + return TRUE + +/obj/machinery/computer/gateway_control/proc/try_to_linkup() + G = locate(/obj/machinery/gateway) in view(7,get_turf(src)) + +/obj/machinery/computer/gateway_control/proc/try_to_connect(datum/gateway_destination/D) + if(!D || !G) + return + if(!D.is_availible() || G.target) + return + G.activate(D) /obj/item/paper/fluff/gateway - info = "Congratulations,

    Your station has been selected to carry out the Gateway Project.

    The equipment will be shipped to you at the start of the next quarter.
    You are to prepare a secure location to house the equipment as outlined in the attached documents.

    --Nanotrasen Blue Space Research" + info = "Congratulations,

    Your station has been selected to carry out the Gateway Project.

    The equipment will be shipped to you at the start of the next quarter.
    You are to prepare a secure location to house the equipment as outlined in the attached documents.

    --Nanotrasen Bluespace Research" name = "Confidential Correspondence, Pg 1" diff --git a/code/modules/awaymissions/zlevel.dm b/code/modules/awaymissions/zlevel.dm index 6c8d8287d8..1e2e1fe43c 100644 --- a/code/modules/awaymissions/zlevel.dm +++ b/code/modules/awaymissions/zlevel.dm @@ -15,24 +15,28 @@ INIT_ANNOUNCE("Loaded [name] in [(REALTIMEOFDAY - start_time)/10]s!") GLOB.random_zlevels_generated[name] = TRUE -/proc/reset_gateway_spawns(reset = FALSE) - for(var/obj/machinery/gateway/G in world) - if(reset) - G.randomspawns = GLOB.awaydestinations - else - G.randomspawns.Add(GLOB.awaydestinations) - /obj/effect/landmark/awaystart name = "away mission spawn" desc = "Randomly picked away mission spawn points." + var/id + var/delay = TRUE // If the generated destination should be delayed by configured gateway delay -/obj/effect/landmark/awaystart/New() - GLOB.awaydestinations += src - ..() +/obj/effect/landmark/awaystart/Initialize() + . = ..() + var/datum/gateway_destination/point/current + for(var/datum/gateway_destination/point/D in GLOB.gateway_destinations) + if(D.id == id) + current = D + if(!current) + current = new + current.id = id + if(delay) + current.wait = CONFIG_GET(number/gateway_delay) + GLOB.gateway_destinations += current + current.target_turfs += get_turf(src) -/obj/effect/landmark/awaystart/Destroy() - GLOB.awaydestinations -= src - return ..() +/obj/effect/landmark/awaystart/nodelay + delay = FALSE /proc/generateMapList(filename) . = list() diff --git a/code/modules/cargo/centcom_podlauncher.dm b/code/modules/cargo/centcom_podlauncher.dm index 3418f78dbd..f33ea7059b 100644 --- a/code/modules/cargo/centcom_podlauncher.dm +++ b/code/modules/cargo/centcom_podlauncher.dm @@ -55,7 +55,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "centcom_podlauncher", "Config/Launch Supplypod", 700, 700, master_ui, state) + ui = new(user, src, ui_key, "CentcomPodLauncher", "Config/Launch Supplypod", 700, 700, master_ui, state) ui.open() /datum/centcom_podlauncher/ui_data(mob/user) //Sends info about the pod to the UI. diff --git a/code/modules/cargo/console.dm b/code/modules/cargo/console.dm index d010cee761..8a438a1342 100644 --- a/code/modules/cargo/console.dm +++ b/code/modules/cargo/console.dm @@ -74,7 +74,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "cargo", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "Cargo", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/computer/cargo/ui_data() diff --git a/code/modules/cargo/expressconsole.dm b/code/modules/cargo/expressconsole.dm index 9fe427c45a..dc7e4b5a06 100644 --- a/code/modules/cargo/expressconsole.dm +++ b/code/modules/cargo/expressconsole.dm @@ -13,6 +13,8 @@ All sales are near instantaneous - please choose carefully" icon_screen = "supply_express" circuit = /obj/item/circuitboard/computer/cargo/express + ui_x = 600 + ui_y = 700 blockade_warning = "Bluespace instability detected. Delivery impossible." req_access = list(ACCESS_QM) var/message @@ -90,7 +92,7 @@ /obj/machinery/computer/cargo/express/ui_interact(mob/living/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state. ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "cargo_express", name, 600, 700, master_ui, state) + ui = new(user, src, ui_key, "CargoExpress", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/computer/cargo/express/ui_data(mob/user) diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index b1ded0cd1b..4846b7ab22 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -20,9 +20,7 @@ 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? @@ -36,10 +34,11 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( if(!usr || usr != mob) //stops us calling Topic for somebody else's client. Also helps prevent usr=null return + // asset_cache 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 var/mtl = CONFIG_GET(number/minute_topic_limit) @@ -894,13 +893,13 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) /client/vv_edit_var(var_name, var_value) switch (var_name) - if ("holder") + if (NAMEOF(src, holder)) return FALSE - if ("ckey") + if (NAMEOF(src, ckey)) return FALSE - if ("key") + if (NAMEOF(src, key)) return FALSE - if("view") + if(NAMEOF(src, view)) change_view(var_value) return TRUE . = ..() diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index aaee5c85f6..8b4c28a1f4 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -165,6 +165,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/custom_speech_verb = "default" //if your say_mod is to be something other than your races var/custom_tongue = "default" //if your tongue is to be something other than your races + /// Security record note section + var/security_records + /// Medical record note section + var/medical_records + var/list/custom_names = list() var/preferred_ai_core_display = "Blue" var/prefered_security_department = SEC_DEPT_RANDOM @@ -340,6 +345,24 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Custom job preferences:
    " dat += "Preferred AI Core Display: [preferred_ai_core_display]
    " dat += "Preferred Security Department: [prefered_security_department]
    " + dat += "
    Records
    " + dat += "
    Security Records
    " + if(length_char(security_records) <= 40) + if(!length(security_records)) + dat += "\[...\]" + else + dat += "[security_records]" + else + dat += "[TextPreview(security_records)]...
    " + + dat += "
    Medical Records
    " + if(length_char(medical_records) <= 40) + if(!length(medical_records)) + dat += "\[...\]
    " + else + dat += "[medical_records]" + else + dat += "[TextPreview(medical_records)]...
    " dat += "" //Character Appearance @@ -1646,6 +1669,16 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(new_age) age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN) + if("security_records") + var/rec = stripped_multiline_input(usr, "Set your security record note section. This should be IC!", "Security Records", html_decode(security_records), MAX_FLAVOR_LEN, TRUE) + if(!isnull(rec)) + security_records = rec + + if("medical_records") + var/rec = stripped_multiline_input(usr, "Set your medical record note section. This should be IC!", "Security Records", html_decode(medical_records), MAX_FLAVOR_LEN, TRUE) + if(!isnull(rec)) + medical_records = rec + if("flavor_text") var/msg = stripped_multiline_input(usr, "Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!", "Flavor Text", html_decode(features["flavor_text"]), MAX_FLAVOR_LEN, TRUE) if(!isnull(msg)) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 3a8e7582cb..440ee1fbc1 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -515,6 +515,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //Quirks S["all_quirks"] >> all_quirks + //Records + S["security_records"] >> security_records + S["medical_records"] >> medical_records + //Citadel code S["feature_genitals_use_skintone"] >> features["genitals_use_skintone"] S["feature_mcolor2"] >> features["mcolor2"] @@ -698,6 +702,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car custom_speech_verb = sanitize_inlist(custom_speech_verb, GLOB.speech_verbs, "default") custom_tongue = sanitize_inlist(custom_tongue, GLOB.roundstart_tongues, "default") + security_records = copytext(security_records, 1, MAX_FLAVOR_LEN) + medical_records = copytext(medical_records, 1, MAX_FLAVOR_LEN) + features["flavor_text"] = copytext(features["flavor_text"], 1, MAX_FLAVOR_LEN) features["silicon_flavor_text"] = copytext(features["silicon_flavor_text"], 1, MAX_FLAVOR_LEN) features["ooc_notes"] = copytext(features["ooc_notes"], 1, MAX_FLAVOR_LEN) @@ -762,6 +769,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["species"] , pref_species.id) WRITE_FILE(S["custom_speech_verb"] , custom_speech_verb) WRITE_FILE(S["custom_tongue"] , custom_tongue) + + // records + WRITE_FILE(S["security_records"] , security_records) + WRITE_FILE(S["medical_records"] , medical_records) + WRITE_FILE(S["feature_mcolor"] , features["mcolor"]) WRITE_FILE(S["feature_lizard_tail"] , features["tail_lizard"]) WRITE_FILE(S["feature_human_tail"] , features["tail_human"]) diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index 723fb93b78..54561c8a24 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -287,7 +287,7 @@ if(!target.IsUnconscious()) to_chat(target, "Your zealous conspirationism rapidly dissipates as the donned hat warps up into a ruined mess. All those theories starting to sound like nothing but a ridicolous fanfare.") -/obj/item/clothing/head/foilhat/attack_hand(mob/user) +/obj/item/clothing/head/foilhat/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(!warped && iscarbon(user)) var/mob/living/carbon/C = user if(src == C.head) diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index 6a836cad7b..c3934aa78c 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -219,7 +219,7 @@ lock = TRUE return -/obj/item/clothing/neck/petcollar/locked/attack_hand(mob/user) +/obj/item/clothing/neck/petcollar/locked/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(loc == user && user.get_item_by_slot(SLOT_NECK) && lock != FALSE) to_chat(user, "The collar is locked! You'll need unlock the collar before you can take it off!") return diff --git a/code/modules/clothing/under/jobs/medical.dm b/code/modules/clothing/under/jobs/medical.dm index 78a905f897..c4eedf93a4 100644 --- a/code/modules/clothing/under/jobs/medical.dm +++ b/code/modules/clothing/under/jobs/medical.dm @@ -85,12 +85,10 @@ item_state = "w_suit" permeability_coefficient = 0.5 armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 10, "rad" = 0, "fire" = 0, "acid" = 0) - can_adjust = FALSE /obj/item/clothing/under/rank/medical/paramedic/light desc = "It's made of a special fiber that provides minor protection against biohazards. It has a dark blue cross on the chest denoting that the wearer is a trained paramedic." icon_state = "paramedic-light" - can_adjust = TRUE /obj/item/clothing/under/rank/medical/paramedic/skirt name = "paramedic jumpskirt" diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm index 9b114829e1..3ee1990d14 100644 --- a/code/modules/detectivework/scanner.dm +++ b/code/modules/detectivework/scanner.dm @@ -18,6 +18,7 @@ var/list/log = list() var/range = 8 var/view_check = TRUE + var/forensicPrintCount = 0 actions_types = list(/datum/action/item_action/displayDetectiveScanResults) /datum/action/item_action/displayDetectiveScanResults @@ -42,12 +43,15 @@ /obj/item/detective_scanner/proc/PrintReport() // Create our paper var/obj/item/paper/P = new(get_turf(src)) - P.name = "paper- 'Scanner Report'" - P.info = "
    Scanner Report


    " + + //This could be a global count like sec and med record printouts. See GLOB.data_core.medicalPrintCount AKA datacore.dm + var frNum = ++forensicPrintCount + + P.name = text("FR-[] 'Forensic Record'", frNum) + P.info = text("
    Forensic Record - (FR-[])


    ", frNum) P.info += jointext(log, "
    ") P.info += "
    Notes:
    " - P.info_links = P.info - P.updateinfolinks() + P.update_icon() if(ismob(loc)) var/mob/M = loc @@ -216,4 +220,4 @@ return to_chat(user, "Scanner Report") for(var/iterLog in log) - to_chat(user, iterLog) \ No newline at end of file + to_chat(user, iterLog) diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index 0ace65ffd3..cf2ac93360 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -143,7 +143,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 if(L && (L.density || prob(10))) L.ex_act(EXPLODE_HEAVY) -obj/effect/immovablerod/attack_hand(mob/living/user) +obj/effect/immovablerod/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) if(ishuman(user)) var/mob/living/carbon/human/U = user if(U.job in list("Research Director")) diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm index fd3a189eb3..f1803b03ee 100644 --- a/code/modules/events/pirates.dm +++ b/code/modules/events/pirates.dm @@ -225,7 +225,8 @@ suit_type = /obj/item/clothing/suit/space helmet_type = /obj/item/clothing/head/helmet/space mask_type = /obj/item/clothing/mask/breath - storage_type = /obj/item/tank/jetpack/void + storage_type = /obj/item/tank/internals/oxygen + /obj/machinery/loot_locator name = "Booty Locator" @@ -280,8 +281,9 @@ /obj/machinery/computer/piratepad_control name = "cargo hold control terminal" - resistance_flags = INDESTRUCTIBLE - var/status_report = "Idle" + ui_x = 600 + ui_y = 230 + var/status_report = "Ready for delivery." var/obj/machinery/piratepad/pad var/warmup_time = 100 var/sending = FALSE @@ -298,7 +300,6 @@ if (istype(I) && istype(I.buffer,/obj/machinery/piratepad)) to_chat(user, "You link [src] with [I.buffer] in [I] buffer.") pad = I.buffer - updateDialog() return TRUE /obj/machinery/computer/piratepad_control/LateInitialize() @@ -311,29 +312,43 @@ else pad = locate() in range(4,src) -/obj/machinery/computer/piratepad_control/ui_interact(mob/user) - . = ..() - var/list/t = list() - t += "
    Cargo Hold Control
    " - t += "Current cargo value : [points]" - t += "
    " - if(!pad) - t += "
    No pad located.

    " - else - t += "
    [status_report]
    " - if(!sending) - t += "Recalculate ValueSend" - else - t += "Stop sending" +/obj/machinery/computer/piratepad_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "CargoHoldTerminal", name, ui_x, ui_y, master_ui, state) + ui.open() - var/datum/browser/popup = new(user, "piratepad", name, 300, 500) - popup.set_content(t.Join()) - popup.open() +/obj/machinery/computer/piratepad_control/ui_data(mob/user) + var/list/data = list() + data["points"] = points + data["pad"] = pad ? TRUE : FALSE + data["sending"] = sending + data["status_report"] = status_report + return data + +/obj/machinery/computer/piratepad_control/ui_act(action, params) + if(..()) + return + if(!pad) + return + + switch(action) + if("recalc") + recalc() + . = TRUE + if("send") + start_sending() + . = TRUE + if("stop") + stop_sending() + . = TRUE /obj/machinery/computer/piratepad_control/proc/recalc() if(sending) return - status_report = "Predicted value:
    " + status_report = "Predicted value: " + var/value = 0 var/datum/export_report/ex = new for(var/atom/movable/AM in get_turf(pad)) if(AM == pad) @@ -341,7 +356,12 @@ export_item_and_contents(AM, EXPORT_PIRATE | EXPORT_CARGO | EXPORT_CONTRABAND | EXPORT_EMAG, apply_elastic = FALSE, dry_run = TRUE, external_report = ex) for(var/datum/export/E in ex.total_amount) - status_report += E.total_printout(ex,notes = FALSE) + "
    " + status_report += E.total_printout(ex,notes = FALSE) + status_report += " " + value += ex.total_value[E] + + if(!value) + status_report += "0" /obj/machinery/computer/piratepad_control/proc/send() if(!sending) @@ -354,14 +374,15 @@ continue export_item_and_contents(AM, EXPORT_PIRATE | EXPORT_CARGO | EXPORT_CONTRABAND | EXPORT_EMAG, apply_elastic = FALSE, delete_unsold = FALSE, external_report = ex) - status_report = "Sold:
    " + status_report = "Sold: " var/value = 0 for(var/datum/export/E in ex.total_amount) var/export_text = E.total_printout(ex,notes = FALSE) //Don't want nanotrasen messages, makes no sense here. if(!export_text) continue - status_report += export_text + "
    " + status_report += export_text + status_report += " " value += ex.total_value[E] if(!total_report) @@ -374,11 +395,12 @@ points += value + if(!value) + status_report += "Nothing" pad.visible_message("[pad] activates!") flick(pad.sending_state,pad) pad.icon_state = pad.idle_state sending = FALSE - updateDialog() /obj/machinery/computer/piratepad_control/proc/start_sending() if(sending) @@ -397,20 +419,6 @@ pad.icon_state = pad.idle_state deltimer(sending_timer) -/obj/machinery/computer/piratepad_control/Topic(href, href_list) - if(..()) - return - if(pad) - if(href_list["recalc"]) - recalc() - if(href_list["send"]) - start_sending() - if(href_list["stop"]) - stop_sending() - updateDialog() - else - updateDialog() - /datum/export/pirate export_category = EXPORT_PIRATE @@ -435,6 +443,8 @@ var/mob/living/carbon/human/H = AM if(H.stat != CONSCIOUS || !H.mind || !H.mind.assigned_role) //mint condition only return 0 + else if("pirate" in H.faction) //can't ransom your fellow pirates to CentCom! + return 0 else if(H.mind.assigned_role in GLOB.command_positions) return 3000 diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm index a17df4db9a..ad786561f4 100644 --- a/code/modules/events/spacevine.dm +++ b/code/modules/events/spacevine.dm @@ -346,7 +346,7 @@ SM.on_cross(src, AM) //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/structure/spacevine/attack_hand(mob/user) +/obj/structure/spacevine/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) for(var/datum/spacevine_mutation/SM in mutations) SM.on_hit(src, user) user_unbuckle_mob(user, user) diff --git a/code/modules/events/travelling_trader.dm b/code/modules/events/travelling_trader.dm new file mode 100644 index 0000000000..b7afc3440e --- /dev/null +++ b/code/modules/events/travelling_trader.dm @@ -0,0 +1,330 @@ +/datum/round_event_control/travelling_trader + name = "Travelling Trader" + typepath = /datum/round_event/travelling_trader + weight = 10 + max_occurrences = 3 + earliest_start = 0 MINUTES + +/datum/round_event/travelling_trader + startWhen = 0 + endWhen = 900 //you effectively have 15 minutes to complete the traders request, before they disappear + var/mob/living/carbon/human/dummy/travelling_trader/trader + var/atom/spawn_location //where the trader appears + +/datum/round_event/travelling_trader/setup() + if(GLOB.generic_event_spawns) + spawn_location = pick(GLOB.generic_event_spawns) + else + message_admins("No event spawn landmarks exist on the map while placing a travelling trader, resorting to random station turf. (go yell at a mapper)") + spawn_location = get_random_station_turf() + +/datum/round_event/travelling_trader/start() + //spawn a type of trader + var/trader_type = pick(subtypesof(/mob/living/carbon/human/dummy/travelling_trader)) + trader = new trader_type(get_turf(spawn_location)) + var/datum/effect_system/smoke_spread/smoke = new + smoke.set_up(1, spawn_location) + smoke.start() + trader.visible_message("[src] suddenly appears in a puff of smoke!") + +/datum/round_event/travelling_trader/announce(fake) + priority_announce("A mysterious figure has been detected on sensors at [get_area(spawn_location)]", "Mysterious Figure") + +/datum/round_event/travelling_trader/end() + if(trader) + trader.visible_message("The [src] has given up on waiting!") + qdel(trader) + +//the actual trader mob +/mob/living/carbon/human/dummy/travelling_trader //similar to a dummy because we want to be resource-efficient + var/trader_name = "Debug Travelling Trader" + status_flags = GODMODE //avoid scenarios of people trying to kill the trader + move_resist = MOVE_FORCE_VERY_STRONG //you can't bluespace bodybag them! + var/datum/outfit/trader_outfit + var/list/possible_wanted_items //weighted list of possible things to request + var/list/possible_rewards //weighted list of possible things to give in return for the requested item + var/atom/requested_item //the thing they chose from possible_wanted_items + var/last_speech //last time someone tried interacting with them using their hand + var/last_refusal //last time they vocally refused an item given to them + var/initial_speech = "It looks like the coders did a mishap!" //first thing they say when interacted with, like a description + var/speech_verb = "says" + var/request_speech = "Please bring me a requested_item you shall be greatly rewarded!" //second thing they say when interacted with + var/acceptance_speech = "This is exactly what I wanted! I shall be on my way now, thank you.!" + var/refusal_speech = "A given_item? I wanted a requested_item!" //what they say when refusing an item + var/active = TRUE + +/mob/living/carbon/human/dummy/travelling_trader/proc/setup_speech(var/input_speech, var/obj/item/given_item) + if(requested_item) + input_speech = replacetext(input_speech, "requested_item", initial(requested_item.name)) + if(given_item) + input_speech = replacetext(input_speech, "given_item", given_item.name) + return input_speech + +/mob/living/carbon/human/dummy/travelling_trader/attack_hand(mob/living/carbon/human/H) + if(active && last_speech + 3 < world.realtime) //can only talk once per 3 seconds, to avoid spam + last_speech = world.realtime + if(initial_speech) + visible_message("[src] [speech_verb] \"[setup_speech(initial_speech)]\"") + sleep(15) + if(active && request_speech) //they might not be active anymore because of the prior sleep! + visible_message("[src] [speech_verb] \"[setup_speech(request_speech)]\"") + +/mob/living/carbon/human/dummy/travelling_trader/attackby(obj/item/I, mob/user) + if(active) + if(check_item(I)) + active = FALSE + visible_message("[src] [speech_verb] \"[setup_speech(acceptance_speech, I)]\"") + qdel(I) + sleep(15) + give_reward(user) + qdel(src) + else + if(last_refusal + 3 < world.realtime) + last_refusal = world.realtime + visible_message("[src] [speech_verb] \"[setup_speech(refusal_speech, I)]\"") + +/mob/living/carbon/human/dummy/travelling_trader/proc/check_item(var/obj/item/supplied_item) //sometimes we might want to care about the properties of the item, etc + return istype(supplied_item, requested_item) + +/mob/living/carbon/human/dummy/travelling_trader/proc/give_reward() + var/reward = pickweight(possible_rewards) + new reward(get_turf(src)) + +/mob/living/carbon/human/dummy/travelling_trader/Initialize() + ..() + ADD_TRAIT(src,TRAIT_PIERCEIMMUNE, "trader_pierce_immune") //don't let people take their blood + equipOutfit(trader_outfit, TRUE) + for(var/obj/item/item in src.get_equipped_items()) + ADD_TRAIT(item, TRAIT_NODROP, "trader_no_drop") //don't let people steal the travellers clothes! + item.resistance_flags |= INDESTRUCTIBLE //don't let people burn their clothes off, either. + if(!requested_item) //sometimes we already picked one + requested_item = pickweight(possible_wanted_items) + name = trader_name //gets changed in humans initialisation so we set it here + +/mob/living/carbon/human/dummy/travelling_trader/Destroy() + var/datum/effect_system/smoke_spread/smoke = new + smoke.set_up(1, loc) + smoke.start() + visible_message("[src] disappears in a puff of smoke, leaving something on the ground!") + ..() + +//travelling trader subtypes (the types that can actually spawn) +//so far there's: cook / botanist / bartender / animal hunter / artifact dealer / surgeon (6 types!) + +//cook +/mob/living/carbon/human/dummy/travelling_trader/cook + trader_name = "Otherworldly Chef" + trader_outfit = /datum/outfit/job/cook + initial_speech = "Mama-mia! I have came to this plane of existence, searching the greatest of foods!" + request_speech = "Can you fetch me the delicacy known as requested_item? I would pay you for your service!" + acceptance_speech = "Grazie! You have done me a service, my friend." + refusal_speech = "A given_item? Surely you must be joking!" + possible_rewards = list(/obj/item/paper/secretrecipe = 1, + /obj/item/pizzabox/infinite = 1, + /obj/item/kitchen/fork/throwing = 1, + /mob/living/simple_animal/cow/random = 1) + +/mob/living/carbon/human/dummy/travelling_trader/cook/Initialize() + //pick a random crafted food item as the requested item + var/datum/crafting_recipe/food_recipe = pick(subtypesof(/datum/crafting_recipe/food)) + var/result = initial(food_recipe.result) + if(ispath(result, /obj/item/reagent_containers/food)) //not all food recipes make food objects (like cak/butterbear) + requested_item = result + else + requested_item = /obj/item/reagent_containers/food/snacks/copypasta + ..() + +//botanist +/mob/living/carbon/human/dummy/travelling_trader/gardener + trader_name = "Otherworldly Gardener" + trader_outfit = /datum/outfit/job/botanist + initial_speech = "I have come across this realm in search of rare plants and believe this station may be able to help me.." + request_speech = "Are you able to bring me the plant known to you as: 'requested_item'? I could see that you get some reward for this task." + acceptance_speech = "Amazing! Ill finally be able to make that salad. Goodbye for now!" + refusal_speech = "A given_item? Did nobody ever teach you the basics of gardening?" + possible_rewards = list(/obj/item/seeds/cherry/bomb = 1, + /obj/item/storage/box/strange_seeds_5pack = 6, + /obj/item/clothing/suit/hooded/bee_costume = 2, + /obj/item/seeds/gatfruit = 1) //overall you have less chance of seeing them than a lifebringer just bringing the seeds to you directly + + +/mob/living/carbon/human/dummy/travelling_trader/gardener/Initialize() + requested_item = pick(subtypesof(/obj/item/reagent_containers/food/snacks/grown) - list(/obj/item/reagent_containers/food/snacks/grown/shell, + /obj/item/reagent_containers/food/snacks/grown/shell/gatfruit, + /obj/item/reagent_containers/food/snacks/grown/cherry_bomb)) + ..() + +//animal hunter +/mob/living/carbon/human/dummy/travelling_trader/animal_hunter + trader_name = "Otherworldly Animal Specialist" + trader_outfit = /datum/outfit/job/doctor + initial_speech = "Greetings, lifeform. I am here to locate a special creature aboard your station." + request_speech = "Find me the creature known as 'requested_item' and you shall be rewarded for your efforts." + refusal_speech = "Do you think me to be a fool, lifeform? I know a requested_item when I see one." + possible_wanted_items = list(/mob/living/simple_animal/pet/dog/corgi/Ian = 1, + /mob/living/simple_animal/sloth/paperwork = 1, + /mob/living/carbon/monkey/punpun = 1, + /mob/living/simple_animal/pet/fox/Renault = 1, + /mob/living/simple_animal/hostile/carp/cayenne = 1, + /mob/living/simple_animal/pet/bumbles = 1, + /mob/living/simple_animal/parrot/Poly = 1) + possible_rewards = list(/mob/living/simple_animal/pet/dog/corgi/exoticcorgi = 1, //rewards are animals, friendly to only the person who handed the reward in! + /mob/living/simple_animal/cockroach = 1, + /mob/living/simple_animal/hostile/skeleton = 1, + /mob/living/simple_animal/hostile/stickman = 1, + /mob/living/simple_animal/hostile/stickman/dog = 1, + /mob/living/simple_animal/hostile/asteroid/fugu = 1, + /mob/living/simple_animal/hostile/bear = 1, + /mob/living/simple_animal/hostile/retaliate/clown/fleshclown = 1, + /mob/living/simple_animal/hostile/tree = 1, + /mob/living/simple_animal/hostile/mimic = 1, + /mob/living/simple_animal/hostile/shark = 1, + /mob/living/simple_animal/hostile/netherworld/blankbody = 1, + /mob/living/simple_animal/hostile/retaliate/goose = 1) + +mob/living/carbon/human/dummy/travelling_trader/animal_hunter/Initialize() + acceptance_speech = pick(list("This lifeform shall make for a great stew, thank you.", "This lifeform shall be of a true use to our cause, thank you.", "The lifeform is adequate. Goodbye.", "This lifeform shall make a great addition to my collection.")) + //make sure they only ask for animals that are still alive + for(var/mob/living/animal in possible_wanted_items) + if(!(animal in GLOB.mob_living_list)) + possible_wanted_items -= animal + if(!possible_wanted_items) + //all the pets are dead, so ask for a monkey, or sometimes a corgi (corgis are more annoying to get a hold of) + possible_wanted_items = list(/mob/living/simple_animal/pet/dog/corgi = 1, /mob/living/carbon/monkey = 3) + ..() + +/mob/living/carbon/human/dummy/travelling_trader/animal_hunter/check_item(var/obj/item/supplied_item) //item is likely to be in contents of whats supplied + for(var/atom/something in supplied_item.contents) + if(istype(something, requested_item)) + qdel(something) //typically things holding mobs release the mob when the container is deleted, so delete the mob first here + return TRUE + return FALSE + +/mob/living/carbon/human/dummy/travelling_trader/animal_hunter/give_reward(var/mob/giver) //the reward is actually given in a jar, because releasing it onto the station might be a bad idea + var/obj/item/pet_carrier/bluespace/jar = new(get_turf(src)) + var/chosen_animal = pickweight(possible_rewards) + var/mob/living/new_animal = new chosen_animal(jar) + if(giver && giver.tag) + new_animal.faction += "\[[giver.tag]\]" + jar.add_occupant(new_animal) + jar.name = "WARNING: [new_animal]" + +//bartender +/mob/living/carbon/human/dummy/travelling_trader/bartender + trader_name = "Otherworldly Bartender" + trader_outfit = /datum/outfit/job/bartender + initial_speech = "Greetings, station inhabitor. I came to this dimension in the pursuit of a particular drink." + request_speech = "Bring me thirty units of the beverage known as 'requested_item'." + acceptance_speech = "This is truly the drink I have been seeking. Thank you." + refusal_speech = "Do not mess with me, simpleton, I do not wish for that which you are trying to give me." + possible_rewards = list(/obj/structure/reagent_dispensers/keg/neurotoxin = 1, //all kegs have 250u aside from neurotoxin/hearty punch which have 100u + /obj/structure/reagent_dispensers/keg/hearty_punch = 3, + /obj/structure/reagent_dispensers/keg/red_queen = 3, + /obj/structure/reagent_dispensers/keg/narsour = 3, + /obj/structure/reagent_dispensers/keg/quintuple_sec = 3) + +/mob/living/carbon/human/dummy/travelling_trader/bartender/Initialize() //pick a subtype of ethanol that isn't found in the default set of the booze dispensers reagents + requested_item = pick(subtypesof(/datum/reagent/consumable/ethanol) - list(/datum/reagent/consumable/ethanol/beer, + /datum/reagent/consumable/ethanol/kahlua, + /datum/reagent/consumable/ethanol/whiskey, + /datum/reagent/consumable/ethanol/wine, + /datum/reagent/consumable/ethanol/vodka, + /datum/reagent/consumable/ethanol/gin, + /datum/reagent/consumable/ethanol/rum, + /datum/reagent/consumable/ethanol/tequila, + /datum/reagent/consumable/ethanol/vermouth, + /datum/reagent/consumable/ethanol/cognac, + /datum/reagent/consumable/ethanol/ale, + /datum/reagent/consumable/ethanol/absinthe, + /datum/reagent/consumable/ethanol/hcider, + /datum/reagent/consumable/ethanol/creme_de_menthe, + /datum/reagent/consumable/ethanol/creme_de_cacao, + /datum/reagent/consumable/ethanol/creme_de_coconut, + /datum/reagent/consumable/ethanol/triple_sec, + /datum/reagent/consumable/ethanol/sake, + /datum/reagent/consumable/ethanol/applejack)) + ..() + +/mob/living/carbon/human/dummy/travelling_trader/bartender/check_item(var/obj/item/supplied_item) //you need to check its reagents + if(istype(supplied_item, /obj/item/reagent_containers)) + var/obj/item/reagent_containers/supplied_container = supplied_item + if(supplied_container.reagents.has_reagent(requested_item, 30)) + return TRUE + return FALSE + +//artifact dealer +/mob/living/carbon/human/dummy/travelling_trader/artifact_dealer + trader_name = "Otherworldly Artifact Dealer" + trader_outfit = /datum/outfit/artifact_dealer //he's cool enough to get his own outfit + initial_speech = "I have come here due to sensing the existence of an object of great power and importance." + request_speech = "Give to me the great object known as: requested_item and I shall make it worth your while, traveller." + acceptance_speech = "This is truly an artifact worthy of my collection, thank you." + refusal_speech = "A given_item? Hah! Worthless." + possible_wanted_items = list(/obj/item/pen/fountain/captain = 1, //various rare things and high risk but not useful things (i.e. champion belt, bedsheet, pen) + /obj/item/storage/belt/champion = 1, + /obj/item/clothing/shoes/wheelys = 1, + /obj/item/relic = 1, + /obj/item/flashlight/lamp/bananalamp = 1, + /obj/item/storage/box/hug = 1, + /obj/item/clothing/gloves/color/yellow = 1, + /obj/item/instrument/saxophone = 1, + /obj/item/bedsheet/captain = 1, + /obj/item/slime_extract/green = 1, + /obj/item/chainsaw = 1, + /obj/item/clothing/head/crown = 1) + possible_rewards = list(/obj/item/storage/bag/money/c5000 = 5, + /obj/item/circuitboard/computer/arcade/amputation = 2, + /obj/item/stack/sticky_tape/infinite = 2, + /obj/item/clothing/suit/hooded/wintercoat/cosmic = 2) + +/mob/living/carbon/human/dummy/travelling_trader/artifact_dealer/Initialize() + possible_rewards += list(pick(subtypesof(/obj/item/clothing/head/collectable)) = 1) //this is slightly lower because it's absolutely useless + ..() + +/datum/outfit/artifact_dealer + uniform = /obj/item/clothing/under/suit/black_really + shoes = /obj/item/clothing/shoes/combat + head = /obj/item/clothing/head/that + glasses = /obj/item/clothing/glasses/monocle + +//surgeon +/mob/living/carbon/human/dummy/travelling_trader/surgeon + trader_name = "Otherworldly Surgeon" + trader_outfit = /datum/outfit/otherworldly_surgeon + initial_speech = "Hello there, meatbag. You can provide me with something I want." + request_speech = "Find me the appendage you call 'requested_item'. I shall make sure it's worth your efforts." + acceptance_speech = "This shall do. Goodbye, meatbag." + refusal_speech = "That is not what I wish for. Give me a requested_item, or I shall take one by force." + possible_wanted_items = list(/obj/item/bodypart/l_arm = 4, + /obj/item/bodypart/r_arm = 4, + /obj/item/bodypart/l_leg = 4, + /obj/item/bodypart/r_leg = 4, + /obj/item/organ/tongue = 2, + /obj/item/organ/liver = 2, + /obj/item/organ/lungs = 2, + /obj/item/organ/heart = 2, + /obj/item/organ/eyes = 1, + /obj/item/organ/brain = 1, + /obj/item/bodypart/head = 1) + possible_rewards = list(/obj/item/organ/cyberimp/mouth/breathing_tube = 1, + /obj/item/organ/eyes/robotic/thermals = 1, + /obj/item/organ/cyberimp/arm/toolset = 1, + /obj/item/organ/cyberimp/arm/surgery = 1, + /obj/item/organ/cyberimp/arm/janitor = 1, + /obj/item/organ/cyberimp/arm/flash = 1, + /obj/item/organ/cyberimp/arm/shield = 1, + /obj/item/organ/cyberimp/eyes/hud/medical = 1, + /obj/item/organ/cyberimp/arm/baton = 1) + +/mob/living/carbon/human/dummy/travelling_trader/surgeon/give_reward() + var/chosen_implant = pickweight(possible_rewards) + var/new_implant = new chosen_implant + var/obj/item/autosurgeon/reward = new(get_turf(src)) + reward.insert_organ(new_implant) + +/datum/outfit/otherworldly_surgeon + uniform = /obj/item/clothing/under/pants/white + shoes = /obj/item/clothing/shoes/sneakers/white + gloves = /obj/item/clothing/gloves/color/latex + mask = /obj/item/clothing/mask/surgical + suit = /obj/item/clothing/suit/apron/surgical diff --git a/code/modules/food_and_drinks/food/snacks.dm b/code/modules/food_and_drinks/food/snacks.dm index 900fc99171..de264ff0e4 100644 --- a/code/modules/food_and_drinks/food/snacks.dm +++ b/code/modules/food_and_drinks/food/snacks.dm @@ -13,15 +13,31 @@ The nutriment reagent and bitesize variable replace the old heal_amt and amount bitesize of 2, then it'll take 3 bites to eat. Unlike the old system, the contained reagents are evenly spread among all the bites. No more contained reagents = no more bites. -Here is an example of the new formatting for anyone who wants to add more food items. +Food formatting and crafting examples. ``` -/obj/item/reagent_containers/food/snacks/xenoburger //Identification path for the object. - name = "Xenoburger" //Name that displays in the UI. - desc = "Smells caustic. Tastes like heresy." //Duh - icon_state = "xburger" //Refers to an icon in food.dmi - list_reagents = list(/datum/reagent/xenomicrobes = 10, - /datum/reagent/consumable/nutriment = 2) //What's inside the snack. - bitesize = 3 //This is the amount each bite consumes. +/obj/item/reagent_containers/food/snacks/saltedcornchips //Identification path for the object. + name = "salted corn chips" //Name that displays when hovered over. + desc = "Manufactured in a far away factory." //Description on examine. + icon_state = "saltychip" //Refers to an icon, usually in food.dmi + bitesize = 3 //How many reagents are consumed in each bite. + list_reagents = list(/datum/reagent/consumable/nutriment = 6, //What's inside the snack, but only if spawned. For example, from a chemical reaction, vendor, or slime core spawn. + /datum/reagent/consumable/nutriment/vitamin = 2) + bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, //What's -added- to the food, in addition to the reagents contained inside the foods used to craft it. Basically, a reward for cooking. + /datum/reagent/consumable/nutriment/vitamin = 1) ^^For example. Egg+Egg = 2Egg + Bonus Reagents. + filling_color = "#F4A460" //What color it will use if put in a custom food. + tastes = list("salt" = 1, "oil" = 1) //Descriptive flavoring displayed when eaten. IE: "You taste a bit of salt and a bit of oil." + foodtype = GRAIN | JUNKFOOD //Tag for racial or custom food preferences. IE: Most Lizards cannot have GRAIN. + +Crafting Recipe (See files in code/modules/food_and_drinks/recipes/tablecraft/) + +/datum/crafting_recipe/food/nachos + name ="Salted Corn Chips" //Name that displays in the Crafting UI + reqs = list( //The list of ingredients to make the food. + /obj/item/reagent_containers/food/snacks/tortilla = 1, + /datum/reagent/consumable/sodiumchloride = 1 //As a note, reagents and non-food items don't get added to the food. If you + ) ^^want the reagents, make sure the food item has it listed under bonus_reagents. + result = /obj/item/reagent_containers/food/snacks/saltedcornchips //Resulting object. + subcategory = CAT_MISCFOOD //Subcategory the food falls under in the Food Tab of the crafting menu. ``` All foods are distributed among various categories. Use common sense. diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm index 0a3d172bb0..d05f0b334f 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm @@ -134,7 +134,7 @@ God bless America. /obj/machinery/deepfryer/attack_ai(mob/user) return -/obj/machinery/deepfryer/attack_hand(mob/user) +/obj/machinery/deepfryer/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(frying) if(frying.loc == src) to_chat(user, "You eject [frying] from [src].") diff --git a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm index dcea93f06f..53da7326a2 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm @@ -63,7 +63,7 @@ /obj/machinery/gibber/relaymove(mob/living/user) go_out() -/obj/machinery/gibber/attack_hand(mob/user) +/obj/machinery/gibber/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/food_and_drinks/kitchen_machinery/grill.dm b/code/modules/food_and_drinks/kitchen_machinery/grill.dm index 547ed244c0..a5a90b33e4 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/grill.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/grill.dm @@ -107,7 +107,7 @@ /obj/machinery/grill/attack_ai(mob/user) return -/obj/machinery/grill/attack_hand(mob/user) +/obj/machinery/grill/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(grilled_item) to_chat(user, "You take out [grilled_item] from [src].") grilled_item.forceMove(drop_location()) diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm index 891a6abec2..36e3b64487 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm @@ -160,7 +160,7 @@ /obj/machinery/smartfridge/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "smartvend", name, 440, 550, master_ui, state) + ui = new(user, src, ui_key, "SmartVend", name, 440, 550, master_ui, state) ui.set_autoupdate(FALSE) ui.open() diff --git a/code/modules/food_and_drinks/pizzabox.dm b/code/modules/food_and_drinks/pizzabox.dm index 19ded25b08..006c3fb6ad 100644 --- a/code/modules/food_and_drinks/pizzabox.dm +++ b/code/modules/food_and_drinks/pizzabox.dm @@ -107,7 +107,7 @@ update_icon() //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/pizzabox/attack_hand(mob/user) +/obj/item/pizzabox/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(user.get_inactive_held_item() != src) return ..() if(open) diff --git a/code/modules/holiday/halloween/bartholomew.dm b/code/modules/holiday/halloween/bartholomew.dm index 82ac374525..eb90a0c82d 100644 --- a/code/modules/holiday/halloween/bartholomew.dm +++ b/code/modules/holiday/halloween/bartholomew.dm @@ -31,7 +31,7 @@ return say("It doesn't seem like that's magical enough!") -/obj/item/barthpot/attack_hand(mob/user) +/obj/item/barthpot/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(!active) say("Meow!") return diff --git a/code/modules/holiday/halloween/jacqueen.dm b/code/modules/holiday/halloween/jacqueen.dm index 957d9df376..01e71d1129 100644 --- a/code/modules/holiday/halloween/jacqueen.dm +++ b/code/modules/holiday/halloween/jacqueen.dm @@ -406,14 +406,14 @@ . = ..() ADD_TRAIT(src, TRAIT_NODROP, GLUED_ITEM_TRAIT) -/obj/item/clothing/suit/ghost_sheet/sticky/attack_hand(mob/user) +/obj/item/clothing/suit/ghost_sheet/sticky/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(iscarbon(user)) to_chat(user, "Boooooo~!") return else ..() -/obj/item/clothing/suit/ghost_sheet/sticky/attack_hand(mob/user) +/obj/item/clothing/suit/ghost_sheet/sticky/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(iscarbon(user)) to_chat(user, "Boooooo~!") return diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index 65c69b995f..d72e1b1fc8 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -83,7 +83,7 @@ /obj/machinery/computer/holodeck/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "holodeck", name, 400, 500, master_ui, state) + ui = new(user, src, ui_key, "Holodeck", name, 400, 500, master_ui, state) ui.open() /obj/machinery/computer/holodeck/ui_data(mob/user) diff --git a/code/modules/holodeck/items.dm b/code/modules/holodeck/items.dm index c68c5de804..b6c89bcf0e 100644 --- a/code/modules/holodeck/items.dm +++ b/code/modules/holodeck/items.dm @@ -105,7 +105,7 @@ if(user.transferItemToLoc(W, drop_location())) visible_message(" [user] dunks [W] into \the [src]!") -/obj/structure/holohoop/attack_hand(mob/user) +/obj/structure/holohoop/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -219,7 +219,7 @@ /obj/item/paper/fluff/holodeck/trek_diploma name = "paper - Starfleet Academy Diploma" - info = {"

    Starfleet Academy


    Official Diploma


    "} + info = {"__Starfleet Academy__\nOfficial Diploma"} /obj/item/paper/fluff/holodeck/disclaimer name = "Holodeck Disclaimer" diff --git a/code/modules/holodeck/turfs.dm b/code/modules/holodeck/turfs.dm index 7b5b0586d1..f686bee63a 100644 --- a/code/modules/holodeck/turfs.dm +++ b/code/modules/holodeck/turfs.dm @@ -134,7 +134,7 @@ tiled_dirt = FALSE baseturfs = /turf/open/floor/holofloor/snow -/turf/open/floor/holofloor/snow/attack_hand(mob/living/user) +/turf/open/floor/holofloor/snow/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/hydroponics/fermenting_barrel.dm b/code/modules/hydroponics/fermenting_barrel.dm index 11bb44ce97..70e204a14f 100644 --- a/code/modules/hydroponics/fermenting_barrel.dm +++ b/code/modules/hydroponics/fermenting_barrel.dm @@ -56,7 +56,7 @@ else return ..() -/obj/structure/fermenting_barrel/attack_hand(mob/user) +/obj/structure/fermenting_barrel/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) open = !open if(open) DISABLE_BITFIELD(reagents.reagents_holder_flags, DRAINABLE) diff --git a/code/modules/hydroponics/grown/chili.dm b/code/modules/hydroponics/grown/chili.dm index 0522b5fd45..42674029fb 100644 --- a/code/modules/hydroponics/grown/chili.dm +++ b/code/modules/hydroponics/grown/chili.dm @@ -80,7 +80,7 @@ foodtype = FRUIT wine_power = 50 -/obj/item/reagent_containers/food/snacks/grown/ghost_chili/attack_hand(mob/user) +/obj/item/reagent_containers/food/snacks/grown/ghost_chili/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/hydroponics/grown/replicapod.dm b/code/modules/hydroponics/grown/replicapod.dm index aeddf771b8..78fddbd989 100644 --- a/code/modules/hydroponics/grown/replicapod.dm +++ b/code/modules/hydroponics/grown/replicapod.dm @@ -115,7 +115,7 @@ features["mcolor"] = "#59CE00" for(var/V in quirks) new V(podman) - podman.hardset_dna(null,null,podman.real_name,blood_type, new /datum/species/pod,features)//Discard SE's and UI's, podman cloning is inaccurate, and always make them a podman + podman.hardset_dna(null,null,null,podman.real_name,blood_type, new /datum/species/pod,features)//Discard SE's and UI's, podman cloning is inaccurate, and always make them a podman podman.set_cloned_appearance() else //else, one packet of seeds. maybe two diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm index 28ae5f4b69..55adab9dcb 100644 --- a/code/modules/hydroponics/grown/towercap.dm +++ b/code/modules/hydroponics/grown/towercap.dm @@ -205,7 +205,7 @@ return ..() -/obj/structure/bonfire/attack_hand(mob/user) +/obj/structure/bonfire/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index b7665d7b5d..b673937c9c 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -888,7 +888,7 @@ return ..() -/obj/machinery/hydroponics/attack_hand(mob/user) +/obj/machinery/hydroponics/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/integrated_electronics/core/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm index 384991e976..c3e0a7abcc 100644 --- a/code/modules/integrated_electronics/core/assemblies.dm +++ b/code/modules/integrated_electronics/core/assemblies.dm @@ -611,7 +611,7 @@ return ..() -/obj/item/electronic_assembly/attack_hand(mob/user) +/obj/item/electronic_assembly/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(anchored) attack_self(user) return diff --git a/code/modules/integrated_electronics/subtypes/output.dm b/code/modules/integrated_electronics/subtypes/output.dm index 47b6e151cb..efd98c4d50 100644 --- a/code/modules/integrated_electronics/subtypes/output.dm +++ b/code/modules/integrated_electronics/subtypes/output.dm @@ -35,7 +35,7 @@ stuff_to_display = replacetext("[I.data]", eol , "
    ") /obj/item/integrated_circuit/output/screen/large - name = "large screen" + name = "medium screen" desc = "Takes any data type as an input and displays it to anybody near the device when pulsed. \ It can also be examined to see the last thing it displayed." icon_state = "screen_medium" @@ -51,15 +51,29 @@ else if(!isturf(assembly.loc)) return + + var/atom/host = assembly || src + var/list/mobs = list() + for(var/mob/M in range(0, get_turf(src))) + mobs += M + to_chat(mobs, "[icon2html(host.icon, world, host.icon_state)] flashes a message: [stuff_to_display]") + host.investigate_log("displayed \"[html_encode(stuff_to_display)]\" as [type].", INVESTIGATE_CIRCUIT) - var/list/nearby_things = range(0, get_turf(src)) - for(var/mob/M in nearby_things) - var/obj/O = assembly ? assembly : src - to_chat(M, "[icon2html(O.icon, world, O.icon_state)] [stuff_to_display]") - if(assembly) - assembly.investigate_log("displayed \"[html_encode(stuff_to_display)]\" with [type].", INVESTIGATE_CIRCUIT) - else - investigate_log("displayed \"[html_encode(stuff_to_display)]\" as [type].", INVESTIGATE_CIRCUIT) +/obj/item/integrated_circuit/output/screen/extralarge // the subtype is called "extralarge" because tg brought back medium screens and they named the subtype /screen/large + name = "large screen" + desc = "Takes any data type as an input and displays it to the user upon examining, and to all nearby beings when pulsed." + icon_state = "screen_large" + power_draw_per_use = 40 + cooldown_per_use = 10 + +/obj/item/integrated_circuit/output/screen/extralarge/do_work() + ..() + var/atom/host = assembly || src + var/list/mobs = list() + for(var/mob/M in viewers(7, get_turf(src))) + mobs += M + to_chat(mobs, "[icon2html(host.icon, world, host.icon_state)] flashes a message: [stuff_to_display]") + host.investigate_log("displayed \"[html_encode(stuff_to_display)]\" as [type].", INVESTIGATE_CIRCUIT) /obj/item/integrated_circuit/output/light name = "light" @@ -389,25 +403,4 @@ //Hippie Ported Code-------------------------------------------------------------------------------------------------------- - - /obj/item/radio/headset/integrated - -/obj/item/integrated_circuit/output/screen/large - name = "medium screen" - -/obj/item/integrated_circuit/output/screen/extralarge // the subtype is called "extralarge" because tg brought back medium screens and they named the subtype /screen/large - name = "large screen" - desc = "Takes any data type as an input and displays it to the user upon examining, and to all nearby beings when pulsed." - icon_state = "screen_large" - power_draw_per_use = 40 - cooldown_per_use = 10 - -/obj/item/integrated_circuit/output/screen/extralarge/do_work() - ..() - var/obj/O = assembly ? get_turf(assembly) : loc - O.visible_message("[icon2html(O.icon, world, O.icon_state)] [stuff_to_display]") - if(assembly) - assembly.investigate_log("displayed \"[html_encode(stuff_to_display)]\" with [type].", INVESTIGATE_CIRCUIT) - else - investigate_log("displayed \"[html_encode(stuff_to_display)]\" as [type].", INVESTIGATE_CIRCUIT) diff --git a/code/modules/integrated_electronics/subtypes/reagents.dm b/code/modules/integrated_electronics/subtypes/reagents.dm index 663ba9fe16..991c806f43 100644 --- a/code/modules/integrated_electronics/subtypes/reagents.dm +++ b/code/modules/integrated_electronics/subtypes/reagents.dm @@ -514,6 +514,8 @@ outputs = list("volume used" = IC_PINTYPE_NUMBER,"self reference" = IC_PINTYPE_SELFREF,"temperature" = IC_PINTYPE_NUMBER) spawn_flags = IC_SPAWN_RESEARCH var/heater_coefficient = 0.1 + var/max_temp = 1000 + var/min_temp = 2.7 /obj/item/integrated_circuit/reagent/storage/heater/on_data_written() if(get_pin_data(IC_INPUT, 2)) @@ -531,7 +533,7 @@ /obj/item/integrated_circuit/reagent/storage/heater/process() if(power_draw_idle) - var/target_temperature = get_pin_data(IC_INPUT, 1) + var/target_temperature = clamp(get_pin_data(IC_INPUT, 1), min_temp, max_temp) if(reagents.chem_temp > target_temperature) reagents.chem_temp += min(-1, (target_temperature - reagents.chem_temp) * heater_coefficient) if(reagents.chem_temp < target_temperature) @@ -795,4 +797,4 @@ ..() if(istype(loc,/obj/item/integrated_circuit/input/beaker_connector)) var/obj/item/integrated_circuit/input/beaker_connector/current_circuit = loc - current_circuit.push_vol() \ No newline at end of file + current_circuit.push_vol() diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index c700d668c5..bd36218211 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -203,21 +203,24 @@ var/pda_slot = SLOT_BELT /datum/outfit/job/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source) - switch(preference_source?.prefs.backbag) - if(GBACKPACK) - back = /obj/item/storage/backpack //Grey backpack - if(GSATCHEL) - back = /obj/item/storage/backpack/satchel //Grey satchel - if(GDUFFELBAG) - back = /obj/item/storage/backpack/duffelbag //Grey Duffel bag - if(LSATCHEL) - back = /obj/item/storage/backpack/satchel/leather //Leather Satchel - if(DSATCHEL) - back = satchel //Department satchel - if(DDUFFELBAG) - back = duffelbag //Department duffel bag - else - back = backpack //Department backpack + var/preference_backpack = preference_source?.prefs.backbag + + if(preference_backpack) + switch(preference_backpack) + if(DBACKPACK) + back = backpack //Department backpack + if(DSATCHEL) + back = satchel //Department satchel + if(DDUFFELBAG) + back = duffelbag //Department duffel bag + else + var/find_preference_backpack = GLOB.backbaglist[preference_backpack] //attempt to find non-department backpack + if(find_preference_backpack) + back = find_preference_backpack + else //tried loading in a backpack that we don't allow as a loadout one + back = backpack + else //somehow doesn't have a preference set, should never reach this point but just-in-case + back = backpack //converts the uniform string into the path we'll wear, whether it's the skirt or regular variant var/holder diff --git a/code/modules/keybindings/keybind/combat.dm b/code/modules/keybindings/keybind/combat.dm index 8a0e713d8f..c4b44b5283 100644 --- a/code/modules/keybindings/keybind/combat.dm +++ b/code/modules/keybindings/keybind/combat.dm @@ -26,6 +26,7 @@ L.keybind_stop_active_blocking() /datum/keybinding/living/active_block_toggle + hotkey_keys = list("Unbound") name = "active_block_toggle" full_name = "Block (Toggle)" category = CATEGORY_COMBAT diff --git a/code/modules/language/language_menu.dm b/code/modules/language/language_menu.dm index a7ce211a18..0df7c01fca 100644 --- a/code/modules/language/language_menu.dm +++ b/code/modules/language/language_menu.dm @@ -11,7 +11,7 @@ /datum/language_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.language_menu_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "language_menu", "Language Menu", 700, 600, master_ui, state) + ui = new(user, src, ui_key, "LanguageMenu", "Language Menu", 700, 600, master_ui, state) ui.open() /datum/language_menu/ui_data(mob/user) diff --git a/code/modules/library/lib_codex_gigas.dm b/code/modules/library/lib_codex_gigas.dm index 57bf37d528..146c4221f8 100644 --- a/code/modules/library/lib_codex_gigas.dm +++ b/code/modules/library/lib_codex_gigas.dm @@ -99,7 +99,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "codex_gigas", name, 450, 450, master_ui, state) + ui = new(user, src, ui_key, "CodexGigas", name, 450, 450, master_ui, state) ui.open() /obj/item/book/codex_gigas/ui_data(mob/user) diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm index 89fa3ac6cf..e5d9672d4a 100644 --- a/code/modules/library/lib_items.dm +++ b/code/modules/library/lib_items.dm @@ -112,7 +112,7 @@ else return ..() -/obj/structure/bookcase/attack_hand(mob/living/user) +/obj/structure/bookcase/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(. || !istype(user)) return diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm index 144037b3a7..f65ea27216 100644 --- a/code/modules/library/lib_machines.dm +++ b/code/modules/library/lib_machines.dm @@ -523,7 +523,7 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums else return ..() -/obj/machinery/libraryscanner/attack_hand(mob/user) +/obj/machinery/libraryscanner/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/library/soapstone.dm b/code/modules/library/soapstone.dm index 272e39957e..50f984c44d 100644 --- a/code/modules/library/soapstone.dm +++ b/code/modules/library/soapstone.dm @@ -209,7 +209,7 @@ /obj/structure/chisel_message/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "engraved_message", name, 600, 300, master_ui, state) + ui = new(user, src, ui_key, "EngravedMessage", name, 600, 300, master_ui, state) ui.open() /obj/structure/chisel_message/ui_data(mob/user) diff --git a/code/modules/lighting/lighting_area.dm b/code/modules/lighting/lighting_area.dm index 58e9a4337a..7e54456483 100644 --- a/code/modules/lighting/lighting_area.dm +++ b/code/modules/lighting/lighting_area.dm @@ -24,7 +24,7 @@ /area/vv_edit_var(var_name, var_value) switch(var_name) - if("dynamic_lighting") + if(NAMEOF(src, dynamic_lighting)) set_dynamic_lighting(var_value) return TRUE - return ..() \ No newline at end of file + return ..() diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm index 779dd9c3ea..71702bef12 100644 --- a/code/modules/lighting/lighting_atom.dm +++ b/code/modules/lighting/lighting_atom.dm @@ -89,17 +89,17 @@ /atom/vv_edit_var(var_name, var_value) switch (var_name) - if ("light_range") + if (NAMEOF(src, light_range)) set_light(l_range=var_value) datum_flags |= DF_VAR_EDITED return TRUE - if ("light_power") + if (NAMEOF(src, light_power)) set_light(l_power=var_value) datum_flags |= DF_VAR_EDITED return TRUE - if ("light_color") + if (NAMEOF(src, light_color)) set_light(l_color=var_value) datum_flags |= DF_VAR_EDITED return TRUE diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm index 94f5be65bf..d2da0f779e 100644 --- a/code/modules/mining/abandoned_crates.dm +++ b/code/modules/mining/abandoned_crates.dm @@ -150,7 +150,7 @@ new /obj/item/clothing/head/bearpelt(src) //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/structure/closet/crate/secure/loot/attack_hand(mob/user) +/obj/structure/closet/crate/secure/loot/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(locked) to_chat(user, "The crate is locked with a Deca-code lock.") var/input = input(usr, "Enter [codelen] digits. All digits must be unique.", "Deca-Code Lock", "") as text diff --git a/code/modules/mining/aux_base.dm b/code/modules/mining/aux_base.dm index 6ec205bf7c..bf7a966f7d 100644 --- a/code/modules/mining/aux_base.dm +++ b/code/modules/mining/aux_base.dm @@ -92,6 +92,7 @@ interface with the mining shuttle at the landing site if a mobile beacon is also say("Launch sequence activated! Prepare for drop!!") playsound(loc, 'sound/machines/warning-buzzer.ogg', 70, 0) launch_warning = FALSE + log_shuttle("[key_name(usr)] has launched the auxillary base.") else if(!shuttle_error) say("Shuttle request uploaded. Please stand away from the doors.") else @@ -274,7 +275,7 @@ interface with the mining shuttle at the landing site if a mobile beacon is also var/anti_spam_cd = 0 //The linking process might be a bit intensive, so this here to prevent over use. var/console_range = 15 //Wifi range of the beacon to find the aux base console -/obj/structure/mining_shuttle_beacon/attack_hand(mob/user) +/obj/structure/mining_shuttle_beacon/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/mining/equipment/marker_beacons.dm b/code/modules/mining/equipment/marker_beacons.dm index 8853a56911..ae2889e8a2 100644 --- a/code/modules/mining/equipment/marker_beacons.dm +++ b/code/modules/mining/equipment/marker_beacons.dm @@ -19,7 +19,7 @@ GLOBAL_LIST_INIT(marker_beacon_colors, list( singular_name = "marker beacon" desc = "Prism-brand path illumination devices. Used by miners to mark paths and warn of danger." icon = 'icons/obj/lighting.dmi' - icon_state = "marker" + icon_state = "markerbronze" merge_type = /obj/item/stack/marker_beacon max_amount = 100 novariants = TRUE @@ -103,7 +103,7 @@ GLOBAL_LIST_INIT(marker_beacon_colors, list( icon_state = "[initial(icon_state)][lowertext(picked_color)]-on" set_light(light_range, light_power, GLOB.marker_beacon_colors[picked_color]) -/obj/structure/marker_beacon/attack_hand(mob/living/user) +/obj/structure/marker_beacon/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm index ab0356aa66..79d138f290 100644 --- a/code/modules/mining/equipment/survival_pod.dm +++ b/code/modules/mining/equipment/survival_pod.dm @@ -167,7 +167,7 @@ qdel(src) return TRUE -/obj/item/gps/computer/attack_hand(mob/user) +/obj/item/gps/computer/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -318,4 +318,4 @@ icon = initial(I.icon) desc = initial(I.desc) icon_state = initial(I.icon_state) - item_state = initial(I.item_state) \ No newline at end of file + item_state = initial(I.item_state) diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm index 14a277a66c..c0d63fab9c 100644 --- a/code/modules/mining/laborcamp/laborstacker.dm +++ b/code/modules/mining/laborcamp/laborstacker.dm @@ -8,6 +8,9 @@ GLOBAL_LIST(labor_sheet_values) icon = 'icons/obj/machines/mining_machines.dmi' icon_state = "console" density = FALSE + ui_x = 315 + ui_y = 430 + var/obj/machinery/mineral/stacking_machine/laborstacker/stacking_machine = null var/machinedir = SOUTH var/obj/machinery/door/airlock/release_door @@ -36,7 +39,7 @@ GLOBAL_LIST(labor_sheet_values) datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "labor_claim_console", name, 315, 430, master_ui, state) + ui = new(user, src, ui_key, "LaborClaimConsole", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/mineral/labor_claim_console/ui_data(mob/user) @@ -100,7 +103,6 @@ GLOBAL_LIST(labor_sheet_values) Radio.talk_into(src, "A prisoner has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY) to_chat(usr, "Shuttle received message and will be sent shortly.") . = TRUE - /obj/machinery/mineral/labor_claim_console/proc/locate_stacking_machine() stacking_machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir)) @@ -110,12 +112,9 @@ GLOBAL_LIST(labor_sheet_values) qdel(src) /obj/machinery/mineral/labor_claim_console/emag_act(mob/user) - . = ..() - if(obj_flags & EMAGGED) - return - obj_flags |= EMAGGED - to_chat(user, "PZZTTPFFFT") - return TRUE + if(!(obj_flags & EMAGGED)) + obj_flags |= EMAGGED + to_chat(user, "PZZTTPFFFT") /**********************Prisoner Collection Unit**************************/ @@ -142,7 +141,7 @@ GLOBAL_LIST(labor_sheet_values) icon_state = "console" density = FALSE -/obj/machinery/mineral/labor_points_checker/attack_hand(mob/user) +/obj/machinery/mineral/labor_points_checker/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/mining/lavaland/ash_flora.dm b/code/modules/mining/lavaland/ash_flora.dm index 38830fd824..e39b833793 100644 --- a/code/modules/mining/lavaland/ash_flora.dm +++ b/code/modules/mining/lavaland/ash_flora.dm @@ -62,7 +62,7 @@ else return ..() -/obj/structure/flora/ash/attack_hand(mob/user) +/obj/structure/flora/ash/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index e611ccf232..3b5ff71705 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -1104,7 +1104,7 @@ var/blast_range = 13 //how long the cardinal blast's walls are var/obj/effect/hierophant/beacon //the associated beacon we teleport to var/teleporting = FALSE //if we ARE teleporting - var/friendly_fire_check = FALSE //if the blasts we make will consider our faction against the faction of hit targets + var/friendly_fire_check = TRUE //if the blasts we make will consider our faction against the faction of hit targets /obj/item/hierophant_club/ComponentInitialize() . = ..() diff --git a/code/modules/mining/lavaland/ruins/gym.dm b/code/modules/mining/lavaland/ruins/gym.dm index 1c535fd9ab..d454c3d118 100644 --- a/code/modules/mining/lavaland/ruins/gym.dm +++ b/code/modules/mining/lavaland/ruins/gym.dm @@ -29,7 +29,7 @@ /obj/structure/weightmachine/proc/AnimateMachine(mob/living/user) return -/obj/structure/weightmachine/attack_hand(mob/living/user) +/obj/structure/weightmachine/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -92,4 +92,4 @@ sleep(3) animate(user, pixel_y = 2, time = 3) sleep(3) - cut_overlay(swole_overlay) \ No newline at end of file + cut_overlay(swole_overlay) diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm index 512fa8f3e4..851d78004b 100644 --- a/code/modules/mining/machine_processing.dm +++ b/code/modules/mining/machine_processing.dm @@ -3,9 +3,54 @@ /**********************Mineral processing unit console**************************/ /obj/machinery/mineral + speed_process = TRUE + init_process = FALSE + /// The current direction of `input_turf`, in relation to the machine. var/input_dir = NORTH + /// The current direction, in relation to the machine, that items will be output to. var/output_dir = SOUTH + /// The turf the machines listens to for items to pick up. Calls the `pickup_item()` proc. + var/turf/input_turf = null + /// Determines if this machine needs to pick up items. Used to avoid registering signals to `/mineral` machines that don't pickup items. + var/needs_item_input = FALSE +/obj/machinery/mineral/Initialize(mapload) + . = ..() + if(needs_item_input && anchored) + register_input_turf() + +/// Gets the turf in the `input_dir` direction adjacent to the machine, and registers signals for ATOM_ENTERED and ATOM_CREATED. Calls the `pickup_item()` proc when it receives these signals. +/obj/machinery/mineral/proc/register_input_turf() + input_turf = get_step(src, input_dir) + if(input_turf) // make sure there is actually a turf + RegisterSignal(input_turf, list(COMSIG_ATOM_CREATED, COMSIG_ATOM_ENTERED), .proc/pickup_item) + +/// Unregisters signals that are registered the machine's input turf, if it has one. +/obj/machinery/mineral/proc/unregister_input_turf() + if(input_turf) + UnregisterSignal(input_turf, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_CREATED)) + +/obj/machinery/mineral/Moved() + . = ..() + if(!needs_item_input || !anchored) + return + unregister_input_turf() + register_input_turf() + +/** + Base proc for all `/mineral` subtype machines to use. Place your item pickup behavior in this proc when you override it for your specific machine. + + Called when the COMSIG_ATOM_ENTERED and COMSIG_ATOM_CREATED signals are sent. + + Arguments: + * source - the turf that is listening for the signals. + * target - the atom that just moved onto the `source` turf. + * oldLoc - the old location that `target` was at before moving onto `source`. +*/ +/obj/machinery/mineral/proc/pickup_item(datum/source, atom/movable/target, atom/oldLoc) + return + +/// Generic unloading proc. Takes an atom as an argument and forceMove's it to the turf adjacent to this machine in the `output_dir` direction. /obj/machinery/mineral/proc/unload_mineral(atom/movable/S) S.forceMove(drop_location()) var/turf/T = get_step(src,output_dir) @@ -19,7 +64,6 @@ density = TRUE var/obj/machinery/mineral/processing_unit/machine = null var/machinedir = EAST - speed_process = TRUE /obj/machinery/mineral/processing_unit_console/Initialize() . = ..() @@ -58,6 +102,7 @@ if(href_list["set_on"]) machine.on = (href_list["set_on"] == "on") + START_PROCESSING(SSmachines, machine) updateUsrDialog() return @@ -75,6 +120,7 @@ icon = 'icons/obj/machines/mining_machines.dmi' icon_state = "furnace" density = TRUE + needs_item_input = TRUE var/obj/machinery/mineral/CONSOLE = null var/on = FALSE var/datum/material/selected_material = null @@ -93,11 +139,10 @@ QDEL_NULL(stored_research) return ..() -/obj/machinery/mineral/processing_unit/HasProximity(atom/movable/AM) - if(istype(AM, /obj/item/stack/ore) && AM.loc == get_step(src, input_dir)) - process_ore(AM) /obj/machinery/mineral/processing_unit/proc/process_ore(obj/item/stack/ore/O) + if(QDELETED(O)) + return var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) var/material_amount = materials.get_item_material_amount(O) if(!materials.has_space(material_amount)) @@ -142,8 +187,14 @@ return dat +/obj/machinery/mineral/processing_unit/pickup_item(datum/source, atom/movable/target, atom/oldLoc) + if(QDELETED(target)) + return + if(istype(target, /obj/item/stack/ore)) + process_ore(target) + /obj/machinery/mineral/processing_unit/process() - if (on) + if(on) if(selected_material) smelt_ore() @@ -153,6 +204,8 @@ if(CONSOLE) CONSOLE.updateUsrDialog() + else + STOP_PROCESSING(SSmachines, src) /obj/machinery/mineral/processing_unit/proc/smelt_ore() var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm index a7b7a84b27..bae0e94032 100644 --- a/code/modules/mining/machine_redemption.dm +++ b/code/modules/mining/machine_redemption.dm @@ -57,6 +57,8 @@ . += "The status display reads: Smelting [ore_multiplier] sheet(s) per piece of ore.
    Reward point generation at [point_upgrade*100]%.
    Ore pickup speed at [ore_pickup_rate].
    " /obj/machinery/mineral/ore_redemption/proc/smelt_ore(obj/item/stack/ore/O) + if(QDELETED(O)) + return var/datum/component/material_container/mat_container = materials.mat_container if (!mat_container) return @@ -196,7 +198,7 @@ /obj/machinery/mineral/ore_redemption/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "ore_redemption_machine", "Ore Redemption Machine", 440, 550, master_ui, state) + ui = new(user, src, ui_key, "OreRedemptionMachine", "Ore Redemption Machine", 440, 550, master_ui, state) ui.open() /obj/machinery/mineral/ore_redemption/ui_data(mob/user) diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machine_stacking.dm index 5a83955bce..a5ff27e75e 100644 --- a/code/modules/mining/machine_stacking.dm +++ b/code/modules/mining/machine_stacking.dm @@ -92,6 +92,8 @@ return ..() /obj/machinery/mineral/stacking_machine/HasProximity(atom/movable/AM) + if(QDELETED(AM)) + return if(istype(AM, /obj/item/stack/sheet) && AM.loc == get_step(src, input_dir)) process_sheet(AM) @@ -104,6 +106,8 @@ return TRUE /obj/machinery/mineral/stacking_machine/proc/process_sheet(obj/item/stack/sheet/inp) + if(QDELETED(inp)) + return var/key = inp.merge_type var/obj/item/stack/sheet/storage = stack_list[key] if(!storage) //It's the first of this sheet added diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm index dd317c5b23..b00e291685 100644 --- a/code/modules/mining/machine_vending.dm +++ b/code/modules/mining/machine_vending.dm @@ -7,6 +7,8 @@ icon_state = "mining" density = TRUE circuit = /obj/item/circuitboard/machine/mining_equipment_vendor + ui_x = 425 + ui_y = 600 var/icon_deny = "mining-deny" var/obj/item/card/id/inserted_id var/list/prize_list = list( //if you add something to this, please, for the love of god, sort it by price/type. use tabs and not spaces. @@ -84,9 +86,14 @@ src.equipment_path = path src.cost = cost -/obj/machinery/mineral/equipment_vendor/power_change() - ..() - update_icon() +/obj/machinery/mineral/equipment_vendor/Initialize() + . = ..() + build_inventory() + +/obj/machinery/mineral/equipment_vendor/proc/build_inventory() + for(var/p in prize_list) + var/datum/data/mining_equipment/M = p + GLOB.vending_products[M.equipment_path] = 1 /obj/machinery/mineral/equipment_vendor/update_icon_state() if(powered()) @@ -94,44 +101,82 @@ else icon_state = "[initial(icon_state)]-off" -/obj/machinery/mineral/equipment_vendor/ui_interact(mob/user) - . = ..() - var/list/dat = list() - dat += "
    Equipment point cost list:
    " +/obj/machinery/mineral/equipment_vendor/ui_base_html(html) + var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/vending) + . = replacetext(html, "", assets.css_tag()) + +/obj/machinery/mineral/equipment_vendor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/vending) + assets.send(user) + ui = new(user, src, ui_key, "MiningVendor", name, ui_x, ui_y, master_ui, state) + ui.open() + +/obj/machinery/mineral/equipment_vendor/ui_static_data(mob/user) + . = list() + .["product_records"] = list() for(var/datum/data/mining_equipment/prize in prize_list) - dat += "" - dat += "
    [prize.equipment_name][prize.cost]Purchase
    " + var/list/product_data = list( + path = replacetext(replacetext("[prize.equipment_path]", "/obj/item/", ""), "/", "-"), + name = prize.equipment_name, + price = prize.cost, + ref = REF(prize) + ) + .["product_records"] += list(product_data) - var/datum/browser/popup = new(user, "miningvendor", "Mining Equipment Vendor", 400, 350) - popup.set_content(dat.Join()) - popup.open() - return +/obj/machinery/mineral/equipment_vendor/ui_data(mob/user) + . = list() + var/mob/living/carbon/human/H + var/obj/item/card/id/C + if(ishuman(user)) + H = user + C = H.get_idcard(TRUE) + if(C) + .["user"] = list() + .["user"]["points"] = C.mining_points + if(C.assignment) + .["user"]["job"] = C.assignment + else + .["user"]["job"] = "No Job" -/obj/machinery/mineral/equipment_vendor/Topic(href, href_list) +/obj/machinery/mineral/equipment_vendor/ui_act(action, params) if(..()) return - if(href_list["purchase"]) - var/mob/M = usr - var/obj/item/card/id/I = M.get_idcard(TRUE) - if(istype(I)) - var/datum/data/mining_equipment/prize = locate(href_list["purchase"]) in prize_list - if (!prize || !(prize in prize_list)) - to_chat(usr, "Error: Invalid choice!") + + switch(action) + if("purchase") + var/mob/M = usr + var/obj/item/card/id/I = M.get_idcard(TRUE) + if(!istype(I)) + to_chat(usr, "Error: An ID is required!") + flick(icon_deny, src) + return + var/datum/data/mining_equipment/prize = locate(params["ref"]) in prize_list + if(!prize || !(prize in prize_list)) + to_chat(usr, "Error: Invalid choice!") flick(icon_deny, src) return if(prize.cost > I.mining_points) - to_chat(usr, "Error: Insufficient credits for [prize.equipment_name] on [I]!") + to_chat(usr, "Error: Insufficient points for [prize.equipment_name] on [I]!") flick(icon_deny, src) - else - I.mining_points -= prize.cost - to_chat(usr, "[src] clanks to life briefly before vending [prize.equipment_name]!") - new prize.equipment_path(src.loc) - SSblackbox.record_feedback("nested tally", "mining_equipment_bought", 1, list("[type]", "[prize.equipment_path]")) - else - to_chat(usr, "Error: An ID with a registered account is required!") - flick(icon_deny, src) - updateUsrDialog() - return + return + I.mining_points -= prize.cost + to_chat(usr, "[src] clanks to life briefly before vending [prize.equipment_name]!") + new prize.equipment_path(loc) + SSblackbox.record_feedback("nested tally", "mining_equipment_bought", 1, list("[type]", "[prize.equipment_path]")) + . = TRUE + +/obj/machinery/mineral/equipment_vendor/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/mining_voucher)) + RedeemVoucher(I, user) + return + if(default_deconstruction_screwdriver(user, "mining-open", "mining", I)) + return + if(default_deconstruction_crowbar(I)) + return + return ..() /obj/machinery/mineral/equipment_vendor/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/mining_voucher)) diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index f10229f4bf..6567793b80 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -80,7 +80,7 @@ var/static/list/dumb_rev_heads = list() //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/machinery/computer/shuttle/mining/attack_hand(mob/user) +/obj/machinery/computer/shuttle/mining/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(is_station_level(user.z) && user.mind && is_head_revolutionary(user) && !(user.mind in dumb_rev_heads)) to_chat(user, "You get a feeling that leaving the station might be a REALLY dumb idea...") dumb_rev_heads += user.mind diff --git a/code/modules/mining/mint.dm b/code/modules/mining/mint.dm index e89bbef58d..57a79553c3 100644 --- a/code/modules/mining/mint.dm +++ b/code/modules/mining/mint.dm @@ -6,11 +6,14 @@ icon = 'icons/obj/economy.dmi' icon_state = "coinpress0" density = TRUE - var/newCoins = 0 //how many coins the machine made in it's last load + input_dir = EAST + ui_x = 300 + ui_y = 250 + needs_item_input = TRUE + var/obj/item/storage/bag/money/bag_to_use + var/produced_coins = 0 // how many coins the machine has made in it's last cycle var/processing = FALSE var/chosen = /datum/material/iron //which material will be used to make coins - var/coinsToProduce = 10 - speed_process = TRUE /obj/machinery/mineral/mint/Initialize() @@ -28,89 +31,105 @@ /datum/material/mythril, /datum/material/plastic, /datum/material/runite - ), MINERAL_MATERIAL_AMOUNT * 50, FALSE, /obj/item/stack) - chosen = SSmaterials.GetMaterialRef(chosen) + ), MINERAL_MATERIAL_AMOUNT * 75, FALSE, /obj/item/stack) + chosen = SSmaterials.GetMaterialRef(chosen) -/obj/machinery/mineral/mint/process() - var/turf/T = get_step(src, input_dir) - if(!T) + +/obj/machinery/mineral/mint/pickup_item(datum/source, atom/movable/target, atom/oldLoc) + if(QDELETED(target)) + return + if(!istype(target, /obj/item/stack)) return var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - for(var/obj/item/stack/sheet/O in T) - var/inserted = materials.insert_item(O) - if(inserted) - qdel(O) + var/obj/item/stack/S = target -/obj/machinery/mineral/mint/attack_hand(mob/user) + if(materials.insert_item(S)) + qdel(S) + +/obj/machinery/mineral/mint/process() + if(processing) + var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) + var/datum/material/M = chosen + + if(!M) + processing = FALSE + icon_state = "coinpress0" + return + + icon_state = "coinpress1" + var/coin_mat = MINERAL_MATERIAL_AMOUNT + + for(var/sheets in 1 to 2) + if(materials.use_amount_mat(coin_mat, chosen)) + for(var/coin_to_make in 1 to 5) + create_coins() + produced_coins++ + CHECK_TICK + else + var/found_new = FALSE + for(var/datum/material/inserted_material in materials.materials) + var/amount = materials.get_material_amount(inserted_material) + + if(amount) + chosen = inserted_material + found_new = TRUE + + if(!found_new) + processing = FALSE + else + STOP_PROCESSING(SSmachines, src) + icon_state = "coinpress0" + +/obj/machinery/mineral/mint/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "Mint", name, ui_x, ui_y, master_ui, state) + ui.open() + +/obj/machinery/mineral/mint/ui_data() + var/list/data = list() + data["inserted_materials"] = list() + data["chosen_material"] = null + + var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) + for(var/datum/material/inserted_material in materials.materials) + var/amount = materials.get_material_amount(inserted_material) + if(!amount) + continue + data["inserted_materials"] += list(list( + "material" = inserted_material.name, + "amount" = amount, + )) + if(chosen == inserted_material) + data["chosen_material"] = inserted_material.name + + data["produced_coins"] = produced_coins + data["processing"] = processing + + return data; + +/obj/machinery/mineral/mint/ui_act(action, params, datum/tgui/ui) . = ..() if(.) return - var/dat = "Coin Press
    " - - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - for(var/datum/material/M in materials.materials) - var/amount = materials.get_material_amount(M) - if(!amount && chosen != M) - continue - dat += "
    [M.name] amount: [amount] cm3 " - if (chosen == M) - dat += "Chosen" - else - dat += "Choose" - - var/datum/material/M = chosen - - dat += "

    Will produce [coinsToProduce] [lowertext(M.name)] coins if enough materials are available.
    " - dat += "-10 " - dat += "-5 " - dat += "-1 " - dat += "+1 " - dat += "+5 " - dat += "+10 " - - dat += "

    In total this machine produced [newCoins] coins." - dat += "
    Make coins" - user << browse(dat, "window=mint") - -/obj/machinery/mineral/mint/Topic(href, href_list) - if(..()) - return - usr.set_machine(src) - src.add_fingerprint(usr) - if(processing==1) - to_chat(usr, "The machine is processing.") - return - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - if(href_list["choose"]) - var/datum/material/new_material = locate(href_list["choose"]) - if(istype(new_material)) - chosen = new_material - if(href_list["chooseAmt"]) - coinsToProduce = clamp(coinsToProduce + text2num(href_list["chooseAmt"]), 0, 1000) - updateUsrDialog() - if(href_list["makeCoins"]) - var/temp_coins = coinsToProduce + if(action == "startpress") + if (!processing) + produced_coins = 0 processing = TRUE - icon_state = "coinpress1" - var/coin_mat = MINERAL_MATERIAL_AMOUNT * 0.2 - var/datum/material/M = chosen - if(!M) - updateUsrDialog() - return - - while(coinsToProduce > 0 && materials.use_amount_mat(coin_mat, chosen)) - create_coins() - coinsToProduce-- - newCoins++ - src.updateUsrDialog() - sleep(5) - - icon_state = "coinpress0" + START_PROCESSING(SSmachines, src) + return TRUE + if (action == "stoppress") processing = FALSE - coinsToProduce = temp_coins - src.updateUsrDialog() - return + STOP_PROCESSING(SSmachines, src) + return TRUE + if (action == "changematerial") + var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) + for(var/datum/material/mat in materials.materials) + if (params["material_name"] == mat.name) + chosen = mat + return TRUE /obj/machinery/mineral/mint/proc/create_coins() var/turf/T = get_step(src,output_dir) @@ -118,9 +137,10 @@ temp_list[chosen] = 400 if(T) var/obj/item/O = new /obj/item/coin(src) - var/obj/item/storage/bag/money/B = locate(/obj/item/storage/bag/money, T) O.set_custom_materials(temp_list) - if(!B) - B = new /obj/item/storage/bag/money(src) - unload_mineral(B) - O.forceMove(B) + if(QDELETED(bag_to_use) || (bag_to_use.loc != T) || !SEND_SIGNAL(bag_to_use, COMSIG_TRY_STORAGE_INSERT, O, null, TRUE)) //important to send the signal so we don't overfill the bag. + bag_to_use = new(src) //make a new bag if we can't find or use the old one. + unload_mineral(bag_to_use) //just forcemove memes. + O.forceMove(bag_to_use) //don't bother sending the signal, the new bag is empty and all that. + + SSblackbox.record_feedback("amount", "coins_minted", 1) diff --git a/code/modules/mining/money_bag.dm b/code/modules/mining/money_bag.dm index 66f99ec40c..7dd13a6fc1 100644 --- a/code/modules/mining/money_bag.dm +++ b/code/modules/mining/money_bag.dm @@ -24,4 +24,8 @@ new /obj/item/coin/silver(src) new /obj/item/coin/gold(src) new /obj/item/coin/gold(src) - new /obj/item/coin/adamantine(src) \ No newline at end of file + new /obj/item/coin/adamantine(src) + +/obj/item/storage/bag/money/c5000/PopulateContents() + for(var/i = 0, i < 5, i++) + new /obj/item/stack/spacecash/c1000(src) \ No newline at end of file diff --git a/code/modules/mining/satchel_ore_boxdm.dm b/code/modules/mining/satchel_ore_boxdm.dm index 1d803371be..f9d18fecc2 100644 --- a/code/modules/mining/satchel_ore_boxdm.dm +++ b/code/modules/mining/satchel_ore_boxdm.dm @@ -9,6 +9,9 @@ density = TRUE pressure_resistance = 5*ONE_ATMOSPHERE + var/ui_x = 335 + var/ui_y = 415 + /obj/structure/ore_box/attackby(obj/item/W, mob/user, params) if (istype(W, /obj/item/stack/ore)) user.transferItemToLoc(W, src) @@ -24,18 +27,18 @@ /obj/structure/ore_box/crowbar_act(mob/living/user, obj/item/I) if(I.use_tool(src, user, 50, volume=50)) - user.visible_message("[user] pries \the [src] apart.", + user.visible_message("[user] pries \the [src] apart.", "You pry apart \the [src].", - "You hear splitting wood.") + "You hear splitting wood.") deconstruct(TRUE, user) return TRUE /obj/structure/ore_box/examine(mob/living/user) if(Adjacent(user) && istype(user)) ui_interact(user) - return ..() + . = ..() -/obj/structure/ore_box/attack_hand(mob/user) +/obj/structure/ore_box/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -62,7 +65,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "ore_box", name, 335, 415, master_ui, state) + ui = new(user, src, ui_key, "OreBox", name, ui_x, ui_y, master_ui, state) ui.open() /obj/structure/ore_box/ui_data() diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 6888a6590f..d3892cc282 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -398,7 +398,7 @@ humanc = character //Let's retypecast the var to be human, if(humanc) //These procs all expect humans - GLOB.data_core.manifest_inject(humanc) + GLOB.data_core.manifest_inject(humanc, humanc.client, humanc.client.prefs) if(SSshuttle.arrivals) SSshuttle.arrivals.QueueAnnounce(humanc, rank) else diff --git a/code/modules/mob/dead/observer/notificationprefs.dm b/code/modules/mob/dead/observer/notificationprefs.dm index 6c1d76eaf3..160abd57e1 100644 --- a/code/modules/mob/dead/observer/notificationprefs.dm +++ b/code/modules/mob/dead/observer/notificationprefs.dm @@ -24,7 +24,7 @@ /datum/notificationpanel/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "notificationpanel", "Notification Preferences", 270, 360, master_ui, state) + ui = new(user, src, ui_key, "NotificationPreferences", "Notification Preferences", 270, 360, master_ui, state) ui.open() /datum/notificationpanel/ui_data(mob/user) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 397af1b9d0..bb39639ec1 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -54,6 +54,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) // Used for displaying in ghost chat, without changing the actual name // of the mob var/deadchat_name + var/datum/orbit_menu/orbit_menu var/datum/spawners_menu/spawners_menu /mob/dead/observer/Initialize(mapload, mob/body) @@ -161,6 +162,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) updateallghostimages() + QDEL_NULL(orbit_menu) QDEL_NULL(spawners_menu) return ..() @@ -490,10 +492,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set name = "Orbit" // "Haunt" set desc = "Follow and orbit a mob." - var/list/mobs = getpois(skip_mindless=1) - var/input = input("Please, select a mob!", "Haunt", null, null) as null|anything in mobs - var/mob/target = mobs[input] - ManualFollow(target) + if(!orbit_menu) + orbit_menu = new(src) + + orbit_menu.ui_interact(src) // This is the ghost's follow verb with an argument /mob/dead/observer/proc/ManualFollow(atom/movable/target) @@ -837,13 +839,13 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp /mob/dead/observer/vv_edit_var(var_name, var_value) . = ..() switch(var_name) - if("icon") + if(NAMEOF(src, icon)) ghostimage_default.icon = icon ghostimage_simple.icon = icon - if("icon_state") + if(NAMEOF(src, icon_state)) ghostimage_default.icon_state = icon_state ghostimage_simple.icon_state = icon_state - if("fun_verbs") + if(NAMEOF(src, fun_verbs)) if(fun_verbs) verbs += /mob/dead/observer/verb/boo verbs += /mob/dead/observer/verb/possess @@ -925,7 +927,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp /mob/dead/observer/vv_edit_var(var_name, var_value) . = ..() - if(var_name == "invisibility") + if(var_name == NAMEOF(src, invisibility)) set_invisibility(invisibility) // updates light /proc/set_observer_default_invisibility(amount, message=null) diff --git a/code/modules/mob/dead/observer/orbit.dm b/code/modules/mob/dead/observer/orbit.dm new file mode 100644 index 0000000000..eb23a5fb67 --- /dev/null +++ b/code/modules/mob/dead/observer/orbit.dm @@ -0,0 +1,78 @@ +/datum/orbit_menu + var/mob/dead/observer/owner + +/datum/orbit_menu/New(mob/dead/observer/new_owner) + if(!istype(new_owner)) + qdel(src) + owner = new_owner + +/datum/orbit_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state) + if (!ui) + ui = new(user, src, ui_key, "Orbit", "Orbit", 350, 700, master_ui, state) + ui.open() + +/datum/orbit_menu/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if (..()) + return + + if (action == "orbit") + var/list/pois = getpois(skip_mindless = 1) + var/atom/movable/poi = pois[params["name"]] + if (poi != null) + owner.ManualFollow(poi) + ui.close() + +/datum/orbit_menu/ui_data(mob/user) + var/list/data = list() + + var/list/alive = list() + var/list/antagonists = list() + var/list/dead = list() + var/list/ghosts = list() + var/list/misc = list() + var/list/npcs = list() + + var/list/pois = getpois(skip_mindless = 1) + for (var/name in pois) + var/list/serialized = list() + serialized["name"] = name + + var/poi = pois[name] + + var/mob/M = poi + if (istype(M)) + if (isobserver(M)) + ghosts += list(serialized) + else if (M.stat == DEAD) + dead += list(serialized) + else if (M.mind == null) + npcs += list(serialized) + else + var/number_of_orbiters = M.orbiters?.orbiters?.len + if (number_of_orbiters) + serialized["orbiters"] = number_of_orbiters + + var/datum/mind/mind = M.mind + var/was_antagonist = FALSE + + for (var/_A in mind.antag_datums) + var/datum/antagonist/A = _A + if (A.show_to_ghosts) + was_antagonist = TRUE + serialized["antag"] = A.name + antagonists += list(serialized) + break + + if (!was_antagonist) + alive += list(serialized) + else + misc += list(serialized) + + data["alive"] = alive + data["antagonists"] = antagonists + data["dead"] = dead + data["ghosts"] = ghosts + data["misc"] = misc + data["npcs"] = npcs + + return data diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 442bcf8027..951185ee92 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -25,7 +25,7 @@ status_flags = CANUNCONSCIOUS|CANPUSH - var/heat_protection = 0.5 + heat_protection = 0.5 var/leaping = 0 gib_type = /obj/effect/decal/cleanable/blood/gibs/xeno unique_name = 1 diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index e35c905539..c5a69553aa 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -59,7 +59,7 @@ return attack_hand(user) //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/clothing/mask/facehugger/attack_hand(mob/user) +/obj/item/clothing/mask/facehugger/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if((stat == CONSCIOUS && !sterile) && !isalien(user)) if(Leap(user)) return diff --git a/code/modules/mob/living/carbon/carbon_active_parry.dm b/code/modules/mob/living/carbon/carbon_active_parry.dm new file mode 100644 index 0000000000..2683b6db6b --- /dev/null +++ b/code/modules/mob/living/carbon/carbon_active_parry.dm @@ -0,0 +1,2 @@ +/mob/living/carbon/check_unarmed_parry_activation_special() + return ..() && length(get_empty_held_indexes()) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index bfa9c40a7c..054c1a6857 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -112,7 +112,7 @@ return //so we don't call the carbon's attack_hand(). //ATTACK HAND IGNORING PARENT RETURN VALUE -/mob/living/carbon/attack_hand(mob/living/carbon/human/user) +/mob/living/carbon/attack_hand(mob/living/carbon/human/user, act_intent, unarmed_attack_flags) . = ..() if(.) //was the attack blocked? return @@ -127,9 +127,9 @@ ContactContractDisease(D) if(lying && surgeries.len) - if(user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM) + if(act_intent == INTENT_HELP || act_intent == INTENT_DISARM) for(var/datum/surgery/S in surgeries) - if(S.next_step(user, user.a_intent)) + if(S.next_step(user, act_intent)) return TRUE diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 15413f76d4..a1c9239e09 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -64,3 +64,11 @@ var/drunkenness = 0 //Overall drunkenness - check handle_alcohol() in life.dm for effects var/tackling = FALSE //Whether or not we are tackling, this will prevent the knock into effects for carbons + + /// Protection (insulation) from the heat, Value 0-1 corresponding to the percentage of protection + var/heat_protection = 0 // No heat protection + /// Protection (insulation) from the cold, Value 0-1 corresponding to the percentage of protection + var/cold_protection = 0 // No cold protection + + /// Timer id of any transformation + var/transformation_timer diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 9464670884..a14845b41f 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -33,6 +33,7 @@ enable_intentional_sprint_mode() RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /atom.proc/clean_blood) + GLOB.human_list += src /mob/living/carbon/human/ComponentInitialize() @@ -47,6 +48,7 @@ /mob/living/carbon/human/Destroy() QDEL_NULL(physiology) QDEL_NULL_LIST(vore_organs) // CITADEL EDIT belly stuff + GLOB.human_list -= src return ..() /mob/living/carbon/human/prepare_data_huds() diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 63296021ff..79dd318b20 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -93,29 +93,28 @@ return dna.species.spec_attacked_by(I, user, affecting, a_intent, src, attackchain_flags, damage_multiplier) /mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE) - if(user.a_intent == INTENT_HARM) - . = ..(user, TRUE) - if(.) - return - var/hulk_verb_continous = "smashes" - var/hulk_verb_simple = "smash" - if(prob(50)) - hulk_verb_continous = "pummels" - hulk_verb_simple = "pummel" - playsound(loc, user.dna.species.attack_sound, 25, 1, -1) - visible_message("[user] [hulk_verb_continous] [src]!", \ - "[user] [hulk_verb_continous] you!", null, COMBAT_MESSAGE_RANGE, null, user, - "You [hulk_verb_simple] [src]!") - adjustBruteLoss(15) - return 1 + . = ..(user, TRUE) + if(.) + return + var/hulk_verb_continous = "smashes" + var/hulk_verb_simple = "smash" + if(prob(50)) + hulk_verb_continous = "pummels" + hulk_verb_simple = "pummel" + playsound(loc, user.dna.species.attack_sound, 25, 1, -1) + visible_message("[user] [hulk_verb_continous] [src]!", \ + "[user] [hulk_verb_continous] you!", null, COMBAT_MESSAGE_RANGE, null, user, + "You [hulk_verb_simple] [src]!") + adjustBruteLoss(15) + return 1 -/mob/living/carbon/human/attack_hand(mob/user) +/mob/living/carbon/human/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) //To allow surgery to return properly. return if(ishuman(user)) var/mob/living/carbon/human/H = user - dna.species.spec_attack_hand(H, src) + dna.species.spec_attack_hand(H, src, null, act_intent, unarmed_attack_flags) /mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/M) var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index e7be540eb9..c72bfe044e 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -7,12 +7,14 @@ buckle_lying = FALSE mob_biotypes = MOB_ORGANIC|MOB_HUMANOID /// Enable stamina combat - combat_flags = COMBAT_FLAGS_DEFAULT + combat_flags = COMBAT_FLAGS_DEFAULT | COMBAT_FLAG_UNARMED_PARRY status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH|CANSTAGGER has_field_of_vision = FALSE //Handled by species. blocks_emissive = EMISSIVE_BLOCK_UNIQUE + block_parry_data = /datum/block_parry_data/unarmed/human + //Hair colour and style var/hair_color = "000" var/hair_style = "Bald" @@ -71,3 +73,45 @@ var/lastpuke = 0 var/account_id var/last_fire_update + +/// Unarmed parry data for human +/datum/block_parry_data/unarmed/human + parry_respect_clickdelay = TRUE + parry_stamina_cost = 4 + parry_attack_types = ATTACK_TYPE_UNARMED + parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK | PARRY_LOCK_ATTACKING + + parry_time_windup = 0 + parry_time_spindown = 1 + parry_time_active = 5 + + parry_time_perfect = 1 + parry_time_perfect_leeway = 1 + parry_imperfect_falloff_percent = 20 + parry_efficiency_perfect = 100 + + parry_efficiency_considered_successful = 0.01 + parry_efficiency_to_counterattack = 0.01 + parry_max_attacks = 3 + parry_cooldown = 30 + parry_failed_stagger_duration = 0 + parry_failed_clickcd_duration = 0.4 + + parry_data = list( // yeah it's snowflake + "HUMAN_PARRY_STAGGER" = 3 SECONDS, + "HUMAN_PARRY_PUNCH" = TRUE, + "HUMAN_PARRY_MININUM_EFFICIENCY" = 0.9 + ) + +/mob/living/carbon/human/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency, parry_time) + var/datum/block_parry_data/D = return_block_parry_datum(block_parry_data) + if(!owner.Adjacent(attacker)) + return ..() + if(parry_efficiency < D.parry_data["HUMAN_PARRY_MINIMUM_EFFICIENCY"]) + return ..() + visible_message("[src] strikes back perfectly at [attacker], staggering them!") + if(D.parry_data["HUMAN_PARRY_PUNCH"]) + UnarmedAttack(attacker, TRUE, INTENT_HARM, UNARMED_ATTACK_PARRY) + var/mob/living/L = attacker + if(istype(L)) + L.Stagger(D.parry_data["HUMAN_PARRY_STAGGER"]) diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 22431f9978..bcb658eab8 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -59,7 +59,7 @@ . = ..() for(var/datum/mutation/human/HM in dna.mutations) HM.on_move(NewLoc) - if(. && (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) && !(movement_type & FLYING) && CHECK_ALL_MOBILITY(src, MOBILITY_MOVE|MOBILITY_STAND) && m_intent == MOVE_INTENT_RUN && has_gravity(loc) && !pulledby) + if(. && (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) && !(movement_type & FLYING) && CHECK_ALL_MOBILITY(src, MOBILITY_MOVE|MOBILITY_STAND) && m_intent == MOVE_INTENT_RUN && has_gravity(loc) && (!pulledby || (pulledby.pulledby == src))) if(!HAS_TRAIT(src, TRAIT_FREESPRINT)) doSprintLossTiles(1) if((oldpseudoheight - pseudo_z_axis) >= 8) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index efff888c41..7f883aafd4 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -382,7 +382,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) //keep it at the right spot, so we can't have people taking shortcuts var/location = C.dna.mutation_index.Find(inert_mutation) C.dna.mutation_index[location] = new_species.inert_mutation + C.dna.default_mutation_genes[location] = C.dna.mutation_index[location] C.dna.mutation_index[new_species.inert_mutation] = create_sequence(new_species.inert_mutation) + C.dna.default_mutation_genes[new_species.inert_mutation] = C.dna.mutation_index[new_species.inert_mutation] if(!new_species.has_field_of_vision && has_field_of_vision && ishuman(C) && CONFIG_GET(flag/use_field_of_vision)) var/datum/component/field_of_vision/F = C.GetComponent(/datum/component/field_of_vision) @@ -1444,7 +1446,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) target.grabbedby(user) return 1 -/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) +/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style, unarmed_attack_flags = NONE) if(!attacker_style && HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, "You don't want to harm [target]!") return FALSE @@ -1456,10 +1458,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) target_message = "[target] blocks your attack!") return FALSE - if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes punching cause staminaloss but funny martial artist types get a discount - user.adjustStaminaLossBuffered(1.5) - else - user.adjustStaminaLossBuffered(3.5) + if(!(unarmed_attack_flags & UNARMED_ATTACK_PARRY)) + if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes punching cause staminaloss but funny martial artist types get a discount + user.adjustStaminaLossBuffered(1.5) + else + user.adjustStaminaLossBuffered(3.5) if(attacker_style && attacker_style.harm_act(user,target)) return TRUE @@ -1497,13 +1500,16 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected)) var/miss_chance = 100//calculate the odds that a punch misses entirely. considers stamina and brute damage of the puncher. punches miss by default to prevent weird cases - if(user.dna.species.punchdamagelow) - if(atk_verb == ATTACK_EFFECT_KICK) //kicks never miss (provided your species deals more than 0 damage) - miss_chance = 0 - else if(HAS_TRAIT(user, TRAIT_PUGILIST)) //pugilists have a flat 10% miss chance - miss_chance = 10 - else - miss_chance = min(10 + max(puncherstam * 0.5, puncherbrute * 0.5), 100) //probability of miss has a base of 10, and modified based on half brute total. Capped at max 100 to prevent weirdness in prob() + if(unarmed_attack_flags & UNARMED_ATTACK_PARRY) + miss_chance = 0 + else + if(user.dna.species.punchdamagelow) + if(atk_verb == ATTACK_EFFECT_KICK) //kicks never miss (provided your species deals more than 0 damage) + miss_chance = 0 + else if(HAS_TRAIT(user, TRAIT_PUGILIST)) //pugilists have a flat 10% miss chance + miss_chance = 10 + else + miss_chance = min(10 + max(puncherstam * 0.5, puncherbrute * 0.5), 100) //probability of miss has a base of 10, and modified based on half brute total. Capped at max 100 to prevent weirdness in prob() if(!damage || !affecting || prob(miss_chance))//future-proofing for species that have 0 damage/weird cases where no zone is targeted playsound(target.loc, user.dna.species.miss_sound, 25, TRUE, -1) @@ -1681,7 +1687,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) /datum/species/proc/spec_hitby(atom/movable/AM, mob/living/carbon/human/H) return -/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style) +/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags) if(!istype(M)) return CHECK_DNA_AND_SPECIES(M) @@ -1693,7 +1699,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) attacker_style = M.mind.martial_art if(attacker_style?.pacifism_check && HAS_TRAIT(M, TRAIT_PACIFISM)) // most martial arts are quite harmful, alas. attacker_style = null - switch(M.a_intent) + switch(act_intent) if("help") help(M, H, attacker_style) @@ -1701,7 +1707,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) grab(M, H, attacker_style) if("harm") - harm(M, H, attacker_style) + harm(M, H, attacker_style, unarmed_attack_flags) if("disarm") disarm(M, H, attacker_style) diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 958e58a8ad..7100caf178 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -422,9 +422,9 @@ else reactive_teleport(H) -/datum/species/golem/bluespace/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style) +/datum/species/golem/bluespace/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags) ..() - if(world.time > last_teleport + teleport_cooldown && M != H && M.a_intent != INTENT_HELP) + if(world.time > last_teleport + teleport_cooldown && M != H && act_intent != INTENT_HELP) reactive_teleport(H) /datum/species/golem/bluespace/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H) @@ -519,9 +519,9 @@ var/golem_name = "[uppertext(clown_name)]" return golem_name -/datum/species/golem/bananium/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style) +/datum/species/golem/bananium/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags) ..() - if(world.time > last_banana + banana_cooldown && M != H && M.a_intent != INTENT_HELP) + if(world.time > last_banana + banana_cooldown && M != H && act_intent != INTENT_HELP) new/obj/item/grown/bananapeel/specialpeel(get_turf(H)) last_banana = world.time @@ -830,9 +830,9 @@ if(world.time > last_gong_time + gong_cooldown) gong(H) -/datum/species/golem/bronze/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style) +/datum/species/golem/bronze/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags) ..() - if(world.time > last_gong_time + gong_cooldown && M.a_intent != INTENT_HELP) + if(world.time > last_gong_time + gong_cooldown && act_intent != INTENT_HELP) gong(H) /datum/species/golem/bronze/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H) diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index a500bea54a..31f326fd53 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -314,7 +314,7 @@ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "slime_swap_body", name, 400, 400, master_ui, state) + ui = new(user, src, ui_key, "SlimeBodySwapper", name, 400, 400, master_ui, state) ui.open() /datum/action/innate/swap_body/ui_data(mob/user) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index b109598973..b40d87a68a 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -1,4 +1,6 @@ /mob/living/carbon/BiologicalLife(seconds, times_fired) + //Updates the number of stored chemicals for powers + handle_changeling() //Reagent processing needs to come before breathing, to prevent edge cases. handle_organs() . = ..() // if . is false, we are dead. @@ -25,8 +27,6 @@ if(stat != DEAD) handle_liver() - //Updates the number of stored chemicals for powers - handle_changeling() /mob/living/carbon/PhysicalLife(seconds, times_fired) if(!(. = ..())) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index a4a800e9c4..971e1ed7d0 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1197,30 +1197,29 @@ /mob/living/vv_edit_var(var_name, var_value) switch(var_name) - if ("maxHealth") + if (NAMEOF(src, maxHealth)) if (!isnum(var_value) || var_value <= 0) return FALSE - if("stat") + if(NAMEOF(src, stat)) if((stat == DEAD) && (var_value < DEAD))//Bringing the dead back to life GLOB.dead_mob_list -= src GLOB.alive_mob_list += src if((stat < DEAD) && (var_value == DEAD))//Kill he GLOB.alive_mob_list -= src GLOB.dead_mob_list += src + if(NAMEOF(src, health)) //this doesn't work. gotta use procs instead. + return FALSE . = ..() switch(var_name) - if("eye_blind") + if(NAMEOF(src, eye_blind)) set_blindness(var_value) - if("eye_damage") - var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES) - E?.setOrganDamage(var_value) - if("eye_blurry") + if(NAMEOF(src, eye_blurry)) set_blurriness(var_value) - if("maxHealth") + if(NAMEOF(src, maxHealth)) updatehealth() - if("resize") + if(NAMEOF(src, resize)) update_transform() - if("lighting_alpha") + if(NAMEOF(src, lighting_alpha)) sync_lighting_plane_alpha() /mob/living/proc/do_adrenaline( diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index 0dab70b045..8141603f64 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -34,7 +34,7 @@ data = mind.martial_art.block_parry_data method = MARTIAL_PARRY tool = mind.martial_art - else if(combat_flags & COMBAT_FLAG_UNARMED_PARRY) + else if((combat_flags & COMBAT_FLAG_UNARMED_PARRY) && check_unarmed_parry_activation_special()) data = block_parry_data method = UNARMED_PARRY tool = src @@ -93,6 +93,12 @@ if(I.can_active_parry()) return I +/** + * Check if we can unarmed parry + */ +/mob/living/proc/check_unarmed_parry_activation_special() + return TRUE + /** * Called via timer when the parry sequence ends. */ diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 07252b4c45..b15275d57b 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -270,10 +270,10 @@ user.set_pull_offsets(src, grab_state) return 1 -/mob/living/attack_hand(mob/user) +/mob/living/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) ..() //Ignoring parent return value here. SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user) - if((user != src) && user.a_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE, null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS)) + if((user != src) && act_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE | ((unarmed_attack_flags & UNARMED_ATTACK_PARRY)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE), null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS)) log_combat(user, src, "attempted to touch") visible_message("[user] attempted to touch [src]!", "[user] attempted to touch you!", target = user, diff --git a/code/modules/mob/living/silicon/ai/robot_control.dm b/code/modules/mob/living/silicon/ai/robot_control.dm new file mode 100644 index 0000000000..0eaea103f2 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/robot_control.dm @@ -0,0 +1,74 @@ +/datum/robot_control + var/mob/living/silicon/ai/owner + +/datum/robot_control/New(mob/living/silicon/ai/new_owner) + if(!istype(new_owner)) + qdel(src) + owner = new_owner + +/datum/robot_control/proc/is_interactable(mob/user) + if(user != owner || owner.incapacitated()) + return FALSE + if(owner.control_disabled) + to_chat(user, "Wireless control is disabled.") + return FALSE + return TRUE + +/datum/robot_control/ui_status(mob/user) + if(is_interactable(user)) + return ..() + return UI_CLOSE + +/datum/robot_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "RemoteRobotControl", "Remote Robot Control", 500, 500, master_ui, state) + ui.open() + +/datum/robot_control/ui_data(mob/user) + if(!owner || user != owner) + return + var/list/data = list() + var/turf/ai_current_turf = get_turf(owner) + var/ai_zlevel = ai_current_turf.z + + data["robots"] = list() + for(var/mob/living/simple_animal/bot/B in GLOB.bots_list) + if(B.z != ai_zlevel || B.remote_disabled) //Only non-emagged bots on the same Z-level are detected! + continue + var/list/robot_data = list( + name = B.name, + model = B.model, + mode = B.get_mode(), + hacked = B.hacked, + location = get_area_name(B, TRUE), + ref = REF(B) + ) + data["robots"] += list(robot_data) + + return data + +/datum/robot_control/ui_act(action, params) + if(..()) + return + if(!is_interactable(usr)) + return + + switch(action) + if("callbot") //Command a bot to move to a selected location. + if(owner.call_bot_cooldown > world.time) + to_chat(usr, "Error: Your last call bot command is still processing, please wait for the bot to finish calculating a route.") + return + owner.Bot = locate(params["ref"]) in GLOB.bots_list + if(!owner.Bot || owner.Bot.remote_disabled || owner.control_disabled) + return + owner.waypoint_mode = TRUE + to_chat(usr, "Set your waypoint by clicking on a valid location free of obstructions.") + . = TRUE + if("interface") //Remotely connect to a bot! + owner.Bot = locate(params["ref"]) in GLOB.bots_list + if(!owner.Bot || owner.Bot.remote_disabled || owner.control_disabled) + return + owner.Bot.attack_ai(usr) + . = TRUE diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm index bb6c37a010..0d8a0880a8 100644 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -2,7 +2,18 @@ //as they handle all relevant stuff like adding it to the player's screen and such //Returns the thing in our active hand (whatever is in our active module-slot, in this case) +//This proc has been butchered into a proc that overrides borg item holding for the sake of making grippers work. +//I'd be immensely thankful if anyone can figure out a less obtuse way of making grippers work without breaking functionality. /mob/living/silicon/robot/get_active_held_item() + var/item = module_active + if(istype(item, /obj/item/weapon/gripper)) + var/obj/item/weapon/gripper/G = item + if(G.wrapped) + if(G.wrapped.loc != G) + G.wrapped = null + return module_active + item = G.wrapped + return item return module_active diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 8f103c496e..ccf38a547b 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -444,7 +444,7 @@ /obj/item/t_scanner, /obj/item/analyzer, /obj/item/storage/part_replacer/cyborg, - /obj/item/holosign_creator/atmos, + /obj/item/holosign_creator/combifan, /obj/item/weapon/gripper, /obj/item/lightreplacer/cyborg, /obj/item/geiger_counter/cyborg, diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 39eccf9ad4..a347b04e50 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -115,6 +115,19 @@ else return "[mode_name[mode]]" +/** + * Returns a status string about the bot's current status, if it's moving, manually controlled, or idle. + */ +/mob/living/simple_animal/bot/proc/get_mode_ui() + if(client) //Player bots do not have modes, thus the override. Also an easy way for PDA users/AI to know when a bot is a player. + return paicard ? "pAI Controlled" : "Autonomous" + else if(!on) + return "Inactive" + else if(!mode) + return "Idle" + else + return "[mode_name[mode]]" + /mob/living/simple_animal/bot/proc/turn_on() if(stat) return FALSE diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index 174ac869fa..5c83482bde 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -341,7 +341,7 @@ target_types = typecacheof(target_types) -/mob/living/simple_animal/bot/cleanbot/UnarmedAttack(atom/A) +/mob/living/simple_animal/bot/cleanbot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) if(istype(A, /obj/effect/decal/cleanable)) anchored = TRUE icon_state = "cleanbot-c" diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 6febb942a1..1f81e8db29 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -518,7 +518,7 @@ Auto Patrol[]"}, /mob/living/simple_animal/bot/ed209/redtag lasercolor = "r" -/mob/living/simple_animal/bot/ed209/UnarmedAttack(atom/A) +/mob/living/simple_animal/bot/ed209/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) if(!on) return if(iscarbon(A)) diff --git a/code/modules/mob/living/simple_animal/bot/firebot.dm b/code/modules/mob/living/simple_animal/bot/firebot.dm index a5ac2e8bca..d0e969dc4e 100644 --- a/code/modules/mob/living/simple_animal/bot/firebot.dm +++ b/code/modules/mob/living/simple_animal/bot/firebot.dm @@ -58,7 +58,7 @@ internal_ext.max_water = INFINITY internal_ext.refill() -/mob/living/simple_animal/bot/firebot/UnarmedAttack(atom/A) +/mob/living/simple_animal/bot/firebot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) if(!on) return if(internal_ext) diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index 0f4608f48c..0ba4023864 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -413,7 +413,7 @@ /obj/machinery/bot_core/floorbot req_one_access = list(ACCESS_CONSTRUCTION, ACCESS_ROBOTICS) -/mob/living/simple_animal/bot/floorbot/UnarmedAttack(atom/A) +/mob/living/simple_animal/bot/floorbot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) if(isturf(A)) repair(A) else diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm index c3c16d5976..43f18d3890 100644 --- a/code/modules/mob/living/simple_animal/bot/honkbot.dm +++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm @@ -141,7 +141,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"}, retaliate(Proj.firer) return ..() -/mob/living/simple_animal/bot/honkbot/UnarmedAttack(atom/A) +/mob/living/simple_animal/bot/honkbot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) if(!on) return if(iscarbon(A)) @@ -367,4 +367,4 @@ Maintenance panel panel is [open ? "opened" : "closed"]"}, ..() /obj/machinery/bot_core/honkbot - req_one_access = list(ACCESS_THEATRE, ACCESS_ROBOTICS) \ No newline at end of file + req_one_access = list(ACCESS_THEATRE, ACCESS_ROBOTICS) diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm index cbb495bf9c..f998f58f02 100644 --- a/code/modules/mob/living/simple_animal/bot/medbot.dm +++ b/code/modules/mob/living/simple_animal/bot/medbot.dm @@ -625,7 +625,7 @@ else ..() -/mob/living/simple_animal/bot/medbot/UnarmedAttack(atom/A) +/mob/living/simple_animal/bot/medbot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) if(iscarbon(A)) var/mob/living/carbon/C = A patient = C @@ -790,4 +790,4 @@ #undef MEDBOT_PANIC_HIGH #undef MEDBOT_PANIC_FUCK #undef MEDBOT_PANIC_ENDING -#undef MEDBOT_PANIC_END \ No newline at end of file +#undef MEDBOT_PANIC_END diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 917fdcf113..5e96818766 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -174,7 +174,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "mulebot", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "Mule", name, ui_x, ui_y, master_ui, state) ui.open() /mob/living/simple_animal/bot/mulebot/ui_data(mob/user) @@ -752,7 +752,7 @@ if(load) unload() -/mob/living/simple_animal/bot/mulebot/UnarmedAttack(atom/A) +/mob/living/simple_animal/bot/mulebot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) if(isturf(A) && isturf(loc) && loc.Adjacent(A) && load) unload(get_dir(loc, A)) else diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index d199bc2ead..cfff3eb751 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -208,7 +208,7 @@ Auto Patrol: []"}, return ..() -/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A) +/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE) if(!on) return if(iscarbon(A)) diff --git a/code/modules/mob/living/simple_animal/friendly/bumbles.dm b/code/modules/mob/living/simple_animal/friendly/bumbles.dm index 2d236a4327..3707aa33f8 100644 --- a/code/modules/mob/living/simple_animal/friendly/bumbles.dm +++ b/code/modules/mob/living/simple_animal/friendly/bumbles.dm @@ -30,6 +30,7 @@ verb_yell = "buzzes intensely" emote_see = list("buzzes.", "makes a loud buzz.", "rolls several times.", "buzzes happily.") speak_chance = 1 + unique_name = TRUE /mob/living/simple_animal/pet/bumbles/Initialize() . = ..() diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm index 4ad97a9f84..1f733a4d55 100644 --- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm +++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm @@ -192,6 +192,15 @@ else ..() +//a cow that produces a random reagent in its udder +/mob/living/simple_animal/cow/random + name = "strange cow" + desc = "Something seems off about the milk this cow is producing." + +/mob/living/simple_animal/cow/random/Initialize() + milk_reagent = get_random_reagent_id() //this has a blacklist so don't worry about romerol cows, etc + ..() + //Wisdom cow, speaks and bestows great wisdoms /mob/living/simple_animal/cow/wisdom name = "wisdom cow" diff --git a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm index f1916b412a..d396434708 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm @@ -87,7 +87,7 @@ detonate(user) //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/guardian_bomb/attack_hand(mob/living/user) +/obj/guardian_bomb/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) detonate(user) /obj/guardian_bomb/examine(mob/user) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index 5816be2917..aa4ff328b5 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -385,7 +385,7 @@ Difficulty: Very Hard if(isliving(speaker)) ActivationReaction(speaker, ACTIVATE_SPEECH) -/obj/machinery/anomalous_crystal/attack_hand(mob/user) +/obj/machinery/anomalous_crystal/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm index 81b541dc7b..982b91c2c9 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm @@ -148,7 +148,7 @@ While using this makes the system rely on OnFire, it still gives options for tim desc = "You're not quite sure how a signal can be menacing." invisibility = 100 -/obj/structure/elite_tumor/attack_hand(mob/user) +/obj/structure/elite_tumor/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(ishuman(user)) switch(activity) diff --git a/code/modules/mob/living/simple_animal/hostile/netherworld.dm b/code/modules/mob/living/simple_animal/hostile/netherworld.dm index 1db6854f96..3620e3ee5f 100644 --- a/code/modules/mob/living/simple_animal/hostile/netherworld.dm +++ b/code/modules/mob/living/simple_animal/hostile/netherworld.dm @@ -86,7 +86,7 @@ .=..() START_PROCESSING(SSprocessing, src) -/obj/structure/spawner/nether/attack_hand(mob/user) +/obj/structure/spawner/nether/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) user.visible_message("[user] is violently pulled into the link!", \ "Touching the portal, you are quickly pulled through into a world of unimaginable horror!") contents.Add(user) diff --git a/code/modules/mob/living/simple_animal/pickle.dm b/code/modules/mob/living/simple_animal/pickle.dm new file mode 100644 index 0000000000..c5469024e6 --- /dev/null +++ b/code/modules/mob/living/simple_animal/pickle.dm @@ -0,0 +1,32 @@ +//funniest shit i've ever seen + +/mob/living/simple_animal/pickle + name = "pickle" + desc = "It's a pickle. It might just be the funniest thing you have ever seen." + health = 100 + maxHealth = 100 + icon = 'icons/mob/32x64.dmi' + icon_state = "pickle" + deathmessage = "The pickle implodes into its own existential dread and disappears!" + friendly_verb_continuous = "tickles" + friendly_verb_simple = "tickle" + del_on_death = TRUE + var/mob/living/original_body + +/mob/living/simple_animal/pickle/UnarmedAttack(atom/A) + ..() //we want the tickle emote to go before the laugh + if(ismob(A)) + var/mob/laugher = A + laugher.emote("laugh") + +/mob/living/simple_animal/pickle/death() + ..() + if(original_body) + original_body.adjustOrganLoss(ORGAN_SLOT_BRAIN, 200) //to be fair, you have to have a very high iq to understand- + original_body.forceMove(get_turf(src)) + if(mind) + mind.transfer_to(original_body) + +/mob/living/simple_animal/pickle/wabbajack_act() //restore users name before its used on the new mob + if(original_body) + real_name = original_body.real_name diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 0b2588bc6c..52b755d926 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -558,3 +558,17 @@ It's fairly easy to fix if dealing with single letters but not so much with comp //Can the mob see reagents inside of containers? /mob/proc/can_see_reagents() return stat == DEAD || silicon_privileges //Dead guys and silicons can always see reagents + +/mob/proc/is_blind() + SHOULD_BE_PURE(TRUE) + return eye_blind ? TRUE : HAS_TRAIT(src, TRAIT_BLIND) + +/mob/proc/can_read(obj/O) + if(is_blind()) + to_chat(src, "As you are trying to read [O], you suddenly feel very stupid!") + return + if(!is_literate()) + to_chat(src, "You try to read [O], but can't comprehend any of it.") + return + return TRUE + diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 5fd94c8a89..7de30a7095 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -1,26 +1,8 @@ -/mob/living/carbon/proc/monkeyize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_DEFAULTMSG)) - if (mob_transforming) +#define TRANSFORMATION_DURATION 22 + +/mob/living/carbon/proc/monkeyize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_KEEPSTUNS | TR_KEEPREAGENTS | TR_DEFAULTMSG)) + if(mob_transforming || transformation_timer) return - //Handle items on mob - - //first implants & organs - var/list/stored_implants = list() - var/list/int_organs = list() - - if (tr_flags & TR_KEEPIMPLANTS) - for(var/X in implants) - var/obj/item/implant/IMP = X - stored_implants += IMP - IMP.removed(src, 1, 1) - - var/list/missing_bodyparts_zones = get_missing_limbs() - - var/obj/item/cavity_object - - var/obj/item/bodypart/chest/CH = get_bodypart(BODY_ZONE_CHEST) - if(CH.cavity_item) - cavity_object = CH.cavity_item - CH.cavity_item = null if(tr_flags & TR_KEEPITEMS) var/Itemlist = get_equipped_items(TRUE) @@ -30,13 +12,36 @@ //Make mob invisible and spawn animation mob_transforming = TRUE - Stun(INFINITY, ignore_canstun = TRUE) + Paralyze(TRANSFORMATION_DURATION, ignore_canstun = TRUE) icon = null cut_overlays() invisibility = INVISIBILITY_MAXIMUM new /obj/effect/temp_visual/monkeyify(loc) - sleep(22) + + transformation_timer = addtimer(CALLBACK(src, .proc/finish_monkeyize, tr_flags), TRANSFORMATION_DURATION, TIMER_UNIQUE) + +/mob/living/carbon/proc/finish_monkeyize(tr_flags) + transformation_timer = null + + var/list/missing_bodyparts_zones = get_missing_limbs() + + var/list/stored_implants = list() + + if (tr_flags & TR_KEEPIMPLANTS) + for(var/X in implants) + var/obj/item/implant/IMP = X + stored_implants += IMP + IMP.removed(src, 1, 1) + + var/list/int_organs = list() + var/obj/item/cavity_object + + var/obj/item/bodypart/chest/CH = get_bodypart(BODY_ZONE_CHEST) + if(CH.cavity_item) + cavity_object = CH.cavity_item + CH.cavity_item = null + var/mob/living/carbon/monkey/O = new /mob/living/carbon/monkey( loc ) // hash the original name? @@ -50,6 +55,7 @@ if(tr_flags & TR_KEEPSE) O.dna.mutation_index = dna.mutation_index + O.dna.default_mutation_genes = dna.default_mutation_genes O.dna.set_se(1, GET_INITIALIZED_MUTATION(RACEMUT)) if(suiciding) @@ -149,12 +155,33 @@ ////////////////////////// Humanize ////////////////////////////// //Could probably be merged with monkeyize but other transformations got their own procs, too -/mob/living/carbon/proc/humanize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_DEFAULTMSG)) - if (mob_transforming) +/mob/living/carbon/proc/humanize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_KEEPSTUNS | TR_KEEPREAGENTS | TR_DEFAULTMSG)) + if (mob_transforming || transformation_timer) return - //Handle items on mob - //first implants & organs + //now the rest + if (tr_flags & TR_KEEPITEMS) + var/Itemlist = get_equipped_items(TRUE) + Itemlist += held_items + for(var/obj/item/W in Itemlist) + dropItemToGround(W, TRUE) + if (client) + client.screen -= W + + //Make mob invisible and spawn animation + mob_transforming = TRUE + Paralyze(TRANSFORMATION_DURATION, ignore_canstun = TRUE) + + icon = null + cut_overlays() + invisibility = INVISIBILITY_MAXIMUM + new /obj/effect/temp_visual/monkeyify/humanify(loc) + + transformation_timer = addtimer(CALLBACK(src, .proc/finish_humanize, tr_flags), TRANSFORMATION_DURATION, TIMER_UNIQUE) + +/mob/living/carbon/proc/finish_humanize(tr_flags) + transformation_timer = null + var/list/stored_implants = list() var/list/int_organs = list() @@ -173,25 +200,6 @@ cavity_object = CH.cavity_item CH.cavity_item = null - //now the rest - if (tr_flags & TR_KEEPITEMS) - var/Itemlist = get_equipped_items(TRUE) - Itemlist += held_items - for(var/obj/item/W in Itemlist) - dropItemToGround(W, TRUE) - if (client) - client.screen -= W - - - - //Make mob invisible and spawn animation - mob_transforming = TRUE - Stun(22, ignore_canstun = TRUE) - icon = null - cut_overlays() - invisibility = INVISIBILITY_MAXIMUM - new /obj/effect/temp_visual/monkeyify/humanify(loc) - sleep(22) var/mob/living/carbon/human/O = new( loc ) for(var/obj/item/C in O.loc) O.equip_to_appropriate_slot(C) @@ -208,6 +216,7 @@ if(tr_flags & TR_KEEPSE) O.dna.mutation_index = dna.mutation_index + O.dna.default_mutation_genes = dna.default_mutation_genes O.dna.set_se(0, GET_INITIALIZED_MUTATION(RACEMUT)) O.domutcheck() @@ -353,7 +362,7 @@ qdel(src) /mob/living/carbon/human/proc/Robotize(delete_items = 0, transfer_after = TRUE) - if (mob_transforming) + if(mob_transforming) return for(var/obj/item/W in src) if(delete_items) @@ -581,3 +590,68 @@ . = new_mob qdel(src) + + +/* Certain mob types have problems and should not be allowed to be controlled by players. + * + * This proc is here to force coders to manually place their mob in this list, hopefully tested. + * This also gives a place to explain -why- players shouldnt be turn into certain mobs and hopefully someone can fix them. + */ +/mob/proc/safe_animal(MP) + +//Bad mobs! - Remember to add a comment explaining what's wrong with the mob + if(!MP) + return 0 //Sanity, this should never happen. + + if(ispath(MP, /mob/living/simple_animal/hostile/construct)) + return 0 //Verbs do not appear for players. + +//Good mobs! + if(ispath(MP, /mob/living/simple_animal/pet/cat)) + return 1 + if(ispath(MP, /mob/living/simple_animal/pet/dog/corgi)) + return 1 + if(ispath(MP, /mob/living/simple_animal/crab)) + return 1 + if(ispath(MP, /mob/living/simple_animal/hostile/carp)) + return 1 + if(ispath(MP, /mob/living/simple_animal/hostile/mushroom)) + return 1 + if(ispath(MP, /mob/living/simple_animal/shade)) + return 1 + if(ispath(MP, /mob/living/simple_animal/hostile/killertomato)) + return 1 + if(ispath(MP, /mob/living/simple_animal/mouse)) + return 1 //It is impossible to pull up the player panel for mice (Fixed! - Nodrak) + if(ispath(MP, /mob/living/simple_animal/hostile/bear)) + return 1 //Bears will auto-attack mobs, even if they're player controlled (Fixed! - Nodrak) + if(ispath(MP, /mob/living/simple_animal/parrot)) + return 1 //Parrots are no longer unfinished! -Nodrak + + //Not in here? Must be untested! + return 0 + +#undef TRANSFORMATION_DURATION + +/mob/living/proc/turn_into_pickle() + //if they're already a pickle, turn them back instead + if(istype(src, /mob/living/simple_animal/pickle)) + //turn them back from being a pickle, but release them alive + var/mob/living/simple_animal/pickle/existing_pickle = src + if(existing_pickle.original_body) + existing_pickle.original_body.forceMove(get_turf(src)) + if(mind) + mind.transfer_to(existing_pickle.original_body) + qdel(src) + else + //make a new pickle on the tile and move their mind into it if possible + var/mob/living/simple_animal/pickle/new_pickle = new /mob/living/simple_animal/pickle(get_turf(src)) + new_pickle.original_body = src + if(mind) + mind.transfer_to(new_pickle) + //give them their old access if any + var/obj/item/card/id/mob_access_card = get_idcard() + if(mob_access_card) + new_pickle.access_card = mob_access_card + //move old body inside the pickle for safekeeping (when they die, we'll return the corpse because we're nice) + src.forceMove(new_pickle) diff --git a/code/modules/modular_computers/computers/item/computer_ui.dm b/code/modules/modular_computers/computers/item/computer_ui.dm index 11f5145478..6266daad2b 100644 --- a/code/modules/modular_computers/computers/item/computer_ui.dm +++ b/code/modules/modular_computers/computers/item/computer_ui.dm @@ -37,9 +37,9 @@ if (!ui) var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers) assets.send(user) - - ui = new(user, src, ui_key, "ntos_main", "NtOS Main menu", 400, 500, master_ui, state) - ui.set_style("ntos") + assets = get_asset_datum(/datum/asset/simple/arcade) + assets.send(user) + ui = new(user, src, ui_key, "NtosMain", "NtOS Main menu", 400, 500, master_ui, state) ui.open() ui.set_autoupdate(state = 1) diff --git a/code/modules/modular_computers/computers/item/laptop.dm b/code/modules/modular_computers/computers/item/laptop.dm index a4d2e74657..4e4c1fcdce 100644 --- a/code/modules/modular_computers/computers/item/laptop.dm +++ b/code/modules/modular_computers/computers/item/laptop.dm @@ -64,7 +64,7 @@ return M.put_in_hand(src, H.held_index) -/obj/item/modular_computer/laptop/attack_hand(mob/user) +/obj/item/modular_computer/laptop/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/modular_computers/computers/machinery/console_presets.dm b/code/modules/modular_computers/computers/machinery/console_presets.dm index f83442b137..066f1fb98b 100644 --- a/code/modules/modular_computers/computers/machinery/console_presets.dm +++ b/code/modules/modular_computers/computers/machinery/console_presets.dm @@ -85,3 +85,4 @@ var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD] hard_drive.store_file(new/datum/computer_file/program/chatclient()) hard_drive.store_file(new/datum/computer_file/program/nttransfer()) + hard_drive.store_file(new/datum/computer_file/program/arcade()) diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm index b54bc9f2be..6b5390fc60 100644 --- a/code/modules/modular_computers/file_system/program.dm +++ b/code/modules/modular_computers/file_system/program.dm @@ -1,26 +1,45 @@ // /program/ files are executable programs that do things. /datum/computer_file/program filetype = "PRG" - filename = "UnknownProgram" // File name. FILE NAME MUST BE UNIQUE IF YOU WANT THE PROGRAM TO BE DOWNLOADABLE FROM NTNET! - var/required_access = null // List of required accesses to *run* the program. - var/transfer_access = null // List of required access to download or file host the program - var/program_state = PROGRAM_STATE_KILLED// PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running. - var/obj/item/modular_computer/computer // Device that runs this program. - var/filedesc = "Unknown Program" // User-friendly name of this program. - var/extended_desc = "N/A" // Short description of this program's function. - var/program_icon_state = null // Program-specific screen icon state - var/requires_ntnet = 0 // Set to 1 for program to require nonstop NTNet connection to run. If NTNet connection is lost program crashes. - var/requires_ntnet_feature = 0 // Optional, if above is set to 1 checks for specific function of NTNet (currently NTNET_SOFTWAREDOWNLOAD, NTNET_PEERTOPEER, NTNET_SYSTEMCONTROL and NTNET_COMMUNICATION) - var/ntnet_status = 1 // NTNet status, updated every tick by computer running this program. Don't use this for checks if NTNet works, computers do that. Use this for calculations, etc. - var/usage_flags = PROGRAM_ALL // Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET combination) or PROGRAM_ALL - var/network_destination = null // Optional string that describes what NTNet server/system this program connects to. Used in default logging. - var/available_on_ntnet = 1 // Whether the program can be downloaded from NTNet. Set to 0 to disable. - var/available_on_syndinet = 0 // Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable. - var/tgui_id // ID of TGUI interface - var/ui_style // ID of custom TGUI style (optional) - var/ui_x = 575 // Default size of TGUI window, in pixels + /// File name. FILE NAME MUST BE UNIQUE IF YOU WANT THE PROGRAM TO BE DOWNLOADABLE FROM NTNET! + filename = "UnknownProgram" + /// List of required accesses to *run* the program. + var/required_access = null + /// List of required access to download or file host the program + var/transfer_access = null + /// PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running. + var/program_state = PROGRAM_STATE_KILLED + /// Device that runs this program. + var/obj/item/modular_computer/computer + /// User-friendly name of this program. + var/filedesc = "Unknown Program" + /// Short description of this program's function. + var/extended_desc = "N/A" + /// Program-specific screen icon state + var/program_icon_state = null + /// Set to 1 for program to require nonstop NTNet connection to run. If NTNet connection is lost program crashes. + var/requires_ntnet = FALSE + /// Optional, if above is set to 1 checks for specific function of NTNet (currently NTNET_SOFTWAREDOWNLOAD, NTNET_PEERTOPEER, NTNET_SYSTEMCONTROL and NTNET_COMMUNICATION) + var/requires_ntnet_feature = 0 + /// NTNet status, updated every tick by computer running this program. Don't use this for checks if NTNet works, computers do that. Use this for calculations, etc. + 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. + var/available_on_syndinet = 0 + /// ID of TGUI interface + var/tgui_id + /// Default size of TGUI window, in pixels + var/ui_x = 575 var/ui_y = 700 - var/ui_header = null // Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /icons/program_icons. Be careful not to use too large images! + /// Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /icons/program_icons. Be careful not to use too large images! + var/ui_header = null + ///Assets specific to programs + var/list/special_assets = list() /datum/computer_file/program/New(obj/item/modular_computer/comp = null) ..() @@ -50,23 +69,23 @@ /datum/computer_file/program/proc/generate_network_log(text) if(computer) return computer.add_log(text) - return 0 + return FALSE /datum/computer_file/program/proc/is_supported_by_hardware(hardware_flag = 0, loud = 0, mob/user = null) if(!(hardware_flag & usage_flags)) if(loud && computer && user) to_chat(user, "\The [computer] flashes an \"Hardware Error - Incompatible software\" warning.") - return 0 - return 1 + return FALSE + return TRUE /datum/computer_file/program/proc/get_signal(specific_action = 0) if(computer) return computer.get_ntnet_status(specific_action) - return 0 + return FALSE // Called by Process() on device that runs us, once every tick. /datum/computer_file/program/proc/process_tick() - return 1 + return TRUE // 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. @@ -87,7 +106,7 @@ if(IsAdminGhost(user)) return TRUE - if(computer && computer.hasSiliconAccessInArea(user)) + if(issilicon(user)) return TRUE if(ishuman(user)) @@ -98,6 +117,7 @@ D = card_slot.GetID() var/mob/living/carbon/human/h = user var/obj/item/card/id/I = h.get_idcard(TRUE) + if(!I && !D) if(loud) to_chat(user, "\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning.") @@ -123,7 +143,7 @@ // This is performed on program startup. May be overridden to add extra logic. Remember to include ..() call. Return 1 on success, 0 on failure. // 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(can_run(user, TRUE)) if(requires_ntnet && network_destination) generate_network_log("Connection opened to [network_destination].") program_state = PROGRAM_STATE_ACTIVE @@ -143,12 +163,11 @@ if(!ui && tgui_id) var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers) assets.send(user) + for(var/i in special_assets) + assets = get_asset_datum(i) + assets.send(user) ui = new(user, src, ui_key, tgui_id, filedesc, ui_x, ui_y, state = state) - - if(ui_style) - ui.set_style(ui_style) - ui.set_autoupdate(state = 1) ui.open() // CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC: @@ -156,7 +175,7 @@ // Calls beginning with "PRG_" are reserved for programs handling. // Calls beginning with "PC_" are reserved for computer handling (by whatever runs the program) // ALWAYS INCLUDE PARENT CALL ..() OR DIE IN FIRE. -/datum/computer_file/program/ui_act(action,params,datum/tgui/ui) +/datum/computer_file/program/ui_act(action,list/params,datum/tgui/ui) if(..()) return TRUE if(computer) diff --git a/code/modules/modular_computers/file_system/programs/airestorer.dm b/code/modules/modular_computers/file_system/programs/airestorer.dm index 1aa292f247..4e9cd85577 100644 --- a/code/modules/modular_computers/file_system/programs/airestorer.dm +++ b/code/modules/modular_computers/file_system/programs/airestorer.dm @@ -4,14 +4,14 @@ program_icon_state = "generic" extended_desc = "This program is capable of reconstructing damaged AI systems. Requires direct AI connection via intellicard slot." size = 12 - requires_ntnet = 0 - usage_flags = PROGRAM_CONSOLE + requires_ntnet = FALSE + usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP transfer_access = ACCESS_HEADS - available_on_ntnet = 1 - tgui_id = "ntos_ai_restorer" - ui_x = 600 + available_on_ntnet = TRUE + tgui_id = "NtosAiRestorer" + ui_x = 370 ui_y = 400 - + /// Variable dictating if we are in the process of restoring the AI in the inserted intellicard var/restoring = FALSE /datum/computer_file/program/aidiag/proc/get_ai(cardcheck) @@ -30,11 +30,11 @@ if(ai_slot.stored_card.AI) return ai_slot.stored_card.AI - return null + return /datum/computer_file/program/aidiag/ui_act(action, params) if(..()) - return TRUE + return var/mob/living/silicon/ai/A = get_ai() if(!A) @@ -44,6 +44,7 @@ if("PRG_beginReconstruction") if(A && A.health < 100) restoring = TRUE + A.notify_ghost_cloning("Your core files are being restored!", source = computer) return TRUE if("PRG_eject") if(computer.all_components[MC_AI]) @@ -53,7 +54,7 @@ return TRUE /datum/computer_file/program/aidiag/process_tick() - ..() + . = ..() if(!restoring) //Put the check here so we don't check for an ai all the time return var/obj/item/aicard/cardhold = get_ai(2) @@ -73,13 +74,13 @@ restoring = FALSE return ai_slot.locked =TRUE - A.adjustOxyLoss(-1, 0) - A.adjustFireLoss(-1, 0) - A.adjustToxLoss(-1, 0) - A.adjustBruteLoss(-1, 0) + A.adjustOxyLoss(-5, 0) + A.adjustFireLoss(-5, 0) + A.adjustToxLoss(-5, 0) + A.adjustBruteLoss(-5, 0) A.updatehealth() if(A.health >= 0 && A.stat == DEAD) - A.revive() + A.revive(full_heal = FALSE, admin_revive = FALSE) // Finished restoring if(A.health >= 100) ai_slot.locked = FALSE @@ -90,14 +91,14 @@ /datum/computer_file/program/aidiag/ui_data(mob/user) var/list/data = get_header_data() - var/mob/living/silicon/ai/AI - // A shortcut for getting the AI stored inside the computer. The program already does necessary checks. - AI = get_ai() + var/mob/living/silicon/ai/AI = get_ai() var/obj/item/aicard/aicard = get_ai(2) + data["ejectable"] = TRUE + data["AI_present"] = FALSE + data["error"] = null if(!aicard) - data["nocard"] = TRUE data["error"] = "Please insert an intelliCard." else if(!AI) @@ -107,15 +108,15 @@ if(cardhold.flush) data["error"] = "Flush in progress" else + data["AI_present"] = TRUE data["name"] = AI.name data["restoring"] = restoring - data["laws"] = AI.laws.get_law_list(include_zeroth = 1) data["health"] = (AI.health + 100) / 2 data["isDead"] = AI.stat == DEAD - data["ai_laws"] = AI.laws.get_law_list(include_zeroth = 1) + data["laws"] = AI.laws.get_law_list(include_zeroth = 1) return data /datum/computer_file/program/aidiag/kill_program(forced) restoring = FALSE - return ..(forced) \ No newline at end of file + return ..() diff --git a/code/modules/modular_computers/file_system/programs/alarm.dm b/code/modules/modular_computers/file_system/programs/alarm.dm index ca075b51e4..34daeff6ca 100644 --- a/code/modules/modular_computers/file_system/programs/alarm.dm +++ b/code/modules/modular_computers/file_system/programs/alarm.dm @@ -7,7 +7,7 @@ requires_ntnet = 1 network_destination = "alarm monitoring network" size = 5 - tgui_id = "ntos_station_alert" + tgui_id = "NtosStationAlertConsole" ui_x = 315 ui_y = 500 @@ -72,15 +72,23 @@ /datum/computer_file/program/alarm_monitor/proc/cancelAlarm(class, area/A, obj/origin) var/list/L = alarms[class] var/cleared = 0 + var/arealevelalarm = FALSE // set to TRUE for alarms that set/clear whole areas + if (class=="Fire") + arealevelalarm = TRUE for (var/I in L) if (I == A.name) - var/list/alarm = L[I] - var/list/srcs = alarm[3] - if (origin in srcs) - srcs -= origin - if (srcs.len == 0) + if (!arealevelalarm) // the traditional behaviour + var/list/alarm = L[I] + var/list/srcs = alarm[3] + if (origin in srcs) + srcs -= origin + if (srcs.len == 0) + cleared = 1 + L -= I + else + L -= I // wipe the instances entirely cleared = 1 - L -= I + update_alarm_display() return !cleared 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 35470cdee9..cf842f086f 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 @@ -8,20 +8,20 @@ available_on_ntnet = 0 unsendable = 1 undeletable = 1 - tgui_id = "synd_contract" - ui_style = "syndicate" - ui_x = 600 + tgui_id = "SyndContractor" + ui_x = 500 ui_y = 600 var/error = "" - var/page = CONTRACT_UPLINK_PAGE_CONTRACTS + var/info_screen = TRUE var/assigned = FALSE + var/first_load = TRUE /datum/computer_file/program/contract_uplink/run_program(var/mob/living/user) . = ..(user) /datum/computer_file/program/contract_uplink/ui_act(action, params) if(..()) - return 1 + return TRUE var/mob/living/user = usr var/obj/item/computer_hardware/hard_drive/small/syndicate/hard_drive = computer.all_components[MC_HDD] switch(action) @@ -31,27 +31,32 @@ hard_drive.traitor_data.contractor_hub.assigned_contracts[contract_id].status = CONTRACT_STATUS_ACTIVE hard_drive.traitor_data.contractor_hub.current_contract = hard_drive.traitor_data.contractor_hub.assigned_contracts[contract_id] program_icon_state = "single_contract" - return 1 + return TRUE if("PRG_login") var/datum/antagonist/traitor/traitor_data = user.mind.has_antag_datum(/datum/antagonist/traitor) - if(traitor_data) // Bake their data right into the hard drive, or we don't allow non-antags gaining access to unused contract system. We also create their contracts at this point. - if(!traitor_data.contractor_hub) // Only play greet sound, and handle contractor hub when assigning for the first time. + + // Bake their data right into the hard drive, or we don't allow non-antags gaining access to an unused + // contract system. + // We also create their contracts at this point. + if(traitor_data) + // Only play greet sound, and handle contractor hub when assigning for the first time. + if(!traitor_data.contractor_hub) + user.playsound_local(user, 'sound/effects/contractstartup.ogg', 100, FALSE) traitor_data.contractor_hub = new traitor_data.contractor_hub.create_hub_items() - user.playsound_local(user, 'sound/effects/contractstartup.ogg', 100, 0) - // Stops any topic exploits such as logging in multiple times on a single system. + // Stops any topic exploits such as logging in multiple times on a single system. if(!assigned) traitor_data.contractor_hub.create_contracts(traitor_data.owner) hard_drive.traitor_data = traitor_data program_icon_state = "contracts" assigned = TRUE else - error = "Incorrect login details." - return 1 + error = "UNAUTHORIZED USER" + return TRUE if("PRG_call_extraction") if(hard_drive.traitor_data.contractor_hub.current_contract.status != CONTRACT_STATUS_EXTRACTING) if(hard_drive.traitor_data.contractor_hub.current_contract.handle_extraction(user)) - user.playsound_local(user, 'sound/effects/confirmdropoff.ogg', 100, 1) + user.playsound_local(user, 'sound/effects/confirmdropoff.ogg', 100, TRUE) hard_drive.traitor_data.contractor_hub.current_contract.status = CONTRACT_STATUS_EXTRACTING program_icon_state = "extracted" else @@ -59,17 +64,18 @@ error = "Either both you or your target aren't at the dropoff location, or the pod hasn't got a valid place to land. Clear space, or make sure you're both inside." else user.playsound_local(user, 'sound/machines/uplinkerror.ogg', 50) - error = "Already extracting... Place the target into the pod. If the pod was destroyed, you will need to cancel this contract." - return 1 + error = "Already extracting... Place the target into the pod. If the pod was destroyed, this contract is no longer possible." + return TRUE if("PRG_contract_abort") var/contract_id = hard_drive.traitor_data.contractor_hub.current_contract.id hard_drive.traitor_data.contractor_hub.current_contract = null hard_drive.traitor_data.contractor_hub.assigned_contracts[contract_id].status = CONTRACT_STATUS_ABORTED program_icon_state = "contracts" - return 1 + return TRUE if("PRG_redeem_TC") if(hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem) - var/obj/item/stack/telecrystal/crystals = new /obj/item/stack/telecrystal(get_turf(user), hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem) + var/obj/item/stack/telecrystal/crystals = new /obj/item/stack/telecrystal(get_turf(user), + hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem) if(ishuman(user)) var/mob/living/carbon/human/H = user if(H.put_in_hands(crystals)) @@ -78,22 +84,23 @@ to_chat(user, "Your payment materializes onto the floor.") hard_drive.traitor_data.contractor_hub.contract_TC_payed_out += hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem = 0 - return 1 + return TRUE else user.playsound_local(user, 'sound/machines/uplinkerror.ogg', 50) - return 1 + return TRUE if("PRG_clear_error") error = "" - if("PRG_contractor_hub") - page = CONTRACT_UPLINK_PAGE_HUB - program_icon_state = "store" - if("PRG_hub_back") - page = CONTRACT_UPLINK_PAGE_CONTRACTS - program_icon_state = "contracts" + return TRUE + if("PRG_set_first_load_finished") + first_load = FALSE + return TRUE + if("PRG_toggle_info") + info_screen = !info_screen + return TRUE if("buy_hub") if(hard_drive.traitor_data.owner.current == user) var/item = params["item"] - for (var/datum/contractor_item/hub_item in hard_drive.traitor_data.contractor_hub.hub_items) + for(var/datum/contractor_item/hub_item in hard_drive.traitor_data.contractor_hub.hub_items) if (hub_item.name == item) hub_item.handle_purchase(hard_drive.traitor_data.contractor_hub, user) else @@ -104,21 +111,28 @@ var/obj/item/computer_hardware/hard_drive/small/syndicate/hard_drive = computer.all_components[MC_HDD] var/screen_to_be = null + data["first_load"] = first_load if(hard_drive && hard_drive.traitor_data != null) var/datum/antagonist/traitor/traitor_data = hard_drive.traitor_data - error = "" - data = get_header_data() + data += get_header_data() if(traitor_data.contractor_hub.current_contract) data["ongoing_contract"] = TRUE screen_to_be = "single_contract" if(traitor_data.contractor_hub.current_contract.status == CONTRACT_STATUS_EXTRACTING) data["extraction_enroute"] = TRUE screen_to_be = "extracted" + else + data["extraction_enroute"] = FALSE + else + data["ongoing_contract"] = FALSE + data["extraction_enroute"] = FALSE data["logged_in"] = TRUE data["station_name"] = GLOB.station_name data["redeemable_tc"] = traitor_data.contractor_hub.contract_TC_to_redeem + data["earned_tc"] = traitor_data.contractor_hub.contract_TC_payed_out + data["contracts_completed"] = traitor_data.contractor_hub.contracts_completed data["contract_rep"] = traitor_data.contractor_hub.contract_rep - data["page"] = page + data["info_screen"] = info_screen data["error"] = error for(var/datum/contractor_item/hub_item in traitor_data.contractor_hub.hub_items) data["contractor_hub_items"] += list(list( @@ -136,7 +150,8 @@ "payout_bonus" = contract.contract.payout_bonus, "dropoff" = contract.contract.dropoff, "id" = contract.id, - "status" = contract.status + "status" = contract.status, + "message" = contract.wanted_message )) var/direction @@ -155,14 +170,8 @@ else direction = "???" data["dropoff_direction"] = direction - if (page == CONTRACT_UPLINK_PAGE_HUB) - screen_to_be = "store" - if (!screen_to_be) - screen_to_be = "contracts" else data["logged_in"] = FALSE - if (!screen_to_be) - screen_to_be = "assign" program_icon_state = screen_to_be update_computer_icon() - return data \ No newline at end of file + return data diff --git a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm index 337e98acaa..9dedc3810f 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm @@ -4,11 +4,10 @@ program_icon_state = "hostile" extended_desc = "This advanced script can perform denial of service attacks against NTNet quantum relays. The system administrator will probably notice this. Multiple devices can run this program together against same relay for increased effect" size = 20 - requires_ntnet = 1 - available_on_ntnet = 0 - available_on_syndinet = 1 - tgui_id = "ntos_net_dos" - ui_style = "syndicate" + requires_ntnet = TRUE + available_on_ntnet = FALSE + available_on_syndinet = TRUE + tgui_id = "NtosNetDos" ui_x = 400 ui_y = 250 @@ -37,64 +36,55 @@ if(target) target.dos_sources.Remove(src) target = null - executed = 0 + executed = FALSE ..() /datum/computer_file/program/ntnet_dos/ui_act(action, params) if(..()) - return 1 + return switch(action) if("PRG_target_relay") for(var/obj/machinery/ntnet_relay/R in SSnetworks.station_network.relays) if("[R.uid]" == params["targid"]) target = R - return 1 + break + return TRUE if("PRG_reset") if(target) target.dos_sources.Remove(src) target = null - executed = 0 + executed = FALSE error = "" - return 1 + return TRUE if("PRG_execute") if(target) - executed = 1 + executed = TRUE target.dos_sources.Add(src) if(SSnetworks.station_network.intrusion_detection_enabled) var/obj/item/computer_hardware/network_card/network_card = computer.all_components[MC_NET] SSnetworks.station_network.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [network_card.get_network_tag()]") - SSnetworks.station_network.intrusion_detection_alarm = 1 - return 1 + SSnetworks.station_network.intrusion_detection_alarm = TRUE + return TRUE /datum/computer_file/program/ntnet_dos/ui_data(mob/user) if(!SSnetworks.station_network) return - var/list/data = list() + var/list/data = get_header_data() - data = get_header_data() - - if(error) - data["error"] = error - else if(target && executed) - data["target"] = 1 + data["error"] = error + if(target && executed) + data["target"] = TRUE data["speed"] = dos_speed - // This is mostly visual, generate some strings of 1s and 0s - // Probability of 1 is equal of completion percentage of DoS attack on this relay. - // Combined with UI updates this adds quite nice effect to the UI - var/percentage = target.dos_overload * 100 / target.dos_capacity - data["dos_strings"] = list() - for(var/j, j<10, j++) - var/string = "" - for(var/i, i<20, i++) - string = "[string][prob(percentage)]" - data["dos_strings"] += list(list("nums" = string)) + data["overload"] = target.dos_overload + data["capacity"] = target.dos_capacity else + data["target"] = FALSE data["relays"] = list() for(var/obj/machinery/ntnet_relay/R in SSnetworks.station_network.relays) data["relays"] += list(list("id" = R.uid)) data["focus"] = target ? target.uid : null - return data \ No newline at end of file + return data 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 103b70e496..a312815008 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm @@ -4,11 +4,10 @@ program_icon_state = "hostile" extended_desc = "This virus can destroy hard drive of system it is executed on. It may be obfuscated to look like another non-malicious program. Once armed, it will destroy the system upon next execution." size = 13 - requires_ntnet = 0 - available_on_ntnet = 0 - available_on_syndinet = 1 - tgui_id = "ntos_revelation" - ui_style = "syndicate" + requires_ntnet = FALSE + available_on_ntnet = FALSE + available_on_syndinet = TRUE + tgui_id = "NtosRevelation" ui_x = 400 ui_y = 250 @@ -22,7 +21,7 @@ /datum/computer_file/program/revelation/proc/activate() if(computer) computer.visible_message("\The [computer]'s screen brightly flashes and loud electrical buzzing is heard.") - computer.enabled = 0 + computer.enabled = FALSE computer.update_icon() var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD] var/obj/item/computer_hardware/battery/battery_module = computer.all_components[MC_CELL] @@ -44,18 +43,20 @@ /datum/computer_file/program/revelation/ui_act(action, params) if(..()) - return 1 + return switch(action) if("PRG_arm") armed = !armed + return TRUE if("PRG_activate") activate() + return TRUE if("PRG_obfuscate") - var/mob/living/user = usr - var/newname = sanitize(input(user, "Enter new program name: ")) + var/newname = params["new_name"] if(!newname) return filedesc = newname + return TRUE /datum/computer_file/program/revelation/clone() @@ -68,4 +69,4 @@ data["armed"] = armed - return data \ No newline at end of file + return data diff --git a/code/modules/modular_computers/file_system/programs/arcade.dm b/code/modules/modular_computers/file_system/programs/arcade.dm new file mode 100644 index 0000000000..87debafd6b --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/arcade.dm @@ -0,0 +1,169 @@ +/datum/computer_file/program/arcade + filename = "arcade" + filedesc = "Nanotrasen 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" + ui_x = 450 + ui_y = 350 + + ///Returns TRUE if the game is being played. + var/game_active = TRUE + ///This disables buttom actions from having any impact if TRUE. Resets to FALSE when the player is allowed to make an action again. + var/pause_state = FALSE + var/boss_hp = 45 + var/boss_mp = 15 + var/player_hp = 30 + var/player_mp = 10 + var/ticket_count = 0 + ///Shows what text is shown on the app, usually showing the log of combat actions taken by the player. + var/heads_up = "Nanotrasen says, winners make us money." + var/boss_name = "Cuban Pete's Minion" + ///Determines which boss image to use on the UI. + var/boss_id = 1 + +/datum/computer_file/program/arcade/proc/game_check(mob/user) + sleep(5) + 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) + game_active = FALSE + program_icon_state = "arcade_off" + if(istype(computer)) + computer.update_icon() + ticket_count += 1 + sleep(10) + else if(player_hp <= 0 || player_mp <= 0) + heads_up = "You have been defeated... how will the station survive?" + playsound(computer.loc, 'sound/arcade/lose.ogg', 50, TRUE, extrarange = -3, falloff = 10) + game_active = FALSE + program_icon_state = "arcade_off" + if(istype(computer)) + computer.update_icon() + sleep(10) + +/datum/computer_file/program/arcade/proc/enemy_check(mob/user) + var/boss_attackamt = 0 //Spam protection from boss attacks as well. + var/boss_mpamt = 0 + var/bossheal = 0 + if(pause_state == TRUE) + boss_attackamt = rand(3,6) + boss_mpamt = rand (2,4) + bossheal = rand (4,6) + if(game_active == FALSE) + return + if (boss_mp <= 5) + heads_up = "[boss_mpamt] magic power has been stolen from you!" + playsound(computer.loc, 'sound/arcade/steal.ogg', 50, TRUE, extrarange = -3, falloff = 10) + player_mp -= boss_mpamt + boss_mp += boss_mpamt + else if(boss_mp > 5 && boss_hp <12) + heads_up = "[boss_name] heals for [bossheal] health!" + playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3, falloff = 10) + boss_hp += bossheal + boss_mp -= boss_mpamt + else + heads_up = "[boss_name] attacks you for [boss_attackamt] damage!" + playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 10) + player_hp -= boss_attackamt + + pause_state = FALSE + game_check() + +/datum/computer_file/program/arcade/ui_interact(mob/user, ui_key, datum/tgui/ui, force_open, datum/tgui/master_ui, datum/ui_state/state) + . = ..() + var/datum/asset/assets = get_asset_datum(/datum/asset/simple/arcade) + assets.send(user) + +/datum/computer_file/program/arcade/ui_data(mob/user) + var/list/data = get_header_data() + + data["Hitpoints"] = boss_hp + data["PlayerHitpoints"] = player_hp + data["PlayerMP"] = player_mp + data["TicketCount"] = ticket_count + data["GameActive"] = game_active + data["PauseState"] = pause_state + data["Status"] = heads_up + data["BossID"] = "boss[boss_id].gif" + return data + +/datum/computer_file/program/arcade/ui_act(action, list/params) + if(..()) + return TRUE + var/obj/item/computer_hardware/printer/printer + if(computer) + printer = computer.all_components[MC_PRINT] + + switch(action) + if("Attack") + var/attackamt = 0 //Spam prevention. + if(pause_state == FALSE) + attackamt = rand(2,6) + pause_state = TRUE + heads_up = "You attack for [attackamt] damage." + playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 10) + boss_hp -= attackamt + sleep(10) + game_check() + enemy_check() + return TRUE + if("Heal") + var/healamt = 0 //More Spam Prevention. + var/healcost = 0 + if(pause_state == FALSE) + healamt = rand(6,8) + var/maxPointCost = 3 + healcost = rand(1, maxPointCost) + pause_state = TRUE + heads_up = "You heal for [healamt] damage." + playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3, falloff = 10) + player_hp += healamt + player_mp -= healcost + sleep(10) + game_check() + enemy_check() + return TRUE + if("Recharge_Power") + var/rechargeamt = 0 //As above. + if(pause_state == FALSE) + rechargeamt = rand(4, 7) + pause_state = TRUE + heads_up = "You regain [rechargeamt] magic power." + playsound(computer.loc, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3, falloff = 10) + player_mp += rechargeamt + sleep(10) + game_check() + enemy_check() + return TRUE + if("Dispense_Tickets") + if(!printer) + to_chat(usr, "Hardware error: A printer is required to redeem tickets.") + return + if(printer.stored_paper <= 0) + to_chat(usr, "Hardware error: Printer is out of paper.") + return + else + computer.visible_message("\The [computer] prints out paper.") + if(ticket_count >= 1) + new /obj/item/stack/arcadeticket((get_turf(computer)), 1) + to_chat(usr, "[src] dispenses a ticket!") + ticket_count -= 1 + printer.stored_paper -= 1 + else + to_chat(usr, "You don't have any stored tickets!") + return TRUE + if("Start_Game") + game_active = TRUE + boss_hp = 45 + player_hp = 30 + player_mp = 10 + heads_up = "You stand before [boss_name]! Prepare for battle!" + program_icon_state = "arcade" + boss_id = rand(1,6) + pause_state = FALSE + if(istype(computer)) + computer.update_icon() diff --git a/code/modules/modular_computers/file_system/programs/atmosscan.dm b/code/modules/modular_computers/file_system/programs/atmosscan.dm new file mode 100644 index 0000000000..fe3833facd --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/atmosscan.dm @@ -0,0 +1,33 @@ +/datum/computer_file/program/atmosscan + filename = "atmosscan" + filedesc = "Atmospheric Scanner" + 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" + ui_x = 300 + ui_y = 350 + +/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/datum/gas_mixture/environment = T.return_air() + var/list/env_gases = environment.gases + var/pressure = environment.return_pressure() + var/total_moles = environment.total_moles() + data["AirPressure"] = round(pressure,0.1) + data["AirTemp"] = round(environment.temperature-T0C) + if (total_moles) + for(var/id in env_gases) + var/gas_level = env_gases[id][MOLES]/total_moles + if(gas_level > 0) + airlist += list(list("name" = "[env_gases[id][GAS_META][META_GAS_NAME]]", "percentage" = round(gas_level*100, 0.01))) + data["AirData"] = airlist + return data + +/datum/computer_file/program/atmosscan/ui_act(action, list/params) + if(..()) + return TRUE diff --git a/code/modules/modular_computers/file_system/programs/borg_monitor.dm b/code/modules/modular_computers/file_system/programs/borg_monitor.dm new file mode 100644 index 0000000000..c493926c65 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/borg_monitor.dm @@ -0,0 +1,69 @@ +/datum/computer_file/program/borg_monitor + filename = "cyborgmonitor" + filedesc = "Cyborg Remote Monitoring" + 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" + ui_x = 600 + ui_y = 800 + +/datum/computer_file/program/borg_monitor/ui_data(mob/user) + var/list/data = get_header_data() + + data["card"] = FALSE + if(computer.GetID()) + data["card"] = TRUE + + data["cyborgs"] = list() + for(var/mob/living/silicon/robot/R in GLOB.silicon_mobs) + if((get_turf(computer)).z != (get_turf(R)).z) + continue + if(R.scrambledcodes) + continue + + var/list/upgrade + for(var/obj/item/borg/upgrade/I in R.upgrades) + upgrade += "\[[I.name]\] " + + var/shell = FALSE + if(R.shell && !R.ckey) + shell = TRUE + + var/list/cyborg_data = list( + name = R.name, + locked_down = R.locked_down, + status = R.stat, + shell_discon = shell, + charge = R.cell ? round(R.cell.percent()) : null, + module = R.module ? "[R.module.name] Module" : "No Module Detected", + upgrades = upgrade, + ref = REF(R) + ) + data["cyborgs"] += list(cyborg_data) + return data + +/datum/computer_file/program/borg_monitor/ui_act(action, params) + if(..()) + return + + switch(action) + if("messagebot") + var/mob/living/silicon/robot/R = locate(params["ref"]) in GLOB.silicon_mobs + if(!istype(R)) + return + var/obj/item/card/id/ID = computer.GetID() + if(!ID) + return + var/message = stripped_input(usr, message = "Enter message to be sent to remote cyborg.", title = "Send Message") + if(!message) + return + to_chat(R, "

    Message from [ID.registered_name] -- \"[message]\"
    ") + SEND_SOUND(R, 'sound/machines/twobeep_high.ogg') + if(R.connected_ai) + to_chat(R.connected_ai, "

    Message from [ID.registered_name] to [R] -- \"[message]\"
    ") + SEND_SOUND(R.connected_ai, 'sound/machines/twobeep_high.ogg') diff --git a/code/modules/modular_computers/file_system/programs/card.dm b/code/modules/modular_computers/file_system/programs/card.dm index bf58b120f2..07d39438d8 100644 --- a/code/modules/modular_computers/file_system/programs/card.dm +++ b/code/modules/modular_computers/file_system/programs/card.dm @@ -1,3 +1,11 @@ +#define CARDCON_DEPARTMENT_SERVICE "Service" +#define CARDCON_DEPARTMENT_SECURITY "Security" +#define CARDCON_DEPARTMENT_MEDICAL "Medical" +#define CARDCON_DEPARTMENT_SUPPLY "Supply" +#define CARDCON_DEPARTMENT_SCIENCE "Science" +#define CARDCON_DEPARTMENT_ENGINEERING "Engineering" +#define CARDCON_DEPARTMENT_COMMAND "Command" + /datum/computer_file/program/card_mod filename = "cardmod" filedesc = "ID Card Modification" @@ -6,97 +14,90 @@ transfer_access = ACCESS_HEADS requires_ntnet = 0 size = 8 - tgui_id = "ntos_card" - ui_x = 600 - ui_y = 700 + tgui_id = "NtosCard" + ui_x = 450 + ui_y = 520 - var/mod_mode = 1 - var/is_centcom = 0 - var/show_assignments = 0 - var/minor = 0 - var/authenticated = 0 - var/list/reg_ids = list() - var/list/region_access = null - var/list/head_subordinates = null - var/target_dept = 0 //Which department this computer has access to. 0=all departments - var/change_position_cooldown = 30 - //Jobs you cannot open new positions for - var/list/blacklisted = list( - "AI", - "Assistant", - "Cyborg", - "Captain", - "Head of Personnel", - "Head of Security", - "Chief Engineer", - "Research Director", - "Chief Medical Officer") + var/is_centcom = FALSE + var/minor = FALSE + var/authenticated = FALSE + var/list/region_access + var/list/head_subordinates + ///Which departments this computer has access to. Defined as access regions. null = all departments + var/target_dept - //The scaling factor of max total positions in relation to the total amount of people on board the station in % - var/max_relative_positions = 30 //30%: Seems reasonable, limit of 6 @ 20 players + //For some reason everything was exploding if this was static. + var/list/sub_managers - //This is used to keep track of opened positions for jobs to allow instant closing - //Assoc array: "JobName" = (int) - var/list/opened_positions = list(); +/datum/computer_file/program/card_mod/New(obj/item/modular_computer/comp) + . = ..() + sub_managers = list( + "[ACCESS_HOP]" = list( + "department" = list(CARDCON_DEPARTMENT_SERVICE, CARDCON_DEPARTMENT_COMMAND), + "region" = 1, + "head" = "Head of Personnel" + ), + "[ACCESS_HOS]" = list( + "department" = CARDCON_DEPARTMENT_SECURITY, + "region" = 2, + "head" = "Head of Security" + ), + "[ACCESS_CMO]" = list( + "department" = CARDCON_DEPARTMENT_MEDICAL, + "region" = 3, + "head" = "Chief Medical Officer" + ), + "[ACCESS_RD]" = list( + "department" = CARDCON_DEPARTMENT_SCIENCE, + "region" = 4, + "head" = "Research Director" + ), + "[ACCESS_CE]" = list( + "department" = CARDCON_DEPARTMENT_ENGINEERING, + "region" = 5, + "head" = "Chief Engineer" + ) + ) -/datum/computer_file/program/card_mod/New() - ..() - addtimer(CALLBACK(src, .proc/SetConfigCooldown), 0) +/datum/computer_file/program/card_mod/proc/authenticate(mob/user, obj/item/card/id/id_card) + if(!id_card) + return -/datum/computer_file/program/card_mod/proc/SetConfigCooldown() - change_position_cooldown = CONFIG_GET(number/id_console_jobslot_delay) + region_access = list() + if(!target_dept && (ACCESS_CHANGE_IDS in id_card.access)) + minor = FALSE + authenticated = TRUE + update_static_data(user) + return TRUE -/datum/computer_file/program/card_mod/event_idremoved(background, slot) - if(!slot || slot == 2)// slot being false means both are removed - minor = 0 - authenticated = 0 - head_subordinates = null - region_access = null + var/list/head_types = list() + for(var/access_text in sub_managers) + var/list/info = sub_managers[access_text] + var/access = text2num(access_text) + if((access in id_card.access) && ((info["region"] in target_dept) || !length(target_dept))) + region_access += info["region"] + //I don't even know what I'm doing anymore + head_types += info["head"] + head_subordinates = list() + if(length(head_types)) + for(var/j in SSjob.occupations) + var/datum/job/job = j + for(var/head in head_types)//god why + if(head in job.department_head) + head_subordinates += job.title -/datum/computer_file/program/card_mod/proc/job_blacklisted(jobtitle) - return (jobtitle in blacklisted) + if(length(region_access)) + minor = TRUE + authenticated = TRUE + update_static_data(user) + return TRUE - -//Logic check for if you can open the job -/datum/computer_file/program/card_mod/proc/can_open_job(datum/job/job) - if(job) - if(!job_blacklisted(job.title)) - if((job.total_positions <= GLOB.player_list.len * (max_relative_positions / 100))) - var/delta = (world.time / 10) - GLOB.time_last_changed_position - if((change_position_cooldown < delta) || (opened_positions[job.title] < 0)) - return 1 - return -2 - return 0 - return 0 - -//Logic check for if you can close the job -/datum/computer_file/program/card_mod/proc/can_close_job(datum/job/job) - if(job) - if(!job_blacklisted(job.title)) - if(job.total_positions > job.current_positions) - var/delta = (world.time / 10) - GLOB.time_last_changed_position - if((change_position_cooldown < delta) || (opened_positions[job.title] > 0)) - return 1 - return -2 - return 0 - return 0 - -/datum/computer_file/program/card_mod/proc/format_jobs(list/jobs) - var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD] - var/obj/item/card/id/id_card = card_slot.stored_card - var/list/formatted = list() - for(var/job in jobs) - formatted.Add(list(list( - "display_name" = replacetext(job, " ", " "), - "target_rank" = id_card && id_card.assignment ? id_card.assignment : "Unassigned", - "job" = job))) - - return formatted + return FALSE /datum/computer_file/program/card_mod/ui_act(action, params) if(..()) - return 1 + return TRUE var/obj/item/computer_hardware/card_slot/card_slot var/obj/item/computer_hardware/printer/printer @@ -106,192 +107,220 @@ if(!card_slot) return - var/obj/item/card/id/user_id_card = null var/mob/user = usr + var/obj/item/card/id/user_id_card = user.get_idcard(FALSE) var/obj/item/card/id/id_card = card_slot.stored_card - var/obj/item/card/id/auth_card = card_slot.stored_card2 - - if(auth_card) - user_id_card = auth_card - else - if(ishuman(user)) - var/mob/living/carbon/human/h = user - user_id_card = h.get_idcard(TRUE) switch(action) - if("PRG_switchm") - if(params["target"] == "mod") - mod_mode = 1 - else if (params["target"] == "manifest") - mod_mode = 0 - else if (params["target"] == "manage") - mod_mode = 2 - if("PRG_togglea") - if(show_assignments) - show_assignments = 0 - else - show_assignments = 1 + if("PRG_authenticate") + if(!computer || !user_id_card) + playsound(computer, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) + return + if(authenticate(user, user_id_card)) + playsound(computer, 'sound/machines/terminal_on.ogg', 50, FALSE) + return TRUE + if("PRG_logout") + authenticated = FALSE + playsound(computer, 'sound/machines/terminal_off.ogg', 50, FALSE) + return TRUE if("PRG_print") - if(computer && printer) //This option should never be called if there is no printer - if(mod_mode) - if(authorized()) - 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"]
    -
    - Assignment: [id_card.assignment]
    - Access:
    - "} + if(!computer || !printer) + return + if(!authenticated) + 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"]
    +
    + Assignment: [id_card.assignment]
    + Access:
    + "} - var/known_access_rights = get_all_accesses() - for(var/A in id_card.access) - if(A in known_access_rights) - contents += " [get_access_desc(A)]" + var/known_access_rights = get_all_accesses() + for(var/A in id_card.access) + if(A in known_access_rights) + contents += " [get_access_desc(A)]" - if(!printer.print_text(contents,"access report")) - to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") - return - else - computer.visible_message("\The [computer] prints out paper.") - else - var/contents = {"

    Crew Manifest

    -
    - [GLOB.data_core ? GLOB.data_core.get_manifest(0) : ""] - "} - if(!printer.print_text(contents,text("crew manifest ([])", STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)))) - to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") - return - else - computer.visible_message("\The [computer] prints out paper.") - if("PRG_eject") - if(computer && card_slot) - var/select = params["target"] - switch(select) - if("id") - if(id_card) - GLOB.data_core.manifest_modify(id_card.registered_name, id_card.assignment) - card_slot.try_eject(1, user) - else - var/obj/item/I = usr.get_active_held_item() - if (istype(I, /obj/item/card/id)) - if(!usr.transferItemToLoc(I, computer)) - return - card_slot.stored_card = I - if("auth") - if(auth_card) - if(id_card) - GLOB.data_core.manifest_modify(id_card.registered_name, id_card.assignment) - head_subordinates = null - region_access = null - authenticated = 0 - minor = 0 - card_slot.try_eject(2, user) - else - var/obj/item/I = usr.get_active_held_item() - if (istype(I, /obj/item/card/id)) - if(!usr.transferItemToLoc(I, computer)) - return - card_slot.stored_card2 = I - if("PRG_terminate") - if(computer && ((id_card.assignment in head_subordinates) || id_card.assignment == "Assistant")) - id_card.assignment = "Unassigned" - remove_nt_access(id_card) - - if("PRG_edit") - if(computer && authorized()) - if(params["name"]) - var/temp_name = reject_bad_name(input("Enter name.", "Name", id_card.registered_name)) - if(temp_name) - id_card.registered_name = temp_name - else - computer.visible_message("[computer] buzzes rudely.") - //else if(params["account"]) - // var/account_num = text2num(input("Enter account number.", "Account", id_card.associated_account_number)) - // id_card.associated_account_number = account_num - if("PRG_assign") - if(computer && authorized() && id_card) - var/t1 = params["assign_target"] - if(t1 == "Custom") - var/temp_t = reject_bad_text(input("Enter a custom job assignment.","Assignment", id_card.assignment), 45) - //let custom jobs function as an impromptu alt title, mainly for sechuds - if(temp_t) - id_card.assignment = temp_t - else - var/list/access = list() - if(is_centcom) - access = get_centcom_access(t1) - else - var/datum/job/jobdatum - for(var/jobtype in typesof(/datum/job)) - var/datum/job/J = new jobtype - if(ckey(J.title) == ckey(t1)) - jobdatum = J - break - if(!jobdatum) - to_chat(usr, "No log exists for this job: [t1]") - return - - access = jobdatum.get_access() - - remove_nt_access(id_card) - apply_access(id_card, access) - id_card.assignment = t1 - - if("PRG_access") - if(params["allowed"] && computer && authorized()) - var/access_type = text2num(params["access_target"]) - var/access_allowed = text2num(params["allowed"]) - if(access_type in (is_centcom ? get_all_centcom_access() : get_all_accesses())) - id_card.access -= access_type - if(!access_allowed) - id_card.access += access_type - if("PRG_open_job") - var/edit_job_target = params["target"] - var/datum/job/j = SSjob.GetJob(edit_job_target) - if(!j) - return 0 - if(can_open_job(j) != 1) - return 0 - if(opened_positions[edit_job_target] >= 0) - GLOB.time_last_changed_position = world.time / 10 - j.total_positions++ - opened_positions[edit_job_target]++ - if("PRG_close_job") - var/edit_job_target = params["target"] - var/datum/job/j = SSjob.GetJob(edit_job_target) - if(!j) - return 0 - if(can_close_job(j) != 1) - return 0 - //Allow instant closing without cooldown if a position has been opened before - if(opened_positions[edit_job_target] <= 0) - GLOB.time_last_changed_position = world.time / 10 - j.total_positions-- - opened_positions[edit_job_target]-- - if("PRG_regsel") - if(!reg_ids) - reg_ids = list() - var/regsel = text2num(params["region"]) - if(regsel in reg_ids) - reg_ids -= regsel + if(!printer.print_text(contents,"access report")) + to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") + return else - reg_ids += regsel + playsound(computer, 'sound/machines/terminal_on.ogg', 50, FALSE) + computer.visible_message("\The [computer] prints out a paper.") + return TRUE + if("PRG_eject") + if(!computer || !card_slot) + return + if(id_card) + GLOB.data_core.manifest_modify(id_card.registered_name, id_card.assignment) + card_slot.try_eject(TRUE, 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 + if("PRG_terminate") + if(!computer || !authenticated) + return + if(minor) + if(!(id_card.assignment in head_subordinates) && id_card.assignment != "Assistant") + return - if(id_card) - id_card.name = text("[id_card.registered_name]'s ID Card ([id_card.assignment])") + id_card.access -= get_all_centcom_access() + get_all_accesses() + id_card.assignment = "Unassigned" + id_card.update_label() + playsound(computer, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) + return TRUE + if("PRG_edit") + if(!computer || !authenticated || !id_card) + return + var/new_name = params["name"] + if(!new_name) + return + id_card.registered_name = new_name + id_card.update_label() + playsound(computer, "terminal_type", 50, FALSE) + return TRUE + if("PRG_assign") + if(!computer || !authenticated || !id_card) + return + var/target = params["assign_target"] + if(!target) + return - return 1 + if(target == "Custom") + var/custom_name = params["custom_name"] + if(custom_name) + id_card.assignment = custom_name + id_card.update_label() + else + if(minor && !(target in head_subordinates)) + return + var/list/new_access = list() + if(is_centcom) + new_access = get_centcom_access(target) + else + var/datum/job/job + for(var/jobtype in subtypesof(/datum/job)) + var/datum/job/J = new jobtype + if(J.title == target) + job = J + break + if(!job) + 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() + playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) + return TRUE + if("PRG_access") + if(!computer || !authenticated) + 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 + else + 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()) + playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) + return TRUE + if("PRG_denyall") + if(!computer || !authenticated || minor) + return + id_card.access.Cut() + playsound(computer, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) + return TRUE + if("PRG_grantregion") + if(!computer || !authenticated) + return + var/region = text2num(params["region"]) + if(isnull(region)) + return + id_card.access |= get_region_accesses(region) + playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) + return TRUE + if("PRG_denyregion") + if(!computer || !authenticated) + return + var/region = text2num(params["region"]) + if(isnull(region)) + return + id_card.access -= get_region_accesses(region) + playsound(computer, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) + return TRUE -/datum/computer_file/program/card_mod/proc/remove_nt_access(obj/item/card/id/id_card) - id_card.access -= get_all_accesses() - id_card.access -= get_all_centcom_access() -/datum/computer_file/program/card_mod/proc/apply_access(obj/item/card/id/id_card, list/accesses) - id_card.access |= accesses + +/datum/computer_file/program/card_mod/ui_static_data(mob/user) + var/list/data = list() + data["station_name"] = station_name() + data["centcom_access"] = is_centcom + data["minor"] = target_dept || minor ? TRUE : FALSE + + var/list/departments = target_dept + if(is_centcom) + departments = list("CentCom" = get_all_centcom_jobs()) + else if(isnull(departments)) + departments = list( + CARDCON_DEPARTMENT_COMMAND = list("Captain"), + CARDCON_DEPARTMENT_ENGINEERING = GLOB.engineering_positions, + CARDCON_DEPARTMENT_MEDICAL = GLOB.medical_positions, + CARDCON_DEPARTMENT_SCIENCE = GLOB.science_positions, + CARDCON_DEPARTMENT_SECURITY = GLOB.security_positions, + CARDCON_DEPARTMENT_SUPPLY = GLOB.supply_positions, + CARDCON_DEPARTMENT_SERVICE = GLOB.civilian_positions + ) + data["jobs"] = list() + for(var/department in departments) + var/list/job_list = departments[department] + var/list/department_jobs = list() + for(var/job in job_list) + if(minor && !(job in head_subordinates)) + continue + department_jobs += list(list( + "display_name" = replacetext(job, " ", " "), + "job" = job + )) + if(length(department_jobs)) + data["jobs"][department] = department_jobs + + var/list/regions = list() + for(var/i in 1 to 7) + if((minor || target_dept) && !(i in region_access)) + continue + + var/list/accesses = list() + for(var/access in get_region_accesses(i)) + if (get_access_desc(access)) + accesses += list(list( + "desc" = replacetext(get_access_desc(access), " ", " "), + "ref" = access, + )) + + regions += list(list( + "name" = get_region_accesses_name(i), + "regid" = i, + "accesses" = accesses + )) + + data["regions"] = regions + + return data /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 @@ -301,181 +330,34 @@ card_slot = computer.all_components[MC_CARD] printer = computer.all_components[MC_PRINT] - data["mmode"] = mod_mode - - var/authed = 0 - if(computer) - if(card_slot) - var/obj/item/card/id/auth_card = card_slot.stored_card2 - data["auth_name"] = auth_card ? strip_html_simple(auth_card.name) : "-----" - authed = authorized() - - - if(mod_mode == 2) - data["slots"] = list() - var/list/pos = list() - for(var/datum/job/job in SSjob.occupations) - if(job.title in blacklisted) - continue - - var/list/status_open = build_manage(job,1) - var/list/status_close = build_manage(job,0) - - pos.Add(list(list( - "title" = job.title, - "current" = job.current_positions, - "total" = job.total_positions, - "status_open" = (authed && !minor) ? status_open["enable"]: 0, - "status_close" = (authed && !minor) ? status_close["enable"] : 0, - "desc_open" = status_open["desc"], - "desc_close" = status_close["desc"]))) - data["slots"] = pos - - data["src"] = "[REF(src)]" data["station_name"] = station_name() - - if(!mod_mode) - data["manifest"] = list() - var/list/crew = list() - for(var/datum/data/record/t in sortRecord(GLOB.data_core.general)) - crew.Add(list(list( - "name" = t.fields["name"], - "rank" = t.fields["rank"]))) - - data["manifest"] = crew - data["assignments"] = show_assignments if(computer) data["have_id_slot"] = !!card_slot data["have_printer"] = !!printer - if(!card_slot && mod_mode == 1) - mod_mode = 0 //We can't modify IDs when there is no card reader else - data["have_id_slot"] = 0 - data["have_printer"] = 0 + data["have_id_slot"] = FALSE + data["have_printer"] = FALSE - data["centcom_access"] = is_centcom - - - data["authenticated"] = authed - - - if(mod_mode == 1 && computer) - if(card_slot) - var/obj/item/card/id/id_card = card_slot.stored_card - - data["has_id"] = !!id_card - data["id_rank"] = id_card && id_card.assignment ? html_encode(id_card.assignment) : "Unassigned" - data["id_owner"] = id_card && id_card.registered_name ? html_encode(id_card.registered_name) : "-----" - data["id_name"] = id_card ? strip_html_simple(id_card.name) : "-----" - - if(show_assignments) - data["engineering_jobs"] = format_jobs(GLOB.engineering_positions) - data["medical_jobs"] = format_jobs(GLOB.medical_positions) - data["science_jobs"] = format_jobs(GLOB.science_positions) - data["security_jobs"] = format_jobs(GLOB.security_positions) - data["cargo_jobs"] = format_jobs(GLOB.supply_positions) - data["civilian_jobs"] = format_jobs(GLOB.civilian_positions) - data["centcom_jobs"] = format_jobs(get_all_centcom_jobs()) - - - if(card_slot.stored_card) - var/obj/item/card/id/id_card = card_slot.stored_card - if(is_centcom) - var/list/all_centcom_access = list() - for(var/access in get_all_centcom_access()) - all_centcom_access.Add(list(list( - "desc" = replacetext(get_centcom_access_desc(access), " ", " "), - "ref" = access, - "allowed" = (access in id_card.access) ? 1 : 0))) - data["all_centcom_access"] = all_centcom_access - else - var/list/regions = list() - for(var/i = 1; i <= 7; i++) - if((minor || target_dept) && !(i in region_access)) - continue - - var/list/accesses = list() - if(i in reg_ids) - for(var/access in get_region_accesses(i)) - if (get_access_desc(access)) - accesses.Add(list(list( - "desc" = replacetext(get_access_desc(access), " ", " "), - "ref" = access, - "allowed" = (access in id_card.access) ? 1 : 0))) - - regions.Add(list(list( - "name" = get_region_accesses_name(i), - "regid" = i, - "selected" = (i in reg_ids) ? 1 : null, - "accesses" = accesses))) - data["regions"] = regions - - data["minor"] = target_dept || minor ? 1 : 0 + data["authenticated"] = authenticated + if(computer) + var/obj/item/card/id/id_card = card_slot.stored_card + data["has_id"] = !!id_card + data["id_name"] = id_card ? id_card.name : "-----" + if(id_card) + data["id_rank"] = id_card.assignment ? id_card.assignment : "Unassigned" + data["id_owner"] = id_card.registered_name ? id_card.registered_name : "-----" + data["access_on_card"] = id_card.access return data -/datum/computer_file/program/card_mod/proc/build_manage(datum/job,open = FALSE) - var/out = "Denied" - var/can_change= 0 - if(open) - can_change = can_open_job(job) - else - can_change = can_close_job(job) - var/enable = 0 - if(can_change == 1) - out = "[open ? "Open Position" : "Close Position"]" - enable = 1 - else if(can_change == -2) - var/time_to_wait = round(change_position_cooldown - ((world.time / 10) - GLOB.time_last_changed_position), 1) - var/mins = round(time_to_wait / 60) - var/seconds = time_to_wait - (60*mins) - out = "Cooldown ongoing: [mins]:[(seconds < 10) ? "0[seconds]" : "[seconds]"]" - else - out = "Denied" - return list("enable" = enable, "desc" = out) - - -/datum/computer_file/program/card_mod/proc/authorized() - if(!authenticated && computer) - var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD] - if(card_slot) - var/obj/item/card/id/auth_card = card_slot.stored_card2 - if(auth_card) - region_access = list() - if(ACCESS_CHANGE_IDS in auth_card.GetAccess()) - minor = 0 - authenticated = 1 - return 1 - else - if((ACCESS_HOP in auth_card.access) && ((target_dept==1) || !target_dept)) - region_access |= 1 - region_access |= 6 - get_subordinates("Head of Personnel") - if((ACCESS_HOS in auth_card.access) && ((target_dept==2) || !target_dept)) - region_access |= 2 - get_subordinates("Head of Security") - if((ACCESS_CMO in auth_card.access) && ((target_dept==3) || !target_dept)) - region_access |= 3 - get_subordinates("Chief Medical Officer") - if((ACCESS_RD in auth_card.access) && ((target_dept==4) || !target_dept)) - region_access |= 4 - get_subordinates("Research Director") - if((ACCESS_CE in auth_card.access) && ((target_dept==5) || !target_dept)) - region_access |= 5 - get_subordinates("Chief Engineer") - if(region_access.len) - minor = 1 - authenticated = 1 - return 1 - else - return authenticated - -/datum/computer_file/program/card_mod/proc/get_subordinates(rank) - head_subordinates = list() - for(var/datum/job/job in SSjob.occupations) - if(rank in job.department_head) - head_subordinates += job.title +#undef CARDCON_DEPARTMENT_SERVICE +#undef CARDCON_DEPARTMENT_SECURITY +#undef CARDCON_DEPARTMENT_MEDICAL +#undef CARDCON_DEPARTMENT_SCIENCE +#undef CARDCON_DEPARTMENT_SUPPLY +#undef CARDCON_DEPARTMENT_ENGINEERING +#undef CARDCON_DEPARTMENT_COMMAND diff --git a/code/modules/modular_computers/file_system/programs/cargoship.dm b/code/modules/modular_computers/file_system/programs/cargoship.dm new file mode 100644 index 0000000000..39543adfa5 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/cargoship.dm @@ -0,0 +1,74 @@ +/datum/computer_file/program/shipping + filename = "shipping" + filedesc = "Nanotrasen Shipping Scanner" + 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" + ui_x = 450 + ui_y = 350 + ///Account used for creating barcodes. + var/datum/bank_account/payments_acc + ///The amount which the tagger will recieve for the sale. + var/percent_cut = 20 + +/datum/computer_file/program/shipping/ui_data(mob/user) + var/list/data = get_header_data() + + var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD] + var/obj/item/computer_hardware/printer/printer = computer.all_components[MC_PRINT] + var/obj/item/card/id/id_card = card_slot ? card_slot.stored_card : null + data["has_id_slot"] = !!card_slot + data["has_printer"] = !!printer + data["paperamt"] = printer ? "[printer.stored_paper] / [printer.max_paper]" : null + data["card_owner"] = card_slot && card_slot.stored_card ? id_card.registered_name : "No Card Inserted." + data["current_user"] = payments_acc ? payments_acc.account_holder : null + data["barcode_split"] = percent_cut + return data + +/datum/computer_file/program/shipping/ui_act(action, list/params) + if(..()) + return TRUE + if(!computer) + return + + // Get components + var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD] + var/obj/item/computer_hardware/printer/printer = computer.all_components[MC_PRINT] + var/obj/item/card/id/id_card = card_slot ? card_slot.stored_card : null + if(!card_slot || !printer) //We need both to successfully use this app. + return + + switch(action) + if("ejectid") + if(id_card) + card_slot.try_eject(TRUE, usr) + if("selectid") + if(!id_card) + return + if(!id_card.registered_account) + playsound(get_turf(ui_host()), 'sound/machines/buzz-sigh.ogg', 50, TRUE, -1) + return + payments_acc = id_card.registered_account + playsound(get_turf(ui_host()), 'sound/machines/ping.ogg', 50, TRUE, -1) + if("resetid") + payments_acc = null + if("setsplit") + var/potential_cut = input("How much would you like to payout to the registered card?","Percentage Profit") as num|null + percent_cut = potential_cut ? clamp(round(potential_cut, 1), 1, 50) : 20 + if("print") + if(!printer) + to_chat(usr, "Hardware error: A printer is required to print barcodes.") + return + if(printer.stored_paper <= 0) + to_chat(usr, "Hardware error: Printer is out of paper.") + return + if(!payments_acc) + to_chat(usr, "Software error: Please set a current user first.") + return + var/obj/item/barcode/barcode = new /obj/item/barcode(get_turf(ui_host())) + barcode.payments_acc = payments_acc + barcode.percent_cut = percent_cut + printer.stored_paper-- + to_chat(usr, "The computer prints out a barcode.") diff --git a/code/modules/modular_computers/file_system/programs/configurator.dm b/code/modules/modular_computers/file_system/programs/configurator.dm index 2d60323d10..76da58ea11 100644 --- a/code/modules/modular_computers/file_system/programs/configurator.dm +++ b/code/modules/modular_computers/file_system/programs/configurator.dm @@ -14,7 +14,7 @@ ui_y = 630 available_on_ntnet = 0 requires_ntnet = 0 - tgui_id = "ntos_configuration" + tgui_id = "NtosConfiguration" var/obj/item/modular_computer/movable = null diff --git a/code/modules/modular_computers/file_system/programs/crewmanifest.dm b/code/modules/modular_computers/file_system/programs/crewmanifest.dm new file mode 100644 index 0000000000..662c867a39 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/crewmanifest.dm @@ -0,0 +1,50 @@ +/datum/computer_file/program/crew_manifest + filename = "crewmani" + filedesc = "Crew Manifest" + program_icon_state = "id" + extended_desc = "Program for viewing and printing the current crew manifest" + transfer_access = ACCESS_HEADS + requires_ntnet = FALSE + size = 4 + tgui_id = "NtosCrewManifest" + ui_x = 400 + ui_y = 480 + +/datum/computer_file/program/crew_manifest/ui_static_data(mob/user) + var/list/data = list() + data["manifest"] = GLOB.data_core.get_manifest() + return data + +/datum/computer_file/program/crew_manifest/ui_data(mob/user) + var/list/data = get_header_data() + + var/obj/item/computer_hardware/printer/printer + if(computer) + printer = computer.all_components[MC_PRINT] + + if(computer) + data["have_printer"] = !!printer + else + data["have_printer"] = FALSE + return data + +/datum/computer_file/program/crew_manifest/ui_act(action, params, datum/tgui/ui) + if(..()) + return + + var/obj/item/computer_hardware/printer/printer + if(computer) + printer = computer.all_components[MC_PRINT] + + switch(action) + if("PRG_print") + if(computer && printer) //This option should never be called if there is no printer + var/contents = {"

    Crew Manifest

    +
    + [GLOB.data_core ? GLOB.data_core.get_manifest_html(0) : ""] + "} + if(!printer.print_text(contents,text("crew manifest ([])", station_time_timestamp()))) + to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") + return + else + computer.visible_message("\The [computer] prints out a paper.") diff --git a/code/modules/modular_computers/file_system/programs/file_browser.dm b/code/modules/modular_computers/file_system/programs/file_browser.dm index cba82eac18..aba826fce8 100644 --- a/code/modules/modular_computers/file_system/programs/file_browser.dm +++ b/code/modules/modular_computers/file_system/programs/file_browser.dm @@ -4,186 +4,67 @@ extended_desc = "This program allows management of files." program_icon_state = "generic" size = 8 - requires_ntnet = 0 - available_on_ntnet = 0 - undeletable = 1 - tgui_id = "ntos_file_manager" + requires_ntnet = FALSE + available_on_ntnet = FALSE + undeletable = TRUE + tgui_id = "NtosFileManager" var/open_file var/error /datum/computer_file/program/filemanager/ui_act(action, params) if(..()) - return 1 + return var/obj/item/computer_hardware/hard_drive/HDD = computer.all_components[MC_HDD] var/obj/item/computer_hardware/hard_drive/RHDD = computer.all_components[MC_SDD] - var/obj/item/computer_hardware/printer/printer = computer.all_components[MC_PRINT] switch(action) - if("PRG_openfile") - . = 1 - open_file = params["name"] - if("PRG_newtextfile") - . = 1 - var/newname = stripped_input(usr, "Enter file name or leave blank to cancel:", "File rename", max_length=50) - if(!newname) - return 1 - if(!HDD) - return 1 - var/datum/computer_file/data/F = new/datum/computer_file/data() - F.filename = newname - F.filetype = "TXT" - HDD.store_file(F) if("PRG_deletefile") - . = 1 if(!HDD) - return 1 + return var/datum/computer_file/file = HDD.find_file_by_name(params["name"]) if(!file || file.undeletable) - return 1 + return HDD.remove_file(file) + return TRUE if("PRG_usbdeletefile") - . = 1 if(!RHDD) - return 1 + return var/datum/computer_file/file = RHDD.find_file_by_name(params["name"]) if(!file || file.undeletable) - return 1 - RHDD.remove_file(file) - if("PRG_closefile") - . = 1 - open_file = null - error = null - if("PRG_clone") - . = 1 - if(!HDD) - return 1 - var/datum/computer_file/F = HDD.find_file_by_name(params["name"]) - if(!F || !istype(F)) - return 1 - var/datum/computer_file/C = F.clone(1) - HDD.store_file(C) - if("PRG_rename") - . = 1 - if(!HDD) - return 1 - var/datum/computer_file/file = HDD.find_file_by_name(params["name"]) - if(!file || !istype(file)) - return 1 - var/newname = stripped_input(usr, "Enter new file name:", "File rename", file.filename, max_length=50) - if(file && newname) - file.filename = newname - if("PRG_edit") - . = 1 - if(!open_file) - return 1 - if(!HDD) - return 1 - var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) - if(!F || !istype(F)) - return 1 - if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No")) - return 1 - // 16384 is the limit for file length in characters. Currently, papers have value of 2048 so this is 8 times as long, since we can't edit parts of the file independently. - var/newtext = stripped_multiline_input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", html_decode(F.stored_data), 16384, TRUE) - if(!newtext) return - if(F) - var/datum/computer_file/data/backup = F.clone() - HDD.remove_file(F) - F.stored_data = newtext - F.calculate_size() - // We can't store the updated file, it's probably too large. Print an error and restore backed up version. - // This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space. - // They will be able to copy-paste the text from error screen and store it in notepad or something. - if(!HDD.store_file(F)) - error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:

    [F.stored_data]

    " - HDD.store_file(backup) - if("PRG_printfile") - . = 1 - if(!open_file) - return 1 + RHDD.remove_file(file) + return TRUE + if("PRG_rename") if(!HDD) - return 1 - var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) - if(!F || !istype(F)) - return 1 - if(!printer) - error = "Missing Hardware: Your computer does not have required hardware to complete this operation." - return 1 - if(!printer.print_text("" + prepare_printjob(F.stored_data) + "", open_file)) - error = "Hardware error: Printer was unable to print the file. It may be out of paper." - return 1 + return + var/datum/computer_file/file = HDD.find_file_by_name(params["name"]) + if(!file) + return + var/newname = params["new_name"] + if(!newname) + return + file.filename = newname + return TRUE if("PRG_copytousb") - . = 1 if(!HDD || !RHDD) - return 1 + return var/datum/computer_file/F = HDD.find_file_by_name(params["name"]) - if(!F || !istype(F)) - return 1 - var/datum/computer_file/C = F.clone(0) + if(!F) + return + var/datum/computer_file/C = F.clone(FALSE) RHDD.store_file(C) + return TRUE if("PRG_copyfromusb") - . = 1 if(!HDD || !RHDD) - return 1 + return var/datum/computer_file/F = RHDD.find_file_by_name(params["name"]) if(!F || !istype(F)) - return 1 - var/datum/computer_file/C = F.clone(0) + return + var/datum/computer_file/C = F.clone(FALSE) HDD.store_file(C) - -/datum/computer_file/program/filemanager/proc/parse_tags(t) - t = replacetext(t, "\[center\]", "
    ") - t = replacetext(t, "\[/center\]", "
    ") - t = replacetext(t, "\[br\]", "
    ") - t = replacetext(t, "\n", "
    ") - t = replacetext(t, "\[b\]", "") - t = replacetext(t, "\[/b\]", "") - t = replacetext(t, "\[i\]", "") - t = replacetext(t, "\[/i\]", "") - t = replacetext(t, "\[u\]", "") - t = replacetext(t, "\[/u\]", "") - t = replacetext(t, "\[time\]", "[STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)]") - t = replacetext(t, "\[date\]", "[time2text(world.realtime, "MMM DD")] [GLOB.year_integer]") - t = replacetext(t, "\[large\]", "") - t = replacetext(t, "\[/large\]", "") - t = replacetext(t, "\[h1\]", "

    ") - t = replacetext(t, "\[/h1\]", "

    ") - t = replacetext(t, "\[h2\]", "

    ") - t = replacetext(t, "\[/h2\]", "

    ") - t = replacetext(t, "\[h3\]", "

    ") - t = replacetext(t, "\[/h3\]", "

    ") - t = replacetext(t, "\[*\]", "
  • ") - t = replacetext(t, "\[hr\]", "
    ") - t = replacetext(t, "\[small\]", "") - t = replacetext(t, "\[/small\]", "") - t = replacetext(t, "\[list\]", "
      ") - t = replacetext(t, "\[/list\]", "
    ") - t = replacetext(t, "\[table\]", "") - t = replacetext(t, "\[/table\]", "
    ") - t = replacetext(t, "\[grid\]", "") - t = replacetext(t, "\[/grid\]", "
    ") - t = replacetext(t, "\[row\]", "") - t = replacetext(t, "\[tr\]", "") - t = replacetext(t, "\[td\]", "") - t = replacetext(t, "\[cell\]", "") - t = replacetext(t, "\[tab\]", "    ") - - t = parsemarkdown_basic(t) - - return t - -/datum/computer_file/program/filemanager/proc/prepare_printjob(t) // Additional stuff to parse if we want to print it and make a happy Head of Personnel. Forms FTW. - t = replacetext(t, "\[field\]", "") - t = replacetext(t, "\[sign\]", "") - - t = parse_tags(t) - - t = replacetext(t, regex("(?:%s(?:ign)|%f(?:ield))(?=\\s|$)", "ig"), "") - - return t + return TRUE /datum/computer_file/program/filemanager/ui_data(mob/user) var/list/data = get_header_data() @@ -192,41 +73,28 @@ var/obj/item/computer_hardware/hard_drive/portable/RHDD = computer.all_components[MC_SDD] if(error) data["error"] = error - if(open_file) - var/datum/computer_file/data/file - - if(!computer || !HDD) - data["error"] = "I/O ERROR: Unable to access hard drive." - else - file = HDD.find_file_by_name(open_file) - if(!istype(file)) - data["error"] = "I/O ERROR: Unable to open file." - else - data["filedata"] = parse_tags(file.stored_data) - data["filename"] = "[file.filename].[file.filetype]" + if(!computer || !HDD) + data["error"] = "I/O ERROR: Unable to access hard drive." else - if(!computer || !HDD) - data["error"] = "I/O ERROR: Unable to access hard drive." - else - var/list/files[0] - for(var/datum/computer_file/F in HDD.stored_files) - files.Add(list(list( + var/list/files = list() + for(var/datum/computer_file/F in HDD.stored_files) + files += list(list( + "name" = F.filename, + "type" = F.filetype, + "size" = F.size, + "undeletable" = F.undeletable + )) + data["files"] = files + if(RHDD) + data["usbconnected"] = TRUE + var/list/usbfiles = list() + for(var/datum/computer_file/F in RHDD.stored_files) + usbfiles += list(list( "name" = F.filename, "type" = F.filetype, "size" = F.size, "undeletable" = F.undeletable - ))) - data["files"] = files - if(RHDD) - data["usbconnected"] = 1 - var/list/usbfiles[0] - for(var/datum/computer_file/F in RHDD.stored_files) - usbfiles.Add(list(list( - "name" = F.filename, - "type" = F.filetype, - "size" = F.size, - "undeletable" = F.undeletable - ))) - data["usbfiles"] = usbfiles + )) + data["usbfiles"] = usbfiles return data diff --git a/code/modules/modular_computers/file_system/programs/jobmanagement.dm b/code/modules/modular_computers/file_system/programs/jobmanagement.dm new file mode 100644 index 0000000000..7b847c123e --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/jobmanagement.dm @@ -0,0 +1,141 @@ +/datum/computer_file/program/job_management + filename = "job_manage" + filedesc = "Job Manager" + program_icon_state = "id" + extended_desc = "Program for viewing and changing job slot avalibility." + transfer_access = ACCESS_HEADS + requires_ntnet = 0 + size = 4 + tgui_id = "NtosJobManager" + ui_x = 400 + ui_y = 620 + + var/change_position_cooldown = 30 + //Jobs you cannot open new positions for + var/list/blacklisted = list( + "AI", + "Assistant", + "Cyborg", + "Captain", + "Head of Personnel", + "Head of Security", + "Chief Engineer", + "Research Director", + "Chief Medical Officer") + + //The scaling factor of max total positions in relation to the total amount of people on board the station in % + var/max_relative_positions = 30 //30%: Seems reasonable, limit of 6 @ 20 players + + //This is used to keep track of opened positions for jobs to allow instant closing + //Assoc array: "JobName" = (int) + var/list/opened_positions = list() + +/datum/computer_file/program/job_management/New() + ..() + change_position_cooldown = CONFIG_GET(number/id_console_jobslot_delay) + +/datum/computer_file/program/job_management/proc/can_open_job(datum/job/job) + if(!(job?.title in blacklisted)) + if((job.total_positions <= length(GLOB.player_list) * (max_relative_positions / 100))) + var/delta = (world.time / 10) - GLOB.time_last_changed_position + if((change_position_cooldown < delta) || (opened_positions[job.title] < 0)) + return TRUE + return FALSE + +/datum/computer_file/program/job_management/proc/can_close_job(datum/job/job) + if(!(job?.title in blacklisted)) + if(job.total_positions > length(GLOB.player_list) * (max_relative_positions / 100)) + var/delta = (world.time / 10) - GLOB.time_last_changed_position + if((change_position_cooldown < delta) || (opened_positions[job.title] > 0)) + return TRUE + return FALSE + +/datum/computer_file/program/job_management/ui_act(action, params, datum/tgui/ui) + if(..()) + return + + var/authed = FALSE + var/mob/user = usr + var/obj/item/card/id/user_id = user.get_idcard() + if(user_id) + if(ACCESS_CHANGE_IDS in user_id.access) + authed = TRUE + + if(!authed) + return + + switch(action) + if("PRG_open_job") + var/edit_job_target = params["target"] + var/datum/job/j = SSjob.GetJob(edit_job_target) + if(!j || !can_open_job(j)) + return + if(opened_positions[edit_job_target] >= 0) + GLOB.time_last_changed_position = world.time / 10 + j.total_positions++ + opened_positions[edit_job_target]++ + playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) + return TRUE + if("PRG_close_job") + var/edit_job_target = params["target"] + var/datum/job/j = SSjob.GetJob(edit_job_target) + if(!j || !can_close_job(j)) + return + //Allow instant closing without cooldown if a position has been opened before + if(opened_positions[edit_job_target] <= 0) + GLOB.time_last_changed_position = world.time / 10 + j.total_positions-- + opened_positions[edit_job_target]-- + playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) + return TRUE + if("PRG_priority") + if(length(SSjob.prioritized_jobs) >= 5) + return + var/priority_target = params["target"] + var/datum/job/j = SSjob.GetJob(priority_target) + if(!j) + return + if(j.total_positions <= j.current_positions) + return + if(j in SSjob.prioritized_jobs) + SSjob.prioritized_jobs -= j + else + SSjob.prioritized_jobs += j + playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) + return TRUE + + +/datum/computer_file/program/job_management/ui_data(mob/user) + var/list/data = get_header_data() + + var/authed = FALSE + var/obj/item/card/id/user_id = user.get_idcard(FALSE) + if(user_id) + if(ACCESS_CHANGE_IDS in user_id.access) + authed = TRUE + + data["authed"] = authed + + var/list/pos = list() + for(var/j in SSjob.occupations) + var/datum/job/job = j + if(job.title in blacklisted) + continue + + pos += list(list( + "title" = job.title, + "current" = job.current_positions, + "total" = job.total_positions, + "status_open" = authed ? can_open_job(job) : FALSE, + "status_close" = authed ? can_close_job(job) : FALSE, + )) + data["slots"] = pos + var/delta = round(change_position_cooldown - ((world.time / 10) - GLOB.time_last_changed_position), 1) + data["cooldown"] = delta < 0 ? 0 : delta + var/list/priority = list() + for(var/j in SSjob.prioritized_jobs) + var/datum/job/job = j + priority += job.title + data["prioritized"] = priority + return data + diff --git a/code/modules/modular_computers/file_system/programs/ntdownloader.dm b/code/modules/modular_computers/file_system/programs/ntdownloader.dm index 92e1453dc6..352f13f305 100644 --- a/code/modules/modular_computers/file_system/programs/ntdownloader.dm +++ b/code/modules/modular_computers/file_system/programs/ntdownloader.dm @@ -10,7 +10,9 @@ requires_ntnet_feature = NTNET_SOFTWAREDOWNLOAD available_on_ntnet = 0 ui_header = "downloader_finished.gif" - tgui_id = "ntos_net_downloader" + tgui_id = "NtosNetDownloader" + ui_x = 480 + ui_y = 735 var/datum/computer_file/program/downloaded_file = null var/hacked_download = 0 @@ -113,49 +115,50 @@ var/list/data = get_header_data() - // This IF cuts on data transferred to client, so i guess it's worth it. - if(downloaderror) // Download errored. Wait until user resets the program. - data["error"] = downloaderror - else if(downloaded_file) // Download running. Wait please.. + data["downloading"] = !!downloaded_file + data["error"] = downloaderror || FALSE + + // Download running. Wait please.. + if(downloaded_file) data["downloadname"] = downloaded_file.filename data["downloaddesc"] = downloaded_file.filedesc data["downloadsize"] = downloaded_file.size data["downloadspeed"] = download_netspeed data["downloadcompletion"] = round(download_completion, 0.1) - else // No download running, pick file. - var/obj/item/computer_hardware/hard_drive/hard_drive = my_computer.all_components[MC_HDD] - data["disk_size"] = hard_drive.max_capacity - data["disk_used"] = hard_drive.used_capacity - var/list/all_entries[0] - for(var/A in SSnetworks.station_network.available_station_software) - 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)) - continue - all_entries.Add(list(list( + + var/obj/item/computer_hardware/hard_drive/hard_drive = my_computer.all_components[MC_HDD] + data["disk_size"] = hard_drive.max_capacity + data["disk_used"] = hard_drive.used_capacity + var/list/all_entries[0] + for(var/A in SSnetworks.station_network.available_station_software) + 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)) + continue + all_entries.Add(list(list( "filename" = P.filename, "filedesc" = P.filedesc, "fileinfo" = P.extended_desc, "compatibility" = check_compatibility(P), - "size" = P.size - ))) - data["hackedavailable"] = 0 - if(computer.obj_flags & EMAGGED) // If we are running on emagged computer we have access to some "bonus" software - var/list/hacked_programs[0] - for(var/S in SSnetworks.station_network.available_antag_software) - var/datum/computer_file/program/P = S - if(hard_drive.find_file_by_name(P.filename)) - continue - data["hackedavailable"] = 1 - hacked_programs.Add(list(list( + "size" = P.size, + ))) + data["hackedavailable"] = FALSE + if(computer.obj_flags & EMAGGED) // If we are running on emagged computer we have access to some "bonus" software + var/list/hacked_programs[0] + for(var/S in SSnetworks.station_network.available_antag_software) + var/datum/computer_file/program/P = S + if(hard_drive.find_file_by_name(P.filename)) + continue + data["hackedavailable"] = TRUE + hacked_programs.Add(list(list( "filename" = P.filename, "filedesc" = P.filedesc, "fileinfo" = P.extended_desc, - "size" = P.size - ))) - data["hacked_programs"] = hacked_programs + "size" = P.size, + ))) + data["hacked_programs"] = hacked_programs - data["downloadable_programs"] = all_entries + data["downloadable_programs"] = all_entries return data @@ -168,4 +171,4 @@ /datum/computer_file/program/ntnetdownload/kill_program(forced) abort_file_download() - return ..(forced) \ No newline at end of file + return ..(forced) diff --git a/code/modules/modular_computers/file_system/programs/ntmonitor.dm b/code/modules/modular_computers/file_system/programs/ntmonitor.dm index 2312db7b11..7d6d89f32c 100644 --- a/code/modules/modular_computers/file_system/programs/ntmonitor.dm +++ b/code/modules/modular_computers/file_system/programs/ntmonitor.dm @@ -4,58 +4,48 @@ 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 - requires_ntnet = 1 + requires_ntnet = TRUE required_access = ACCESS_NETWORK //NETWORK CONTROL IS A MORE SECURE PROGRAM. - available_on_ntnet = 1 - tgui_id = "ntos_net_monitor" + available_on_ntnet = TRUE + tgui_id = "NtosNetMonitor" /datum/computer_file/program/ntnetmonitor/ui_act(action, params) if(..()) - return 1 + return switch(action) if("resetIDS") - . = 1 if(SSnetworks.station_network) SSnetworks.station_network.resetIDS() - return 1 + return TRUE if("toggleIDS") - . = 1 if(SSnetworks.station_network) SSnetworks.station_network.toggleIDS() - return 1 + return TRUE if("toggleWireless") - . = 1 if(!SSnetworks.station_network) - return 1 + return // NTNet is disabled. Enabling can be done without user prompt if(SSnetworks.station_network.setting_disabled) - SSnetworks.station_network.setting_disabled = 0 - return 1 + SSnetworks.station_network.setting_disabled = FALSE + return TRUE - // NTNet is enabled and user is about to shut it down. Let's ask them if they really want to do it, as wirelessly connected computers won't connect without NTNet being enabled (which may prevent people from turning it back on) - var/mob/user = usr - if(!user) - return 1 - var/response = alert(user, "Really disable NTNet wireless? If your computer is connected wirelessly you won't be able to turn it back on! This will affect all connected wireless devices.", "NTNet shutdown", "Yes", "No") - if(response == "Yes") - SSnetworks.station_network.setting_disabled = 1 - return 1 + SSnetworks.station_network.setting_disabled = TRUE + return TRUE if("purgelogs") - . = 1 if(SSnetworks.station_network) SSnetworks.station_network.purge_logs() + return TRUE if("updatemaxlogs") - . = 1 - var/mob/user = usr - var/logcount = text2num(input(user,"Enter amount of logs to keep in memory ([MIN_NTNET_LOGS]-[MAX_NTNET_LOGS]):")) + var/logcount = params["new_number"] if(SSnetworks.station_network) SSnetworks.station_network.update_max_log_count(logcount) + return TRUE if("toggle_function") - . = 1 if(!SSnetworks.station_network) - return 1 + return SSnetworks.station_network.toggle_function(text2num(params["id"])) + return TRUE /datum/computer_file/program/ntnetmonitor/ui_data(mob/user) if(!SSnetworks.station_network) @@ -73,9 +63,11 @@ data["config_systemcontrol"] = SSnetworks.station_network.setting_systemcontrol data["ntnetlogs"] = list() + data["minlogs"] = MIN_NTNET_LOGS + data["maxlogs"] = MAX_NTNET_LOGS for(var/i in SSnetworks.station_network.logs) data["ntnetlogs"] += list(list("entry" = i)) data["ntnetmaxlogs"] = SSnetworks.station_network.setting_maxlogcount - return data \ No newline at end of file + return data 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 d8b3f96f42..4ae5bd326b 100644 --- a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm +++ b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm @@ -9,7 +9,7 @@ network_destination = "NTNRC server" ui_header = "ntnrc_idle.gif" available_on_ntnet = 1 - tgui_id = "ntos_net_chat" + tgui_id = "NtosNetChat" ui_x = 900 ui_y = 675 diff --git a/code/modules/modular_computers/file_system/programs/powermonitor.dm b/code/modules/modular_computers/file_system/programs/powermonitor.dm index f7c734667b..d2d57b1447 100644 --- a/code/modules/modular_computers/file_system/programs/powermonitor.dm +++ b/code/modules/modular_computers/file_system/programs/powermonitor.dm @@ -11,8 +11,7 @@ requires_ntnet = 0 network_destination = "power monitoring system" size = 9 - tgui_id = "ntos_power_monitor" - ui_style = "ntos" + tgui_id = "NtosPowerMonitor" ui_x = 550 ui_y = 700 diff --git a/code/modules/modular_computers/file_system/programs/radar.dm b/code/modules/modular_computers/file_system/programs/radar.dm new file mode 100644 index 0000000000..7a6e80267c --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/radar.dm @@ -0,0 +1,249 @@ +/datum/computer_file/program/radar //generic parent that handles most of the process + filename = "genericfinder" + filedesc = "debug_finder" + ui_header = "borg_mon.gif" //DEBUG -- new icon before PR + program_icon_state = "generic" + extended_desc = "generic" + requires_ntnet = TRUE + transfer_access = null + available_on_ntnet = FALSE + network_destination = "tracking program" + size = 5 + tgui_id = "NtosRadar" + ui_x = 800 + ui_y = 600 + special_assets = list( + /datum/asset/simple/radar_assets, + ) + ///List of trackable entities. Updated by the scan() proc. + var/list/objects + ///Ref of the last trackable object selected by the user in the tgui window. Updated in the ui_act() proc. + var/atom/selected + ///Used to store when the next scan is available. Updated by the scan() proc. + var/next_scan = 0 + +/datum/computer_file/program/radar/kill_program(forced = FALSE) + objects = list() + selected = null + return ..() + +/datum/computer_file/program/radar/ui_data(mob/user) + var/list/data = get_header_data() + data["selected"] = selected + data["objects"] = list() + data["scanning"] = (world.time < next_scan) + for(var/list/i in objects) + var/list/objectdata = list( + ref = i["ref"], + name = i["name"], + ) + data["object"] += list(objectdata) + + data["target"] = list() + var/list/trackinfo = track() + if(trackinfo) + data["target"] = trackinfo + return data + +/datum/computer_file/program/radar/ui_act(action, params) + if(..()) + return + + switch(action) + if("selecttarget") + selected = params["ref"] + if("scan") + scan() + +/** + *Updates tracking information of the selected target. + * + *The track() proc updates the entire set of information about the location + *of the target, including whether the Ntos window should use a pinpointer + *crosshair over the up/down arrows, or none in favor of a rotating arrow + *for far away targets. This information is returned in the form of a list. + * +*/ +/datum/computer_file/program/radar/proc/track() + return + +/** + * + *Checks the trackability of the selected target. + * + *If the target is on the computer's Z level, or both are on station Z + *levels, and the target isn't untrackable, return TRUE. + *Arguments: + **arg1 is the atom being evaluated. +*/ +/datum/computer_file/program/radar/proc/trackable(atom/movable/signal) + if(!signal) + return FALSE + var/turf/here = get_turf(computer) + var/turf/there = get_turf(signal) + return (there.z == here.z) || (is_station_level(here.z) && is_station_level(there.z)) + +/** + * + *Runs a scan of all the trackable atoms. + * + *Checks each entry in the GLOB of the specific trackable atoms against + *the track() proc, and fill the objects list with lists containing the + *atoms' names and REFs. The objects list is handed to the tgui screen + *for displaying to, and being selected by, the user. A two second + *sleep is used to delay the scan, both for thematical reasons as well + *as to limit the load players may place on the server using these + *somewhat costly loops. +*/ +/datum/computer_file/program/radar/proc/scan() + return + +/////////////////// +//Suit Sensor App// +/////////////////// + +///A program that tracks crew members via suit sensors +/datum/computer_file/program/radar/lifeline + filename = "Lifeline" + filedesc = "Lifeline" + program_icon_state = "generic" + extended_desc = "This program allows for tracking of crew members via their suit sensors." + requires_ntnet = TRUE + transfer_access = ACCESS_MEDICAL + available_on_ntnet = TRUE + +/datum/computer_file/program/radar/lifeline/track() + var/mob/living/carbon/human/humanoid = locate(selected) in GLOB.human_list + if(!istype(humanoid) || !trackable(humanoid)) + return + + var/turf/here_turf = (get_turf(computer)) + var/turf/target_turf = (get_turf(humanoid)) + var/userot = FALSE + var/rot = 0 + var/pointer="crosshairs" + var/locx = (target_turf.x - here_turf.x) + var/locy = (here_turf.y - target_turf.y) + if(get_dist_euclidian(here_turf, target_turf) > 24) //If they're too far away, we need the angle for the arrow along the edge of the radar display + userot = TRUE + rot = round(Get_Angle(here_turf, target_turf)) + else + locx = locx + 24 + locy = locy + 24 + if(target_turf.z > here_turf.z) + pointer="caret-up" + else if(target_turf.z < here_turf.z) + pointer="caret-down" + var/list/trackinfo = list( + locx = locx, + locy = locy, + userot = userot, + rot = rot, + arrowstyle = "ntosradarpointer.png", //For the rotation arrow, it's stupid I know + color = "green", + pointer = pointer, + ) + return trackinfo + +/datum/computer_file/program/radar/lifeline/scan() + if(world.time < next_scan) + return + next_scan = world.time + (2 SECONDS) + objects = list() + for(var/i in GLOB.human_list) + var/mob/living/carbon/human/humanoid = i + if(!trackable(humanoid)) + continue + var/crewmember_name = "Unknown" + if(humanoid.wear_id) + var/obj/item/card/id/ID = humanoid.wear_id.GetID() + if(ID && ID.registered_name) + crewmember_name = ID.registered_name + var/list/crewinfo = list( + ref = REF(humanoid), + name = crewmember_name, + ) + objects += list(crewinfo) + +/datum/computer_file/program/radar/lifeline/trackable(mob/living/carbon/human/humanoid) + if(!humanoid || !istype(humanoid)) + return FALSE + if(..() && istype(humanoid.w_uniform, /obj/item/clothing/under)) + + var/obj/item/clothing/under/uniform = humanoid.w_uniform + if(!uniform.has_sensor || (uniform.sensor_mode < SENSOR_COORDS)) // Suit sensors must be on maximum. + return FALSE + + return TRUE + +//////////////////////// +//Nuke Disk Finder App// +//////////////////////// + +///A program that tracks crew members via suit sensors +/datum/computer_file/program/radar/fission360 + filename = "Fission360" + filedesc = "Fission360" + program_icon_state = "generic" + extended_desc = "This program allows for tracking of nuclear authorization disks and warheads." + requires_ntnet = FALSE + transfer_access = null + available_on_ntnet = FALSE + available_on_syndinet = TRUE + tgui_id = "NtosRadarSyndicate" + +/datum/computer_file/program/radar/fission360/track() + var/obj/nuke = locate(selected) in GLOB.poi_list + if(!trackable(nuke)) + return + + var/turf/here_turf = (get_turf(computer)) + var/turf/target_turf = (get_turf(nuke)) + var/userot = FALSE + var/rot = 0 + var/pointer="crosshairs" + var/locx = (target_turf.x - here_turf.x) + var/locy = (here_turf.y - target_turf.y) + if(get_dist_euclidian(here_turf, target_turf) > 24) //If they're too far away, we need the angle for the arrow along the edge of the radar display + userot = TRUE + rot = round(Get_Angle(here_turf, target_turf)) + else + locx = locx + 24 + locy = locy + 24 + if(target_turf.z > here_turf.z) + pointer="caret-up" + else if(target_turf.z < here_turf.z) + pointer="caret-down" + var/list/trackinfo = list( + locx = locx, + locy = locy, + userot = userot, + rot = rot, + arrowstyle = "ntosradarpointerS.png", + color = "red", + pointer = pointer, + ) + return trackinfo + +/datum/computer_file/program/radar/fission360/scan() + if(world.time < next_scan) + return + next_scan = world.time + (2 SECONDS) + 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), + name = nuke.name, + ) + 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) diff --git a/code/modules/modular_computers/file_system/programs/robocontrol.dm b/code/modules/modular_computers/file_system/programs/robocontrol.dm new file mode 100644 index 0000000000..910f923327 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/robocontrol.dm @@ -0,0 +1,86 @@ + +/datum/computer_file/program/robocontrol + filename = "robocontrol" + filedesc = "Bot Remote Controller" + 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" + ui_x = 550 + ui_y = 550 + ///Number of simple robots on-station. + var/botcount = 0 + ///Used to find the location of the user for the purposes of summoning robots. + var/mob/current_user + ///Access granted by the used to summon robots. + var/list/current_access = list() + +/datum/computer_file/program/robocontrol/ui_data(mob/user) + var/list/data = get_header_data() + var/turf/current_turf = get_turf(ui_host()) + var/zlevel = current_turf.z + var/list/botlist = list() + var/list/mulelist = list() + + var/obj/item/computer_hardware/card_slot/card_slot = computer ? computer.all_components[MC_CARD] : null + data["have_id_slot"] = !!card_slot + if(computer) + var/obj/item/card/id/id_card = card_slot ? card_slot.stored_card : null + data["has_id"] = !!id_card + data["id_owner"] = id_card ? id_card.registered_name : "No Card Inserted." + data["access_on_card"] = id_card ? id_card.access : null + + botcount = 0 + current_user = user + + for(var/B in GLOB.bots_list) + var/mob/living/simple_animal/bot/Bot = B + if(!Bot.on || Bot.z != zlevel || Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected! + continue //Also, the PDA must have access to the bot type. + var/list/newbot = list("name" = Bot.name, "mode" = Bot.get_mode_ui(), "model" = Bot.model, "locat" = get_area(Bot), "bot_ref" = REF(Bot), "mule_check" = FALSE) + if(Bot.bot_type == MULE_BOT) + var/mob/living/simple_animal/bot/mulebot/MULE = Bot + mulelist += list(list("name" = MULE.name, "dest" = MULE.destination, "power" = MULE.cell ? MULE.cell.percent() : 0, "home" = MULE.home_destination, "autoReturn" = MULE.auto_return, "autoPickup" = MULE.auto_pickup, "reportDelivery" = MULE.report_delivery, "mule_ref" = REF(MULE))) + if(MULE.load) + data["load"] = MULE.load.name + newbot["mule_check"] = TRUE + botlist += list(newbot) + + data["bots"] = botlist + data["mules"] = mulelist + data["botcount"] = botlist.len + + return data + +/datum/computer_file/program/robocontrol/ui_act(action, list/params) + if(..()) + return TRUE + var/obj/item/computer_hardware/card_slot/card_slot + var/obj/item/card/id/id_card + if(computer) + card_slot = computer.all_components[MC_CARD] + if(card_slot) + id_card = card_slot.stored_card + + var/list/standard_actions = list("patroloff", "patrolon", "ejectpai") + var/list/MULE_actions = list("stop", "go", "home", "destination", "setid", "sethome", "unload", "autoret", "autopick", "report", "ejectpai") + var/mob/living/simple_animal/bot/Bot = locate(params["robot"]) in GLOB.bots_list + if (action in standard_actions) + Bot.bot_control(action, current_user, current_access) + if (action in MULE_actions) + Bot.bot_control(action, current_user, current_access, TRUE) + switch(action) + if("summon") + Bot.bot_control(action, current_user, id_card ? id_card.access : current_access) + if("ejectcard") + if(!computer || !card_slot) + return + if(id_card) + GLOB.data_core.manifest_modify(id_card.registered_name, id_card.assignment) + card_slot.try_eject(TRUE, 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 101f533e8f..0a675a7abc 100644 --- a/code/modules/modular_computers/file_system/programs/sm_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/sm_monitor.dm @@ -8,8 +8,7 @@ transfer_access = ACCESS_CONSTRUCTION network_destination = "supermatter monitoring system" size = 5 - tgui_id = "ntos_supermatter_monitor" - ui_style = "ntos" + tgui_id = "NtosSupermatterMonitor" ui_x = 600 ui_y = 350 var/last_status = SUPERMATTER_INACTIVE diff --git a/code/modules/modular_computers/hardware/printer.dm b/code/modules/modular_computers/hardware/printer.dm index 44383822cc..36c666e5d6 100644 --- a/code/modules/modular_computers/hardware/printer.dm +++ b/code/modules/modular_computers/hardware/printer.dm @@ -27,13 +27,11 @@ // Damaged printer causes the resulting paper to be somewhat harder to read. if(damage > damage_malfunction) - P.info = stars(text_to_print, 100-malfunction_probability) + P.setText(stars(text_to_print, 100-malfunction_probability)) else - P.info = text_to_print + P.setText(text_to_print) if(paper_title) P.name = paper_title - P.update_icon() - P.reload_fields() stored_paper-- P = null return TRUE @@ -59,4 +57,4 @@ icon_state = "printer_mini" w_class = WEIGHT_CLASS_TINY stored_paper = 5 - max_paper = 15 \ No newline at end of file + max_paper = 15 diff --git a/code/modules/modular_computers/laptop_vendor.dm b/code/modules/modular_computers/laptop_vendor.dm index 9e0e1c8014..ee9def4191 100644 --- a/code/modules/modular_computers/laptop_vendor.dm +++ b/code/modules/modular_computers/laptop_vendor.dm @@ -232,7 +232,7 @@ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if (!ui) - ui = new(user, src, ui_key, "computer_fabricator", "Personal Computer Vendor", ui_x, ui_y, state = state) + ui = new(user, src, ui_key, "ComputerFabricator", "Personal Computer Vendor", ui_x, ui_y, state = state) ui.open() /obj/machinery/lapvend/attackby(obj/item/I, mob/user) diff --git a/code/modules/movespeed/_movespeed_modifier.dm b/code/modules/movespeed/_movespeed_modifier.dm index 0976f4d067..a338919c4b 100644 --- a/code/modules/movespeed/_movespeed_modifier.dm +++ b/code/modules/movespeed/_movespeed_modifier.dm @@ -144,6 +144,10 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache) /// Handles the special case of editing the movement var /mob/vv_edit_var(var_name, var_value) + if(var_name == NAMEOF(src, control_object)) + var/obj/O = var_name + if(!istype(O) || (O.obj_flags & DANGEROUS_POSSESSION)) + return FALSE var/slowdown_edit = (var_name == NAMEOF(src, cached_multiplicative_slowdown)) var/diff if(slowdown_edit && isnum(cached_multiplicative_slowdown) && isnum(var_value)) diff --git a/code/modules/oracle_ui/README.md b/code/modules/oracle_ui/README.md deleted file mode 100644 index bc96eb1f51..0000000000 --- a/code/modules/oracle_ui/README.md +++ /dev/null @@ -1,233 +0,0 @@ -# `/datum/oracle_ui` - -This datum is a replacement for tgui which does not use any Node.js dependencies, and works entirely through raw HTML, JS and CSS. It's designed to be reasonably easy to port something from tgui to oracle_ui. - -### How to create a UI - -For this example, we're going to port the disposals bin from tgui to oracle_ui. - -#### Step 1 - -In order to create a UI, you will first need to create an instance of `/datum/oracle_ui` or one of its subclasses, in this case `/datum/oracle_ui/themed/nano`. - -You need to pass in `src`, the width of the window, the height of the window, and the template to render from. You can optionally set some flags to disallow window resizing and whether to automatically refresh the UI. - -`code/modules/recycling/disposal-unit.dm` -```dm -/obj/machinery/disposal/bin/Initialize(mapload, obj/structure/disposalconstruct/make_from) - . = ..() - ui = new /datum/oracle_ui/themed/nano(src, 330, 190, "disposal_bin") - ui.auto_refresh = TRUE - ui.can_resize = FALSE -``` - -#### Step 2 - -You will now need to make a template in `html/oracle_ui/content/{template_name}`. - -Values defined as `@{value}` will get replaced at runtime by oracle_ui. - -`html/oracle_ui/content/disposal_bin/index.html` -```html -
    -
    - State: -
    @{full_pressure}
    -
    -
    - Pressure: -
    -
    -
    -
    @{per}
    -
    -
    -
    -
    - Handle: -
    @{flush}
    -
    -
    - Eject: -
    @{contents}
    -
    -
    - Compressor: -
    @{pressure_charging}
    -
    -
    -``` - -#### Step 3 - -Now you need to implement the methods that provide data to oracle_ui. `oui_data` can be adapted from the `ui_data` proc that tgui uses. - -The `act` proc generates a hyperlink that will result in `oui_act` getting called on your object when clicked. The `class` argument defines a css class to be added to the hyperlink, and disabled determines whether the hyperlink will be disabled or not. - -Calling `soft_update_fields` will result in the UI being updated on all clients, which is useful when the object changes state. - -`code/modules/recycling/disposal-unit.dm` -```dm -/obj/machinery/disposal/bin/oui_data(mob/user) - var/list/data = list() - data["flush"] = flush ? ui.act("Disengage", user, "handle-0", class="active") : ui.act("Engage", user, "handle-1") - data["full_pressure"] = full_pressure ? "Ready" : (pressure_charging ? "Pressurizing" : "Off") - data["pressure_charging"] = pressure_charging ? ui.act("Turn Off", user, "pump-0", class="active", disabled=full_pressure) : ui.act("Turn On", user, "pump-1", disabled=full_pressure) - var/per = full_pressure ? 100 : Clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 99) - data["per"] = "[round(per, 1)]%" - data["contents"] = ui.act("Eject Contents", user, "eject", disabled=contents.len < 1) - data["isai"] = isAI(user) - return data -/obj/machinery/disposal/bin/oui_act(mob/user, action, list/params) - if(..()) - return - switch(action) - if("handle-0") - flush = FALSE - update_icon() - . = TRUE - if("handle-1") - if(!panel_open) - flush = TRUE - update_icon() - . = TRUE - if("pump-0") - if(pressure_charging) - pressure_charging = FALSE - update_icon() - . = TRUE - if("pump-1") - if(!pressure_charging) - pressure_charging = TRUE - update_icon() - . = TRUE - if("eject") - eject() - . = TRUE - ui.soft_update_fields() -``` - -#### Step 4 - -You now need to hook in and ensure oracle_ui is invoked upon clicking. `render` should be used to open the UI for a user, typically on click. - -`code/modules/recycling/disposal-unit.dm` -```dm -/obj/machinery/disposal/bin/ui_interact(mob/user, state) - if(stat & BROKEN) - return - if(user.loc == src) - to_chat(user, "You cannot reach the controls from inside!") - return - ui.render(user) -``` - -#### Done - -![gif](https://user-images.githubusercontent.com/202160/37561879-1bb9179e-2a52-11e8-902c-80e6e6df7204.gif) - -You should have a functional UI at this point. Some additional odds and ends can be discovered throughout `code/modules/recycling/disposal-unit.dm`. For a full diff of the changes made to it, refer to [the original pull request on GitHub](https://github.com/OracleStation/OracleStation/pull/702/files#diff-4b6c20ec7d37222630e7524d9577e230). - -### API Reference - -#### `/datum/oracle_ui` - -The main datum which handles the UI. - -##### `get_content(mob/target)` -Returns the HTML that should be displayed for a specified target mob. Calls `oui_getcontent` on the datasource to get the return value. *This proc is not used in the themed subclass.* - -##### `can_view(mob/target)` -Returns whether the specified target mob can view the UI. Calls `oui_canview` on the datasource to get the return value. - -##### `test_viewer(mob/target, updating)` -Tests whether the client is valid and can view the UI. If updating is TRUE, checks to see if they still have the UI window open. - -##### `render(mob/target, updating = FALSE)` -Opens the UI for a target mob, sending HTML. If updating is TRUE, will only do it to clients which still have the window open. - -##### `render_all()` -Does the above, but for all viewers and with updating set to TRUE. - -##### `close(mob/target)` -Closes the UI for the specified target mob. - -##### `close_all()` -Does the above, but for all viewers. - -##### `check_view(mob/target)` -Checks if the specified target mob can view the UI, and if they can't closes their UI - -##### `check_view_all()` -Does the above, but for all viewers. - -##### `call_js(mob/target, js_func, list/parameters = list())` -Invokes `js_func` in the UI of the specified target mob with the specified parameters. - -##### `call_js_all(js_func, list/parameters = list()))` -Does the above, but for all viewers. - -##### `steal_focus(mob/target)` -Causes the UI to steal focus for the specified target mob. - -##### `steal_focus_all()` -Does the above, but for all viewers. - -##### `flash(mob/target, times = -1)` -Causes the UI to flash for the specified target mob the specified number of times, the default keeps the element flashing until focused. - -##### `flash_all()` -Does the above, but for all viewers. - -##### `href(mob/user, action, list/parameters = list())` -Generates a href for the specified user which will invoke `oui_act` on the datasource with the specified action and parameters. - -#### `/datum/oracle_ui/themed` - -A subclass which supports templating and theming. - -##### `get_file(path)` -Loads a file from disk and returns the contents. Caches files loaded from disk for you. - -##### `get_content_file(filename)` -Loads a file from the current content folder and returns the contents. - -##### `get_themed_file(filename)` -Loads a file from the current theme folder and returns the contents. - -##### `process_template(template, variables)` -Processes a template and populates it with the provided variables. - -##### `get_inner_content(mob/target)` -Returns the templated content to be inserted into the main template for the specified target mob. - -##### `soft_update_fields()` -For all viewers, updates the fields in the template via the `updateFields` javaScript function. - -##### `soft_update_all()` -For all viewers, updates the content body in the template via the `replaceContent` javaScript function. - -##### `change_page(var/newpage)` -Changes the template to use to draw the page and forces an update to all viewers - -##### `act(label, mob/user, action, list/parameters = list(), class = "", disabled = FALSE` -Returns a fully formatted hyperlink for the specified user. `label` will be the hyperlink label, `action` and `parameters` are what will be passed to `oui_act`, `class` is any CSS classes to apply to the hyperlink and `disabled` will disable the hyperlink. - -#### `/datum` - -Functions built into all objects to support oracle_ui. There are default implementations for most major superclasses. - -##### `oui_canview(mob/user)` -Returns whether the specified user view the UI at this time. - -##### `oui_getcontent(mob/user)` -Returns the raw HTML to be sent to the specified user. *This proc is not used in the themed subclass of oracle_ui.* - -##### `oui_data(mob/user)` -Returns templating data for the specified user. *This proc is only used in the themed subclass of oracle_ui.* - -##### `oui_data_debug(mob/user)` -Returns the above, but JSON-encoded and escaped, for copy pasting into the web IDE. *This proc is only used for debugging purposes.* - -##### `oui_act(mob/user, action, list/params)` -Called when a hyperlink is clicked in the UI. diff --git a/code/modules/oracle_ui/assets.dm b/code/modules/oracle_ui/assets.dm deleted file mode 100644 index 348860b48d..0000000000 --- a/code/modules/oracle_ui/assets.dm +++ /dev/null @@ -1,11 +0,0 @@ -/datum/asset/group/oui_theme_nano - children = list( - /datum/asset/simple/jquery, - /datum/asset/simple/oui_theme_nano - ) - -/datum/asset/simple/oui_theme_nano - assets = list( - "sui-nano-common.js" = 'html/oracle_ui/themes/nano/sui-nano-common.js', - "sui-nano-common.css" = 'html/oracle_ui/themes/nano/sui-nano-common.css', - ) diff --git a/code/modules/oracle_ui/hookup_procs.dm b/code/modules/oracle_ui/hookup_procs.dm deleted file mode 100644 index 30db9d92b9..0000000000 --- a/code/modules/oracle_ui/hookup_procs.dm +++ /dev/null @@ -1,46 +0,0 @@ -/datum/proc/oui_canview(mob/user) - return TRUE - -/datum/proc/oui_getcontent(mob/user) - return "Default Implementation" - -/datum/proc/oui_canuse(mob/user) - if(isobserver(user) && !user.silicon_privileges) - return FALSE - return oui_canview(user) - -/datum/proc/oui_data(mob/user) - return list() - -/datum/proc/oui_data_debug(mob/user) - return html_encode(json_encode(oui_data(user))) - -/datum/proc/oui_act(mob/user, action, list/params) - // No Implementation - -/atom/oui_canview(mob/user) - if(isobserver(user)) - return TRUE - if(user.incapacitated()) - return FALSE - if(isobj(src.loc) && get_dist(src, user) < 2) - return TRUE - if(isturf(src.loc) && Adjacent(user)) - return TRUE - return FALSE - -/obj/item/oui_canview(mob/user) - if(src.loc == user) - return src in user.held_items - return ..() - -/obj/machinery/oui_canview(mob/user) - if(hasSiliconAccessInArea(user, ALL)) - return TRUE - if(!can_interact(user)) - return FALSE - if(iscyborg(user)) - return can_see(user, src, 7) - if(isAI(user)) - return GLOB.cameranet.checkTurfVis(get_turf_pixel(src)) - return ..() diff --git a/code/modules/oracle_ui/oracle_ui.dm b/code/modules/oracle_ui/oracle_ui.dm deleted file mode 100644 index 5e8d6b9c7b..0000000000 --- a/code/modules/oracle_ui/oracle_ui.dm +++ /dev/null @@ -1,134 +0,0 @@ -/datum/oracle_ui - var/width = 512 - var/height = 512 - var/can_close = TRUE - var/can_minimize = FALSE - var/can_resize = TRUE - var/titlebar = TRUE - var/window_id = null - var/viewers[0] - var/auto_check_view = TRUE - var/auto_refresh = FALSE - var/atom/datasource = null - var/datum/asset/assets = null - -/datum/oracle_ui/New(atom/n_datasource, n_width = 512, n_height = 512, n_assets = null) - datasource = n_datasource - window_id = REF(src) - width = n_width - height = n_height - -/datum/oracle_ui/Destroy() - close_all() - if(src.datum_flags & DF_ISPROCESSING) - STOP_PROCESSING(SSobj, src) - return ..() - -/datum/oracle_ui/process() - if(auto_check_view) - check_view_all() - if(auto_refresh) - render_all() - -/datum/oracle_ui/proc/get_content(mob/target) - return call(datasource, "oui_getcontent")(target) - -/datum/oracle_ui/proc/can_view(mob/target) - return call(datasource, "oui_canview")(target) - -/datum/oracle_ui/proc/test_viewer(mob/target, updating) - //If the target is null or does not have a client, remove from viewers and return - if(!target | !target.client | !can_view(target)) - viewers -= target - if(viewers.len < 1 && (src.datum_flags & DF_ISPROCESSING)) - STOP_PROCESSING(SSobj, src) //No more viewers, stop polling - close(target) - return FALSE - //If this is an update, and they have closed the window, remove from viewers and return - if(updating && winget(target, window_id, "is-visible") != "true") - viewers -= target - if(viewers.len < 1 && (src.datum_flags & DF_ISPROCESSING)) - STOP_PROCESSING(SSobj, src) //No more viewers, stop polling - return FALSE - return TRUE - -/datum/oracle_ui/proc/render(mob/target, updating = FALSE) - set waitfor = FALSE //Makes this an async call - if(!can_view(target)) - return - //Check to see if they have the window open still if updating - if(updating && !test_viewer(target, updating)) - return - //Send assets - if(!updating && assets) - assets.send(target) - //Add them to the viewers if they aren't there already - viewers |= target - if(!(src.datum_flags & DF_ISPROCESSING) && (auto_refresh | auto_check_view)) - START_PROCESSING(SSobj, src) //Start processing to poll for viewability - //Send the content - if(updating) - target << output(get_content(target), "[window_id].browser") - else - target << browse(get_content(target), "window=[window_id];size=[width]x[height];can_close=[can_close];can_minimize=[can_minimize];can_resize=[can_resize];titlebar=[titlebar];focus=false;") - steal_focus(target) - -/datum/oracle_ui/proc/render_all() - for(var/viewer in viewers) - render(viewer, TRUE) - -/datum/oracle_ui/proc/close(mob/target) - if(target && target.client) - target << browse(null, "window=[window_id]") - -/datum/oracle_ui/proc/close_all() - for(var/viewer in viewers) - close(viewer) - viewers = list() - -/datum/oracle_ui/proc/check_view_all() - for(var/viewer in viewers) - check_view(viewer) - -/datum/oracle_ui/proc/check_view(mob/target) - set waitfor = FALSE //Makes this an async call - if(!test_viewer(target, TRUE)) - close(target) - -/datum/oracle_ui/proc/call_js(mob/target, js_func, list/parameters = list()) - set waitfor = FALSE //Makes this an async call - if(!test_viewer(target, TRUE)) - return - target << output(list2params(parameters),"[window_id].browser:[js_func]") - -/datum/oracle_ui/proc/call_js_all(js_func, list/parameters = list()) - for(var/viewer in viewers) - call_js(viewer, js_func, parameters) - -/datum/oracle_ui/proc/steal_focus(mob/target) - set waitfor = FALSE //Makes this an async call - winset(target, "[window_id]","focus=true") - -/datum/oracle_ui/proc/steal_focus_all() - for(var/viewer in viewers) - steal_focus(viewer) - -/datum/oracle_ui/proc/flash(mob/target, times = -1) - set waitfor = FALSE //Makes this an async call - winset(target, "[window_id]","flash=[times]") - -/datum/oracle_ui/proc/flash_all(times = -1) - for(var/viewer in viewers) - flash(viewer, times) - -/datum/oracle_ui/proc/href(mob/user, action, list/parameters = list()) - var/params_string = replacetext(list2params(parameters),"&",";") - return "?src=[REF(src)];sui_action=[action];sui_user=[REF(user)];[params_string]" - -/datum/oracle_ui/Topic(href, parameters) - var/action = parameters["sui_action"] - var/mob/current_user = locate(parameters["sui_user"]) - if(!call(datasource, "oui_canuse")(current_user)) - return - if(datasource) - call(datasource, "oui_act")(current_user, action, parameters); diff --git a/code/modules/oracle_ui/themed.dm b/code/modules/oracle_ui/themed.dm deleted file mode 100644 index 56b82c2647..0000000000 --- a/code/modules/oracle_ui/themed.dm +++ /dev/null @@ -1,82 +0,0 @@ -/datum/oracle_ui/themed - var/theme = "" - var/content_root = "" - var/current_page = "index.html" - var/root_template = "" - -/datum/oracle_ui/themed/New(atom/n_datasource, n_width = 512, n_height = 512, n_content_root = "") - root_template = get_themed_file("index.html") - content_root = n_content_root - return ..(n_datasource, n_width, n_height, get_asset_datum(/datum/asset/simple/oui_theme_nano)) - -/datum/oracle_ui/themed/process() - if(auto_check_view) - check_view_all() - if(auto_refresh) - soft_update_fields() - -GLOBAL_LIST_EMPTY(oui_template_variables) -GLOBAL_LIST_EMPTY(oui_file_cache) - -/datum/oracle_ui/themed/proc/get_file(path) - if(GLOB.oui_file_cache[path]) - return GLOB.oui_file_cache[path] - else if(fexists(path)) - var/data = file2text(path) - GLOB.oui_file_cache[path] = data - return data - else - var/errormsg = "MISSING PATH '[path]'" -#ifndef UNIT_TESTS - log_world(errormsg) //Because Travis absolutely hates these procs -#endif - return errormsg - -/datum/oracle_ui/themed/proc/get_content_file(filename) - return get_file("./html/oracle_ui/content/[content_root]/[filename]") - -/datum/oracle_ui/themed/proc/get_themed_file(filename) - return get_file("./html/oracle_ui/themes/[theme]/[filename]") - -/datum/oracle_ui/themed/proc/process_template(template, variables) - var/regex/pattern = regex("\\@\\{(\\w+)\\}","gi") - GLOB.oui_template_variables = variables - var/replaced = pattern.Replace(template, /proc/oui_process_template_replace) - GLOB.oui_template_variables = null - return replaced - -/proc/oui_process_template_replace(match, group1) - var/value = GLOB.oui_template_variables[group1] - return "[value]" - -/datum/oracle_ui/themed/proc/get_inner_content(mob/target) - var/list/data = call(datasource, "oui_data")(target) - return process_template(get_content_file(current_page), data) - -/datum/oracle_ui/themed/get_content(mob/target) - var/list/template_data = list("title" = datasource.name, "body" = get_inner_content(target)) - return process_template(root_template, template_data) - -/datum/oracle_ui/themed/proc/soft_update_fields() - for(var/viewer in viewers) - var/json = json_encode(call(datasource, "oui_data")(viewer)) - call_js(viewer, "updateFields", list(json)) - -/datum/oracle_ui/themed/proc/soft_update_all() - for(var/viewer in viewers) - call_js(viewer, "replaceContent", list(get_inner_content(viewer))) - -/datum/oracle_ui/themed/proc/change_page(newpage) - if(newpage == current_page) - return - current_page = newpage - render_all() - -/datum/oracle_ui/themed/proc/act(label, mob/user, action, list/parameters = list(), class = "", disabled = FALSE) - if(disabled) - return "[label]" - else - return "[label]" - -/datum/oracle_ui/themed/nano - theme = "nano" diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm index a599ec9deb..c32afab342 100644 --- a/code/modules/paperwork/folders.dm +++ b/code/modules/paperwork/folders.dm @@ -50,6 +50,14 @@ name = "folder - '[inputvalue]'" +/obj/item/folder/Destroy() + for(var/obj/important_thing in contents) + if(!(important_thing.resistance_flags & INDESTRUCTIBLE)) + continue + important_thing.forceMove(drop_location()) //don't destroy round critical content such as objective documents. + return ..() + + /obj/item/folder/attack_self(mob/user) var/dat = "[name]" diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 4afc2f1d5b..67f62bbb9d 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -4,7 +4,57 @@ * * lipstick wiping is in code/game/objects/items/weapons/cosmetics.dm! */ +#define MAX_PAPER_LENGTH 5000 +#define MAX_PAPER_STAMPS 30 // Too low? +#define MAX_PAPER_STAMPS_OVERLAYS 4 +#define MODE_READING 0 +#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 + ** so we do loose a bit of functionality but we gain in easy of use of + ** paper and getting rid of that crashing bug + **/ /obj/item/paper name = "paper" gender = NEUTER @@ -21,19 +71,76 @@ resistance_flags = FLAMMABLE max_integrity = 50 dog_fashion = /datum/dog_fashion/head + color = "white" + /// What's actually written on the paper. + var/info = "" + var/show_written_words = TRUE - var/info //What's actually written on the paper. - var/info_links //A different version of the paper which includes html links at fields and EOF - var/stamps //The (text for the) stamps on the paper. - var/fields = 0 //Amount of user created fields - var/list/stamped + /// The (text for the) stamps on the paper. + 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 - var/datum/oracle_ui/ui = null - var/force_stars = FALSE // If we should force the text to get obfuscated with asterisks + // ui stuff + var/ui_x = 600 + var/ui_y = 800 + // 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 + . = ..() + +/** + ** This proc copies this sheet of paper to a new + ** sheet, Makes it nice and easy for carbon and + ** the copyer machine + **/ +/obj/item/paper/proc/copy() + var/obj/item/paper/N = new(arglist(args)) + N.info = info + N.color = color + N.update_icon_state() + N.stamps = stamps + N.stamped = stamped.Copy() + N.form_fields = form_fields.Copy() + N.field_counter = field_counter + copy_overlays(N, TRUE) + return N + +/** + ** This proc sets the text of the paper and updates the + ** icons. You can modify the pen_color after if need + ** be. + **/ +/obj/item/paper/proc/setText(text) + info = text + form_fields = null + field_counter = 0 + update_icon_state() /obj/item/paper/pickup(user) if(contact_poison && ishuman(user)) @@ -42,59 +149,25 @@ if(!istype(G) || G.transfer_prints) H.reagents.add_reagent(contact_poison,contact_poison_volume) contact_poison = null - ui.check_view_all() - ..() - -/obj/item/paper/dropped(mob/user) - ui.check_view(user) - return ..() + . = ..() /obj/item/paper/Initialize() . = ..() pixel_y = rand(-8, 8) pixel_x = rand(-9, 9) - ui = new /datum/oracle_ui(src, 420, 600, get_asset_datum(/datum/asset/spritesheet/simple/paper)) - ui.can_resize = FALSE update_icon() - updateinfolinks() -/obj/item/paper/oui_getcontent(mob/target) - if(!target.is_literate() || force_stars) - force_stars = FALSE - return "[name][stars(info)]
    [stamps]" - else if(istype(target.get_active_held_item(), /obj/item/pen) | istype(target.get_active_held_item(), /obj/item/toy/crayon)) - return "[name][info_links]
    [stamps]" - else - return "[name][info]
    [stamps]" - -/obj/item/paper/oui_canview(mob/target) - if(check_rights_for(target.client, R_FUN)) //Allows admins to view faxes - return TRUE - if(isAI(target)) - force_stars = TRUE - return TRUE - if(iscyborg(target)) - return get_dist(src, target) < 2 - return ..() /obj/item/paper/update_icon_state() - if(resistance_flags & ON_FIRE) - icon_state = "paper_onfire" - return - if(info) - icon_state = "paper_words" - return - icon_state = "paper" + if(info && show_written_words) + icon_state = "[initial(icon_state)]_words" +/obj/item/paper/ui_base_html(html) + /// This might change in a future PR + var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/simple/paper) + . = replacetext(html, "", assets.css_tag()) -/obj/item/paper/examine(mob/user) - . = ..() - . += "Alt-click to fold it." - if(oui_canview(user)) - ui.render(user) - else - . += "You're too far away to read it!" /obj/item/paper/examine_more(mob/user) ui_interact(user) @@ -120,243 +193,256 @@ if((loc == usr && usr.stat == CONSCIOUS)) name = "paper[(n_name ? text("- '[n_name]'") : null)]" add_fingerprint(usr) - ui.render_all() + /obj/item/paper/suicide_act(mob/user) 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) - show_content(user) if(rigged && (SSevents.holidays && SSevents.holidays[APRIL_FOOLS])) if(!spam_flag) spam_flag = TRUE - playsound(loc, 'sound/items/bikehorn.ogg', 50, 1) + playsound(loc, 'sound/items/bikehorn.ogg', 50, TRUE) addtimer(CALLBACK(src, .proc/reset_spamflag), 20) - -/obj/item/paper/attack_ai(mob/living/silicon/ai/user) - show_content(user) - -/obj/item/paper/proc/addtofield(id, text, links = 0) - var/locid = 0 - var/laststart = 1 - var/textindex = 1 - while(locid < 15) //hey whoever decided a while(1) was a good idea here, i hate you - var/istart = 0 - if(links) - istart = findtext(info_links, "", laststart) - else - istart = findtext(info, "", laststart) - - if(istart == 0) - return //No field found with matching id - - if(links) - laststart = istart + length(info_links[istart]) - else - laststart = istart + length(info[istart]) - locid++ - if(locid == id) - var/iend = 1 - if(links) - iend = findtext(info_links, "", istart) - else - iend = findtext(info, "", istart) - - //textindex = istart+26 - textindex = iend - break - - if(links) - var/before = copytext(info_links, 1, textindex) - var/after = copytext(info_links, textindex) - info_links = before + text + after - else - var/before = copytext(info, 1, textindex) - var/after = copytext(info, textindex) - info = before + text + after - updateinfolinks() - - -/obj/item/paper/proc/updateinfolinks() - info_links = info - for(var/i in 1 to min(fields, 15)) - addtofield(i, "write", 1) - info_links = info_links + "write" - ui.render_all() + . = ..() /obj/item/paper/proc/clearpaper() - info = null + info = "" stamps = null LAZYCLEARLIST(stamped) cut_overlays() - updateinfolinks() - update_icon() + update_icon_state() -/obj/item/paper/proc/parsepencode(t, obj/item/pen/P, mob/user, iscrayon = 0) - if(length(t) < 1) //No input means nothing needs to be parsed +/obj/item/paper/examine(mob/user) + ui_interact(user) + + +/obj/item/paper/can_interact(mob/user) + if(!..()) + return FALSE + if(resistance_flags & ON_FIRE) // Are we on fire? Hard ot read if so + return FALSE + if(user.is_blind()) // Even harder to read if your blind...braile? humm + return FALSE + return user.can_read(src) // checks if the user can read. + + +/** + ** This creates the ui, since we are using a custom state but not much else + ** just makes it easyer to make it. Also we make a custom ui_key as I am + ** not sure how tgui handles many producers? +**/ +/obj/item/paper/proc/create_ui(mob/user, datum/ui_state/default/paper_state/state) + ui_interact(user, "main", null, FALSE, null, 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) + if(!ignition_message) + return + . = TRUE + if(!bypass_clumsy && 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 - t = parsemarkdown(t, user, iscrayon) + 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()) - if(!iscrayon) - t = "[t]" - else - var/obj/item/toy/crayon/C = P - t = "[t]" - - // Count the fields - var/laststart = 1 - while(fields < 15) - var/i = findtext(t, "", laststart) - if(i == 0) - break - laststart = i+1 - fields++ - - return t - -/obj/item/paper/proc/reload_fields() // Useful if you made the paper programicly and want to include fields. Also runs updateinfolinks() for you. - fields = 0 - var/laststart = 1 - while(fields < 15) - var/i = findtext(info, "", laststart) - if(i == 0) - break - laststart = i+1 - fields++ - updateinfolinks() - - -/obj/item/paper/proc/openhelp(mob/user) - user << browse({"Paper Help - - You can use backslash (\\) to escape special characters.
    -
    -
    Crayon&Pen commands

    -
    - # text : Defines a header.
    - |text| : Centers the text.
    - **text** : Makes the text bold.
    - *text* : Makes the text italic.
    - ^text^ : Increases the size of the text.
    - %s : Inserts a signature of your name in a foolproof way.
    - %f : Inserts an invisible field which lets you start type from there. Useful for forms.
    -
    -
    Pen exclusive commands

    - ((text)) : Decreases the size of the text.
    - * item : An unordered list item.
    -   * item: An unordered list child item.
    - --- : Adds a horizontal rule. - "}, "window=paper_help") - - -/obj/item/paper/Topic(href, href_list) - ..() - var/literate = usr.is_literate() - if(!usr.canUseTopic(src, BE_CLOSE, literate)) - return - - if(href_list["help"]) - openhelp(usr) - return - if(href_list["write"]) - var/id = href_list["write"] - var/t = stripped_multiline_input("Enter what you want to write:", "Write", no_trim=TRUE) - if(!t || !usr.canUseTopic(src, BE_CLOSE, literate)) - return - var/obj/item/i = usr.get_active_held_item() //Check to see if he still got that darn pen, also check if he's using a crayon or pen. - var/iscrayon = 0 - if(!istype(i, /obj/item/pen)) - if(!istype(i, /obj/item/toy/crayon)) - return - iscrayon = 1 - - if(!in_range(src, usr) && loc != usr && !istype(loc, /obj/item/clipboard) && loc.loc != usr && usr.get_active_held_item() != i) //Some check to see if he's allowed to write - return - - t = parsepencode(t, i, usr, iscrayon) // Encode everything from pencode to html - - if(t != null) //No input from the user means nothing needs to be added - if(id!="end") - addtofield(text2num(id), t) // He wants to edit a field, let him. - else - info += t // Oh, he wants to edit to the end of the file, let him. - updateinfolinks() - show_content(usr) - update_icon() - - -/obj/item/paper/attackby(obj/item/P, mob/living/carbon/human/user, params) - ..() - - if(resistance_flags & ON_FIRE) - return - - if(is_blind(user)) +/obj/item/paper/attackby(obj/item/P, mob/living/user, params) + if(burn_paper_product_attackby_check(P, user)) + close_all_ui() return if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon)) - if(user.is_literate()) - show_content(user) - return - else - to_chat(user, "You don't know how to read or write.") + 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) + return else if(istype(P, /obj/item/stamp)) - if(!in_range(src, user)) - return + 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 var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/simple/paper) - if (isnull(stamps)) - stamps = sheet.css_tag() - stamps += sheet.icon_tag(P.icon_state) - var/mutable_appearance/stampoverlay = mutable_appearance('icons/obj/bureaucracy.dmi', "paper_[P.icon_state]") - stampoverlay.pixel_x = rand(-2, 2) - stampoverlay.pixel_y = rand(-3, 2) + state.stamp_class = sheet.icon_class_name(P.icon_state) - LAZYADD(stamped, P.icon_state) - add_overlay(stampoverlay) + to_chat(user, "You ready your stamp over the paper! ") - to_chat(user, "You stamp the paper with your rubber stamp.") - ui.render_all() + create_ui(user, state) + 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 - if(P.get_temperature()) - if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(10)) - user.visible_message("[user] accidentally ignites [user.p_them()]self!", \ - "You miss the paper and accidentally light yourself on fire!") - user.dropItemToGround(P) - user.adjust_fire_stacks(1) - user.IgniteMob() - return + 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) /obj/item/paper/fire_act(exposed_temperature, exposed_volume) - ..() - if(!(resistance_flags & FIRE_PROOF)) - icon_state = "paper_onfire" + . = ..() + if(.) info = "[stars(info)]" +/obj/item/paper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/default/paper_state/state = new) + ui_key = "main-[REF(user)]" + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/simple/paper) + assets.send(user) + // The x size is because we double the width for the editor + ui = new(user, src, ui_key, "PaperSheet", name, ui_x, ui_y, master_ui, state) + ui.set_autoupdate(FALSE) + viewing_ui[user] = ui + ui.open() + else + var/datum/ui_state/default/paper_state/last_state = ui.state + if(last_state) + last_state.copy_from(state) + else + ui.state = state + + +/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.update() + +// 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 + + 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) + if(..()) + return + switch(action) + if("stamp") + var/stamp_x = text2num(params["x"]) + var/stamp_y = text2num(params["y"]) + var/stamp_r = text2num(params["r"]) // rotation in degrees + + if (isnull(stamps)) + stamps = new/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 + + /// This does the overlay stuff + if (isnull(stamped)) + stamped = new/list() + if(stamped.len < MAX_PAPER_STAMPS_OVERLAYS) + var/mutable_appearance/stampoverlay = mutable_appearance('icons/obj/bureaucracy.dmi', "paper_[state.stamp_icon_state]") + stampoverlay.pixel_x = rand(-2, 2) + stampoverlay.pixel_y = rand(-3, 2) + add_overlay(stampoverlay) + LAZYADD(stamped, state.stamp_icon_state) + + ui.user.visible_message("[ui.user] stamps [src] with [state.stamp_name]!", "You stamp [src] with [state.stamp_name]!") + 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) + // Side note, the only way we should get here is if + // the javascript was modified, somehow, outside of + // byond. but right now we are logging it as + // the generated html might get beyond this limit + log_paper("[key_name(ui.user)] writing to paper [name], and overwrote it by [paper_len-MAX_PAPER_LENGTH]") + if(paper_len == 0) + to_chat(ui.user, pick("Writing block strikes again!", "You forgot to write anthing!")) + else + log_paper("[key_name(ui.user)] writing to paper [name]") + 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_all_ui() + update_icon() + + . = TRUE -/obj/item/paper/extinguish() - ..() - update_icon() /* * Construction paper @@ -380,13 +466,20 @@ name = "paper scrap" icon_state = "scrap" slot_flags = null + show_written_words = FALSE -/obj/item/paper/crumpled/ComponentInitialize() - . = ..() - AddElement(/datum/element/update_icon_blocker) +/obj/item/paper/crumpled/update_icon_state() + return /obj/item/paper/crumpled/bloody icon_state = "scrap_bloodied" /obj/item/paper/crumpled/muddy icon_state = "scrap_mud" + +#undef MAX_PAPER_LENGTH +#undef MAX_PAPER_STAMPS +#undef MAX_PAPER_STAMPS_OVERLAYS +#undef MODE_READING +#undef MODE_WRITING +#undef MODE_STAMPING diff --git a/code/modules/paperwork/paper_cutter.dm b/code/modules/paperwork/paper_cutter.dm index 0a7bf011a7..770a6682e0 100644 --- a/code/modules/paperwork/paper_cutter.dm +++ b/code/modules/paperwork/paper_cutter.dm @@ -66,7 +66,7 @@ return ..() -/obj/item/papercutter/attack_hand(mob/user) +/obj/item/papercutter/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/paperwork/paper_premade.dm b/code/modules/paperwork/paper_premade.dm index 23c8d47323..414026924a 100644 --- a/code/modules/paperwork/paper_premade.dm +++ b/code/modules/paperwork/paper_premade.dm @@ -4,7 +4,49 @@ /obj/item/paper/fluff/sop name = "paper- 'Standard Operating Procedure'" - 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!" + 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! +"}; /obj/item/paper/fluff/shuttles/daniel info = "i love daniel
    daniel is my best friend

    you are tearing me apart elise" @@ -150,7 +192,7 @@ /obj/item/paper/fluff/cogstation/mime name = "Au futur Mime" - info = "Toutes mes excuses pour toute mauvaise grammaire, je ne suis pas un haut-parleur naturel Français et a dû utiliser NanoTranslate. Bien que vous puissiez être mécontent de l’emplacement de votre bureau, s’il vous plaît comprendre que c’était le seul endroit où nous pourrions le mettre sans problèmes de sécurité et/ou CentClown se plaindre à ce sujet. Nous nous excusons également pour l’absence d’une zone de performance dédiée, mais nous espérons que vous accorder un accès à l’entretien compensera.
    \n
    \n-C. Donnelly
    \n
    \nAnalyste Architectural" + info = "Toutes mes excuses pour toute mauvaise grammaire, je ne suis pas un haut-parleur naturel Fran�ais et a d� utiliser NanoTranslate. Bien que vous puissiez �tre m�content de l�emplacement de votre bureau, s�il vous pla�t comprendre que c��tait le seul endroit o� nous pourrions le mettre sans probl�mes de s�curit� et/ou CentClown se plaindre � ce sujet. Nous nous excusons �galement pour l�absence d�une zone de performance d�di�e, mais nous esp�rons que vous accorder un acc�s � l�entretien compensera.
    \n
    \n-C. Donnelly
    \n
    \nAnalyste Architectural" /obj/item/paper/fluff/cogstation/bsrb name = "Message from the NTBSRB" diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm index 517a12029e..2931110882 100644 --- a/code/modules/paperwork/paperbin.dm +++ b/code/modules/paperwork/paperbin.dm @@ -63,7 +63,7 @@ return attack_hand(user) //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/paper_bin/attack_hand(mob/user) +/obj/item/paper_bin/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(user.lying) return if(bin_pen) @@ -86,9 +86,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
    APRIL FOOLS
    " + P.info = "*HONK HONK HONK HONK HONK HONK HONK
    HOOOOOOOOOOOOOOOOOOOOOONK*\n*APRIL FOOLS*\n" P.rigged = 1 - P.updateinfolinks() P.add_fingerprint(user) P.forceMove(user.loc) @@ -150,7 +149,7 @@ papertype = /obj/item/paper/natural resistance_flags = FLAMMABLE -/obj/item/paper_bin/bundlenatural/attack_hand(mob/user) +/obj/item/paper_bin/bundlenatural/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) ..() if(total_paper < 1) qdel(src) diff --git a/code/modules/paperwork/paperplane.dm b/code/modules/paperwork/paperplane.dm index a9baf60c0c..c6a1ee1389 100644 --- a/code/modules/paperwork/paperplane.dm +++ b/code/modules/paperwork/paperplane.dm @@ -123,6 +123,7 @@ H.DefaultCombatKnockdown(40) H.emote("scream") + /obj/item/paper/examine(mob/user) . = ..() . += "Alt-click [src] to fold it into a paper plane." diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index 3c4aebdba3..0b1f3bb01d 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -31,7 +31,7 @@ /obj/machinery/photocopier/ui_interact(mob/user) . = ..() - var/dat = "Photocopier

    " + var/list/dat = list("Photocopier

    ") if(copy || photocopy || doccopy || (ass && (ass.loc == src.loc))) dat += "Remove Paper
    " if(toner) @@ -48,7 +48,7 @@ dat += "Current toner level: [toner]" if(!toner) dat +="
    Please insert a new toner cartridge!" - user << browse(dat, "window=copier") + user << browse(dat.Join(""), "window=copier") onclose(user, "copier") /obj/machinery/photocopier/Topic(href, href_list) @@ -77,17 +77,14 @@ c.info += copied c.info += "" c.name = copy.name - c.fields = copy.fields c.update_icon() - c.updateinfolinks() c.stamps = copy.stamps if(copy.stamped) c.stamped = copy.stamped.Copy() c.copy_overlays(copy, TRUE) toner-- busy = TRUE - sleep(15) - busy = FALSE + addtimer(CALLBACK(src, .proc/reset_busy), 1.5 SECONDS) else break updateUsrDialog() @@ -96,8 +93,7 @@ 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 - sleep(15) - busy = FALSE + addtimer(CALLBACK(src, .proc/reset_busy), 1.5 SECONDS) else break else if(doccopy) @@ -106,40 +102,35 @@ new /obj/item/documents/photocopy(loc, doccopy) toner-= 6 // the sprite shows 6 papers, yes I checked busy = TRUE - sleep(15) - busy = FALSE + 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(SLOT_W_UNIFORM) || ass.get_item_by_slot(SLOT_WEAR_SUIT))) + 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 - var/mob/living/carbon/human/H = ass - if(H.dna.features["body_model"] == FEMALE) - temp_img = icon('icons/ass/assfemale.png') - else - temp_img = icon('icons/ass/assmale.png') + 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 - var/obj/item/photo/p = new /obj/item/photo (loc) - p.pixel_x = rand(-10, 10) - p.pixel_y = rand(-10, 10) - p.picture = new(null, "You see [ass]'s ass on the photo.", temp_img) - p.picture.psize_x = 128 - p.picture.psize_y = 128 - p.update_icon() - toner -= 5 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 @@ -179,8 +170,7 @@ photo.pixel_y = rand(-10, 10) toner -= 5 //AI prints color pictures only, thus they can do it more efficiently busy = TRUE - sleep(15) - busy = FALSE + addtimer(CALLBACK(src, .proc/reset_busy), 1.5 SECONDS) updateUsrDialog() else if(href_list["colortoggle"]) if(greytoggle == "Greyscale") @@ -189,9 +179,13 @@ greytoggle = "Greyscale" updateUsrDialog() +/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].") + to_chat(user, "You insert [O] into [src].") flick("photocopier1", src) updateUsrDialog() @@ -256,10 +250,10 @@ return ..() /obj/machinery/photocopier/obj_break(damage_flag) - if(!(flags_1 & NODECONSTRUCT_1)) - if(toner > 0) - new /obj/effect/decal/cleanable/oil(get_turf(src)) - toner = 0 + . = ..() + if(. && toner > 0) + new /obj/effect/decal/cleanable/oil(get_turf(src)) + toner = 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. @@ -267,7 +261,7 @@ return src.add_fingerprint(user) if(target == user) - user.visible_message("[user] starts climbing onto the photocopier!", "You start climbing onto the photocopier...") + user.visible_message("[user] starts climbing onto the photocopier!", "You start climbing onto the photocopier...") else user.visible_message("[user] starts putting [target] onto the photocopier!", "You start putting [target] onto the photocopier...") @@ -276,7 +270,7 @@ return if(target == user) - user.visible_message("[user] climbs onto the photocopier!", "You climb onto the photocopier.") + user.visible_message("[user] climbs onto the photocopier!", "You climb onto the photocopier.") else user.visible_message("[user] puts [target] onto the photocopier!", "You put [target] onto the photocopier.") @@ -302,7 +296,7 @@ updateUsrDialog() return 0 else if(ishuman(ass)) - if(!ass.get_item_by_slot(SLOT_W_UNIFORM) && !ass.get_item_by_slot(SLOT_WEAR_SUIT)) + if(!ass.get_item_by_slot(ITEM_SLOT_ICLOTHING) && !ass.get_item_by_slot(ITEM_SLOT_OCLOTHING)) return 1 else return 0 diff --git a/code/modules/photography/photos/frame.dm b/code/modules/photography/photos/frame.dm index 9e6f827629..6f7bc643c8 100644 --- a/code/modules/photography/photos/frame.dm +++ b/code/modules/photography/photos/frame.dm @@ -22,7 +22,7 @@ ..() //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/wallframe/picture/attack_hand(mob/user) +/obj/item/wallframe/picture/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(user.get_inactive_held_item() != src) ..() return @@ -141,7 +141,7 @@ ..() -/obj/structure/sign/picture_frame/attack_hand(mob/user) +/obj/structure/sign/picture_frame/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/pool/pool_drain.dm b/code/modules/pool/pool_drain.dm index 940f7cd219..8deb9b1ffe 100644 --- a/code/modules/pool/pool_drain.dm +++ b/code/modules/pool/pool_drain.dm @@ -154,7 +154,7 @@ else new /mob/living/simple_animal/hostile/shark/laser(loc) -/obj/machinery/pool/filter/attack_hand(mob/user) +/obj/machinery/pool/filter/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) to_chat(user, "You search the filter.") for(var/obj/O in contents) O.forceMove(loc) diff --git a/code/modules/pool/pool_main.dm b/code/modules/pool/pool_main.dm index b45c0f36a2..30d1744b57 100644 --- a/code/modules/pool/pool_main.dm +++ b/code/modules/pool/pool_main.dm @@ -177,7 +177,7 @@ else return ..() -/turf/open/pool/attack_hand(mob/living/user) +/turf/open/pool/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/pool/pool_structures.dm b/code/modules/pool/pool_structures.dm index 4cea485237..6b71e95639 100644 --- a/code/modules/pool/pool_structures.dm +++ b/code/modules/pool/pool_structures.dm @@ -11,7 +11,7 @@ layer = ABOVE_MOB_LAYER dir = EAST -/obj/structure/pool/ladder/attack_hand(mob/living/user) +/obj/structure/pool/ladder/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -52,7 +52,7 @@ user.pixel_x = initial_px user.pixel_y = initial_py -/obj/structure/pool/Lboard/attack_hand(mob/living/user) +/obj/structure/pool/Lboard/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) if(iscarbon(user)) var/mob/living/carbon/jumper = user if(jumping) diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 7d0ecf3e66..19e32bae0b 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -833,7 +833,7 @@ // attack with hand - remove cell (if cover open) or interact with the APC -/obj/machinery/power/apc/attack_hand(mob/user) +/obj/machinery/power/apc/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -849,17 +849,12 @@ if((stat & MAINT) && !opened) //no board; no interface return -/obj/machinery/power/apc/oui_canview(mob/user) - if(area.hasSiliconAccessInArea(user)) //some APCs are mapped outside their assigned area, so this is required. - return TRUE - return ..() - /obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "apc", name, 450, 460, master_ui, state) + ui = new(user, src, ui_key, "Apc", name, 480, 460, master_ui, state) ui.open() /obj/machinery/power/apc/ui_data(mob/user) @@ -868,7 +863,7 @@ if (H && !H.stealthmode && H.toggled) abilitiesavail = TRUE var/list/data = list( - "locked" = locked && !(integration_cog && is_servant_of_ratvar(user)) && !area.hasSiliconAccessInArea(user, PRIVILEDGES_SILICON|PRIVILEDGES_DRONE), + "locked" = locked, "lock_nightshift" = nightshift_requires_auth, "failTime" = failure_timer, "isOperating" = operating, @@ -986,7 +981,7 @@ failure_timer = 0 update_icon() update() - if (action == "hijack" && can_use(usr, 1)) //don't need auth for hijack button + if(action == "hijack" && can_use(usr, 1)) //don't need auth for hijack button hijack(usr) return var/authorized = (!locked || area.hasSiliconAccessInArea(usr, PRIVILEDGES_SILICON|PRIVILEDGES_DRONE) || (integration_cog && (is_servant_of_ratvar(usr)))) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index e89507f33d..c8b02669e8 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -564,7 +564,7 @@ By design, d1 is the smallest direction and d2 is the highest icon_state = "[initial(item_state)][amount < 3 ? amount : ""]" name = "cable [amount < 3 ? "piece" : "coil"]" -/obj/item/stack/cable_coil/attack_hand(mob/user) +/obj/item/stack/cable_coil/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index c788b9b033..ba6311a94d 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -45,7 +45,7 @@ /obj/item/stock_parts/cell/vv_edit_var(var_name, var_value) switch(var_name) - if("self_recharge") + if(NAMEOF(src, self_recharge)) if(var_value) START_PROCESSING(SSobj, src) else diff --git a/code/modules/power/floodlight.dm b/code/modules/power/floodlight.dm index e0b3f5f316..2bd4c04402 100644 --- a/code/modules/power/floodlight.dm +++ b/code/modules/power/floodlight.dm @@ -92,7 +92,7 @@ else . = ..() -/obj/machinery/power/floodlight/attack_hand(mob/user) +/obj/machinery/power/floodlight/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -113,4 +113,4 @@ qdel(src) /obj/machinery/power/floodlight/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) - playsound(src, 'sound/effects/glasshit.ogg', 75, 1) \ No newline at end of file + playsound(src, 'sound/effects/glasshit.ogg', 75, 1) diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 1644673ece..76154907ae 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -28,7 +28,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF var/sprite_number = 0 -/obj/machinery/gravity_generator/safe_throw_at() +/obj/machinery/gravity_generator/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, gentle = FALSE) return FALSE /obj/machinery/gravity_generator/ex_act(severity, target) @@ -56,7 +56,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne qdel(src) /obj/machinery/gravity_generator/proc/set_broken() - stat |= BROKEN + obj_break() /obj/machinery/gravity_generator/proc/set_fix() stat &= ~BROKEN @@ -80,7 +80,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne /obj/machinery/gravity_generator/part/get_status() return main_part?.get_status() -/obj/machinery/gravity_generator/part/attack_hand(mob/user) +/obj/machinery/gravity_generator/part/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) return main_part.attack_hand(user) /obj/machinery/gravity_generator/part/set_broken() @@ -116,6 +116,8 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne sprite_number = 8 use_power = IDLE_POWER_USE interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OFFLINE + ui_x = 400 + ui_y = 165 var/on = TRUE var/breaker = TRUE var/list/parts = list() @@ -187,14 +189,14 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne /obj/machinery/gravity_generator/main/attackby(obj/item/I, mob/user, params) switch(broken_state) if(GRAV_NEEDS_SCREWDRIVER) - if(istype(I, /obj/item/screwdriver)) + if(I.tool_behaviour == TOOL_SCREWDRIVER) to_chat(user, "You secure the screws of the framework.") I.play_tool_sound(src) broken_state++ update_icon() return if(GRAV_NEEDS_WELDING) - if(istype(I, /obj/item/weldingtool)) + if(I.tool_behaviour == TOOL_WELDER) if(I.use_tool(src, user, 0, volume=50, amount=1)) to_chat(user, "You mend the damaged framework.") broken_state++ @@ -206,14 +208,14 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne if(PS.get_amount() >= 10) PS.use(10) to_chat(user, "You add the plating to the framework.") - playsound(src.loc, 'sound/machines/click.ogg', 75, 1) + playsound(src.loc, 'sound/machines/click.ogg', 75, TRUE) broken_state++ update_icon() else to_chat(user, "You need 10 sheets of plasteel!") return if(GRAV_NEEDS_WRENCH) - if(istype(I, /obj/item/wrench)) + if(I.tool_behaviour == TOOL_WRENCH) to_chat(user, "You secure the plating to the framework.") I.play_tool_sound(src) set_fix() @@ -224,7 +226,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "gravity_generator", name, 400, 200, master_ui, state) + ui = new(user, src, ui_key, "GravityGenerator", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/gravity_generator/main/ui_data(mob/user) @@ -241,16 +243,18 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne /obj/machinery/gravity_generator/main/ui_act(action, params) if(..()) return + switch(action) if("gentoggle") breaker = !breaker investigate_log("was toggled [breaker ? "ON" : "OFF"] by [key_name(usr)].", INVESTIGATE_GRAVITY) set_power() + . = TRUE // Power and Icon States /obj/machinery/gravity_generator/main/power_change() - ..() + . = ..() investigate_log("has [stat & NOPOWER ? "lost" : "regained"] power.", INVESTIGATE_GRAVITY) set_power() @@ -313,7 +317,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne charge_count -= 2 if(charge_count % 4 == 0 && prob(75)) // Let them know it is charging/discharging. - playsound(src.loc, 'sound/effects/empulse.ogg', 100, 1) + playsound(src.loc, 'sound/effects/empulse.ogg', 100, TRUE) updateDialog() if(prob(25)) // To help stop "Your clothes feel warm." spam. @@ -390,16 +394,13 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne // Misc /obj/item/paper/guides/jobs/engi/gravity_gen - name = "paper- 'Generate your own gravity!'" - info = {"

    Gravity Generator Instructions For Dummies

    -

    Surprisingly, gravity isn't that hard to make! All you have to do is inject deadly radioactive minerals into a ball of - energy and you have yourself gravity! You can turn the machine on or off when required but you must remember that the generator - will EMIT RADIATION when charging or discharging, you can tell it is charging or discharging by the noise it makes, so please WEAR PROTECTIVE CLOTHING.

    -
    -

    It blew up!

    -

    Don't panic! The gravity generator was designed to be easily repaired. If, somehow, the sturdy framework did not survive then - please proceed to panic; otherwise follow these steps.

      -
    1. Secure the screws of the framework with a screwdriver.
    2. -
    3. Mend the damaged framework with a welding tool.
    4. -
    5. Add additional plasteel plating.
    6. -
    7. Secure the additional plating with a wrench.
    "} + info = {" +# Gravity Generator Instructions For Dummies +Surprisingly, gravity isn't that hard to make! All you have to do is inject deadly radioactive minerals into a ball of energy and you have yourself gravity! You can turn the machine on or off when required but you must remember that the generator will EMIT RADIATION when charging or discharging, you can tell it is charging or discharging by the noise it makes, so please WEAR PROTECTIVE CLOTHING.

    +### It blew up! +Don't panic! The gravity generator was designed to be easily repaired. If, somehow, the sturdy framework did not survive then please proceed to panic; otherwise follow these steps. +1. Secure the screws of the framework with a screwdriver. +2. Mend the damaged framework with a welding tool. +3. Add additional plasteel plating. +4. Secure the additional plating with a wrench. +"} diff --git a/code/modules/power/monitor.dm b/code/modules/power/monitor.dm index f4ee102ccc..974fb1b9e2 100644 --- a/code/modules/power/monitor.dm +++ b/code/modules/power/monitor.dm @@ -10,6 +10,9 @@ idle_power_usage = 20 active_power_usage = 100 circuit = /obj/item/circuitboard/computer/powermonitor + tgui_id = "PowerMonitor" + ui_x = 550 + ui_y = 700 var/obj/structure/cable/attached_wire var/obj/machinery/power/apc/local_apc @@ -19,8 +22,6 @@ var/record_interval = 50 var/next_record = 0 var/is_secret_monitor = FALSE - tgui_id = "power_monitor" - ui_style = "ntos" /obj/machinery/computer/monitor/secret //Hides the power monitor (such as ones on ruins & CentCom) from PDA's to prevent metagaming. name = "outdated power monitoring console" @@ -87,7 +88,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, tgui_id, name, 550, 700, master_ui, state) + ui = new(user, src, ui_key, "PowerMonitor", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/computer/monitor/ui_data() diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm index 3c20f2f69c..d4e0df8359 100644 --- a/code/modules/power/port_gen.dm +++ b/code/modules/power/port_gen.dm @@ -1,4 +1,3 @@ - //Baseline portable generator. Has all the default handling. Not intended to be used on it's own (since it generates unlimited power). /obj/machinery/power/port_gen name = "portable generator" @@ -8,10 +7,11 @@ density = TRUE anchored = FALSE use_power = NO_POWER_USE + ui_x = 450 + ui_y = 340 - var/active = 0 + var/active = FALSE var/power_gen = 5000 - var/recent_fault = 0 var/power_output = 1 var/consumption = 0 var/base_icon = "portgen0" @@ -27,8 +27,13 @@ QDEL_NULL(soundloop) return ..() +/obj/machinery/power/port_gen/connect_to_network() + if(!anchored) + return FALSE + . = ..() + /obj/machinery/power/port_gen/proc/HasFuel() //Placeholder for fuel check. - return 1 + return TRUE /obj/machinery/power/port_gen/proc/UseFuel() //Placeholder for fuel use. return @@ -39,26 +44,38 @@ /obj/machinery/power/port_gen/proc/handleInactive() return +/obj/machinery/power/port_gen/proc/TogglePower() + if(active) + active = FALSE + update_icon() + soundloop.stop() + else if(HasFuel()) + active = TRUE + START_PROCESSING(SSmachines, src) + update_icon() + soundloop.start() + /obj/machinery/power/port_gen/update_icon_state() icon_state = "[base_icon]_[active]" /obj/machinery/power/port_gen/process() - if(active && HasFuel() && !crit_fail && anchored && powernet) - add_avail(power_gen * power_output) + if(active) + if(!HasFuel() || !anchored) + TogglePower() + return + if(powernet) + add_avail(power_gen * power_output) UseFuel() - src.updateDialog() - soundloop.start() - else - active = 0 handleInactive() - update_icon() - soundloop.stop() /obj/machinery/power/port_gen/examine(mob/user) . = ..() . += "It is[!active?"n't":""] running." +///////////////// +// P.A.C.M.A.N // +///////////////// /obj/machinery/power/port_gen/pacman name = "\improper P.A.C.M.A.N.-type portable generator" circuit = /obj/item/circuitboard/machine/pacman @@ -78,8 +95,8 @@ /obj/machinery/power/port_gen/pacman/Initialize() . = ..() - var/obj/sheet = new sheet_path(null) - sheet_name = sheet.name + var/obj/S = sheet_path + sheet_name = initial(S.name) /obj/machinery/power/port_gen/pacman/Destroy() DropFuel() @@ -100,16 +117,16 @@ /obj/machinery/power/port_gen/pacman/examine(mob/user) . = ..() - . += "The generator has [sheets] units of [sheet_name] fuel left, producing [power_gen] per cycle." - if(crit_fail) - . += "The generator seems to have broken down." + . += "The generator has [sheets] units of [sheet_name] fuel left, producing [DisplayPower(power_gen)] per cycle." + if(anchored) + . += "It is anchored to the ground." if(in_range(user, src) || isobserver(user)) . += "The status display reads: Fuel efficiency increased by [(consumption*100)-100]%." /obj/machinery/power/port_gen/pacman/HasFuel() if(sheets >= 1 / (time_per_sheet / power_output) - sheet_left) - return 1 - return 0 + return TRUE + return FALSE /obj/machinery/power/port_gen/pacman/DropFuel() if(sheets) @@ -145,13 +162,11 @@ if (current_heat > 300) overheat() qdel(src) - return /obj/machinery/power/port_gen/pacman/handleInactive() - - if (current_heat > 0) - current_heat = max(current_heat - 2, 0) - src.updateDialog() + current_heat = max(current_heat - 2, 0) + if(current_heat == 0) + STOP_PROCESSING(SSmachines, src) /obj/machinery/power/port_gen/pacman/proc/overheat() explosion(src.loc, 2, 5, 2, -1) @@ -166,24 +181,21 @@ to_chat(user, "You add [amount] sheets to the [src.name].") sheets += amount addstack.use(amount) - updateUsrDialog() return else if(!active) - - if(istype(O, /obj/item/wrench)) - + if(O.tool_behaviour == TOOL_WRENCH) if(!anchored && !isinspace()) + anchored = TRUE connect_to_network() to_chat(user, "You secure the generator to the floor.") - anchored = TRUE else if(anchored) + anchored = FALSE disconnect_from_network() to_chat(user, "You unsecure the generator from the floor.") - anchored = FALSE - playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1) + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) return - else if(istype(O, /obj/item/screwdriver)) + else if(O.tool_behaviour == TOOL_SCREWDRIVER) panel_open = !panel_open O.play_tool_sound(src) if(panel_open) @@ -196,12 +208,10 @@ return ..() /obj/machinery/power/port_gen/pacman/emag_act(mob/user) - . = ..() if(obj_flags & EMAGGED) return obj_flags |= EMAGGED emp_act(EMP_HEAVY) - return TRUE /obj/machinery/power/port_gen/pacman/attack_ai(mob/user) interact(user) @@ -209,60 +219,52 @@ /obj/machinery/power/port_gen/pacman/attack_paw(mob/user) interact(user) -/obj/machinery/power/port_gen/pacman/ui_interact(mob/user) - . = ..() - if (get_dist(src, user) > 1 ) - if(!isAI(user)) - user.unset_machine() - user << browse(null, "window=port_gen") - return +/obj/machinery/power/port_gen/pacman/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "PortableGenerator", name, ui_x, ui_y, master_ui, state) + ui.open() - var/dat = text("[name]
    ") - if (active) - dat += text("Generator: On
    ") - else - dat += text("Generator: Off
    ") - dat += text("[capitalize(sheet_name)]: [sheets] - Eject
    ") - var/stack_percent = round(sheet_left * 100, 1) - dat += text("Current stack: [stack_percent]%
    ") - dat += text("Power output: - [power_gen * power_output] +
    ") - dat += text("Power current: [(powernet == null ? "Unconnected" : "[DisplayPower(avail())]")]
    ") - dat += text("Heat: [current_heat]
    ") - dat += "
    Close" - user << browse(dat, "window=port_gen") - onclose(user, "port_gen") +/obj/machinery/power/port_gen/pacman/ui_data() + var/data = list() -/obj/machinery/power/port_gen/pacman/Topic(href, href_list) + data["active"] = active + data["sheet_name"] = capitalize(sheet_name) + data["sheets"] = sheets + data["stack_percent"] = round(sheet_left * 100, 0.1) + + data["anchored"] = anchored + data["connected"] = (powernet == null ? 0 : 1) + data["ready_to_boot"] = anchored && HasFuel() + data["power_generated"] = DisplayPower(power_gen) + data["power_output"] = DisplayPower(power_gen * power_output) + data["power_available"] = (powernet == null ? 0 : DisplayPower(avail())) + data["current_heat"] = current_heat + . = data + +/obj/machinery/power/port_gen/pacman/ui_act(action, params) if(..()) return + switch(action) + if("toggle_power") + TogglePower() + . = TRUE - src.add_fingerprint(usr) - if(href_list["action"]) - if(href_list["action"] == "enable") - if(!active && HasFuel() && !crit_fail) - active = 1 - src.updateUsrDialog() - update_icon() - if(href_list["action"] == "disable") - if (active) - active = 0 - src.updateUsrDialog() - update_icon() - if(href_list["action"] == "eject") + if("eject") if(!active) DropFuel() - src.updateUsrDialog() - if(href_list["action"] == "lower_power") + . = TRUE + + if("lower_power") if (power_output > 1) power_output-- - src.updateUsrDialog() - if (href_list["action"] == "higher_power") + . = TRUE + + if("higher_power") if (power_output < 4 || (obj_flags & EMAGGED)) power_output++ - src.updateUsrDialog() - if (href_list["action"] == "close") - usr << browse(null, "window=port_gen") - usr.unset_machine() + . = TRUE /obj/machinery/power/port_gen/pacman/super name = "\improper S.U.P.E.R.P.A.C.M.A.N.-type portable generator" diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index d5b19b495c..9bbdcf4f66 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -386,4 +386,4 @@ var/target = base_area ? base_area : src for(var/obj/machinery/power/apc/APC in GLOB.apcs_list) if(APC.area == target) - return APC \ No newline at end of file + return APC diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm index 89596eb82f..5ef66e26d9 100644 --- a/code/modules/power/singularity/containment_field.dm +++ b/code/modules/power/singularity/containment_field.dm @@ -22,7 +22,7 @@ return ..() //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/machinery/field/containment/attack_hand(mob/user) +/obj/machinery/field/containment/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(get_dist(src, user) > 1) return FALSE else diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm index 957ceb986f..beaf4bfc43 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_control.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm @@ -9,15 +9,17 @@ idle_power_usage = 500 active_power_usage = 10000 dir = NORTH - var/strength_upper_limit = 2 - var/interface_control = 1 - var/list/obj/structure/particle_accelerator/connected_parts - var/assembled = 0 - var/construction_state = PA_CONSTRUCTION_UNSECURED - var/active = 0 - var/strength = 0 - var/powered = 0 mouse_opacity = MOUSE_OPACITY_OPAQUE + ui_x = 350 + ui_y = 185 + var/strength_upper_limit = 2 + var/interface_control = TRUE + var/list/obj/structure/particle_accelerator/connected_parts + var/assembled = FALSE + var/construction_state = PA_CONSTRUCTION_UNSECURED + var/active = FALSE + var/strength = 0 + var/powered = FALSE /obj/machinery/particle_accelerator/control_box/Initialize() . = ..() @@ -34,30 +36,27 @@ QDEL_NULL(wires) return ..() -/obj/machinery/particle_accelerator/control_box/attack_hand(mob/user) +/obj/machinery/particle_accelerator/control_box/multitool_act(mob/living/user, obj/item/I) . = ..() - if(.) - return - if(construction_state == PA_CONSTRUCTION_COMPLETE) - interact(user) - else if(construction_state == PA_CONSTRUCTION_PANEL_OPEN) + if(construction_state == PA_CONSTRUCTION_PANEL_OPEN) wires.interact(user) + return TRUE /obj/machinery/particle_accelerator/control_box/proc/update_state() if(construction_state < PA_CONSTRUCTION_COMPLETE) use_power = NO_POWER_USE - assembled = 0 - active = 0 + assembled = FALSE + active = FALSE for(var/CP in connected_parts) var/obj/structure/particle_accelerator/part = CP part.strength = null - part.powered = 0 + part.powered = FALSE part.update_icon() connected_parts.Cut() return if(!part_scan()) use_power = IDLE_POWER_USE - active = 0 + active = FALSE connected_parts.Cut() /obj/machinery/particle_accelerator/control_box/update_icon_state() @@ -78,36 +77,6 @@ else icon_state = "control_boxc" -/obj/machinery/particle_accelerator/control_box/Topic(href, href_list) - if(..()) - return - - if(!interface_control) - to_chat(usr, "ERROR: Request timed out. Check wire contacts.") - return - - if(href_list["close"]) - usr << browse(null, "window=pacontrol") - usr.unset_machine() - return - if(href_list["togglep"]) - if(!wires.is_cut(WIRE_POWER)) - toggle_power() - - else if(href_list["scan"]) - part_scan() - - else if(href_list["strengthup"]) - if(!wires.is_cut(WIRE_STRENGTH)) - add_strength() - - else if(href_list["strengthdown"]) - if(!wires.is_cut(WIRE_STRENGTH)) - remove_strength() - - updateDialog() - update_icon() - /obj/machinery/particle_accelerator/control_box/proc/strength_change() for(var/CP in connected_parts) var/obj/structure/particle_accelerator/part = CP @@ -123,7 +92,6 @@ log_game("PA Control Computer increased to [strength] by [key_name(usr)] in [AREACOORD(src)]") investigate_log("increased to [strength] by [key_name(usr)] at [AREACOORD(src)]", INVESTIGATE_SINGULO) - /obj/machinery/particle_accelerator/control_box/proc/remove_strength(s) if(assembled && (strength > 0)) strength-- @@ -133,11 +101,10 @@ log_game("PA Control Computer decreased to [strength] by [key_name(usr)] in [AREACOORD(src)]") investigate_log("decreased to [strength] by [key_name(usr)] at [AREACOORD(src)]", INVESTIGATE_SINGULO) - /obj/machinery/particle_accelerator/control_box/power_change() - ..() + . = ..() if(stat & NOPOWER) - active = 0 + active = FALSE use_power = NO_POWER_USE else if(!stat && construction_state == PA_CONSTRUCTION_COMPLETE) use_power = IDLE_POWER_USE @@ -160,49 +127,48 @@ var/odir = turn(dir,180) var/turf/T = loc - assembled = 0 + assembled = FALSE critical_machine = FALSE var/obj/structure/particle_accelerator/fuel_chamber/F = locate() in orange(1,src) if(!F) - return 0 + return FALSE setDir(F.dir) connected_parts.Cut() T = get_step(T,rdir) if(!check_part(T, /obj/structure/particle_accelerator/fuel_chamber)) - return 0 + return FALSE T = get_step(T,odir) if(!check_part(T, /obj/structure/particle_accelerator/end_cap)) - return 0 + return FALSE T = get_step(T,dir) T = get_step(T,dir) if(!check_part(T, /obj/structure/particle_accelerator/power_box)) - return 0 + return FALSE T = get_step(T,dir) if(!check_part(T, /obj/structure/particle_accelerator/particle_emitter/center)) - return 0 + return FALSE T = get_step(T,ldir) if(!check_part(T, /obj/structure/particle_accelerator/particle_emitter/left)) - return 0 + return FALSE T = get_step(T,rdir) T = get_step(T,rdir) if(!check_part(T, /obj/structure/particle_accelerator/particle_emitter/right)) - return 0 + return FALSE - assembled = 1 + assembled = TRUE critical_machine = TRUE //Only counts if the PA is actually assembled. - return 1 + return TRUE /obj/machinery/particle_accelerator/control_box/proc/check_part(turf/T, type) var/obj/structure/particle_accelerator/PA = locate(/obj/structure/particle_accelerator) in T if(istype(PA, type) && (PA.construction_state == PA_CONSTRUCTION_COMPLETE)) if(PA.connect_master(src)) connected_parts.Add(PA) - return 1 - return 0 - + return TRUE + return FALSE /obj/machinery/particle_accelerator/control_box/proc/toggle_power() active = !active @@ -214,47 +180,16 @@ for(var/CP in connected_parts) var/obj/structure/particle_accelerator/part = CP part.strength = strength - part.powered = 1 + part.powered = TRUE part.update_icon() else use_power = IDLE_POWER_USE for(var/CP in connected_parts) var/obj/structure/particle_accelerator/part = CP part.strength = null - part.powered = 0 + part.powered = FALSE part.update_icon() - return 1 - - -/obj/machinery/particle_accelerator/control_box/ui_interact(mob/user) - . = ..() - if((get_dist(src, user) > 1) || (stat & (BROKEN|NOPOWER))) - if(!issilicon(user)) - user.unset_machine() - user << browse(null, "window=pacontrol") - return - - var/dat = "" - dat += "Close

    " - dat += "

    Status

    " - if(!assembled) - dat += "Unable to detect all parts!
    " - dat += "Run Scan

    " - else - dat += "All parts in place.

    " - dat += "Power:" - if(active) - dat += "On
    " - else - dat += "Off
    " - dat += "Toggle Power

    " - dat += "Particle Strength: [strength] " - dat += "--|++

    " - - var/datum/browser/popup = new(user, "pacontrol", name, 420, 300) - popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) - popup.open() + return TRUE /obj/machinery/particle_accelerator/control_box/examine(mob/user) . = ..() @@ -266,48 +201,47 @@ if(PA_CONSTRUCTION_PANEL_OPEN) . += "The panel is open." - /obj/machinery/particle_accelerator/control_box/attackby(obj/item/W, mob/user, params) var/did_something = FALSE switch(construction_state) if(PA_CONSTRUCTION_UNSECURED) - if(istype(W, /obj/item/wrench) && !isinspace()) + if(W.tool_behaviour == TOOL_WRENCH && !isinspace()) W.play_tool_sound(src, 75) anchored = TRUE - user.visible_message("[user.name] secures the [name] to the floor.", \ - "You secure the external bolts.") + user.visible_message("[user.name] secures the [name] to the floor.", \ + "You secure the external bolts.") construction_state = PA_CONSTRUCTION_UNWIRED did_something = TRUE if(PA_CONSTRUCTION_UNWIRED) - if(istype(W, /obj/item/wrench)) + if(W.tool_behaviour == TOOL_WRENCH) W.play_tool_sound(src, 75) anchored = FALSE - user.visible_message("[user.name] detaches the [name] from the floor.", \ - "You remove the external bolts.") + user.visible_message("[user.name] detaches the [name] from the floor.", \ + "You remove the external bolts.") construction_state = PA_CONSTRUCTION_UNSECURED did_something = TRUE else if(istype(W, /obj/item/stack/cable_coil)) if(W.use_tool(src, user, 0, 1)) - user.visible_message("[user.name] adds wires to the [name].", \ - "You add some wires.") + user.visible_message("[user.name] adds wires to the [name].", \ + "You add some wires.") construction_state = PA_CONSTRUCTION_PANEL_OPEN did_something = TRUE if(PA_CONSTRUCTION_PANEL_OPEN) - if(istype(W, /obj/item/wirecutters))//TODO:Shock user if its on? - user.visible_message("[user.name] removes some wires from the [name].", \ - "You remove some wires.") + if(W.tool_behaviour == TOOL_WIRECUTTER)//TODO:Shock user if its on? + user.visible_message("[user.name] removes some wires from the [name].", \ + "You remove some wires.") construction_state = PA_CONSTRUCTION_UNWIRED did_something = TRUE - else if(istype(W, /obj/item/screwdriver)) - user.visible_message("[user.name] closes the [name]'s access panel.", \ - "You close the access panel.") + else if(W.tool_behaviour == TOOL_SCREWDRIVER) + user.visible_message("[user.name] closes the [name]'s access panel.", \ + "You close the access panel.") construction_state = PA_CONSTRUCTION_COMPLETE did_something = TRUE if(PA_CONSTRUCTION_COMPLETE) - if(istype(W, /obj/item/screwdriver)) - user.visible_message("[user.name] opens the [name]'s access panel.", \ - "You open the access panel.") + if(W.tool_behaviour == TOOL_SCREWDRIVER) + user.visible_message("[user.name] opens the [name]'s access panel.", \ + "You open the access panel.") construction_state = PA_CONSTRUCTION_PANEL_OPEN did_something = TRUE @@ -323,6 +257,65 @@ if(prob(50)) qdel(src) +/obj/machinery/particle_accelerator/control_box/interact(mob/user) + if(construction_state == PA_CONSTRUCTION_PANEL_OPEN) + wires.interact(user) + else + ..() + +/obj/machinery/particle_accelerator/control_box/proc/is_interactive(mob/user) + if(!interface_control) + to_chat(user, "ERROR: Request timed out. Check wire contacts.") + return FALSE + if(construction_state != PA_CONSTRUCTION_COMPLETE) + return FALSE + return TRUE + +/obj/machinery/particle_accelerator/control_box/ui_status(mob/user) + if(is_interactive(user)) + return ..() + return UI_CLOSE + +/obj/machinery/particle_accelerator/control_box/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "ParticleAccelerator", name, ui_x, ui_y, master_ui, state) + ui.open() + +/obj/machinery/particle_accelerator/control_box/ui_data(mob/user) + var/list/data = list() + data["assembled"] = assembled + data["power"] = active + data["strength"] = strength + return data + +/obj/machinery/particle_accelerator/control_box/ui_act(action, params) + if(..()) + return + + switch(action) + if("power") + if(wires.is_cut(WIRE_POWER)) + return + toggle_power() + . = TRUE + if("scan") + part_scan() + . = TRUE + if("add_strength") + if(wires.is_cut(WIRE_STRENGTH)) + return + add_strength() + . = TRUE + if("remove_strength") + if(wires.is_cut(WIRE_STRENGTH)) + return + remove_strength() + . = TRUE + + update_icon() + #undef PA_CONSTRUCTION_UNSECURED #undef PA_CONSTRUCTION_UNWIRED #undef PA_CONSTRUCTION_PANEL_OPEN diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 025784e909..96f8b4e996 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -59,7 +59,7 @@ last_failed_movement = direct return 0 -/obj/singularity/attack_hand(mob/user) +/obj/singularity/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) consume(user) return TRUE diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index 788b4b1441..fcc7faa29e 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -21,6 +21,9 @@ density = TRUE use_power = NO_POWER_USE circuit = /obj/item/circuitboard/machine/smes + ui_x = 340 + ui_y = 350 + var/capacity = 5e6 // maximum charge var/charge = 0 // actual charge @@ -54,7 +57,7 @@ break dir_loop if(!terminal) - stat |= BROKEN + obj_break() return terminal.master = src update_icon() @@ -123,22 +126,22 @@ return to_chat(user, "You start building the power terminal...") - playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1) + playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE) if(C.use_tool(src, user, 20, 10)) var/obj/structure/cable/N = T.get_cable_node() //get the connecting node cable, if there's one if (prob(50) && electrocute_mob(usr, N, N, 1, TRUE)) //animate the electrocution if uncautious and unlucky do_sparks(5, TRUE, src) return + if(!terminal) + C.use(10) + user.visible_message("[user.name] builds a power terminal.",\ + "You build the power terminal.") - user.visible_message(\ - "[user.name] has built a power terminal.",\ - "You build the power terminal.") - - //build the terminal and link it to the network - make_terminal(T) - terminal.connect_to_network() - connect_to_network() + //build the terminal and link it to the network + make_terminal(T) + terminal.connect_to_network() + connect_to_network() return //crowbarring it ! @@ -148,13 +151,14 @@ log_game("[src] has been deconstructed by [key_name(user)] at [AREACOORD(src)]") investigate_log("SMES deconstructed by [key_name(user)] at [AREACOORD(src)]", INVESTIGATE_SINGULO) return - else if(panel_open && istype(I, /obj/item/crowbar)) + else if(panel_open && I.tool_behaviour == TOOL_CROWBAR) return return ..() /obj/machinery/power/smes/wirecutter_act(mob/living/user, obj/item/I) //disassembling the terminal + . = ..() if(terminal && panel_open) terminal.dismantle(user, I) return TRUE @@ -193,7 +197,7 @@ if(terminal) terminal.master = null terminal = null - stat |= BROKEN + obj_break() /obj/machinery/power/smes/update_overlays() @@ -201,6 +205,9 @@ if((stat & BROKEN) || panel_open) return + if(panel_open) + return + if(outputting) . += "smes-op1" else @@ -208,14 +215,14 @@ if(inputting) . += "smes-oc1" - else - if(input_attempt) - . += "smes-oc0" + else if(input_attempt) + . += "smes-oc0" var/clevel = chargedisplay() if(clevel>0) . += "smes-og[clevel]" + /obj/machinery/power/smes/proc/chargedisplay() return clamp(round(5.5*charge/capacity),0,5) @@ -315,28 +322,26 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "smes", name, 340, 440, master_ui, state) + ui = new(user, src, ui_key, "Smes", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/power/smes/ui_data() var/list/data = list( - "capacityPercent" = round(100*charge/capacity, 0.1), "capacity" = capacity, + "capacityPercent" = round(100*charge/capacity, 0.1), "charge" = charge, - "inputAttempt" = input_attempt, "inputting" = inputting, "inputLevel" = input_level, "inputLevel_text" = DisplayPower(input_level), "inputLevelMax" = input_level_max, - "inputAvailable" = DisplayPower(input_available), - + "inputAvailable" = input_available, "outputAttempt" = output_attempt, "outputting" = outputting, "outputLevel" = output_level, "outputLevel_text" = DisplayPower(output_level), "outputLevelMax" = output_level_max, - "outputUsed" = DisplayPower(output_used) + "outputUsed" = output_used, ) return data @@ -357,11 +362,7 @@ if("input") var/target = params["target"] var/adjust = text2num(params["adjust"]) - if(target == "input") - target = input("New input target (0-[input_level_max]):", name, input_level) as num|null - if(!isnull(target) && !..()) - . = TRUE - else if(target == "min") + if(target == "min") target = 0 . = TRUE else if(target == "max") @@ -379,11 +380,7 @@ if("output") var/target = params["target"] var/adjust = text2num(params["adjust"]) - if(target == "input") - target = input("New output target (0-[output_level_max]):", name, output_level) as num|null - if(!isnull(target) && !..()) - . = TRUE - else if(target == "min") + if(target == "min") target = 0 . = TRUE else if(target == "max") diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index 89452affcb..2c258c1f49 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -350,7 +350,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "solar_control", name, 380, 230, master_ui, state) + ui = new(user, src, ui_key, "SolarControl", name, 380, 230, master_ui, state) ui.open() /obj/machinery/power/solar_control/ui_data() @@ -481,8 +481,12 @@ // /obj/item/paper/guides/jobs/engi/solars - name = "paper- 'Going green! Setup your own solar array instructions.'" - info = "

    Welcome

    At greencorps we love the environment, and space. With this package you are able to help mother nature and produce energy without any usage of fossil fuel or plasma! Singularity energy is dangerous while solar energy is safe, which is why it's better. Now here is how you setup your own solar array.

    You can make a solar panel by wrenching the solar assembly onto a cable node. Adding a glass panel, reinforced or regular glass will do, will finish the construction of your solar panel. It is that easy!

    Now after setting up 19 more of these solar panels you will want to create a solar tracker to keep track of our mother nature's gift, the sun. These are the same steps as before except you insert the tracker equipment circuit into the assembly before performing the final step of adding the glass. You now have a tracker! Now the last step is to add a computer to calculate the sun's movements and to send commands to the solar panels to change direction with the sun. Setting up the solar computer is the same as setting up any computer, so you should have no trouble in doing that. You do need to put a wire node under the computer, and the wire needs to be connected to the tracker.

    Congratulations, you should have a working solar array. If you are having trouble, here are some tips. Make sure all solar equipment are on a cable node, even the computer. You can always deconstruct your creations if you make a mistake.

    That's all to it, be safe, be green!

    " + info = {" +# Welcome! +At greencorps we love the environment, and space. With this package you are able to help mother nature and produce energy without any usage of fossil fuel or plasma! Singularity energy is dangerous while solar energy is safe, which is why it's better. Now here is how you setup your own solar array. +You can make a solar panel by wrenching the solar assembly onto a cable node. Adding a glass panel, reinforced or regular glass will do, will finish the construction of your solar panel. It is that easy!

    Now after setting up 19 more of these solar panels you will want to create a solar tracker to keep track of our mother nature's gift, the sun. These are the same steps as before except you insert the tracker equipment circuit into the assembly before performing the final step of adding the glass. You now have a tracker! Now the last step is to add a computer to calculate the sun's movements and to send commands to the solar panels to change direction with the sun. Setting up the solar computer is the same as setting up any computer, so you should have no trouble in doing that. You do need to put a wire node under the computer, and the wire needs to be connected to the tracker. +Congratulations, you should have a working solar array. If you are having trouble, here are some tips. Make sure all solar equipment are on a cable node, even the computer. You can always deconstruct your creations if you make a mistake.

    That's all to it, be safe, be green! +"} #undef SOLAR_GEN_RATE #undef OCCLUSION_DISTANCE diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 87bdfe99e2..823ba75e43 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -571,7 +571,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) /obj/machinery/power/supermatter_crystal/attack_ai(mob/user) return -/obj/machinery/power/supermatter_crystal/attack_hand(mob/living/user) +/obj/machinery/power/supermatter_crystal/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/power/turbine.dm b/code/modules/power/turbine.dm index 6fd1b27a47..e7a97c554f 100644 --- a/code/modules/power/turbine.dm +++ b/code/modules/power/turbine.dm @@ -41,6 +41,11 @@ var/comp_id = 0 var/efficiency +/obj/machinery/power/compressor/Destroy() + if(turbine && turbine.compressor == src) + turbine.compressor = null + turbine = null + return ..() /obj/machinery/power/turbine name = "gas turbine generator" @@ -51,12 +56,20 @@ resistance_flags = FIRE_PROOF CanAtmosPass = ATMOS_PASS_DENSITY circuit = /obj/item/circuitboard/machine/power_turbine + ui_x = 310 + ui_y = 150 var/opened = 0 var/obj/machinery/power/compressor/compressor var/turf/outturf var/lastgen var/productivity = 1 +/obj/machinery/power/turbine/Destroy() + if(compressor && compressor.turbine == src) + compressor.turbine = null + compressor = null + return ..() + // the inlet stage of the gas turbine electricity generator /obj/machinery/power/compressor/Initialize() @@ -66,12 +79,10 @@ inturf = get_step(src, dir) locate_machinery() if(!turbine) - stat |= BROKEN - + obj_break() #define COMPFRICTION 5e5 - /obj/machinery/power/compressor/locate_machinery() if(turbine) return @@ -103,7 +114,7 @@ stat &= ~BROKEN else to_chat(user, "Turbine not connected.") - stat |= BROKEN + obj_break() return default_deconstruction_crowbar(I) @@ -129,9 +140,9 @@ // RPM function to include compression friction - be advised that too low/high of a compfriction value can make things screwy + rpm = min(rpm, (COMPFRICTION*efficiency)/2) rpm = max(0, rpm - (rpm*rpm)/(COMPFRICTION*efficiency)) - if(starter && !(stat & NOPOWER)) use_power(2800) if(rpm<1000) @@ -140,8 +151,6 @@ if(rpm<1000) rpmtarget = 0 - - if(rpm>50000) add_overlay(mutable_appearance(icon, "comp-o4", FLY_LAYER)) else if(rpm>10000) @@ -164,7 +173,7 @@ outturf = get_step(src, dir) locate_machinery() if(!compressor) - stat |= BROKEN + obj_break() connect_to_network() /obj/machinery/power/turbine/RefreshParts() @@ -222,8 +231,6 @@ if(lastgen > 100) add_overlay(mutable_appearance(icon, "turb-o", FLY_LAYER)) - updateDialog() - /obj/machinery/power/turbine/attackby(obj/item/I, mob/user, params) if(default_deconstruction_screwdriver(user, initial(icon_state), initial(icon_state), I)) return @@ -237,53 +244,42 @@ stat &= ~BROKEN else to_chat(user, "Compressor not connected.") - stat |= BROKEN + obj_break() return default_deconstruction_crowbar(I) -/obj/machinery/power/turbine/ui_interact(mob/user) +/obj/machinery/power/turbine/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "TurbineComputer", name, ui_x, ui_y, master_ui, state) + ui.open() - if(!Adjacent(user) || (stat & (NOPOWER|BROKEN)) && !issilicon(user)) - user.unset_machine(src) - user << browse(null, "window=turbine") - return +/obj/machinery/power/turbine/ui_data(mob/user) + var/list/data = list() + data["compressor"] = compressor ? TRUE : FALSE + data["compressor_broke"] = (!compressor || (compressor.stat & BROKEN)) ? TRUE : FALSE + data["turbine"] = compressor?.turbine ? TRUE : FALSE + data["turbine_broke"] = (!compressor || !compressor.turbine || (compressor.turbine.stat & BROKEN)) ? TRUE : FALSE + data["online"] = compressor?.starter + data["power"] = DisplayPower(compressor?.turbine?.lastgen) + data["rpm"] = compressor?.rpm + data["temp"] = compressor?.gas_contained.return_temperature() + return data - var/t = "Gas Turbine Generator


    "
    -
    -	t += "Generated power : [DisplayPower(lastgen)]

    " - - t += "Turbine: [round(compressor.rpm)] RPM
    " - - t += "Starter: [ compressor.starter ? "Off On" : "Off On"]" - - t += "

    Close" - - t += "" - var/datum/browser/popup = new(user, "turbine", name) - popup.set_content(t) - popup.open() - - return - -/obj/machinery/power/turbine/Topic(href, href_list) +/obj/machinery/power/turbine/ui_act(action, params) if(..()) return - if( href_list["close"] ) - usr << browse(null, "window=turbine") - usr.unset_machine(src) - return - - else if( href_list["str"] ) - if(compressor) - compressor.starter = !compressor.starter - - updateDialog() - - - - + switch(action) + if("toggle_power") + if(compressor && compressor.turbine) + compressor.starter = !compressor.starter + . = TRUE + if("reconnect") + locate_machinery() + . = TRUE ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -296,6 +292,8 @@ icon_screen = "turbinecomp" icon_keyboard = "tech_key" circuit = /obj/item/circuitboard/computer/turbine_computer + ui_x = 310 + ui_y = 150 var/obj/machinery/power/compressor/compressor var/id = 0 @@ -319,18 +317,16 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "turbine_computer", name, 300, 200, master_ui, state) + ui = new(user, src, ui_key, "TurbineComputer", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/computer/turbine_computer/ui_data(mob/user) var/list/data = list() - data["compressor"] = compressor ? TRUE : FALSE data["compressor_broke"] = (!compressor || (compressor.stat & BROKEN)) ? TRUE : FALSE data["turbine"] = compressor?.turbine ? TRUE : FALSE data["turbine_broke"] = (!compressor || !compressor.turbine || (compressor.turbine.stat & BROKEN)) ? TRUE : FALSE data["online"] = compressor?.starter - data["power"] = DisplayPower(compressor?.turbine?.lastgen) data["rpm"] = compressor?.rpm data["temp"] = compressor?.gas_contained.return_temperature() @@ -340,6 +336,7 @@ /obj/machinery/computer/turbine_computer/ui_act(action, params) if(..()) return + switch(action) if("toggle_power") if(compressor && compressor.turbine) diff --git a/code/modules/projectiles/ammunition/energy/special.dm b/code/modules/projectiles/ammunition/energy/special.dm index 994b0f7f01..ab180cb629 100644 --- a/code/modules/projectiles/ammunition/energy/special.dm +++ b/code/modules/projectiles/ammunition/energy/special.dm @@ -75,4 +75,9 @@ /obj/item/ammo_casing/energy/shrink projectile_type = /obj/item/projectile/beam/shrink select_name = "shrink ray" - e_cost = 200 \ No newline at end of file + e_cost = 200 + +/obj/item/ammo_casing/energy/pickle //ammo for an adminspawn gun + projectile_type = /obj/item/projectile/energy/pickle + select_name = "pickle ray" + e_cost = 0 \ No newline at end of file diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index 4aeefde6d4..e5dc056011 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -98,7 +98,7 @@ update_icon() //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/gun/ballistic/attack_hand(mob/user) +/obj/item/gun/ballistic/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(loc == user) if(suppressed && can_unsuppress) var/obj/item/suppressor/S = suppressed diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm index 39956ef3e8..89e30e765b 100644 --- a/code/modules/projectiles/guns/ballistic/automatic.dm +++ b/code/modules/projectiles/guns/ballistic/automatic.dm @@ -328,7 +328,7 @@ update_icon() //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/item/gun/ballistic/automatic/l6_saw/attack_hand(mob/user) +/obj/item/gun/ballistic/automatic/l6_saw/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(loc != user) ..() return //let them pick it up diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 8f9e364302..c2b821dfcf 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -290,7 +290,7 @@ /obj/item/gun/energy/vv_edit_var(var_name, var_value) switch(var_name) - if("selfcharge") + if(NAMEOF(src, selfcharge)) if(var_value) START_PROCESSING(SSobj, src) else diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index b55e26b6a3..6489920b98 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -329,3 +329,11 @@ add_overlay("emitter_carbine_empty") else add_overlay("emitter_carbine") + +//the pickle ray +/obj/item/gun/energy/pickle_gun + name = "pickle ray" + desc = "funniest shit i've ever seen" + icon_state = "decloner" + no_pin_required = TRUE + ammo_type = list(/obj/item/ammo_casing/energy/pickle) \ No newline at end of file diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm index 0c8a9deaf8..ebc4a2f2a4 100644 --- a/code/modules/projectiles/guns/magic.dm +++ b/code/modules/projectiles/guns/magic.dm @@ -83,6 +83,6 @@ /obj/item/gun/magic/vv_edit_var(var_name, var_value) . = ..() - switch (var_name) - if ("charges") + switch(var_name) + if(NAMEOF(src, charges)) recharge_newshot() diff --git a/code/modules/projectiles/projectile/energy/misc.dm b/code/modules/projectiles/projectile/energy/misc.dm index d5346b954d..bfa15e9ef8 100644 --- a/code/modules/projectiles/projectile/energy/misc.dm +++ b/code/modules/projectiles/projectile/energy/misc.dm @@ -13,3 +13,13 @@ damage_type = TOX knockdown = 100 range = 7 + +/obj/item/projectile/energy/pickle //projectile for adminspawn only gun + name = "pickle-izing beam" + icon_state = "declone" + +/obj/item/projectile/energy/pickle/on_hit(atom/target) + //we don't care if they blocked it, they're turning into a pickle + if(isliving(target)) + var/mob/living/living_target = target + living_target.turn_into_pickle() //yes this is a real proc diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index 7ef52aef25..c9ca4e9ba3 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -207,7 +207,8 @@ /mob/living/simple_animal/pet/fox, /mob/living/simple_animal/butterfly, /mob/living/simple_animal/pet/cat/cak, - /mob/living/simple_animal/chick) + /mob/living/simple_animal/chick, + /mob/living/simple_animal/pickle) new_mob = new path(M.loc) if("humanoid") diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index 4cf50cd072..c2662a8342 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -463,17 +463,10 @@ if(total_matching_reagents == total_required_reagents && total_matching_catalysts == total_required_catalysts && matching_container && matching_other && meets_temp_requirement && can_special_react) possible_reactions += C + sortTim(possible_reactions, /proc/cmp_chemical_reactions_default, FALSE) + if(possible_reactions.len) var/datum/chemical_reaction/selected_reaction = possible_reactions[1] - //select the reaction with the most extreme temperature requirements - for(var/V in possible_reactions) - var/datum/chemical_reaction/competitor = V - if(selected_reaction.is_cold_recipe) - if(competitor.required_temp <= selected_reaction.required_temp) - selected_reaction = competitor - else - if(competitor.required_temp >= selected_reaction.required_temp) //will return with the hotter reacting first. - selected_reaction = competitor var/list/cached_required_reagents = selected_reaction.required_reagents//update reagents list var/list/cached_results = selected_reaction.results//resultant chemical list var/special_react_result = selected_reaction.check_special_react(src) diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index b85d7aefc9..da33f935da 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -32,7 +32,6 @@ var/nopower_state = "dispenser_nopower" var/has_panel_overlay = TRUE var/obj/item/reagent_containers/beaker = null - //dispensable_reagents is copypasted in plumbing synthesizers. Please update accordingly. (I didn't make it global because that would limit custom chem dispensers) var/list/dispensable_reagents = list( /datum/reagent/hydrogen, /datum/reagent/lithium, @@ -182,7 +181,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "chem_dispenser", name, 565, 550, master_ui, state) + ui = new(user, src, ui_key, "ChemDispenser", name, 565, 550, master_ui, state) if(user.hallucinating()) ui.set_autoupdate(FALSE) //to not ruin the immersion by constantly changing the fake chemicals ui.open() diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm index 8572d30efe..5697a2385c 100644 --- a/code/modules/reagents/chemistry/machinery/chem_heater.dm +++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm @@ -103,7 +103,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "chem_heater", name, 275, 400, master_ui, state) + ui = new(user, src, ui_key, "ChemHeater", name, 300, 400, master_ui, state) ui.open() /obj/machinery/chem_heater/ui_data() @@ -155,4 +155,4 @@ if("eject") on = FALSE replace_beaker(usr) - . = TRUE \ No newline at end of file + . = TRUE diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index 24c5200a54..dd9dd7c0bf 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -165,7 +165,8 @@ if(!ui) var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/simple/pills) assets.send(user) - ui = new(user, src, ui_key, "chem_master", name, 500, 550, master_ui, state) + + ui = new(user, src, ui_key, "ChemMaster", name, 520, 550, master_ui, state) ui.open() /obj/machinery/chem_master/ui_data(mob/user) diff --git a/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm b/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm index ed23e7c75c..66c2616972 100644 --- a/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm +++ b/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm @@ -16,7 +16,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "chem_synthesizer", name, 390, 330, master_ui, state) + ui = new(user, src, ui_key, "ChemDebugSynthesizer", name, 390, 330, master_ui, state) ui.open() /obj/machinery/chem_dispenser/chem_synthesizer/ui_act(action, params) diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm index 38a05cd541..4a4bbdb546 100644 --- a/code/modules/reagents/chemistry/machinery/pandemic.dm +++ b/code/modules/reagents/chemistry/machinery/pandemic.dm @@ -123,7 +123,7 @@ /obj/machinery/computer/pandemic/ui_interact(mob/user, ui_key = "main", datum/tgui/ui, force_open = FALSE, datum/tgui/master_ui, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "pandemic", name, 520, 550, master_ui, state) + ui = new(user, src, ui_key, "Pandemic", name, 520, 550, master_ui, state) ui.open() /obj/machinery/computer/pandemic/ui_data(mob/user) diff --git a/code/modules/reagents/chemistry/machinery/smoke_machine.dm b/code/modules/reagents/chemistry/machinery/smoke_machine.dm index 0a08395c1b..cac90d1c14 100644 --- a/code/modules/reagents/chemistry/machinery/smoke_machine.dm +++ b/code/modules/reagents/chemistry/machinery/smoke_machine.dm @@ -104,7 +104,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "smoke_machine", name, 350, 350, master_ui, state) + ui = new(user, src, ui_key, "SmokeMachine", name, 350, 350, master_ui, state) ui.open() /obj/machinery/smoke_machine/ui_data(mob/user) diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm index 98d66a2b1b..7df061c8aa 100644 --- a/code/modules/reagents/chemistry/recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -5,6 +5,9 @@ var/list/required_reagents = new/list() var/list/required_catalysts = new/list() + /// Higher is higher priority, determines which order reactions are checked. + var/priority = CHEMICAL_REACTION_PRIORITY_DEFAULT + // Both of these variables are mostly going to be used with slime cores - but if you want to, you can use them for other things var/required_container = null // the exact container path required for the reaction to happen var/required_other = 0 // an integer required for the reaction to happen diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index a8aec91669..57567403b4 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -704,6 +704,14 @@ required_reagents = list(/datum/reagent/liquid_dark_matter = 5, /datum/reagent/medicine/synaptizine = 10, /datum/reagent/medicine/oculine = 10, /datum/reagent/mutationtoxin = 1) required_temp = 600 +/datum/chemical_reaction/slime_extractification + required_reagents = list(/datum/reagent/toxin/slimejelly = 30, /datum/reagent/consumable/frostoil = 5, /datum/reagent/toxin/plasma = 5) + mix_message = "The mixture condenses into a ball." + +/datum/chemical_reaction/slime_extractification/on_reaction(datum/reagents/holder, created_volume) + var/location = get_turf(holder.my_atom) + new /obj/item/slime_extract/grey(location) + // Liquid Carpets /datum/chemical_reaction/carpet diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index 1d06aaacde..efa92ef7d6 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -280,6 +280,7 @@ /datum/chemical_reaction/smoke_powder name = "smoke_powder" id = /datum/reagent/smoke_powder + priority = CHEMICAL_REACTION_PRIORITY_SMOKE results = list(/datum/reagent/smoke_powder = 3) required_reagents = list(/datum/reagent/potassium = 1, /datum/reagent/consumable/sugar = 1, /datum/reagent/phosphorus = 1) diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 799a6db9f5..efdd137ece 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -354,7 +354,7 @@ obj_flags |= EMAGGED return TRUE -/obj/item/hypospray/mkii/attack_hand(mob/user) +/obj/item/hypospray/mkii/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() //Don't bother changing this or removing it from containers will break. /obj/item/hypospray/mkii/attack(obj/item/I, mob/user, params) diff --git a/code/modules/reagents/reagent_containers/maunamug.dm b/code/modules/reagents/reagent_containers/maunamug.dm index 18e6cfa847..1600699226 100644 --- a/code/modules/reagents/reagent_containers/maunamug.dm +++ b/code/modules/reagents/reagent_containers/maunamug.dm @@ -88,7 +88,7 @@ user.visible_message("[user] inserts a power cell into [src].", "You insert the power cell into [src].") update_icon() -/obj/item/reagent_containers/glass/maunamug/attack_hand(mob/living/user) +/obj/item/reagent_containers/glass/maunamug/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) if(cell && open) cell.update_icon() user.put_in_hands(cell) diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index bc4e214161..0131e6d028 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -79,7 +79,7 @@ else . += "There are no paper cups left." -/obj/structure/reagent_dispensers/water_cooler/attack_hand(mob/living/user) +/obj/structure/reagent_dispensers/water_cooler/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -247,3 +247,42 @@ icon_state = "bluekeg" reagent_id = /datum/reagent/consumable/ethanol/gargle_blaster tank_volume = 100 + +//kegs given by the travelling trader's bartender subtype + +/obj/structure/reagent_dispensers/keg/quintuple_sec + name = "keg of quintuple sec" + desc = "A keg of pure justice." + icon_state = "redkeg" + reagent_id = /datum/reagent/consumable/ethanol/quintuple_sec + tank_volume = 250 + +/obj/structure/reagent_dispensers/keg/narsour + name = "keg of narsour" + desc = "A keg of eldritch terrors." + icon_state = "redkeg" + reagent_id = /datum/reagent/consumable/ethanol/narsour + tank_volume = 250 + +/obj/structure/reagent_dispensers/keg/red_queen + name = "keg of red queen" + desc = "A strange keg, filled with a kind of tea." + icon_state = "redkeg" + reagent_id = /datum/reagent/consumable/red_queen + tank_volume = 250 + +/obj/structure/reagent_dispensers/keg/hearty_punch + name = "keg of hearty punch" + desc = "A keg that will get you right back on your feet." + icon_state = "redkeg" + reagent_id = /datum/reagent/consumable/ethanol/hearty_punch + tank_volume = 100 //this usually has a 15:1 ratio when being made, so we provide less of it + +/obj/structure/reagent_dispensers/keg/neurotoxin + name = "keg of neurotoxin" + desc = "A keg of the sickly substance known as 'neurotoxin'." + icon_state = "bluekeg" + reagent_id = /datum/reagent/consumable/ethanol/neurotoxin + tank_volume = 100 //2.5x less than the other kegs because it's harder to get + + diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm index cadd9ba04f..d8cb462c97 100644 --- a/code/modules/recycling/conveyor2.dm +++ b/code/modules/recycling/conveyor2.dm @@ -68,7 +68,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) . = ..() /obj/machinery/conveyor/vv_edit_var(var_name, var_value) - if (var_name == "id") + if (var_name == NAMEOF(src, id)) // if "id" is varedited, update our list membership LAZYREMOVE(GLOB.conveyors_by_id[id], src) . = ..() @@ -174,7 +174,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) return ..() // attack with hand, move pulled object onto conveyor -/obj/machinery/conveyor/attack_hand(mob/user) +/obj/machinery/conveyor/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return @@ -243,7 +243,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) . = ..() /obj/machinery/conveyor_switch/vv_edit_var(var_name, var_value) - if (var_name == "id") + if (var_name == NAMEOF(src, id)) // if "id" is varedited, update our list membership LAZYREMOVE(GLOB.conveyors_by_id[id], src) . = ..() diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index fb615563df..64fe786219 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -305,7 +305,7 @@ return ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "disposal_unit", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "DisposalUnit", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/disposal/bin/ui_data(mob/user) diff --git a/code/modules/research/bepis.dm b/code/modules/research/bepis.dm index 20ca7987d5..87aec72646 100644 --- a/code/modules/research/bepis.dm +++ b/code/modules/research/bepis.dm @@ -182,7 +182,7 @@ /obj/machinery/rnd/bepis/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "bepis", name, 500, 480, master_ui, state) + ui = new(user, src, ui_key, "Bepis", name, 500, 480, master_ui, state) ui.open() RefreshParts() diff --git a/code/modules/research/nanites/nanite_chamber_computer.dm b/code/modules/research/nanites/nanite_chamber_computer.dm index 4650af5c80..b9623b751d 100644 --- a/code/modules/research/nanites/nanite_chamber_computer.dm +++ b/code/modules/research/nanites/nanite_chamber_computer.dm @@ -3,8 +3,8 @@ desc = "Controls a connected nanite chamber. Can inoculate nanites, load programs, and analyze existing nanite swarms." var/obj/machinery/nanite_chamber/chamber var/obj/item/disk/nanite_program/disk - circuit = /obj/item/circuitboard/computer/nanite_chamber_control icon_screen = "nanite_chamber_control" + circuit = /obj/item/circuitboard/computer/nanite_chamber_control ui_x = 380 ui_y = 570 @@ -28,7 +28,7 @@ /obj/machinery/computer/nanite_chamber_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "nanite_chamber_control", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "NaniteChamberControl", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/computer/nanite_chamber_control/ui_data() diff --git a/code/modules/research/nanites/nanite_cloud_controller.dm b/code/modules/research/nanites/nanite_cloud_controller.dm index f9d4d71b01..ef0fc33bd7 100644 --- a/code/modules/research/nanites/nanite_cloud_controller.dm +++ b/code/modules/research/nanites/nanite_cloud_controller.dm @@ -56,7 +56,7 @@ /obj/machinery/computer/nanite_cloud_controller/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "nanite_cloud_control", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "NaniteCloudControl", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/computer/nanite_cloud_controller/ui_data() diff --git a/code/modules/research/nanites/nanite_program_hub.dm b/code/modules/research/nanites/nanite_program_hub.dm index 47ee2447d2..3f62a11f89 100644 --- a/code/modules/research/nanites/nanite_program_hub.dm +++ b/code/modules/research/nanites/nanite_program_hub.dm @@ -50,7 +50,7 @@ /obj/machinery/nanite_program_hub/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "nanite_program_hub", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "NaniteProgramHub", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/nanite_program_hub/ui_data() diff --git a/code/modules/research/nanites/nanite_programmer.dm b/code/modules/research/nanites/nanite_programmer.dm index 5315a7a507..3de2a974e2 100644 --- a/code/modules/research/nanites/nanite_programmer.dm +++ b/code/modules/research/nanites/nanite_programmer.dm @@ -37,7 +37,7 @@ /obj/machinery/nanite_programmer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "nanite_programmer", name, ui_x, ui_y, master_ui, state) + ui = new(user, src, ui_key, "NaniteProgrammer", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/nanite_programmer/ui_data() diff --git a/code/modules/research/nanites/nanite_remote.dm b/code/modules/research/nanites/nanite_remote.dm index 0d9361b534..b222b2ad35 100644 --- a/code/modules/research/nanites/nanite_remote.dm +++ b/code/modules/research/nanites/nanite_remote.dm @@ -83,7 +83,7 @@ /obj/item/nanite_remote/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "nanite_remote", name, 420, 500, master_ui, state) + ui = new(user, src, ui_key, "NaniteRemote", name, 420, 500, master_ui, state) ui.open() /obj/item/nanite_remote/ui_data() diff --git a/code/modules/research/xenobiology/crossbreeding/_clothing.dm b/code/modules/research/xenobiology/crossbreeding/_clothing.dm index 795a57b82c..996b84131f 100644 --- a/code/modules/research/xenobiology/crossbreeding/_clothing.dm +++ b/code/modules/research/xenobiology/crossbreeding/_clothing.dm @@ -57,7 +57,7 @@ Slimecrossing Armor light_color = newcolor set_light(5) -/obj/structure/light_prism/attack_hand(mob/user) +/obj/structure/light_prism/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) to_chat(user, "You dispel [src]") qdel(src) @@ -118,7 +118,7 @@ Slimecrossing Armor ..() REMOVE_TRAIT(user, TRAIT_PACIFISM, "peaceflower_[REF(src)]") -/obj/item/clothing/head/peaceflower/attack_hand(mob/user) +/obj/item/clothing/head/peaceflower/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(iscarbon(user)) var/mob/living/carbon/C = user if(src == C.head) diff --git a/code/modules/ruins/objects_and_mobs/necropolis_gate.dm b/code/modules/ruins/objects_and_mobs/necropolis_gate.dm index c80b4d972c..e6f87eea13 100644 --- a/code/modules/ruins/objects_and_mobs/necropolis_gate.dm +++ b/code/modules/ruins/objects_and_mobs/necropolis_gate.dm @@ -88,7 +88,7 @@ return QDEL_HINT_LETMELIVE //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/structure/necropolis_gate/attack_hand(mob/user) +/obj/structure/necropolis_gate/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(locked || uses == 0) to_chat(user, "It's [open ? "stuck open":"locked"].") return @@ -167,7 +167,7 @@ GLOBAL_DATUM(necropolis_gate, /obj/structure/necropolis_gate/legion_gate) return QDEL_HINT_LETMELIVE //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/structure/necropolis_gate/legion_gate/attack_hand(mob/user) +/obj/structure/necropolis_gate/legion_gate/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(!open && !changing_openness) var/safety = alert(user, "You think this might be a bad idea...", "Knock on the door?", "Proceed", "Abort") if(safety == "Abort" || !in_range(src, user) || !src || open || changing_openness || user.incapacitated()) diff --git a/code/modules/ruins/objects_and_mobs/sin_ruins.dm b/code/modules/ruins/objects_and_mobs/sin_ruins.dm index 76897b5276..8a98a1939f 100644 --- a/code/modules/ruins/objects_and_mobs/sin_ruins.dm +++ b/code/modules/ruins/objects_and_mobs/sin_ruins.dm @@ -57,7 +57,7 @@ canvas rotting away and contents vanishing.
    ") qdel(src) -/obj/structure/cursed_money/attack_hand(mob/living/user) +/obj/structure/cursed_money/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/ruins/spaceruin_code/DJstation.dm b/code/modules/ruins/spaceruin_code/DJstation.dm index 29814d8c1f..ace32b694d 100644 --- a/code/modules/ruins/spaceruin_code/DJstation.dm +++ b/code/modules/ruins/spaceruin_code/DJstation.dm @@ -2,4 +2,20 @@ /obj/item/paper/fluff/ruins/djstation name = "paper - 'DJ Listening Outpost'" - info = "Welcome new owner!

    You have purchased the latest in listening equipment. The telecommunication setup we created is the best in listening to common and private radio frequencies. Here is a step by step guide to start listening in on those saucy radio channels:
    1. Equip yourself with a multitool
    2. Use the multitool on the relay.
    3. Turn it on. It has already been configured for you to listen on.
    Simple as that. Now to listen to the private channels, you'll have to configure the intercoms. They are located on the front desk. Here is a list of frequencies for you to listen on.
    • 145.9 - Common Channel
    • 144.7 - Private AI Channel
    • 135.9 - Security Channel
    • 135.7 - Engineering Channel
    • 135.5 - Medical Channel
    • 135.3 - Command Channel
    • 135.1 - Science Channel
    • 134.9 - Service Channel
    • 134.7 - Supply Channel
    • " + info = {" +**Welcome new owner!** +You have purchased the latest in listening equipment. The telecommunication setup we created is the best in listening to common and private radio frequencies. Here is a step by step guide to start listening in on those saucy radio channels: +1. Equip yourself with a multitool +2. Use the multitool on the relay. +3. Turn it on. It has already been configured for you to listen on. +Simple as that. Now to listen to the private channels, you'll have to configure the intercoms. They are located on the front desk. Here is a list of frequencies for you to listen on. +* 145.9 - Common Channel +* 144.7 - Private AI Channel +* 135.9 - Security Channel +* 135.7 - Engineering Channel +* 135.5 - Medical Channel +* 135.3 - Command Channel +* 135.1 - Science Channel +* 134.9 - Service Channel +* 134.7 - Supply Channel +"} diff --git a/code/modules/ruins/spaceruin_code/TheDerelict.dm b/code/modules/ruins/spaceruin_code/TheDerelict.dm index 58e257d587..513d16a0cb 100644 --- a/code/modules/ruins/spaceruin_code/TheDerelict.dm +++ b/code/modules/ruins/spaceruin_code/TheDerelict.dm @@ -6,14 +6,208 @@ /obj/item/paper/fluff/ruins/thederelict/syndie_mission name = "Mission Objectives" - info = "The Syndicate have cunningly disguised a Syndicate Uplink as your PDA. Simply enter the code \"678 Bravo\" into the ringtone select to unlock its hidden features.

      Objective #1. Kill the God damn AI in a fire blast that it rocks the station. Success!
      Objective #2. Escape alive. Failed." + info = "The Syndicate have cunningly disguised a Syndicate Uplink as your PDA. Simply enter the code \"678 Bravo\" into the ringtone select to unlock its hidden features.\n \n__Objective #1__. Kill the God damn AI in a fire blast that it rocks the station. __Success!__ \n \n__Objective #2__. Escape alive. __Failed.__" /obj/item/paper/fluff/ruins/thederelict/nukie_objectives name = "Objectives of a Nuclear Operative" - info = "Objective #1: Destroy the station with a nuclear device." + info = "__Objective #1__: Destroy the station with a nuclear device." /obj/item/paper/crumpled/bloody/ruins/thederelict/unfinished name = "unfinished paper scrap" desc = "Looks like someone started shakily writing a will in space common, but were interrupted by something bloody..." - info = "I, Victor Belyakov, do hereby leave my _- " + info = "__Objectives #1__: Find out what is hidden in Kosmicheskaya Stantsiya 13s Vault" + +/// Vault controller for use on the derelict/KS13. +/obj/machinery/computer/vaultcontroller + name = "vault controller" + desc = "It seems to be powering and controlling the vault locks." + icon_screen = "power" + icon_keyboard = "power_key" + light_color = LIGHT_COLOR_YELLOW + use_power = NO_POWER_USE + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + + var/obj/structure/cable/attached_cable + var/obj/machinery/door/airlock/vault/derelict/door1 + var/obj/machinery/door/airlock/vault/derelict/door2 + var/locked = TRUE + var/siphoned_power = 0 + var/siphon_max = 1e7 + + ui_x = 300 + ui_y = 120 + + +/obj/machinery/computer/monitor/examine(mob/user) + . = ..() + . += "It appears to be powered via a cable connector." + + +//Checks for cable connection, charges if possible. +/obj/machinery/computer/vaultcontroller/process() + if(siphoned_power >= siphon_max) + return + update_cable() + if(attached_cable) + attempt_siphon() + + +///Looks for a cable connection beneath the machine. +/obj/machinery/computer/vaultcontroller/proc/update_cable() + var/turf/T = get_turf(src) + attached_cable = locate(/obj/structure/cable) in T + + +///Initializes airlock links. +/obj/machinery/computer/vaultcontroller/proc/find_airlocks() + for(var/obj/machinery/door/airlock/A in GLOB.airlocks) + if(A.id_tag == "derelictvault") + if(!door1) + door1 = A + continue + if(door1 && !door2) + door2 = A + break + + +///Tries to charge from powernet excess, no upper limit except max charge. +/obj/machinery/computer/vaultcontroller/proc/attempt_siphon() + var/surpluspower = clamp(attached_cable.surplus(), 0, (siphon_max - siphoned_power)) + if(surpluspower) + attached_cable.add_load(surpluspower) + siphoned_power += surpluspower + + +///Handles the doors closing +/obj/machinery/computer/vaultcontroller/proc/cycle_close(obj/machinery/door/airlock/A) + A.safe = FALSE //Make sure its forced closed, always + A.unbolt() + A.close() + A.bolt() + + +///Handles the doors opening +/obj/machinery/computer/vaultcontroller/proc/cycle_open(obj/machinery/door/airlock/A) + A.unbolt() + A.open() + A.bolt() + + +///Attempts to lock the vault doors +/obj/machinery/computer/vaultcontroller/proc/lock_vault() + if(door1 && !door1.density) + cycle_close(door1) + if(door2 && !door2.density) + cycle_close(door2) + if(door1.density && door1.locked && door2.density && door2.locked) + locked = TRUE + + +///Attempts to unlock the vault doors +/obj/machinery/computer/vaultcontroller/proc/unlock_vault() + if(door1 && door1.density) + cycle_open(door1) + if(door2 && door2.density) + cycle_open(door2) + if(!door1.density && door1.locked && !door2.density && door2.locked) + locked = FALSE + + +///Attempts to lock/unlock vault doors, if machine is charged. +/obj/machinery/computer/vaultcontroller/proc/activate_lock() + if(siphoned_power < siphon_max) + return + if(!door1 || !door2) + find_airlocks() + if(locked) + unlock_vault() + else + lock_vault() + + +/obj/machinery/computer/vaultcontroller/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "VaultController", name, ui_x, ui_y, master_ui, state) + ui.open() + + +/obj/machinery/computer/vaultcontroller/ui_act(action, params) + if(..()) + return + switch(action) + if("togglelock") + activate_lock() + + +/obj/machinery/computer/vaultcontroller/ui_data() + var/list/data = list() + data["stored"] = siphoned_power + data["max"] = siphon_max + data["doorstatus"] = locked + return data + + +///Airlock that can't be deconstructed, broken or hacked. +/obj/machinery/door/airlock/vault/derelict + locked = TRUE + move_resist = INFINITY + use_power = NO_POWER_USE + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + id_tag = "derelictvault" + + +///Overrides screwdriver attack to prevent all deconstruction and hacking. +/obj/machinery/door/airlock/vault/derelict/attackby(obj/item/C, mob/user, params) + if(C.tool_behaviour == TOOL_SCREWDRIVER) + return + ..() + + +// So drones can teach borgs and AI dronespeak. For best effect, combine with mother drone lawset. + +/obj/item/dronespeak_manual + name = "dronespeak manual" + desc = "The book's cover reads: \"Understanding Dronespeak - An exercise in futility.\"" + icon = 'icons/obj/library.dmi' + icon_state = "book2" + +/obj/item/dronespeak_manual/attack_self(mob/living/user) + ..() + if(isdrone(user) || issilicon(user)) + if(user.has_language(/datum/language/drone)) + to_chat(user, "You start skimming through [src], but you already know dronespeak.") + else + to_chat(user, "You start skimming through [src], and suddenly the drone chittering makes sense.") + user.grant_language(/datum/language/drone, TRUE, TRUE) + return + + if(user.has_language(/datum/language/drone)) + to_chat(user, "You start skimming through [src], but you already know dronespeak.") + else + to_chat(user, "You start skimming through [src], but you can't make any sense of the contents.") + +/obj/item/dronespeak_manual/attack(mob/living/M, mob/living/user) + if(!istype(M) || !istype(user)) + return + if(M == user) + attack_self(user) + return + + playsound(loc, "punch", 25, TRUE, -1) + if(isdrone(M) || issilicon(M)) + if(M.has_language(/datum/language/drone)) + M.visible_message("[user] beats [M] over the head with [src]!", "[user] beats you over the head with [src]!", "You hear smacking.") + else + M.visible_message("[user] teaches [M] by beating [M.p_them()] over the head with [src]!", "As [user] hits you with [src], chitters resonate in your mind.", "You hear smacking.") + M.grant_language(/datum/language/drone, TRUE, TRUE) + return + +/obj/structure/fluff/oldturret + name = "broken turret" + desc = "An obsolete model of turret, long non-functional." + icon = 'icons/obj/turrets.dmi' + icon_state = "turretCover" + density = TRUE diff --git a/code/modules/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/ruins/spaceruin_code/hilbertshotel.dm index ec5e98b2e6..b74b32009f 100644 --- a/code/modules/ruins/spaceruin_code/hilbertshotel.dm +++ b/code/modules/ruins/spaceruin_code/hilbertshotel.dm @@ -263,7 +263,7 @@ GLOBAL_VAR_INIT(hhmysteryRoomNumber, 1337) /turf/closed/indestructible/hoteldoor/attack_tk(mob/user) return //need to be close. -/turf/closed/indestructible/hoteldoor/attack_hand(mob/user) +/turf/closed/indestructible/hoteldoor/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) promptExit(user) /turf/closed/indestructible/hoteldoor/attack_animal(mob/user) @@ -474,29 +474,29 @@ GLOBAL_VAR_INIT(hhmysteryRoomNumber, 1337) /obj/item/paper/crumpled/docslogs/Initialize() . = ..() GLOB.hhmysteryRoomNumber = rand(1, SHORT_REAL_LIMIT) - info = {"

      Research Logs

      - I might just be onto something here!
      - The strange space-warping properties of bluespace have been known about for awhile now, but I might be on the verge of discovering a new way of harnessing it.
      - It's too soon to say for sure, but this might be the start of something quite important!
      - I'll be sure to log any major future breakthroughs. This might be a lot more than I can manage on my own, perhaps I should hire that secretary after all...
      -

      Breakthrough!

      - I can't believe it, but I did it! Just when I was certain it couldn't be done, I made the final necessary breakthrough.
      - Exploiting the effects of space dilation caused by specific bluespace structures combined with a precise use of geometric calculus, I've discovered a way to correlate an infinite amount of space within a finite area!
      - While the potential applications are endless, I utilized it in quite a nifty way so far by designing a system that recursively constructs subspace rooms and spatially links them to any of the infinite infinitesimally distinct points on the spheres surface.
      - I call it: Hilbert's Hotel!
      -

      Goodbye

      - I can't take this anymore. I know what happens next, and the fear of what is coming leaves me unable to continue working.
      - Any fool in my field has heard the stories. It's not that I didn't believe them, it's just... I guess I underestimated the importance of my own research...
      - Robert has reported a further increase in frequency of the strange, prying visitors who ask questions they have no business asking. I've requested him to keep everything on strict lockdown and have permanently dismissed all other assistants.
      - I've also instructed him to use the encryption method we discussed for any important quantitative data. The poor lad... I don't think he truly understands what he's gotten himself into...
      - It's clear what happens now. One day they'll show up uninvited, and claim my research as their own, leaving me as nothing more than a bullet ridden corpse floating in space.
      - I can't stick around to the let that happen.
      - I'm escaping into the very thing that brought all this trouble to my doorstep in the first place - my hotel.
      - I'll be in [uppertext(num2hex(GLOB.hhmysteryRoomNumber, 0))] (That will make sense to anyone who should know)
      - I'm sorry that I must go like this. Maybe one day things will be different and it will be safe to return... maybe...
      - Goodbye
      -
      - Doctor Hilbert"} + info = {" +### Research Logs +I might just be onto something here! +The strange space-warping properties of bluespace have been known about for awhile now, but I might be on the verge of discovering a new way of harnessing it. +It's too soon to say for sure, but this might be the start of something quite important! +I'll be sure to log any major future breakthroughs. This might be a lot more than I can manage on my own, perhaps I should hire that secretary after all... +### Breakthrough! +I can't believe it, but I did it! Just when I was certain it couldn't be done, I made the final necessary breakthrough. +Exploiting the effects of space dilation caused by specific bluespace structures combined with a precise use of geometric calculus, I've discovered a way to correlate an infinite amount of space within a finite area! +While the potential applications are endless, I utilized it in quite a nifty way so far by designing a system that recursively constructs subspace rooms and spatially links them to any of the infinite infinitesimally distinct points on the spheres surface. +I call it: Hilbert's Hotel! +

      Goodbye

      +I can't take this anymore. I know what happens next, and the fear of what is coming leaves me unable to continue working. +Any fool in my field has heard the stories. It's not that I didn't believe them, it's just... I guess I underestimated the importance of my own research... +Robert has reported a further increase in frequency of the strange, prying visitors who ask questions they have no business asking. I've requested him to keep everything on strict lockdown and have permanently dismissed all other assistants. +I've also instructed him to use the encryption method we discussed for any important quantitative data. The poor lad... I don't think he truly understands what he's gotten himself into... +It's clear what happens now. One day they'll show up uninvited, and claim my research as their own, leaving me as nothing more than a bullet ridden corpse floating in space. +I can't stick around to the let that happen. +I'm escaping into the very thing that brought all this trouble to my doorstep in the first place - my hotel. +I'll be in [uppertext(num2hex(GLOB.hhmysteryRoomNumber, 0))] (That will make sense to anyone who should know) +I'm sorry that I must go like this. Maybe one day things will be different and it will be safe to return... maybe... +Goodbye + _Doctor Hilbert_"} /obj/item/paper/crumpled/robertsworkjournal name = "Work Journal" @@ -526,16 +526,15 @@ GLOBAL_VAR_INIT(hhmysteryRoomNumber, 1337) /obj/item/paper/crumpled/bloody/docsdeathnote name = "note" - info = {"This is it isn't it?
      - No one's coming to help, that much has become clear.
      - Sure, it's lonely, but do I have much choice? At least I brought the analyzer with me, they shouldn't be able to find me without it.
      - Who knows who's waiting for me out there. Its either die out there in their hands, or die a slower, slightly more comfortable death in here.
      - Everyday I can feel myself slipping away more and more, both physically and mentally. Who knows what happens now...
      - Heh, so it's true then, this must be the inescapable path of all great minds... so be it then.
      -
      -
      -
      - Choose a room, and enter the sphere
      - Lay your head to rest, it soon becomes clear
      - There's always more room around every bend
      - Not all that's countable has an end..."} + info = {" +This is it isn't it? +No one's coming to help, that much has become clear. +Sure, it's lonely, but do I have much choice? At least I brought the analyzer with me, they shouldn't be able to find me without it. +Who knows who's waiting for me out there. Its either die out there in their hands, or die a slower, slightly more comfortable death in here. +Everyday I can feel myself slipping away more and more, both physically and mentally. Who knows what happens now... +Heh, so it's true then, this must be the inescapable path of all great minds... so be it then. +_Choose a room, and enter the sphere +Lay your head to rest, it soon becomes clear +There's always more room around every bend +Not all that's countable has an end..._ +"} diff --git a/code/modules/ruins/spaceruin_code/oldstation.dm b/code/modules/ruins/spaceruin_code/oldstation.dm index e72dbea044..90de7040f4 100644 --- a/code/modules/ruins/spaceruin_code/oldstation.dm +++ b/code/modules/ruins/spaceruin_code/oldstation.dm @@ -38,8 +38,15 @@ /obj/item/paper/fluff/ruins/oldstation/protoinv name = "Laboratory Inventory" - info = "*Inventory*

      (1) Prototype Hardsuit

      (1)Health Analyser

      (1)Prototype Energy Gun

      (1)Singularity Generation Disk

      DO NOT REMOVE WITHOUT \ - THE CAPTAIN AND RESEARCH DIRECTOR'S AUTHORISATION" + info = {" +**Inventory** +* (1) Prototype Hardsuit +* (1)Health Analyser +* (1)Prototype Energy Gun +* (1)Singularity Generation Disk +__DO NOT REMOVE WITHOUT HE CAPTAIN AND RESEARCH DIRECTOR'S AUTHORISATION__ +"} + /obj/item/paper/fluff/ruins/oldstation/report name = "Crew Reawakening Report" diff --git a/code/modules/ruins/spaceruin_code/originalcontent.dm b/code/modules/ruins/spaceruin_code/originalcontent.dm index 5da28af26d..62d9170c2f 100644 --- a/code/modules/ruins/spaceruin_code/originalcontent.dm +++ b/code/modules/ruins/spaceruin_code/originalcontent.dm @@ -1,28 +1,28 @@ /////////// originalcontent items /obj/item/paper/crumpled/ruins/originalcontent - desc = "Various scrawled out drawings and sketches reside on the paper, apparently he didn't much care for these drawings." + desc = "_Various scrawled out drawings and sketches reside on the paper, apparently he didn't much care for these drawings._" /obj/item/paper/pamphlet/ruin/originalcontent icon = 'icons/obj/fluff.dmi' /obj/item/paper/pamphlet/ruin/originalcontent/stickman name = "Painting - 'BANG'" - info = "This picture depicts a crudely-drawn stickman firing a crudely-drawn gun." + info = "_This picture depicts a crudely-drawn stickman firing a crudely-drawn gun._" icon_state = "painting4" /obj/item/paper/pamphlet/ruin/originalcontent/treeside name = "Painting - 'Treeside'" - info = "This picture depicts a sunny day on a lush hillside, set under a shaded tree." + info = "_This picture depicts a sunny day on a lush hillside, set under a shaded tree._" icon_state = "painting1" /obj/item/paper/pamphlet/ruin/originalcontent/pennywise name = "Painting - 'Pennywise'" - info = "This picture depicts a smiling clown. Something doesn't feel right about this.." + info = "_This picture depicts a smiling clown. Something doesn't feel right about this.._" icon_state = "painting3" /obj/item/paper/pamphlet/ruin/originalcontent/yelling name = "Painting - 'Hands-On-Face'" - info = "This picture depicts a man yelling on a bridge for no apparent reason." + info = "_This picture depicts a man yelling on a bridge for no apparent reason._" icon_state = "painting2" diff --git a/code/modules/ruins/spaceruin_code/spacehotel.dm b/code/modules/ruins/spaceruin_code/spacehotel.dm index 69eebd8535..caea851783 100644 --- a/code/modules/ruins/spaceruin_code/spacehotel.dm +++ b/code/modules/ruins/spaceruin_code/spacehotel.dm @@ -3,10 +3,9 @@ /obj/item/paper/fluff/ruins/spacehotel/notice name = "!NOTICE!" - info = "!NOTICE!

      We are expecting arriving guests soon from a nearby station! Stay sharp and make sure guests enjoy their time spent here. Don't think you can sneak off while they're here, either.
      " + info = "__!NOTICE!__\n \nWe are expecting arriving guests soon from a nearby station! Stay sharp and make sure guests enjoy their time spent here. Don't think you can sneak off while they're here, either." /obj/item/paper/pamphlet/ruin/spacehotel name = "hotel pamphlet" - info = "
      The Twin Nexus Hotel

      A place of Sanctuary


      Welcome to The Twin-Nexus Hotel, \[insert name here]! The loyal staff stride to their best effort to cater for the best possible experience for all space(wo)men! If you have any questions or comments, please ask one of our on-board staff for more information.
      " - + info = "__The Twin Nexus Hotel__\n*A place of Sanctuary*\n \nWelcome to The Twin-Nexus Hotel, \[insert name here]! The loyal staff strive to their best effort to cater for the best possible experience for all space(wo)men! If you have any questions or comments, please ask one of our on-board staff for more information." diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm index adf53ff0da..f6418b9236 100644 --- a/code/modules/security_levels/keycard_authentication.dm +++ b/code/modules/security_levels/keycard_authentication.dm @@ -16,6 +16,9 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new) power_channel = ENVIRON req_access = list(ACCESS_KEYCARD_AUTH) resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + ui_x = 375 + ui_y = 125 + var/datum/callback/ev var/event = "" var/obj/machinery/keycard_auth/event_source @@ -36,7 +39,7 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new) datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "keycard_auth", name, 375, 125, master_ui, state) + ui = new(user, src, ui_key, "KeycardAuth", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/keycard_auth/ui_data() @@ -108,13 +111,13 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new) /obj/machinery/keycard_auth/proc/trigger_event(confirmer) log_game("[key_name(triggerer)] triggered and [key_name(confirmer)] confirmed event [event]") - message_admins("[key_name(triggerer)] triggered and [key_name(confirmer)] confirmed event [event]") + message_admins("[ADMIN_LOOKUPFLW(triggerer)] triggered and [ADMIN_LOOKUPFLW(confirmer)] confirmed event [event]") var/area/A1 = get_area(triggerer) - deadchat_broadcast("[triggerer] triggered [event] at [A1.name].", triggerer) + deadchat_broadcast(" triggered [event] at [A1.name].", "[triggerer]", triggerer) var/area/A2 = get_area(confirmer) - deadchat_broadcast("[confirmer] confirmed [event] at [A2.name].", confirmer) + deadchat_broadcast(" confirmed [event] at [A2.name].", "[confirmer]", confirmer) switch(event) if(KEYCARD_RED_ALERT) set_security_level(SEC_LEVEL_RED) diff --git a/code/modules/shuttle/arrivals.dm b/code/modules/shuttle/arrivals.dm index 190db2c362..8322c6cdd8 100644 --- a/code/modules/shuttle/arrivals.dm +++ b/code/modules/shuttle/arrivals.dm @@ -201,6 +201,6 @@ /obj/docking_port/mobile/arrivals/vv_edit_var(var_name, var_value) switch(var_name) - if("perma_docked") + if(NAMEOF(src, perma_docked)) SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("arrivals shuttle", "[var_value ? "stopped" : "started"]")) return ..() diff --git a/code/modules/shuttle/computer.dm b/code/modules/shuttle/computer.dm index 75bf55a5a3..682a7fa14b 100644 --- a/code/modules/shuttle/computer.dm +++ b/code/modules/shuttle/computer.dm @@ -57,6 +57,7 @@ switch(SSshuttle.moveShuttle(shuttleId, href_list["move"], 1)) if(0) say("Shuttle departing. Please stand away from the doors.") + log_shuttle("[key_name(usr)] has sent shuttle \"[M]\" towards \"[href_list["move"]]\", using [src].") if(1) to_chat(usr, "Invalid shuttle requested.") else @@ -73,4 +74,4 @@ /obj/machinery/computer/shuttle/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) if(port && (shuttleId == initial(shuttleId) || override)) - shuttleId = port.id \ No newline at end of file + shuttleId = port.id diff --git a/code/modules/shuttle/custom_shuttle.dm b/code/modules/shuttle/custom_shuttle.dm index 6e06e3fefe..6ff15c628e 100644 --- a/code/modules/shuttle/custom_shuttle.dm +++ b/code/modules/shuttle/custom_shuttle.dm @@ -257,7 +257,7 @@ return ..() -/obj/machinery/computer/camera_advanced/shuttle_docker/custom/attack_hand(mob/user) +/obj/machinery/computer/camera_advanced/shuttle_docker/custom/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(!shuttleId) to_chat(user, "You must link the console to a shuttle first.") return diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index 358fc5ad50..637d9ae334 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -49,8 +49,7 @@ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "emergency_shuttle_console", name, - 400, 350, master_ui, state) + ui = new(user, src, ui_key, "EmergencyShuttleConsole", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/computer/emergency_shuttle/ui_data() @@ -145,7 +144,7 @@ authorized += ID message_admins("[ADMIN_LOOKUPFLW(user)] has authorized early shuttle launch") - log_game("[key_name(user)] has authorized early shuttle launch in [COORD(src)]") + log_shuttle("[key_name(user)] has authorized early shuttle launch in [COORD(src)]") // Now check if we're on our way . = TRUE process() @@ -251,7 +250,7 @@ var/time = TIME_LEFT message_admins("[ADMIN_LOOKUPFLW(user.client)] has emagged the emergency shuttle [time] seconds before launch.") - log_game("[key_name(user)] has emagged the emergency shuttle in [COORD(src)] [time] seconds before launch.") + log_shuttle("[key_name(user)] has emagged the emergency shuttle in [COORD(src)] [time] seconds before launch.") obj_flags |= EMAGGED SSshuttle.emergency.movement_force = list("KNOCKDOWN" = 60, "THROW" = 20)//YOUR PUNY SEATBELTS can SAVE YOU NOW, MORTAL var/datum/species/S = new diff --git a/code/modules/shuttle/manipulator.dm b/code/modules/shuttle/manipulator.dm index 8f98a89c36..5f120791cb 100644 --- a/code/modules/shuttle/manipulator.dm +++ b/code/modules/shuttle/manipulator.dm @@ -11,363 +11,13 @@ density = TRUE - // UI state variables - var/datum/map_template/shuttle/selected - - var/obj/docking_port/mobile/existing_shuttle - - var/obj/docking_port/mobile/preview_shuttle - var/datum/map_template/shuttle/preview_template - -/obj/machinery/shuttle_manipulator/Initialize() - . = ..() - update_icon() - SSshuttle.manipulator = src - -/obj/machinery/shuttle_manipulator/Destroy(force) - if(!force) - . = QDEL_HINT_LETMELIVE - else - SSshuttle.manipulator = null - . = ..() - /obj/machinery/shuttle_manipulator/update_overlays() . = ..() var/mutable_appearance/hologram_projection = mutable_appearance(icon, "hologram_on") hologram_projection.pixel_y = 22 var/mutable_appearance/hologram_ship = mutable_appearance(icon, "hologram_whiteship") hologram_ship.pixel_y = 27 + add_overlay(hologram_projection) + add_overlay(hologram_ship) . += hologram_projection . += hologram_ship - -/obj/machinery/shuttle_manipulator/can_interact(mob/user) - // Only admins can use this, but they can use it from anywhere - return user.client && check_rights_for(user.client, R_ADMIN) - -/obj/machinery/shuttle_manipulator/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) - if(!ui) - ui = new(user, src, ui_key, "shuttle_manipulator", name, 800, 600, master_ui, state) - ui.open() - -/proc/shuttlemode2str(mode) - switch(mode) - if(SHUTTLE_IDLE) - . = "idle" - if(SHUTTLE_IGNITING) - . = "engines charging" - if(SHUTTLE_RECALL) - . = "recalled" - if(SHUTTLE_CALL) - . = "called" - if(SHUTTLE_DOCKED) - . = "docked" - if(SHUTTLE_STRANDED) - . = "stranded" - if(SHUTTLE_ESCAPE) - . = "escape" - if(SHUTTLE_ENDGAME) - . = "endgame" - if(!.) - CRASH("shuttlemode2str(): invalid mode [mode]") - - -/obj/machinery/shuttle_manipulator/ui_data(mob/user) - var/list/data = list() - data["tabs"] = list("Status", "Templates", "Modification") - - // Templates panel - data["templates"] = list() - var/list/templates = data["templates"] - data["templates_tabs"] = list() - data["selected"] = list() - - for(var/shuttle_id in SSmapping.shuttle_templates) - var/datum/map_template/shuttle/S = SSmapping.shuttle_templates[shuttle_id] - - if(!templates[S.port_id]) - data["templates_tabs"] += S.port_id - templates[S.port_id] = list( - "port_id" = S.port_id, - "templates" = list()) - - var/list/L = list() - L["name"] = S.name - L["shuttle_id"] = S.shuttle_id - L["port_id"] = S.port_id - L["description"] = S.description - L["admin_notes"] = S.admin_notes - - if(selected == S) - data["selected"] = L - - templates[S.port_id]["templates"] += list(L) - - data["templates_tabs"] = sortList(data["templates_tabs"]) - - data["existing_shuttle"] = null - - // Status panel - data["shuttles"] = list() - for(var/i in SSshuttle.mobile) - var/obj/docking_port/mobile/M = i - var/timeleft = M.timeLeft(1) - var/list/L = list() - L["name"] = M.name - L["id"] = M.id - L["timer"] = M.timer - L["timeleft"] = M.getTimerStr() - if (timeleft > 1 HOURS) - L["timeleft"] = "Infinity" - L["can_fast_travel"] = M.timer && timeleft >= 50 - L["can_fly"] = TRUE - if(istype(M, /obj/docking_port/mobile/emergency)) - L["can_fly"] = FALSE - else if(!M.destination) - L["can_fast_travel"] = FALSE - if (M.mode != SHUTTLE_IDLE) - L["mode"] = capitalize(shuttlemode2str(M.mode)) - L["status"] = M.getDbgStatusText() - if(M == existing_shuttle) - data["existing_shuttle"] = L - - data["shuttles"] += list(L) - - return data - -/obj/machinery/shuttle_manipulator/ui_act(action, params) - if(..()) - return - - var/mob/user = usr - - // Preload some common parameters - var/shuttle_id = params["shuttle_id"] - var/datum/map_template/shuttle/S = SSmapping.shuttle_templates[shuttle_id] - - switch(action) - if("select_template") - if(S) - existing_shuttle = SSshuttle.getShuttle(S.port_id) - selected = S - . = TRUE - if("jump_to") - if(params["type"] == "mobile") - for(var/i in SSshuttle.mobile) - var/obj/docking_port/mobile/M = i - if(M.id == params["id"]) - user.forceMove(get_turf(M)) - . = TRUE - break - - if("fly") - for(var/i in SSshuttle.mobile) - var/obj/docking_port/mobile/M = i - if(M.id == params["id"]) - . = TRUE - M.admin_fly_shuttle(user) - break - - if("fast_travel") - for(var/i in SSshuttle.mobile) - var/obj/docking_port/mobile/M = i - if(M.id == params["id"] && M.timer && M.timeLeft(1) >= 50) - M.setTimer(50) - . = TRUE - message_admins("[key_name_admin(usr)] fast travelled [M]") - log_admin("[key_name(usr)] fast travelled [M]") - SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[M.name]") - break - - if("preview") - if(S) - . = TRUE - unload_preview() - load_template(S) - if(preview_shuttle) - preview_template = S - user.forceMove(get_turf(preview_shuttle)) - if("load") - if(existing_shuttle == SSshuttle.backup_shuttle) - // TODO make the load button disabled - WARNING("The shuttle that the selected shuttle will replace \ - is the backup shuttle. Backup shuttle is required to be \ - intact for round sanity.") - else if(S) - . = TRUE - // If successful, returns the mobile docking port - var/obj/docking_port/mobile/mdp = action_load(S) - if(mdp) - user.forceMove(get_turf(mdp)) - message_admins("[key_name_admin(usr)] loaded [mdp] with the shuttle manipulator.") - log_admin("[key_name(usr)] loaded [mdp] with the shuttle manipulator.") - SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[mdp.name]") - - update_icon() - -/obj/machinery/shuttle_manipulator/proc/action_load(datum/map_template/shuttle/loading_template, obj/docking_port/stationary/destination_port) - // Check for an existing preview - if(preview_shuttle && (loading_template != preview_template)) - preview_shuttle.jumpToNullSpace() - preview_shuttle = null - preview_template = null - - if(!preview_shuttle) - if(load_template(loading_template)) - preview_shuttle.linkup(loading_template, destination_port) - preview_template = loading_template - - // get the existing shuttle information, if any - var/timer = 0 - var/mode = SHUTTLE_IDLE - var/obj/docking_port/stationary/D - - if(istype(destination_port)) - D = destination_port - else if(existing_shuttle) - timer = existing_shuttle.timer - mode = existing_shuttle.mode - D = existing_shuttle.get_docked() - - if(!D) - CRASH("No dock found for preview shuttle ([preview_template.name]), aborting.") - - var/result = preview_shuttle.canDock(D) - // truthy value means that it cannot dock for some reason - // but we can ignore the someone else docked error because we'll - // be moving into their place shortly - if((result != SHUTTLE_CAN_DOCK) && (result != SHUTTLE_SOMEONE_ELSE_DOCKED)) - WARNING("Template shuttle [preview_shuttle] cannot dock at [D] ([result]).") - return - - if(existing_shuttle) - existing_shuttle.jumpToNullSpace() - - var/list/force_memory = preview_shuttle.movement_force - preview_shuttle.movement_force = list("KNOCKDOWN" = 0, "THROW" = 0) - preview_shuttle.initiate_docking(D) - preview_shuttle.movement_force = force_memory - - . = preview_shuttle - - // Shuttle state involves a mode and a timer based on world.time, so - // plugging the existing shuttles old values in works fine. - preview_shuttle.timer = timer - preview_shuttle.mode = mode - - preview_shuttle.register() - - // TODO indicate to the user that success happened, rather than just - // blanking the modification tab - preview_shuttle = null - preview_template = null - existing_shuttle = null - selected = null - -/obj/machinery/shuttle_manipulator/proc/load_template(datum/map_template/shuttle/S) - . = FALSE - // load shuttle template, centred at shuttle import landmark, - var/turf/landmark_turf = get_turf(locate(/obj/effect/landmark/shuttle_import) in GLOB.landmarks_list) - S.load(landmark_turf, centered = TRUE, register = FALSE) - - var/affected = S.get_affected_turfs(landmark_turf, centered = TRUE) - - var/found = 0 - // Search the turfs for docking ports - // - We need to find the mobile docking port because that is the heart of - // the shuttle. - // - We need to check that no additional ports have slipped in from the - // template, because that causes unintended behaviour. - for(var/T in affected) - for(var/obj/docking_port/P in T) - if(istype(P, /obj/docking_port/mobile)) - found++ - if(found > 1) - qdel(P, force=TRUE) - log_world("Map warning: Shuttle Template [S.mappath] has multiple mobile docking ports.") - else - preview_shuttle = P - if(istype(P, /obj/docking_port/stationary)) - log_world("Map warning: Shuttle Template [S.mappath] has a stationary docking port.") - if(!found) - var/msg = "load_template(): Shuttle Template [S.mappath] has no mobile docking port. Aborting import." - for(var/T in affected) - var/turf/T0 = T - T0.empty() - - message_admins(msg) - WARNING(msg) - return - //Everything fine - S.on_bought() - return TRUE - -/obj/machinery/shuttle_manipulator/proc/unload_preview() - if(preview_shuttle) - preview_shuttle.jumpToNullSpace() - preview_shuttle = null - -/obj/docking_port/mobile/proc/admin_fly_shuttle(mob/user) - var/list/options = list() - - for(var/port in SSshuttle.stationary) - if (istype(port, /obj/docking_port/stationary/transit)) - continue // please don't do this - var/obj/docking_port/stationary/S = port - if (canDock(S) == SHUTTLE_CAN_DOCK) - options[S.name || S.id] = S - - options += "--------" - options += "Infinite Transit" - options += "Delete Shuttle" - options += "Into The Sunset (delete & greentext 'escape')" - - var/selection = input(user, "Select where to fly [name || id]:", "Fly Shuttle") as null|anything in options - if(!selection) - return - - switch(selection) - if("Infinite Transit") - destination = null - mode = SHUTTLE_IGNITING - setTimer(ignitionTime) - - if("Delete Shuttle") - if(alert(user, "Really delete [name || id]?", "Delete Shuttle", "Cancel", "Really!") != "Really!") - return - jumpToNullSpace() - - if("Into The Sunset (delete & greentext 'escape')") - if(alert(user, "Really delete [name || id] and greentext escape objectives?", "Delete Shuttle", "Cancel", "Really!") != "Really!") - return - intoTheSunset() - - else - if(options[selection]) - request(options[selection]) - -/obj/docking_port/mobile/emergency/admin_fly_shuttle(mob/user) - return // use the existing verbs for this - -/obj/docking_port/mobile/arrivals/admin_fly_shuttle(mob/user) - switch(alert(user, "Would you like to fly the arrivals shuttle once or change its destination?", "Fly Shuttle", "Fly", "Retarget", "Cancel")) - if("Cancel") - return - if("Fly") - return ..() - - var/list/options = list() - - for(var/port in SSshuttle.stationary) - if (istype(port, /obj/docking_port/stationary/transit)) - continue // please don't do this - var/obj/docking_port/stationary/S = port - if (canDock(S) == SHUTTLE_CAN_DOCK) - options[S.name || S.id] = S - - var/selection = input(user, "Select the new arrivals destination:", "Fly Shuttle") as null|anything in options - if(!selection) - return - target_dock = options[selection] - if(!QDELETED(target_dock)) - destination = target_dock diff --git a/code/modules/shuttle/navigation_computer.dm b/code/modules/shuttle/navigation_computer.dm index 4f53e5d9d0..0cf348a95b 100644 --- a/code/modules/shuttle/navigation_computer.dm +++ b/code/modules/shuttle/navigation_computer.dm @@ -29,7 +29,7 @@ . = ..() GLOB.navigation_computers -= src -/obj/machinery/computer/camera_advanced/shuttle_docker/attack_hand(mob/user) +/obj/machinery/computer/camera_advanced/shuttle_docker/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(jammed) to_chat(user, "The Syndicate is jamming the console!") return diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index bce2da74e4..d7a6d4a583 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -216,10 +216,10 @@ roundstart_template = SSmapping.shuttle_templates[sid] if(!roundstart_template) - CRASH("Invalid path ([roundstart_template]) passed to docking port.") + CRASH("Invalid path ([sid]/[roundstart_template]) passed to docking port.") if(roundstart_template) - SSshuttle.manipulator.action_load(roundstart_template, src) + SSshuttle.action_load(roundstart_template, src) //returns first-found touching shuttleport /obj/docking_port/stationary/get_docked() diff --git a/code/modules/shuttle/shuttle_creation/shuttle_creator_console.dm b/code/modules/shuttle/shuttle_creation/shuttle_creator_console.dm index f5ddf12182..9af6d7fe9f 100644 --- a/code/modules/shuttle/shuttle_creation/shuttle_creator_console.dm +++ b/code/modules/shuttle/shuttle_creation/shuttle_creator_console.dm @@ -61,7 +61,7 @@ if(user?.client) user.client.images -= eyeobj.user_image -/obj/machinery/computer/camera_advanced/shuttle_creator/attack_hand(mob/user) +/obj/machinery/computer/camera_advanced/shuttle_creator/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(!is_operational()) //you cant use broken machine you chumbis return if(current_user) diff --git a/code/modules/spells/spell_types/lichdom.dm b/code/modules/spells/spell_types/lichdom.dm index f6f56c049a..11518b236f 100644 --- a/code/modules/spells/spell_types/lichdom.dm +++ b/code/modules/spells/spell_types/lichdom.dm @@ -132,7 +132,7 @@ lich.real_name = mind.name mind.transfer_to(lich) mind.grab_ghost(force=TRUE) - lich.hardset_dna(null,null,lich.real_name,null, new /datum/species/skeleton/space) + lich.hardset_dna(null,null,null,lich.real_name,null, new /datum/species/skeleton) to_chat(lich, "Your bones clatter and shudder as you are pulled back into this world!") var/turf/body_turf = get_turf(old_body) lich.DefaultCombatKnockdown(200 + 200*resurrections) diff --git a/code/modules/spells/spell_types/spacetime_distortion.dm b/code/modules/spells/spell_types/spacetime_distortion.dm index 3af4d3883f..bec0f7871a 100644 --- a/code/modules/spells/spell_types/spacetime_distortion.dm +++ b/code/modules/spells/spell_types/spacetime_distortion.dm @@ -111,7 +111,7 @@ walk_link(user) //ATTACK HAND IGNORING PARENT RETURN VALUE -/obj/effect/cross_action/spacetime_dist/attack_hand(mob/user) +/obj/effect/cross_action/spacetime_dist/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) walk_link(user) /obj/effect/cross_action/spacetime_dist/attack_paw(mob/user) diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm index 183462a8f7..2ca0e65477 100644 --- a/code/modules/station_goals/bsa.dm +++ b/code/modules/station_goals/bsa.dm @@ -223,7 +223,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "bsa", name, 400, 220, master_ui, state) + ui = new(user, src, ui_key, "BluespaceArtillery", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/computer/bsa_control/ui_data() diff --git a/code/modules/station_goals/dna_vault.dm b/code/modules/station_goals/dna_vault.dm index 64a1de8857..6d8ab9cc7f 100644 --- a/code/modules/station_goals/dna_vault.dm +++ b/code/modules/station_goals/dna_vault.dm @@ -178,7 +178,7 @@ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) roll_powers(user) - ui = new(user, src, ui_key, "dna_vault", name, 350, 400, master_ui, state) + ui = new(user, src, ui_key, "DnaVault", name, ui_x, ui_y, master_ui, state) ui.open() diff --git a/code/modules/station_goals/shield.dm b/code/modules/station_goals/shield.dm index cf0d79c742..299fda4a26 100644 --- a/code/modules/station_goals/shield.dm +++ b/code/modules/station_goals/shield.dm @@ -45,7 +45,7 @@ /obj/machinery/computer/sat_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "sat_control", name, 400, 305, master_ui, state) + ui = new(user, src, ui_key, "SatelliteControl", name, ui_x, ui_y, master_ui, state) ui.open() /obj/machinery/computer/sat_control/ui_act(action, params) diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index 65e53df26f..fa49e3eff5 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -254,7 +254,6 @@ var/static/regex/clap_words = regex("clap|applaud") var/static/regex/honk_words = regex("ho+nk") //hooooooonk var/static/regex/multispin_words = regex("like a record baby|right round") - var/static/regex/orgasm_words = regex("cum|orgasm|climax|squirt|heyo") //CITADEL CHANGE var/static/regex/dab_words = regex("dab|mood") //CITADEL CHANGE var/static/regex/snap_words = regex("snap") //CITADEL CHANGE var/static/regex/bwoink_words = regex("what the fuck are you doing|bwoink|hey you got a moment?") //CITADEL CHANGE @@ -572,16 +571,6 @@ var/mob/living/L = V L.SpinAnimation(speed = 10, loops = 5) - //CITADEL CHANGES - //ORGASM - else if((findtext(message, orgasm_words))) - cooldown = COOLDOWN_MEME - for(var/V in listeners) - var/mob/living/carbon/human/H = V - - if(H.client && H.client.prefs && H.client.prefs.cit_toggles & HYPNO) // probably a redundant check but for good measure - H.mob_climax(forced_climax=TRUE) - //DAB else if((findtext(message, dab_words))) cooldown = COOLDOWN_DAMAGE @@ -765,7 +754,6 @@ var/static/regex/forget_words = regex("forget|muddled|awake and forget") var/static/regex/attract_words = regex("come here|come to me|get over here|attract") //phase 2 - var/static/regex/orgasm_words = regex("cum|orgasm|climax|squirt|heyo") //wah, lewd var/static/regex/awoo_words = regex("howl|awoo|bark") var/static/regex/nya_words = regex("nya|meow|mewl") var/static/regex/sleep_words = regex("sleep|slumber|rest") @@ -1092,28 +1080,6 @@ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You are drawn towards [user]!"), 5) to_chat(user, "You draw [L] towards you!") - - //teir 2 - - /* removed for now - //ORGASM - else if((findtext(message, orgasm_words))) - for(var/V in listeners) - var/mob/living/carbon/human/H = V - var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) - if(E.phase > 1) - if(E.lewd) // probably a redundant check but for good measure - addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "Your [E.enthrallGender] pushes you over the limit, overwhelming your body with pleasure."), 5) - H.mob_climax(forced_climax=TRUE) - H.SetStun(20) - E.resistanceTally = 0 //makes resistance 0, but resets arousal, resistance buildup is faster unaroused (massively so). - E.enthrallTally += power_multiplier - E.cooldown += 6 - else - H.throw_at(get_step_towards(user,H), 3 * power_multiplier, 1 * power_multiplier) - */ - - //awoo else if((findtext(message, awoo_words))) for(var/V in listeners) diff --git a/code/modules/tgui/external.dm b/code/modules/tgui/external.dm index 38a5a27e0c..5de54c439c 100644 --- a/code/modules/tgui/external.dm +++ b/code/modules/tgui/external.dm @@ -1,133 +1,142 @@ - /** - * tgui external - * - * Contains all external tgui declarations. - **/ +/** + * tgui external + * + * Contains all external tgui declarations. + */ - /** - * public - * - * Used to open and update UIs. - * If this proc is not implemented properly, the UI will not update correctly. - * - * required user mob The mob who opened/is using the UI. - * optional ui_key string The ui_key of the UI. - * optional ui datum/tgui The UI to be updated, if it exists. - * optional force_open bool If the UI should be re-opened instead of updated. - * optional master_ui datum/tgui The parent UI. - * optional state datum/ui_state The state used to determine status. - **/ +/** + * public + * + * Used to open and update UIs. + * If this proc is not implemented properly, the UI will not update correctly. + * + * required user mob The mob who opened/is using the UI. + * optional ui_key string The ui_key of the UI. + * optional ui datum/tgui The UI to be updated, if it exists. + * optional force_open bool If the UI should be re-opened instead of updated. + * optional master_ui datum/tgui The parent UI. + * optional state datum/ui_state The state used to determine status. + */ /datum/proc/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) return FALSE // Not implemented. - /** - * public - * - * Data to be sent to the UI. - * This must be implemented for a UI to work. - * - * required user mob The mob interacting with the UI. - * - * return list Data to be sent to the UI. - **/ +/** + * public + * + * Data to be sent to the UI. + * This must be implemented for a UI to work. + * + * required user mob The mob interacting with the UI. + * + * return list Data to be sent to the UI. + */ /datum/proc/ui_data(mob/user) return list() // Not implemented. - /** - * public - * - * Static Data to be sent to the UI. - * Static data differs from normal data in that it's large data that should be sent infrequently - * This is implemented optionally for heavy uis that would be sending a lot of redundant data - * frequently. - * Gets squished into one object on the frontend side, but the static part is cached. - * - * required user mob The mob interacting with the UI. - * - * return list Statuic Data to be sent to the UI. - **/ +/** + * public + * + * Static Data to be sent to the UI. + * Static data differs from normal data in that it's large data that should be sent infrequently + * This is implemented optionally for heavy uis that would be sending a lot of redundant data + * frequently. + * Gets squished into one object on the frontend side, but the static part is cached. + * + * required user mob The mob interacting with the UI. + * + * return list Statuic Data to be sent to the UI. + */ /datum/proc/ui_static_data(mob/user) return list() /** - * public - * - * Forces an update on static data. Should be done manually whenever something happens to change static data. - * - * required user the mob currently interacting with the ui - * optional ui ui to be updated - * optional ui_key ui key of ui to be updated - * -**/ + * public + * + * Forces an update on static data. Should be done manually whenever something happens to change static data. + * + * required user the mob currently interacting with the ui + * optional ui ui to be updated + * optional ui_key ui key of ui to be updated + */ /datum/proc/update_static_data(mob/user, datum/tgui/ui, ui_key = "main") ui = SStgui.try_update_ui(user, src, ui_key, ui) + // If there was no ui to update, there's no static data to update either. if(!ui) - return //If there was no ui to update, there's no static data to update either. + return ui.push_data(null, ui_static_data(), TRUE) - /** - * public - * - * Called on a UI when the UI receieves a href. - * Think of this as Topic(). - * - * required action string The action/button that has been invoked by the user. - * required params list A list of parameters attached to the button. - * - * return bool If the UI should be updated or not. - **/ +/** + * public + * + * Called on a UI when the UI receieves a href. + * Think of this as Topic(). + * + * required action string The action/button that has been invoked by the user. + * required params list A list of parameters attached to the button. + * + * return bool If the UI should be updated or not. + */ /datum/proc/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + // If UI is not interactive or usr calling Topic is not the UI user, bail. if(!ui || ui.status != UI_INTERACTIVE) - return 1 // If UI is not interactive or usr calling Topic is not the UI user, bail. + return 1 - /** - * public - * - * Called on an object when a tgui object is being created, allowing you to customise the html - * For example: inserting a custom stylesheet that you need in the head - * - * For this purpose, some tags are available in the html, to be parsed out with replacetext - * (customheadhtml) - Additions to the head tag - * - * required html the html base text - * - **/ +/** + * public + * + * Called on an object when a tgui object is being created, allowing you to + * customise the html + * For example: inserting a custom stylesheet that you need in the head + * + * For this purpose, some tags are available in the html, to be parsed out + ^ with replacetext + * (customheadhtml) - Additions to the head tag + * + * required html the html base text + */ /datum/proc/ui_base_html(html) return html - /** - * private - * - * The UI's host object (usually src_object). - * This allows modules/datums to have the UI attached to them, - * and be a part of another object. - **/ +/** + * private + * + * The UI's host object (usually src_object). + * This allows modules/datums to have the UI attached to them, + * and be a part of another object. + */ /datum/proc/ui_host(mob/user) return src // Default src. - /** - * global - * - * Used to track UIs for a mob. - **/ -/mob/var/list/open_uis = list() - /** - * public - * - * Called on a UI's object when the UI is closed, not to be confused with client/verb/uiclose(), which closes the ui window - * - * - **/ -/datum/proc/ui_close() +/** + * global + * + * Associative list of JSON-encoded shared states that were set by + * tgui clients. + */ +/datum/var/list/tgui_shared_states - /** - * verb - * - * Called by UIs when they are closed. - * Must be a verb so winset() can call it. - * - * required uiref ref The UI that was closed. - **/ +/** + * global + * + * Used to track UIs for a mob. + */ +/mob/var/list/open_uis = list() +/** + * public + * + * Called on a UI's object when the UI is closed, not to be confused with + * client/verb/uiclose(), which closes the ui window + */ +/datum/proc/ui_close(mob/user) + +/** + * verb + * + * Called by UIs when they are closed. + * Must be a verb so winset() can call it. + * + * required uiref ref The UI that was closed. + */ /client/verb/uiclose(ref as text) // Name the verb, and hide it from the user panel. set name = "uiclose" diff --git a/code/modules/tgui/states.dm b/code/modules/tgui/states.dm index 723e5f90ed..e626b98815 100644 --- a/code/modules/tgui/states.dm +++ b/code/modules/tgui/states.dm @@ -1,19 +1,19 @@ - /** - * tgui states - * - * Base state and helpers for states. Just does some sanity checks, implement a state for in-depth checks. - **/ +/** + * tgui states + * + * Base state and helpers for states. Just does some sanity checks, implement a state for in-depth checks. + */ - /** - * public - * - * Checks the UI state for a mob. - * - * required user mob The mob who opened/is using the UI. - * required state datum/ui_state The state to check. - * - * return UI_state The state of the UI. - **/ +/** + * public + * + * Checks the UI state for a mob. + * + * required user mob The mob who opened/is using the UI. + * required state datum/ui_state The state to check. + * + * return UI_state The state of the UI. + */ /datum/proc/ui_status(mob/user, datum/ui_state/state) var/src_object = ui_host(user) . = UI_CLOSE @@ -34,27 +34,27 @@ var/result = state.can_use_topic(src_object, user) . = max(., result) - /** - * private - * - * Checks if a user can use src_object's UI, and returns the state. - * Can call a mob proc, which allows overrides for each mob. - * - * required src_object datum The object/datum which owns the UI. - * required user mob The mob who opened/is using the UI. - * - * return UI_state The state of the UI. - **/ +/** + * private + * + * Checks if a user can use src_object's UI, and returns the state. + * Can call a mob proc, which allows overrides for each mob. + * + * required src_object datum The object/datum which owns the UI. + * required user mob The mob who opened/is using the UI. + * + * return UI_state The state of the UI. + */ /datum/ui_state/proc/can_use_topic(src_object, mob/user) return UI_CLOSE // Don't allow interaction by default. - /** - * public - * - * Standard interaction/sanity checks. Different mob types may have overrides. - * - * return UI_state The state of the UI. - **/ +/** + * public + * + * Standard interaction/sanity checks. Different mob types may have overrides. + * + * return UI_state The state of the UI. + */ /mob/proc/shared_ui_interaction(src_object) if(!client) // Close UIs if mindless. return UI_CLOSE @@ -75,31 +75,31 @@ return ..() /** - * public - * - * Check the distance for a living mob. - * Really only used for checks outside the context of a mob. - * Otherwise, use shared_living_ui_distance(). - * - * required src_object The object which owns the UI. - * required user mob The mob who opened/is using the UI. - * - * return UI_state The state of the UI. - **/ + * public + * + * Check the distance for a living mob. + * Really only used for checks outside the context of a mob. + * Otherwise, use shared_living_ui_distance(). + * + * required src_object The object which owns the UI. + * required user mob The mob who opened/is using the UI. + * + * return UI_state The state of the UI. + */ /atom/proc/contents_ui_distance(src_object, mob/living/user) return user.shared_living_ui_distance(src_object) // Just call this mob's check. - /** - * public - * - * Distance versus interaction check. - * - * required src_object atom/movable The object which owns the UI. - * - * return UI_state The state of the UI. - **/ -/mob/living/proc/shared_living_ui_distance(atom/movable/src_object) - if(!(src_object in fov_view())) // If the object is obscured, close it. +/** + * public + * + * Distance versus interaction check. + * + * required src_object atom/movable The object which owns the UI. + * + * return UI_state The state of the UI. + */ +/mob/living/proc/shared_living_ui_distance(atom/movable/src_object, viewcheck = TRUE) + if(viewcheck && !(src_object in view(src))) // If the object is obscured, close it. return UI_CLOSE var/dist = get_dist(src_object, src) @@ -111,7 +111,7 @@ return UI_DISABLED return UI_CLOSE // Otherwise, we got nothing. -/mob/living/carbon/human/shared_living_ui_distance(atom/movable/src_object) +/mob/living/carbon/human/shared_living_ui_distance(atom/movable/src_object, viewcheck = TRUE) if(dna.check_mutation(TK) && tkMaxRangeCheck(src, src_object)) return UI_INTERACTIVE return ..() diff --git a/code/modules/tgui/states/admin.dm b/code/modules/tgui/states/admin.dm index 945a864430..61fc373118 100644 --- a/code/modules/tgui/states/admin.dm +++ b/code/modules/tgui/states/admin.dm @@ -1,8 +1,8 @@ - /** - * tgui state: admin_state - * - * Checks that the user is an admin, end-of-story. - **/ +/** + * tgui state: admin_state + * + * Checks that the user is an admin, end-of-story. + */ GLOBAL_DATUM_INIT(admin_state, /datum/ui_state/admin_state, new) diff --git a/code/modules/tgui/states/always.dm b/code/modules/tgui/states/always.dm index b6c689d5d8..a741e2e3d4 100644 --- a/code/modules/tgui/states/always.dm +++ b/code/modules/tgui/states/always.dm @@ -1,9 +1,8 @@ - - /** - * tgui state: always_state - * - * Always grants the user UI_INTERACTIVE. Period. - **/ +/** + * tgui state: always_state + * + * Always grants the user UI_INTERACTIVE. Period. + */ GLOBAL_DATUM_INIT(always_state, /datum/ui_state/always_state, new) diff --git a/code/modules/tgui/states/conscious.dm b/code/modules/tgui/states/conscious.dm index 4323c1391c..4e2793d130 100644 --- a/code/modules/tgui/states/conscious.dm +++ b/code/modules/tgui/states/conscious.dm @@ -1,8 +1,8 @@ - /** - * tgui state: conscious_state - * - * Only checks if the user is conscious. - **/ +/** + * tgui state: conscious_state + * + * Only checks if the user is conscious. + */ GLOBAL_DATUM_INIT(conscious_state, /datum/ui_state/conscious_state, new) diff --git a/code/modules/tgui/states/contained.dm b/code/modules/tgui/states/contained.dm index 7387f7e6cb..f02424d01e 100644 --- a/code/modules/tgui/states/contained.dm +++ b/code/modules/tgui/states/contained.dm @@ -1,8 +1,8 @@ - /** - * tgui state: contained_state - * - * Checks that the user is inside the src_object. - **/ +/** + * tgui state: contained_state + * + * Checks that the user is inside the src_object. + */ GLOBAL_DATUM_INIT(contained_state, /datum/ui_state/contained_state, new) diff --git a/code/modules/tgui/states/deep_inventory.dm b/code/modules/tgui/states/deep_inventory.dm index 06bdb92f3a..43758cbab1 100644 --- a/code/modules/tgui/states/deep_inventory.dm +++ b/code/modules/tgui/states/deep_inventory.dm @@ -1,8 +1,8 @@ - /** - * tgui state: deep_inventory_state - * - * Checks that the src_object is in the user's deep (backpack, box, toolbox, etc) inventory. - **/ +/** + * tgui state: deep_inventory_state + * + * Checks that the src_object is in the user's deep (backpack, box, toolbox, etc) inventory. + */ GLOBAL_DATUM_INIT(deep_inventory_state, /datum/ui_state/deep_inventory_state, new) diff --git a/code/modules/tgui/states/default.dm b/code/modules/tgui/states/default.dm index c6741f20b8..6bb159640e 100644 --- a/code/modules/tgui/states/default.dm +++ b/code/modules/tgui/states/default.dm @@ -1,8 +1,8 @@ - /** - * tgui state: default_state - * - * Checks a number of things -- mostly physical distance for humans and view for robots. - **/ +/** + * tgui state: default_state + * + * Checks a number of things -- mostly physical distance for humans and view for robots. + */ GLOBAL_DATUM_INIT(default_state, /datum/ui_state/default, new) diff --git a/code/modules/tgui/states/default_contained.dm b/code/modules/tgui/states/default_contained.dm new file mode 100644 index 0000000000..c532e9f5d1 --- /dev/null +++ b/code/modules/tgui/states/default_contained.dm @@ -0,0 +1,13 @@ +/** + * tgui state: default_contained + * + * Basically default and contained combined, allowing for both + */ + +GLOBAL_DATUM_INIT(default_contained_state, /datum/ui_state/default/contained, new) + +/datum/ui_state/default/contained/can_use_topic(atom/src_object, mob/user) + if(src_object.contains(user)) + return UI_INTERACTIVE + return ..() + \ No newline at end of file diff --git a/code/modules/tgui/states/hands.dm b/code/modules/tgui/states/hands.dm index 5da0e5d500..d73d1058ea 100644 --- a/code/modules/tgui/states/hands.dm +++ b/code/modules/tgui/states/hands.dm @@ -1,8 +1,8 @@ - /** - * tgui state: hands_state - * - * Checks that the src_object is in the user's hands. - **/ +/** + * tgui state: hands_state + * + * Checks that the src_object is in the user's hands. + */ GLOBAL_DATUM_INIT(hands_state, /datum/ui_state/hands_state, new) @@ -19,7 +19,7 @@ GLOBAL_DATUM_INIT(hands_state, /datum/ui_state/hands_state, new) return UI_INTERACTIVE return UI_CLOSE -/mob/living/silicon/robot/hands_can_use_topic(src_object) - if(activated(src_object)) +/mob/living/silicon/robot/hands_can_use_topic(obj/src_object) + if(activated(src_object) || istype(src_object.loc, /obj/item/weapon/gripper)) return UI_INTERACTIVE return UI_CLOSE diff --git a/code/modules/tgui/states/human_adjacent.dm b/code/modules/tgui/states/human_adjacent.dm index 0ab20b36ff..7aefe43e44 100644 --- a/code/modules/tgui/states/human_adjacent.dm +++ b/code/modules/tgui/states/human_adjacent.dm @@ -1,10 +1,9 @@ - - /** - * tgui state: human_adjacent_state - * - * In addition to default checks, only allows interaction for a - * human adjacent user. - **/ +/** + * tgui state: human_adjacent_state + * + * In addition to default checks, only allows interaction for a + * human adjacent user. + */ GLOBAL_DATUM_INIT(human_adjacent_state, /datum/ui_state/human_adjacent_state, new) diff --git a/code/modules/tgui/states/inventory.dm b/code/modules/tgui/states/inventory.dm index b8b1ad3b6a..43fe2cb451 100644 --- a/code/modules/tgui/states/inventory.dm +++ b/code/modules/tgui/states/inventory.dm @@ -1,8 +1,8 @@ - /** - * tgui state: inventory_state - * - * Checks that the src_object is in the user's top-level (hand, ear, pocket, belt, etc) inventory. - **/ +/** + * tgui state: inventory_state + * + * Checks that the src_object is in the user's top-level (hand, ear, pocket, belt, etc) inventory. + */ GLOBAL_DATUM_INIT(inventory_state, /datum/ui_state/inventory_state, new) diff --git a/code/modules/tgui/states/language_menu.dm b/code/modules/tgui/states/language_menu.dm index fedc4320e4..5c816c8922 100644 --- a/code/modules/tgui/states/language_menu.dm +++ b/code/modules/tgui/states/language_menu.dm @@ -1,6 +1,6 @@ - /** - * tgui state: language_menu_state - */ +/** + * tgui state: language_menu_state + */ GLOBAL_DATUM_INIT(language_menu_state, /datum/ui_state/language_menu, new) diff --git a/code/modules/tgui/states/not_incapacitated.dm b/code/modules/tgui/states/not_incapacitated.dm index 12fe266bc5..364b59424d 100644 --- a/code/modules/tgui/states/not_incapacitated.dm +++ b/code/modules/tgui/states/not_incapacitated.dm @@ -1,16 +1,16 @@ - /** - * tgui state: not_incapacitated_state - * - * Checks that the user isn't incapacitated - **/ +/** + * tgui state: not_incapacitated_state + * + * Checks that the user isn't incapacitated + */ GLOBAL_DATUM_INIT(not_incapacitated_state, /datum/ui_state/not_incapacitated_state, new) - /** - * tgui state: not_incapacitated_turf_state - * - * Checks that the user isn't incapacitated and that their loc is a turf - **/ +/** + * tgui state: not_incapacitated_turf_state + * + * Checks that the user isn't incapacitated and that their loc is a turf + */ GLOBAL_DATUM_INIT(not_incapacitated_turf_state, /datum/ui_state/not_incapacitated_state, new(no_turfs = TRUE)) diff --git a/code/modules/tgui/states/notcontained.dm b/code/modules/tgui/states/notcontained.dm index 77a7fe01b0..642c6ce95f 100644 --- a/code/modules/tgui/states/notcontained.dm +++ b/code/modules/tgui/states/notcontained.dm @@ -1,8 +1,8 @@ - /** - * tgui state: notcontained_state - * - * Checks that the user is not inside src_object, and then makes the default checks. - **/ +/** + * tgui state: notcontained_state + * + * Checks that the user is not inside src_object, and then makes the default checks. + */ GLOBAL_DATUM_INIT(notcontained_state, /datum/ui_state/notcontained_state, new) diff --git a/code/modules/tgui/states/observer.dm b/code/modules/tgui/states/observer.dm index ade0ce66bb..86ad776b13 100644 --- a/code/modules/tgui/states/observer.dm +++ b/code/modules/tgui/states/observer.dm @@ -1,8 +1,8 @@ - /** - * tgui state: observer_state - * - * Checks that the user is an observer/ghost. - **/ +/** + * tgui state: observer_state + * + * Checks that the user is an observer/ghost. + */ GLOBAL_DATUM_INIT(observer_state, /datum/ui_state/observer_state, new) diff --git a/code/modules/tgui/states/physical.dm b/code/modules/tgui/states/physical.dm index 3b13dc5b3d..88c8a291aa 100644 --- a/code/modules/tgui/states/physical.dm +++ b/code/modules/tgui/states/physical.dm @@ -1,8 +1,8 @@ - /** - * tgui state: physical_state - * - * Short-circuits the default state to only check physical distance. - */ +/** + * tgui state: physical_state + * + * Short-circuits the default state to only check physical distance. + */ GLOBAL_DATUM_INIT(physical_state, /datum/ui_state/physical, new) @@ -23,6 +23,7 @@ GLOBAL_DATUM_INIT(physical_state, /datum/ui_state/physical, new) /mob/living/silicon/ai/physical_can_use_topic(src_object) return UI_UPDATE // AIs are not physical. + /** * tgui state: physical_obscured_state * @@ -40,10 +41,10 @@ GLOBAL_DATUM_INIT(physical_obscured_state, /datum/ui_state/physical_obscured_sta return UI_CLOSE /mob/living/physical_obscured_can_use_topic(src_object) - return shared_living_ui_distance(src_object) + return shared_living_ui_distance(src_object, viewcheck = FALSE) /mob/living/silicon/physical_obscured_can_use_topic(src_object) - return max(UI_UPDATE, shared_living_ui_distance(src_object)) // Silicons can always see. + return max(UI_UPDATE, shared_living_ui_distance(src_object, viewcheck = FALSE)) // Silicons can always see. /mob/living/silicon/ai/physical_obscured_can_use_topic(src_object) - return UI_UPDATE // AIs are not physical. \ No newline at end of file + return UI_UPDATE // AIs are not physical. diff --git a/code/modules/tgui/states/self.dm b/code/modules/tgui/states/self.dm index 10849772c6..b0c9500fbc 100644 --- a/code/modules/tgui/states/self.dm +++ b/code/modules/tgui/states/self.dm @@ -1,8 +1,8 @@ - /** - * tgui state: self_state - * - * Only checks that the user and src_object are the same. - **/ +/** + * tgui state: self_state + * + * Only checks that the user and src_object are the same. + */ GLOBAL_DATUM_INIT(self_state, /datum/ui_state/self_state, new) diff --git a/code/modules/tgui/states/zlevel.dm b/code/modules/tgui/states/zlevel.dm index 6ccfd0fe7d..5e3ccfb7de 100644 --- a/code/modules/tgui/states/zlevel.dm +++ b/code/modules/tgui/states/zlevel.dm @@ -1,8 +1,8 @@ - /** - * tgui state: z_state - * - * Only checks that the Z-level of the user and src_object are the same. - **/ +/** + * tgui state: z_state + * + * Only checks that the Z-level of the user and src_object are the same. + */ GLOBAL_DATUM_INIT(z_state, /datum/ui_state/z_state, new) diff --git a/code/modules/tgui/subsystem.dm b/code/modules/tgui/subsystem.dm index 90a00fb607..cbe94e2d7f 100644 --- a/code/modules/tgui/subsystem.dm +++ b/code/modules/tgui/subsystem.dm @@ -1,22 +1,22 @@ - /** - * tgui subsystem - * - * Contains all tgui state and subsystem code. - **/ +/** + * tgui subsystem + * + * Contains all tgui state and subsystem code. + */ - /** - * public - * - * Get a open UI given a user, src_object, and ui_key and try to update it with data. - * - * required user mob The mob who opened/is using the UI. - * required src_object datum The object/datum which owns the UI. - * required ui_key string The ui_key of the UI. - * optional ui datum/tgui The UI to be updated, if it exists. - * optional force_open bool If the UI should be re-opened instead of updated. - * - * return datum/tgui The found UI. - **/ +/** + * public + * + * Get a open UI given a user, src_object, and ui_key and try to update it with data. + * + * required user mob The mob who opened/is using the UI. + * required src_object datum The object/datum which owns the UI. + * required ui_key string The ui_key of the UI. + * optional ui datum/tgui The UI to be updated, if it exists. + * optional force_open bool If the UI should be re-opened instead of updated. + * + * return datum/tgui The found UI. + */ /datum/controller/subsystem/tgui/proc/try_update_ui(mob/user, datum/src_object, ui_key, datum/tgui/ui, force_open = FALSE) if(isnull(ui)) // No UI was passed, so look for one. ui = get_open_ui(user, src_object, ui_key) @@ -31,17 +31,17 @@ else return null // We couldn't find a UI. - /** - * private - * - * Get a open UI given a user, src_object, and ui_key. - * - * required user mob The mob who opened/is using the UI. - * required src_object datum The object/datum which owns the UI. - * required ui_key string The ui_key of the UI. - * - * return datum/tgui The found UI. - **/ +/** + * private + * + * Get a open UI given a user, src_object, and ui_key. + * + * required user mob The mob who opened/is using the UI. + * required src_object datum The object/datum which owns the UI. + * required ui_key string The ui_key of the UI. + * + * return datum/tgui The found UI. + */ /datum/controller/subsystem/tgui/proc/get_open_ui(mob/user, datum/src_object, ui_key) var/src_object_key = "[REF(src_object)]" if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) @@ -55,15 +55,15 @@ return null // Couldn't find a UI! - /** - * private - * - * Update all UIs attached to src_object. - * - * required src_object datum The object/datum which owns the UIs. - * - * return int The number of UIs updated. - **/ +/** + * private + * + * Update all UIs attached to src_object. + * + * required src_object datum The object/datum which owns the UIs. + * + * return int The number of UIs updated. + */ /datum/controller/subsystem/tgui/proc/update_uis(datum/src_object) var/src_object_key = "[REF(src_object)]" if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) @@ -77,15 +77,15 @@ update_count++ // Count each UI we update. return update_count - /** - * private - * - * Close all UIs attached to src_object. - * - * required src_object datum The object/datum which owns the UIs. - * - * return int The number of UIs closed. - **/ +/** + * private + * + * Close all UIs attached to src_object. + * + * required src_object datum The object/datum which owns the UIs. + * + * return int The number of UIs closed. + */ /datum/controller/subsystem/tgui/proc/close_uis(datum/src_object) var/src_object_key = "[REF(src_object)]" if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) @@ -99,13 +99,13 @@ close_count++ // Count each UI we close. return close_count - /** - * private - * - * Close *ALL* UIs - * - * return int The number of UIs closed. - **/ +/** + * private + * + * Close *ALL* UIs + * + * return int The number of UIs closed. + */ /datum/controller/subsystem/tgui/proc/close_all_uis() var/close_count = 0 for(var/src_object_key in open_uis) @@ -116,17 +116,17 @@ close_count++ // Count each UI we close. return close_count - /** - * private - * - * Update all UIs belonging to a user. - * - * required user mob The mob who opened/is using the UI. - * optional src_object datum If provided, only update UIs belonging this src_object. - * optional ui_key string If provided, only update UIs with this UI key. - * - * return int The number of UIs updated. - **/ +/** + * private + * + * Update all UIs belonging to a user. + * + * required user mob The mob who opened/is using the UI. + * optional src_object datum If provided, only update UIs belonging this src_object. + * optional ui_key string If provided, only update UIs with this UI key. + * + * return int The number of UIs updated. + */ /datum/controller/subsystem/tgui/proc/update_user_uis(mob/user, datum/src_object = null, ui_key = null) if(isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0) return 0 // Couldn't find any UIs for this user. @@ -138,17 +138,17 @@ update_count++ // Count each UI we upadte. return update_count - /** - * private - * - * Close all UIs belonging to a user. - * - * required user mob The mob who opened/is using the UI. - * optional src_object datum If provided, only close UIs belonging this src_object. - * optional ui_key string If provided, only close UIs with this UI key. - * - * return int The number of UIs closed. - **/ +/** + * private + * + * Close all UIs belonging to a user. + * + * required user mob The mob who opened/is using the UI. + * optional src_object datum If provided, only close UIs belonging this src_object. + * optional ui_key string If provided, only close UIs with this UI key. + * + * return int The number of UIs closed. + */ /datum/controller/subsystem/tgui/proc/close_user_uis(mob/user, datum/src_object = null, ui_key = null) if(isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0) return 0 // Couldn't find any UIs for this user. @@ -160,13 +160,13 @@ close_count++ // Count each UI we close. return close_count - /** - * private - * - * Add a UI to the list of open UIs. - * - * required ui datum/tgui The UI to be added. - **/ +/** + * private + * + * Add a UI to the list of open UIs. + * + * required ui datum/tgui The UI to be added. + */ /datum/controller/subsystem/tgui/proc/on_open(datum/tgui/ui) var/src_object_key = "[REF(ui.src_object)]" if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) @@ -180,15 +180,15 @@ uis |= ui processing_uis |= ui - /** - * private - * - * Remove a UI from the list of open UIs. - * - * required ui datum/tgui The UI to be removed. - * - * return bool If the UI was removed or not. - **/ +/** + * private + * + * Remove a UI from the list of open UIs. + * + * required ui datum/tgui The UI to be removed. + * + * return bool If the UI was removed or not. + */ /datum/controller/subsystem/tgui/proc/on_close(datum/tgui/ui) var/src_object_key = "[REF(ui.src_object)]" if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) @@ -210,28 +210,28 @@ return 1 // Let the caller know we did it. - /** - * private - * - * Handle client logout, by closing all their UIs. - * - * required user mob The mob which logged out. - * - * return int The number of UIs closed. - **/ +/** + * private + * + * Handle client logout, by closing all their UIs. + * + * required user mob The mob which logged out. + * + * return int The number of UIs closed. + */ /datum/controller/subsystem/tgui/proc/on_logout(mob/user) return close_user_uis(user) - /** - * private - * - * Handle clients switching mobs, by transferring their UIs. - * - * required user source The client's original mob. - * required user target The client's new mob. - * - * return bool If the UIs were transferred. - **/ +/** + * private + * + * Handle clients switching mobs, by transferring their UIs. + * + * required user source The client's original mob. + * required user target The client's new mob. + * + * return bool If the UIs were transferred. + */ /datum/controller/subsystem/tgui/proc/on_transfer(mob/source, mob/target) if(!source || isnull(source.open_uis) || !istype(source.open_uis, /list) || open_uis.len == 0) return 0 // The old mob had no open UIs. diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm index 55fe8f0bb5..7971a940d4 100644 --- a/code/modules/tgui/tgui.dm +++ b/code/modules/tgui/tgui.dm @@ -1,12 +1,12 @@ - /** - * tgui - * - * /tg/station user interface library - **/ +/** + * tgui + * + * /tg/station user interface library + */ - /** - * tgui datum (represents a UI). - **/ +/** + * tgui datum (represents a UI). + */ /datum/tgui /// The mob who opened/is using the UI. var/mob/user @@ -22,8 +22,6 @@ var/width = 0 /// The window height var/height = 0 - /// The style to be used for this UI. - var/style = "nanotrasen" /// The interface (template) to be used for this UI. var/interface /// Update the UI every MC tick. @@ -34,6 +32,8 @@ var/list/initial_data /// The static data used to initialize the UI. var/list/initial_static_data + /// Holder for the json string, that is sent during the initial update + var/_initial_update /// The status/visibility of the UI. var/status = UI_INTERACTIVE /// Topic state used to determine status/interactability. @@ -42,34 +42,31 @@ var/datum/tgui/master_ui /// Children of this UI. var/list/datum/tgui/children = list() - var/custom_browser_id = FALSE - var/ui_screen = "home" - /** - * public - * - * Create a new UI. - * - * required user mob The mob who opened/is using the UI. - * required src_object datum The object or datum which owns the UI. - * required ui_key string The ui_key of the UI. - * required interface string The interface used to render the UI. - * optional title string The title of the UI. - * optional width int The window width. - * optional height int The window height. - * optional master_ui datum/tgui The parent UI. - * optional state datum/ui_state The state used to determine status. - * - * return datum/tgui The requested UI. - **/ -/datum/tgui/New(mob/user, datum/src_object, ui_key, interface, title, width = 0, height = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state, browser_id = null) +/** + * public + * + * Create a new UI. + * + * required user mob The mob who opened/is using the UI. + * required src_object datum The object or datum which owns the UI. + * required ui_key string The ui_key of the UI. + * required interface string The interface used to render the UI. + * optional title string The title of the UI. + * optional width int The window width. + * optional height int The window height. + * optional master_ui datum/tgui The parent UI. + * optional state datum/ui_state The state used to determine status. + * + * return datum/tgui The requested UI. + */ +/datum/tgui/New(mob/user, datum/src_object, ui_key, interface, title, width = 0, height = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) src.user = user src.src_object = src_object src.ui_key = ui_key - src.window_id = browser_id ? browser_id : "[REF(src_object)]-[ui_key]" // DO NOT replace with \ref here. src_object could potentially be tagged - src.custom_browser_id = browser_id ? TRUE : FALSE - - set_interface(interface) + // DO NOT replace with \ref here. src_object could potentially be tagged + src.window_id = "[REF(src_object)]-[ui_key]" + src.interface = interface if(title) src.title = sanitize(title) @@ -86,11 +83,11 @@ var/datum/asset/assets = get_asset_datum(/datum/asset/group/tgui) assets.send(user) - /** - * public - * - * Open this UI (and initialize it with data). - **/ +/** + * public + * + * Open this UI (and initialize it with data). + */ /datum/tgui/proc/open() if(!user.client) return // Bail if there is no client. @@ -99,18 +96,16 @@ if(status < UI_UPDATE) return // Bail if we're not supposed to open. - var/window_size - if(width && height) // If we have a width and height, use them. - window_size = "size=[width]x[height];" - else - window_size = "" - + // Build window options + var/window_options = "can_minimize=0;auto_format=0;" + // If we have a width and height, use them. + if(width && height) + window_options += "size=[width]x[height];" // Remove titlebar and resize handles for a fancy window - var/have_title_bar if(user.client.prefs.tgui_fancy) - have_title_bar = "titlebar=0;can_resize=0;" + window_options += "titlebar=0;can_resize=0;" else - have_title_bar = "titlebar=1;can_resize=1;" + window_options += "titlebar=1;can_resize=1;" // Generate page html var/html @@ -120,50 +115,54 @@ // Replace template tokens with important UI data // NOTE: Intentional \ref usage; tgui datums can't/shouldn't // be tagged, so this is an effective unwrap - html = replacetextEx(html, "\[ref]", "\ref[src]") - html = replacetextEx(html, "\[style]", style) + html = replacetextEx(html, "\[tgui:ref]", "\ref[src]") // Open the window. - user << browse(html, "window=[window_id];can_minimize=0;auto_format=0;[window_size][have_title_bar]") - if (!custom_browser_id) - // Instruct the client to signal UI when the window is closed. - // NOTE: Intentional \ref usage; tgui datums can't/shouldn't - // be tagged, so this is an effective unwrap - winset(user, window_id, "on-close=\"uiclose \ref[src]\"") + user << browse(html, "window=[window_id];[window_options]") - if(!initial_data) + // Instruct the client to signal UI when the window is closed. + // NOTE: Intentional \ref usage; tgui datums can't/shouldn't + // be tagged, so this is an effective unwrap + winset(user, window_id, "on-close=\"uiclose \ref[src]\"") + + // Pre-fetch initial state while browser is still loading in + // another thread + if(!initial_data) { initial_data = src_object.ui_data(user) - if(!initial_static_data) + } + if(!initial_static_data) { initial_static_data = src_object.ui_static_data(user) + } + _initial_update = url_encode(get_json(initial_data, initial_static_data)) SStgui.on_open(src) - /** - * public - * - * Reinitialize the UI. - * (Possibly with a new interface and/or data). - * - * optional template string The name of the new interface. - * optional data list The new initial data. - **/ +/** + * public + * + * Reinitialize the UI. + * (Possibly with a new interface and/or data). + * + * optional template string The name of the new interface. + * optional data list The new initial data. + */ /datum/tgui/proc/reinitialize(interface, list/data, list/static_data) if(interface) - set_interface(interface) // Set a new interface. + src.interface = interface if(data) initial_data = data if(static_data) initial_static_data = static_data open() - /** - * public - * - * Close the UI, and all its children. - **/ +/** + * public + * + * Close the UI, and all its children. + */ /datum/tgui/proc/close() user << browse(null, "window=[window_id]") // Close the window. - src_object.ui_close() + src_object.ui_close(user) SStgui.on_close(src) for(var/datum/tgui/child in children) // Loop through and close all children. child.close() @@ -172,67 +171,49 @@ master_ui = null qdel(src) - /** - * public - * - * Set the style for this UI. - * - * required style string The new UI style. - **/ -/datum/tgui/proc/set_style(style) - src.style = lowertext(style) - - /** - * public - * - * Set the interface (template) for this UI. - * - * required interface string The new UI interface. - **/ -/datum/tgui/proc/set_interface(interface) - src.interface = lowertext(interface) - - /** - * public - * - * Enable/disable auto-updating of the UI. - * - * required state bool Enable/disable auto-updating. - **/ +/** + * public + * + * Enable/disable auto-updating of the UI. + * + * required state bool Enable/disable auto-updating. + */ /datum/tgui/proc/set_autoupdate(state = TRUE) autoupdate = state - /** - * private - * - * Package the data to send to the UI, as JSON. - * This includes the UI data and config_data. - * - * return string The packaged JSON. - **/ +/** + * private + * + * Package the data to send to the UI, as JSON. + * This includes the UI data and config_data. + * + * return string The packaged JSON. + */ /datum/tgui/proc/get_json(list/data, list/static_data) var/list/json_data = list() json_data["config"] = list( "title" = title, "status" = status, - "screen" = ui_screen, - "style" = style, "interface" = interface, "fancy" = user.client.prefs.tgui_fancy, - "locked" = user.client.prefs.tgui_lock && !custom_browser_id, + "locked" = user.client.prefs.tgui_lock, "observer" = isobserver(user), "window" = window_id, // NOTE: Intentional \ref usage; tgui datums can't/shouldn't // be tagged, so this is an effective unwrap "ref" = "\ref[src]" ) - + if(!isnull(data)) json_data["data"] = data if(!isnull(static_data)) json_data["static_data"] = static_data + // Send shared states + if(src_object.tgui_shared_states) + json_data["shared"] = src_object.tgui_shared_states + // Generate the JSON. var/json = json_encode(json_data) // Strip #255/improper. @@ -240,13 +221,13 @@ json = replacetext(json, "\improper", "") return json - /** - * private - * - * Handle clicks from the UI. - * Call the src_object's ui_act() if status is UI_INTERACTIVE. - * If the src_object's ui_act() returns 1, update all UIs attacked to it. - **/ +/** + * private + * + * Handle clicks from the UI. + * Call the src_object's ui_act() if status is UI_INTERACTIVE. + * If the src_object's ui_act() returns 1, update all UIs attacked to it. + */ /datum/tgui/Topic(href, href_list) if(user != usr) return // Something is not right here. @@ -256,35 +237,47 @@ switch(action) if("tgui:initialize") - user << output(url_encode(get_json(initial_data, initial_static_data)), "[custom_browser_id ? window_id : "[window_id].browser"]:initialize") + user << output(_initial_update, "[window_id].browser:update") initialized = TRUE - if("tgui:view") - if(params["screen"]) - ui_screen = params["screen"] + if("tgui:setSharedState") + // Update the window state. + update_status(push = FALSE) + // Bail if UI is not interactive or usr calling Topic + // is not the UI user. + if(status != UI_INTERACTIVE) + return + var/key = params["key"] + var/value = params["value"] + if(!src_object.tgui_shared_states) + src_object.tgui_shared_states = list() + src_object.tgui_shared_states[key] = value SStgui.update_uis(src_object) + if("tgui:setFancy") + var/value = text2num(params["value"]) + user.client.prefs.tgui_fancy = value if("tgui:log") // Force window to show frills on fatal errors if(params["fatal"]) winset(user, window_id, "titlebar=1;can-resize=1;size=600x600") + log_message(params["log"]) if("tgui:link") user << link(params["url"]) - if("tgui:fancy") - user.client.prefs.tgui_fancy = TRUE - if("tgui:nofrills") - user.client.prefs.tgui_fancy = FALSE else - update_status(push = FALSE) // Update the window state. - if(src_object.ui_act(action, params, src, state)) // Call ui_act() on the src_object. - SStgui.update_uis(src_object) // Update if the object requested it. + // Update the window state. + update_status(push = FALSE) + // Call ui_act() on the src_object. + if(src_object.ui_act(action, params, src, state)) + // Update if the object requested it. + SStgui.update_uis(src_object) - /** - * private - * - * Update the UI. - * Only updates the data if update is true, otherwise only updates the status. - * - * optional force bool If the UI should be forced to update. - **/ +/** + * private + * + * Update the UI. + * Only updates the data if update is true, otherwise only updates the status. + * + * optional force bool If the UI should be forced to update. + */ /datum/tgui/process(force = FALSE) var/datum/host = src_object.ui_host(user) if(!src_object || !host || !user) // If the object or user died (or something else), abort. @@ -296,42 +289,46 @@ else update_status(push = TRUE) // Otherwise only update status. - /** - * private - * - * Push data to an already open UI. - * - * required data list The data to send. - * optional force bool If the update should be sent regardless of state. - **/ +/** + * private + * + * Push data to an already open UI. + * + * required data list The data to send. + * optional force bool If the update should be sent regardless of state. + */ /datum/tgui/proc/push_data(data, static_data, force = FALSE) - update_status(push = FALSE) // Update the window state. + // Update the window state. + update_status(push = FALSE) + // Cannot update UI if it is not set up yet. if(!initialized) - return // Cannot update UI if it is not set up yet. + return + // Cannot update UI, we have no visibility. if(status <= UI_DISABLED && !force) - return // Cannot update UI, we have no visibility. - + return // Send the new JSON to the update() Javascript function. - user << output(url_encode(get_json(data, static_data)), "[custom_browser_id ? window_id : "[window_id].browser"]:update") + user << output( + url_encode(get_json(data, static_data)), + "[window_id].browser:update") - /** - * private - * - * Updates the UI by interacting with the src_object again, which will hopefully - * call try_ui_update on it. - * - * optional force_open bool If force_open should be passed to ui_interact. - **/ +/** + * private + * + * Updates the UI by interacting with the src_object again, which will hopefully + * call try_ui_update on it. + * + * optional force_open bool If force_open should be passed to ui_interact. + */ /datum/tgui/proc/update(force_open = FALSE) src_object.ui_interact(user, ui_key, src, force_open, master_ui, state) - /** - * private - * - * Update the status/visibility of the UI for its user. - * - * optional push bool Push an update to the UI (an update is always sent for UI_DISABLED). - **/ +/** + * private + * + * Update the status/visibility of the UI for its user. + * + * optional push bool Push an update to the UI (an update is always sent for UI_DISABLED). + */ /datum/tgui/proc/update_status(push = FALSE) var/status = src_object.ui_status(user, state) if(master_ui) @@ -340,25 +337,26 @@ if(status == UI_CLOSE) close() - /** - * private - * - * Set the status/visibility of the UI. - * - * required status int The status to set (UI_CLOSE/UI_DISABLED/UI_UPDATE/UI_INTERACTIVE). - * optional push bool Push an update to the UI (an update is always sent for UI_DISABLED). - **/ +/** + * private + * + * Set the status/visibility of the UI. + * + * required status int The status to set (UI_CLOSE/UI_DISABLED/UI_UPDATE/UI_INTERACTIVE). + * optional push bool Push an update to the UI (an update is always sent for UI_DISABLED). + */ /datum/tgui/proc/set_status(status, push = FALSE) - if(src.status != status) // Only update if status has changed. + // Only update if status has changed. + if(src.status != status) if(src.status == UI_DISABLED) src.status = status if(push) update() else src.status = status - if(status == UI_DISABLED || push) // Update if the UI just because disabled, or a push is requested. + // Update if the UI just because disabled, or a push is requested. + if(status == UI_DISABLED || push) push_data(null, force = TRUE) /datum/tgui/proc/log_message(message) log_tgui("[user] ([user.ckey]) using \"[title]\":\n[message]") - diff --git a/code/modules/uplink/uplink_items/uplink_stealth.dm b/code/modules/uplink/uplink_items/uplink_stealth.dm index b4933b30ba..c60d4ef177 100644 --- a/code/modules/uplink/uplink_items/uplink_stealth.dm +++ b/code/modules/uplink/uplink_items/uplink_stealth.dm @@ -51,7 +51,7 @@ gain skin as hard as steel and swat bullets from the air, but you also refuse to use dishonorable ranged weaponry." item = /obj/item/book/granter/martial/carp cost = 17 - player_minimum = 30 + player_minimum = 20 surplus = 0 exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) @@ -61,7 +61,7 @@ and dodging all ranged weapon fire, but you will refuse to use dishonorable ranged weaponry." item = /obj/item/book/granter/martial/bass cost = 18 - player_minimum = 30 + player_minimum = 20 surplus = 0 exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) diff --git a/code/modules/vehicles/cars/car.dm b/code/modules/vehicles/cars/car.dm index d45cb8d26f..fb30e66f97 100644 --- a/code/modules/vehicles/cars/car.dm +++ b/code/modules/vehicles/cars/car.dm @@ -57,7 +57,7 @@ return FALSE return ..() -/obj/vehicle/sealed/car/attack_hand(mob/living/user) +/obj/vehicle/sealed/car/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(!(car_traits & CAN_KIDNAP)) return diff --git a/code/modules/vehicles/pimpin_ride.dm b/code/modules/vehicles/pimpin_ride.dm index ef374f5db0..547eef7af2 100644 --- a/code/modules/vehicles/pimpin_ride.dm +++ b/code/modules/vehicles/pimpin_ride.dm @@ -62,7 +62,7 @@ if(floorbuffer) . += "cart_buffer" -/obj/vehicle/ridden/janicart/attack_hand(mob/user) +/obj/vehicle/ridden/janicart/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) . = ..() if(.) return diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index 7adf0512de..fca137a87d 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -667,7 +667,7 @@ GLOBAL_LIST_EMPTY(vending_products) if(!ui) var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/vending) assets.send(user) - ui = new(user, src, ui_key, "vending", name, 450, 600, master_ui, state) + ui = new(user, src, ui_key, "Vending", ui_key, 450, 600, master_ui, state) ui.open() /obj/machinery/vending/ui_static_data(mob/user) diff --git a/code/modules/vending/clothesmate.dm b/code/modules/vending/clothesmate.dm index 963fff9368..2691906af4 100644 --- a/code/modules/vending/clothesmate.dm +++ b/code/modules/vending/clothesmate.dm @@ -150,7 +150,8 @@ /obj/item/clothing/under/costume/qipao/red = 3, /obj/item/clothing/under/costume/cheongsam = 3, /obj/item/clothing/under/costume/cheongsam/white = 3, - /obj/item/clothing/under/costume/cheongsam/red = 3) + /obj/item/clothing/under/costume/cheongsam/red = 3, + /obj/item/storage/backpack/snail = 3) contraband = list(/obj/item/clothing/under/syndicate/tacticool = 3, /obj/item/clothing/under/syndicate/tacticool/skirt = 3, /obj/item/clothing/mask/balaclava = 3, diff --git a/code/modules/vore/eating/bellymodes.dm b/code/modules/vore/eating/bellymodes.dm index 77864021b4..291ef8654f 100644 --- a/code/modules/vore/eating/bellymodes.dm +++ b/code/modules/vore/eating/bellymodes.dm @@ -76,7 +76,7 @@ play_sound = pick(pred_digest) //Pref protection! - if (!M.vore_flags & DIGESTABLE || M.vore_flags & ABSORBED) + if (!CHECK_BITFIELD(M.vore_flags, DIGESTABLE) || M.vore_flags & ABSORBED) continue //Person just died in guts! diff --git a/code/modules/vore/eating/living.dm b/code/modules/vore/eating/living.dm index bffb8b2517..1c9bf029ea 100644 --- a/code/modules/vore/eating/living.dm +++ b/code/modules/vore/eating/living.dm @@ -116,7 +116,7 @@ testing("[user] attempted to feed [prey] to [pred], via [lowertext(belly.name)] but it went wrong.") return - if (!prey.vore_flags & DEVOURABLE) + if (!CHECK_BITFIELD(prey.vore_flags, DEVOURABLE)) to_chat(user, "This can't be eaten!") return FALSE diff --git a/config/plushies/defines.txt b/config/plushies/defines.txt index e7a92f6ac2..7cd1d88f3e 100644 --- a/config/plushies/defines.txt +++ b/config/plushies/defines.txt @@ -1,2 +1,2 @@ -# EXAMPLE -# SNOWFLAKE_PLUSHIES example {"name":"example","desc":"thanks, coders.","icon_state":"","attack_verb":["thumped","whomped","bumped"],"squeak_override":{"sound/weapons/magout.ogg":1}} +# EXAMPLE +# SNOWFLAKE_PLUSHIES example {"name":"example","desc":"thanks, coders.","icon_state":"","attack_verb":["thumped","whomped","bumped"],"squeak_override":{"sound/weapons/magout.ogg":1}} diff --git a/dependencies.sh b/dependencies.sh index 83254509b9..75e49f3fe1 100644 --- a/dependencies.sh +++ b/dependencies.sh @@ -11,7 +11,7 @@ export BYOND_MINOR=${LIST[1]} unset LIST #rust_g git tag -export RUST_G_VERSION=0.4.3 +export RUST_G_VERSION=0.4.4 #bsql git tag export BSQL_VERSION=v1.4.0.0 diff --git a/html/changelog.html b/html/changelog.html index c0141074c5..1442691167 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -50,6 +50,68 @@ -->
      +

      17 July 2020

      +

      ShizCalev, Fikou updated:

      +
        +
      • Added some sanity checking for varedit values.
      • +
      • Fixed an exploit involving coins and mints that could crash the server.
      • +
      • Fixed an exploit that would allow you to destroy round-critical / indestructible items with folders.
      • +
      • Swarmers can no longer cut power lines by deconstructing catwalks underneath them.
      • +
      • Fixed a scenario that allowed infinite resource generation via ore machines.
      • +
      • you can no longer inject html in ahelps
      • +
      • you cant either, jannies
      • +
      +

      timothyteakettle updated:

      +
        +
      • fixes a small pickle related issue
      • +
      • recent culinary and scientific advancements have brought forth new pickle related technologies
      • +
      + +

      16 July 2020

      +

      DeltaFire15 updated:

      +
        +
      • Fixes a zeolite runtime caused by a missing check.
      • +
      +

      Sneakyrat6 updated:

      +
        +
      • Fixes being able to meta people real name with OOC Notes
      • +
      +

      timothyteakettle updated:

      +
        +
      • travelling traders from another dimension can now visit the station in search of something specific, and reward you for giving it to them
      • +
      • small error with pet carrier logic fixed and also making sure simple mobs are catered for properly inside bluespace jars
      • +
      • fixes coin related issue
      • +
      + +

      15 July 2020

      +

      Sonic121x updated:

      +
        +
      • Paramedic jumpsuit
      • +
      + +

      14 July 2020

      +

      silicons updated:

      +
        +
      • chemical reactions now are sorted by priority first and temperature second.
      • +
      • sec and medical records have been added to character setup.
      • +
      • circuit reagent heaters are now sanitized for temperature from 2.7 to 1000.
      • +
      +

      timothyteakettle updated:

      +
        +
      • ports a money bag exploit
      • +
      + +

      13 July 2020

      +

      Linzolle updated:

      +
        +
      • you can no longer vore and digest people regardless of vore preferences
      • +
      +

      Owai-Seek updated:

      +
        +
      • Trashbags can now hold most shoes, and organs.
      • +
      • You can no longer nest nuke disks or hold brains in the trash.
      • +
      +

      12 July 2020

      DeltaFire15 updated:

        diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 025e1d2685..05e4c0cf69 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -26344,3 +26344,46 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. people. zeroisthebiggay: - bugfix: a singular stray pixel +2020-07-13: + Linzolle: + - bugfix: you can no longer vore and digest people regardless of vore preferences + Owai-Seek: + - tweak: Trashbags can now hold most shoes, and organs. + - balance: You can no longer nest nuke disks or hold brains in the trash. +2020-07-14: + silicons: + - rscadd: chemical reactions now are sorted by priority first and temperature second. + - rscadd: sec and medical records have been added to character setup. + - bugfix: circuit reagent heaters are now sanitized for temperature from 2.7 to + 1000. + timothyteakettle: + - bugfix: ports a money bag exploit +2020-07-15: + Sonic121x: + - bugfix: Paramedic jumpsuit +2020-07-16: + DeltaFire15: + - bugfix: Fixes a zeolite runtime caused by a missing check. + Sneakyrat6: + - bugfix: Fixes being able to meta people real name with OOC Notes + timothyteakettle: + - rscadd: travelling traders from another dimension can now visit the station in + search of something specific, and reward you for giving it to them + - bugfix: small error with pet carrier logic fixed and also making sure simple mobs + are catered for properly inside bluespace jars + - bugfix: fixes coin related issue +2020-07-17: + ShizCalev, Fikou: + - bugfix: Added some sanity checking for varedit values. + - bugfix: Fixed an exploit involving coins and mints that could crash the server. + - bugfix: Fixed an exploit that would allow you to destroy round-critical / indestructible + items with folders. + - bugfix: Swarmers can no longer cut power lines by deconstructing catwalks underneath + them. + - bugfix: Fixed a scenario that allowed infinite resource generation via ore machines. + - bugfix: you can no longer inject html in ahelps + - admin: you cant either, jannies + timothyteakettle: + - bugfix: fixes a small pickle related issue + - rscadd: recent culinary and scientific advancements have brought forth new pickle + related technologies diff --git a/html/changelogs/AutoChangeLog-pr-12229.yml b/html/changelogs/AutoChangeLog-pr-12229.yml new file mode 100644 index 0000000000..02316f0323 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12229.yml @@ -0,0 +1,4 @@ +author: "Arturlang" +delete-after: True +changes: + - rscadd: "TGUI 3.0 and enables all the UIs, plus the smart asset cache, and all the things required for them" diff --git a/html/changelogs/AutoChangeLog-pr-12679.yml b/html/changelogs/AutoChangeLog-pr-12679.yml new file mode 100644 index 0000000000..5cb7906927 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12679.yml @@ -0,0 +1,4 @@ +author: "silicons" +delete-after: True +changes: + - rscadd: "Unarmed parry is now a thing." diff --git a/html/changelogs/AutoChangeLog-pr-12733.yml b/html/changelogs/AutoChangeLog-pr-12733.yml new file mode 100644 index 0000000000..79c6035e5e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12733.yml @@ -0,0 +1,4 @@ +author: "TheObserver-sys" +delete-after: True +changes: + - rscadd: "Adds a new reaction: Slime Extractification. Take 30u Slime Jelly, 5u Frost Oil, and 5u plasma to generate a fresh grey slime extract." diff --git a/html/changelogs/AutoChangeLog-pr-12750.yml b/html/changelogs/AutoChangeLog-pr-12750.yml new file mode 100644 index 0000000000..722b3c5c93 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12750.yml @@ -0,0 +1,4 @@ +author: "timothyteakettle" +delete-after: True +changes: + - rscadd: "plushies in the loadout have been replaced with a box that lets you choose one instead" diff --git a/html/changelogs/AutoChangeLog-pr-12758.yml b/html/changelogs/AutoChangeLog-pr-12758.yml new file mode 100644 index 0000000000..5fb00341ea --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12758.yml @@ -0,0 +1,4 @@ +author: "MrJWhit" +delete-after: True +changes: + - rscadd: "Adds a small light next to the kitchen counter" diff --git a/html/changelogs/AutoChangeLog-pr-12759.yml b/html/changelogs/AutoChangeLog-pr-12759.yml new file mode 100644 index 0000000000..bef328da68 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12759.yml @@ -0,0 +1,4 @@ +author: "Yakumo Chen" +delete-after: True +changes: + - tweak: "Hierophant club now checks for friendly fire by default." diff --git a/html/changelogs/AutoChangeLog-pr-12761.yml b/html/changelogs/AutoChangeLog-pr-12761.yml new file mode 100644 index 0000000000..f3db58516e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12761.yml @@ -0,0 +1,6 @@ +author: "EmeraldSundisk" +delete-after: True +changes: + - rscadd: "Adds a pool to Delta Station" + - rscadd: "Adds light fixtures to specified areas" + - tweak: "Relocates objects in impacted areas of Delta's starboard maintenance" diff --git a/html/changelogs/AutoChangeLog-pr-12762.yml b/html/changelogs/AutoChangeLog-pr-12762.yml new file mode 100644 index 0000000000..12432db3b2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12762.yml @@ -0,0 +1,4 @@ +author: "zeroisthebiggay" +delete-after: True +changes: + - tweak: "martial arts twenty minpop" diff --git a/html/changelogs/AutoChangeLog-pr-12763.yml b/html/changelogs/AutoChangeLog-pr-12763.yml new file mode 100644 index 0000000000..613323cd64 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12763.yml @@ -0,0 +1,4 @@ +author: "zeroisthebiggay" +delete-after: True +changes: + - bugfix: "records" diff --git a/html/changelogs/AutoChangeLog-pr-12775.yml b/html/changelogs/AutoChangeLog-pr-12775.yml new file mode 100644 index 0000000000..e7e28914a4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12775.yml @@ -0,0 +1,4 @@ +author: "timothyteakettle" +delete-after: True +changes: + - bugfix: "wrestling should no longer have the ability to permanently rotate people" diff --git a/html/changelogs/AutoChangeLog-pr-12776.yml b/html/changelogs/AutoChangeLog-pr-12776.yml new file mode 100644 index 0000000000..d51b334a67 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12776.yml @@ -0,0 +1,4 @@ +author: "timothyteakettle" +delete-after: True +changes: + - rscadd: "you can now select to wear a snail shell as your backpack in the customization menu" diff --git a/html/changelogs/AutoChangeLog-pr-12779.yml b/html/changelogs/AutoChangeLog-pr-12779.yml new file mode 100644 index 0000000000..49c4c20ed1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12779.yml @@ -0,0 +1,4 @@ +author: "b1tt3r1n0" +delete-after: True +changes: + - rscadd: "Added the updated circle game" diff --git a/html/changelogs/AutoChangeLog-pr-12812.yml b/html/changelogs/AutoChangeLog-pr-12812.yml new file mode 100644 index 0000000000..7504025e37 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12812.yml @@ -0,0 +1,4 @@ +author: "Putnam3145" +delete-after: True +changes: + - bugfix: "Pen uplinks no longer broken" diff --git a/html/ghost.png b/html/ghost.png new file mode 100644 index 0000000000..e4b426ca47 Binary files /dev/null and b/html/ghost.png differ diff --git a/icons/UI_Icons/Arcade/boss1.gif b/icons/UI_Icons/Arcade/boss1.gif new file mode 100644 index 0000000000..4730ac0021 Binary files /dev/null and b/icons/UI_Icons/Arcade/boss1.gif differ diff --git a/icons/UI_Icons/Arcade/boss2.gif b/icons/UI_Icons/Arcade/boss2.gif new file mode 100644 index 0000000000..d95fd84f0e Binary files /dev/null and b/icons/UI_Icons/Arcade/boss2.gif differ diff --git a/icons/UI_Icons/Arcade/boss3.gif b/icons/UI_Icons/Arcade/boss3.gif new file mode 100644 index 0000000000..e97056998a Binary files /dev/null and b/icons/UI_Icons/Arcade/boss3.gif differ diff --git a/icons/UI_Icons/Arcade/boss4.gif b/icons/UI_Icons/Arcade/boss4.gif new file mode 100644 index 0000000000..6695b6cfbf Binary files /dev/null and b/icons/UI_Icons/Arcade/boss4.gif differ diff --git a/icons/UI_Icons/Arcade/boss5.gif b/icons/UI_Icons/Arcade/boss5.gif new file mode 100644 index 0000000000..a827fb8c4e Binary files /dev/null and b/icons/UI_Icons/Arcade/boss5.gif differ diff --git a/icons/UI_Icons/Arcade/boss6.gif b/icons/UI_Icons/Arcade/boss6.gif new file mode 100644 index 0000000000..7a926cf89d Binary files /dev/null and b/icons/UI_Icons/Arcade/boss6.gif differ diff --git a/icons/UI_Icons/tgui/ntosradar_background.png b/icons/UI_Icons/tgui/ntosradar_background.png new file mode 100644 index 0000000000..bac7647e3a Binary files /dev/null and b/icons/UI_Icons/tgui/ntosradar_background.png differ diff --git a/icons/UI_Icons/tgui/ntosradar_pointer.png b/icons/UI_Icons/tgui/ntosradar_pointer.png new file mode 100644 index 0000000000..e71823f391 Binary files /dev/null and b/icons/UI_Icons/tgui/ntosradar_pointer.png differ diff --git a/icons/UI_Icons/tgui/ntosradar_pointer_S.png b/icons/UI_Icons/tgui/ntosradar_pointer_S.png new file mode 100644 index 0000000000..51a0dd49d9 Binary files /dev/null and b/icons/UI_Icons/tgui/ntosradar_pointer_S.png differ diff --git a/icons/mob/32x64.dmi b/icons/mob/32x64.dmi index 32b25ba739..cddf9599b4 100644 Binary files a/icons/mob/32x64.dmi and b/icons/mob/32x64.dmi differ diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi index 0a1372ac2b..00cffd9006 100644 Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ diff --git a/icons/mob/clothing/uniform.dmi b/icons/mob/clothing/uniform.dmi index 163d2dc2f2..fa376635f9 100644 Binary files a/icons/mob/clothing/uniform.dmi and b/icons/mob/clothing/uniform.dmi differ diff --git a/icons/mob/clothing/uniform_digi.dmi b/icons/mob/clothing/uniform_digi.dmi index b1b9ded7f0..af72ac0e7b 100644 Binary files a/icons/mob/clothing/uniform_digi.dmi and b/icons/mob/clothing/uniform_digi.dmi differ diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi index 19738ed490..315ca5e924 100644 Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi index 9589e338e1..6af883f2e8 100644 Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ diff --git a/icons/mob/map_backgrounds.dmi b/icons/mob/map_backgrounds.dmi new file mode 100644 index 0000000000..dc6e3e46b1 Binary files /dev/null and b/icons/mob/map_backgrounds.dmi differ diff --git a/icons/obj/machines/gateway.dmi b/icons/obj/machines/gateway.dmi index cfe4c26709..fc45145ae8 100644 Binary files a/icons/obj/machines/gateway.dmi and b/icons/obj/machines/gateway.dmi differ diff --git a/icons/obj/modular_console.dmi b/icons/obj/modular_console.dmi index 8d4ec3e2d8..cdcf6f1bd5 100644 Binary files a/icons/obj/modular_console.dmi and b/icons/obj/modular_console.dmi differ diff --git a/icons/obj/modular_laptop.dmi b/icons/obj/modular_laptop.dmi index 1e506ca6fe..7cf5a77621 100644 Binary files a/icons/obj/modular_laptop.dmi and b/icons/obj/modular_laptop.dmi differ diff --git a/icons/obj/modular_tablet.dmi b/icons/obj/modular_tablet.dmi index 621874a969..2f9a0559ae 100644 Binary files a/icons/obj/modular_tablet.dmi and b/icons/obj/modular_tablet.dmi differ diff --git a/icons/obj/pet_carrier.dmi b/icons/obj/pet_carrier.dmi index b3c11be98f..b02f9d6ce4 100644 Binary files a/icons/obj/pet_carrier.dmi and b/icons/obj/pet_carrier.dmi differ diff --git a/icons/obj/stack_objects.dmi b/icons/obj/stack_objects.dmi index d8c7d6b722..196373dea7 100644 Binary files a/icons/obj/stack_objects.dmi and b/icons/obj/stack_objects.dmi differ diff --git a/icons/obj/storage.dmi b/icons/obj/storage.dmi index a719356804..1f1709a10c 100644 Binary files a/icons/obj/storage.dmi and b/icons/obj/storage.dmi differ diff --git a/icons/program_icons/borg_mon.gif b/icons/program_icons/borg_mon.gif new file mode 100644 index 0000000000..35d0f442fd Binary files /dev/null and b/icons/program_icons/borg_mon.gif differ diff --git a/modular_citadel/code/modules/client/loadout/backpack.dm b/modular_citadel/code/modules/client/loadout/backpack.dm index 8d089a129a..690e012840 100644 --- a/modular_citadel/code/modules/client/loadout/backpack.dm +++ b/modular_citadel/code/modules/client/loadout/backpack.dm @@ -1,27 +1,7 @@ -/datum/gear/plushcarp - name = "Space carp plushie" +/datum/gear/plushbox + name = "Plushie Choice Box" category = SLOT_IN_BACKPACK - path = /obj/item/toy/plush/carpplushie - -/datum/gear/plushliz - name = "Lizard plushie" - category = SLOT_IN_BACKPACK - path = /obj/item/toy/plush/lizardplushie - -/datum/gear/plushsnek - name = "Snake plushie" - category = SLOT_IN_BACKPACK - path = /obj/item/toy/plush/snakeplushie - -/datum/gear/plushslime - name = "Slime plushie" - category = SLOT_IN_BACKPACK - path = /obj/item/toy/plush/slimeplushie - -/datum/gear/plushlamp - name = "Lamp plushie" - category = SLOT_IN_BACKPACK - path = /obj/item/toy/plush/lampplushie + path = /obj/item/choice_beacon/box/plushie /datum/gear/tennis name = "Classic Tennis Ball" diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/healing.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/healing.dm index 56b2ad2a2c..a6a9d7a85f 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/healing.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/healing.dm @@ -210,7 +210,7 @@ var/datum/component/radioactive/contamination = M.GetComponent(/datum/component/radioactive) if(M.radiation > 0) M.radiation -= min(M.radiation, 60) - if(contamination.strength > 0) + if(contamination && contamination.strength > 0) contamination.strength -= min(contamination.strength, 100) ..() diff --git a/modular_citadel/code/modules/reagents/objects/clothes.dm b/modular_citadel/code/modules/reagents/objects/clothes.dm index de4cb38360..d3c566ce70 100644 --- a/modular_citadel/code/modules/reagents/objects/clothes.dm +++ b/modular_citadel/code/modules/reagents/objects/clothes.dm @@ -9,7 +9,7 @@ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0) //item_flags = NODROP //Tips their hat! -/obj/item/clothing/head/hattip/attack_hand(mob/user) +/obj/item/clothing/head/hattip/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(iscarbon(user)) var/mob/living/carbon/C = user if(is_ninja(C)) diff --git a/modular_citadel/code/modules/reagents/objects/items.dm b/modular_citadel/code/modules/reagents/objects/items.dm index 1924e7ee00..27b8961835 100644 --- a/modular_citadel/code/modules/reagents/objects/items.dm +++ b/modular_citadel/code/modules/reagents/objects/items.dm @@ -9,7 +9,7 @@ w_class = WEIGHT_CLASS_TINY //A little janky with pockets -/obj/item/fermichem/pHbooklet/attack_hand(mob/user) +/obj/item/fermichem/pHbooklet/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) if(user.get_held_index_of_item(src))//Does this check pockets too..? if(numberOfPages == 50) icon_state = "pHbookletOpen" diff --git a/rust_g.dll b/rust_g.dll old mode 100644 new mode 100755 index f4be6e730a..8cd62b8ca4 Binary files a/rust_g.dll and b/rust_g.dll differ diff --git a/sound/ambience/LICENSE.txt b/sound/ambience/license.txt similarity index 52% rename from sound/ambience/LICENSE.txt rename to sound/ambience/license.txt index 5fb0ece74d..51f5a7e2bc 100644 --- a/sound/ambience/LICENSE.txt +++ b/sound/ambience/license.txt @@ -4,3 +4,8 @@ ambidet2.ogg is Night on the Docks, Piano by Kevin Macleod. It has been licensed It has been cropped for use ingame, and also fades in. aurora_caelus.ogg is Music for Manatees, by Kevin Macleod. It has been licensed under CC-BY 3.0 license. It has been cropped for use ingame, and also fades out. +title1.ogg is Flip-Flap created by Jakub "AceMan" SzelÄ…g and taken from http://www.modules.pl/?id=module&mod=453 +title2.ogg is Robocop Theme (gameboy) remixed by Eric Schumacker +title3.ogg is Tintin On The Moon remixed by Cuboos https://tgstation13.org/phpBB/viewtopic.php?f=10&t=2157 (assumed CC under allowing it to be submitted to the github, see thread) + +CC-BY 3.0: http://creativecommons.org/licenses/by/3.0/ diff --git a/sound/effects/license.txt b/sound/effects/license.txt new file mode 100644 index 0000000000..c928a9872f --- /dev/null +++ b/sound/effects/license.txt @@ -0,0 +1,2 @@ +hit_punch.ogg and hit_kick.ogg are made by Taira Komori +(https://taira-komori.jpn.org/freesounden.html) diff --git a/strings/wanted_message.json b/strings/wanted_message.json new file mode 100644 index 0000000000..18965b7026 --- /dev/null +++ b/strings/wanted_message.json @@ -0,0 +1,74 @@ +{ + "basemessage": [ + "Fugitive from the law due to", + "Needs to be interrogated for information about", + "Wanted by The Syndicate for", + "Ransomable to Nanotrasen for", + "Has exploitable information about" + ], + "verb": [ + "murdering", + "killing", + "accidentally destroying", + "destroying", + "knowing information about", + "stealing", + "slipping", + "sabotaging", + "robusting", + "collaborating with", + "being close friends with", + "cloning", + "befriending", + "bombing", + "kidnapping", + "pretending to be", + "seducing", + "ignoring", + "assassinating" + ], + "noun": { + "secret plans": 50, + "the hand teleporter": 50, + "an NT CentCom uniform": 50, + "a supermatter shard": 50, + "internal Syndicate documents": 50, + "experimental Nanotrasen technology": 50, + "bluespace crystals": 50, + "a cult": 50, + "shapeshifting creatures": 50, + "a toolbox": 10, + "a bar of soap": 10, + "lizardmen": 10, + "two million credits": 10, + "a gondola": 10, + "one billion credits": 5, + "research on floor clowns": 5, + "Officer Beepsky": 5, + "clown tears": 5, + "John F Kennedy 2": 5, + "Nanotrasen's swimsuit calendar": 5, + "a suspicious bus": 5, + "administrators": 5, + "a solid gold gondola": 5, + "the anime archive": 5, + "YALPER": 1, + "absolutely nothing": 1, + "Cuban Pete": 1, + "your mother": 1, + "WGW": 1 + }, + "location": { + "on Space Station 13": 50, + "somewhere in deep space": 50, + "on a remote syndicate base": 50, + "in a secure NT facility": 50, + "while on an escape shuttle": 10, + "while infiltrating CentCom headquarters": 10, + "deep in the necropolis": 10, + "during a drunken bar fight": 5, + "while stuck in a bathroom": 5, + "in a back alley on Mars": 5, + "on Virgo Orbital": 1 + } +} diff --git a/tgstation.dme b/tgstation.dme index f5081b4a94..53fb12e152 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -120,17 +120,18 @@ #include "code\__DEFINES\wall_dents.dm" #include "code\__DEFINES\wires.dm" #include "code\__DEFINES\_flags\_flags.dm" +#include "code\__DEFINES\_flags\do_after.dm" #include "code\__DEFINES\_flags\item_flags.dm" #include "code\__DEFINES\_flags\obj_flags.dm" +#include "code\__DEFINES\_flags\shields.dm" #include "code\__DEFINES\admin\keybindings.dm" +#include "code\__DEFINES\chemistry\reactions.dm" #include "code\__DEFINES\combat\attack_types.dm" #include "code\__DEFINES\combat\block.dm" #include "code\__DEFINES\combat\block_parry.dm" #include "code\__DEFINES\dcs\flags.dm" #include "code\__DEFINES\dcs\helpers.dm" #include "code\__DEFINES\dcs\signals.dm" -#include "code\__DEFINES\flags\do_after.dm" -#include "code\__DEFINES\flags\shields.dm" #include "code\__DEFINES\mapping\maploader.dm" #include "code\__DEFINES\material\worth.dm" #include "code\__DEFINES\misc\return_values.dm" @@ -238,6 +239,7 @@ #include "code\_onclick\hud\hud.dm" #include "code\_onclick\hud\human.dm" #include "code\_onclick\hud\lavaland_elite.dm" +#include "code\_onclick\hud\map_popups.dm" #include "code\_onclick\hud\monkey.dm" #include "code\_onclick\hud\movable_screen_objects.dm" #include "code\_onclick\hud\parallax.dm" @@ -455,7 +457,7 @@ #include "code\datums\components\virtual_reality.dm" #include "code\datums\components\wearertargeting.dm" #include "code\datums\components\wet_floor.dm" -#include "code\datums\components\crafting\craft.dm" +#include "code\datums\components\crafting\crafting.dm" #include "code\datums\components\crafting\guncrafting.dm" #include "code\datums\components\crafting\recipes.dm" #include "code\datums\components\crafting\glassware\glassware.dm" @@ -1121,6 +1123,7 @@ #include "code\game\objects\items\stacks\stack.dm" #include "code\game\objects\items\stacks\tape.dm" #include "code\game\objects\items\stacks\telecrystal.dm" +#include "code\game\objects\items\stacks\tickets.dm" #include "code\game\objects\items\stacks\wrap.dm" #include "code\game\objects\items\stacks\sheets\glass.dm" #include "code\game\objects\items\stacks\sheets\leather.dm" @@ -1349,6 +1352,7 @@ #include "code\modules\admin\verbs\pray.dm" #include "code\modules\admin\verbs\randomverbs.dm" #include "code\modules\admin\verbs\reestablish_db_connection.dm" +#include "code\modules\admin\verbs\shuttlepanel.dm" #include "code\modules\admin\verbs\spawnobjasmob.dm" #include "code\modules\admin\verbs\tripAI.dm" #include "code\modules\admin\verbs\SDQL2\SDQL_2.dm" @@ -1955,6 +1959,7 @@ #include "code\modules\events\spider_infestation.dm" #include "code\modules\events\spontaneous_appendicitis.dm" #include "code\modules\events\stray_cargo.dm" +#include "code\modules\events\travelling_trader.dm" #include "code\modules\events\vent_clog.dm" #include "code\modules\events\wisdomcow.dm" #include "code\modules\events\wormholes.dm" @@ -2353,6 +2358,7 @@ #include "code\modules\mob\dead\observer\notificationprefs.dm" #include "code\modules\mob\dead\observer\observer.dm" #include "code\modules\mob\dead\observer\observer_movement.dm" +#include "code\modules\mob\dead\observer\orbit.dm" #include "code\modules\mob\dead\observer\say.dm" #include "code\modules\mob\living\blood.dm" #include "code\modules\mob\living\bloodcrawl.dm" @@ -2387,6 +2393,7 @@ #include "code\modules\mob\living\brain\say.dm" #include "code\modules\mob\living\brain\status_procs.dm" #include "code\modules\mob\living\carbon\carbon.dm" +#include "code\modules\mob\living\carbon\carbon_active_parry.dm" #include "code\modules\mob\living\carbon\carbon_defense.dm" #include "code\modules\mob\living\carbon\carbon_defines.dm" #include "code\modules\mob\living\carbon\carbon_movement.dm" @@ -2541,6 +2548,7 @@ #include "code\modules\mob\living\simple_animal\corpse.dm" #include "code\modules\mob\living\simple_animal\damage_procs.dm" #include "code\modules\mob\living\simple_animal\parrot.dm" +#include "code\modules\mob\living\simple_animal\pickle.dm" #include "code\modules\mob\living\simple_animal\shade.dm" #include "code\modules\mob\living\simple_animal\simple_animal.dm" #include "code\modules\mob\living\simple_animal\simple_animal_vr.dm" @@ -2698,6 +2706,7 @@ #include "code\modules\modular_computers\file_system\program_events.dm" #include "code\modules\modular_computers\file_system\programs\airestorer.dm" #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\card.dm" #include "code\modules\modular_computers\file_system\programs\configurator.dm" #include "code\modules\modular_computers\file_system\programs\file_browser.dm" @@ -2706,6 +2715,8 @@ #include "code\modules\modular_computers\file_system\programs\ntnrc_client.dm" #include "code\modules\modular_computers\file_system\programs\nttransfer.dm" #include "code\modules\modular_computers\file_system\programs\powermonitor.dm" +#include "code\modules\modular_computers\file_system\programs\radar.dm" +#include "code\modules\modular_computers\file_system\programs\robocontrol.dm" #include "code\modules\modular_computers\file_system\programs\sm_monitor.dm" #include "code\modules\modular_computers\file_system\programs\antagonist\contract_uplink.dm" #include "code\modules\modular_computers\file_system\programs\antagonist\dos.dm" @@ -2764,10 +2775,6 @@ #include "code\modules\NTNet\network.dm" #include "code\modules\NTNet\relays.dm" #include "code\modules\NTNet\services\_service.dm" -#include "code\modules\oracle_ui\assets.dm" -#include "code\modules\oracle_ui\hookup_procs.dm" -#include "code\modules\oracle_ui\oracle_ui.dm" -#include "code\modules\oracle_ui\themed.dm" #include "code\modules\paperwork\clipboard.dm" #include "code\modules\paperwork\contract.dm" #include "code\modules\paperwork\filingcabinet.dm" @@ -3325,6 +3332,7 @@ #include "code\modules\tgui\states\contained.dm" #include "code\modules\tgui\states\deep_inventory.dm" #include "code\modules\tgui\states\default.dm" +#include "code\modules\tgui\states\default_contained.dm" #include "code\modules\tgui\states\hands.dm" #include "code\modules\tgui\states\human_adjacent.dm" #include "code\modules\tgui\states\inventory.dm" diff --git a/tgui-next/.gitattributes b/tgui-next/.gitattributes deleted file mode 100644 index 0016cc3bf6..0000000000 --- a/tgui-next/.gitattributes +++ /dev/null @@ -1,10 +0,0 @@ -* text=auto - -## Enforce text mode and LF line breaks -*.js text eol=lf -*.css text eol=lf -*.html text eol=lf -*.json text eol=lf - -## Treat bundles as binary and ignore them during conflicts -*.bundle.* binary merge=tgui-merge-bundle diff --git a/tgui-next/.gitignore b/tgui-next/.gitignore deleted file mode 100644 index 416ca3768d..0000000000 --- a/tgui-next/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -node_modules -*.log -package-lock.json - -/packages/tgui/public/.tmp/**/* -/packages/tgui/public/**/*.hot-update.* -/packages/tgui/public/**/*.map diff --git a/tgui-next/docs/tutorial-and-examples.md b/tgui-next/docs/tutorial-and-examples.md deleted file mode 100644 index d038c1de61..0000000000 --- a/tgui-next/docs/tutorial-and-examples.md +++ /dev/null @@ -1,245 +0,0 @@ -# Tutorial and Examples - -## Main concepts - -Basic tgui backend code consists of the following vars and procs: - -``` -ui_interact(mob/user, ui_key, datum/tgui/ui, force_open, - datum/tgui/master_ui, datum/ui_state/state) -ui_data(mob/user) -ui_act(action, params) -``` - -- `src_object` - The atom, which UI corresponds to in the game world. -- `ui_interact` - The proc where you will handle a request to open an -interface. Typically, you would update an existing UI (if it exists), -or set up a new instance of UI by calling the `SStgui` subsystem. -- `ui_data` - In this proc you munges whatever complex data your `src_object` -has into an associative list, which will then be sent to UI as a JSON string. -- `ui_act` - This proc receives user actions and reacts to them by changing -the state of the game. -- `ui_state` (set in `ui_interact`) - This var dictates under what conditions -a UI may be interacted with. This may be the standard checks that check if -you are in range and conscious, or more. - -Once backend is complete, you create an new interface component on the -frontend, which will receive this JSON data and render it on screen. - -States are easy to write and extend, and what make tgui interactions so -powerful. Because states can be overridden from other procs, you can build -powerful interactions for embedded objects or remote access. - -## Using It - -### Backend - -Let's start with a very basic hello world. - -```dm -/obj/machinery/my_machine/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "my_machine", name, 300, 300, master_ui, state) - ui.open() -``` - -This is the proc that defines our interface. There's a bit going on here, so -let's break it down. First, we override the ui_interact proc on our object. This -will be called by `interact` for you, which is in turn called by `attack_hand` -(or `attack_self` for items). `ui_interact` is also called to update a UI (hence -the `try_update_ui`), so we accept an existing UI to update. The `state` is a -default argument so that a caller can overload it with named arguments -(`ui_interact(state = overloaded_state)`) if needed. - -Inside the `if(!ui)` block (which means we are creating a new UI), we choose our -template, title, and size; we can also set various options like `style` (for -themes), or autoupdate. These options will be elaborated on later (as will -`ui_state`s). - -After `ui_interact`, we need to define `ui_data`. This just returns a list of -data for our object to use. Let's imagine our object has a few vars: - -```dm -/obj/machinery/my_machine/ui_data(mob/user) - var/list/data = list() - data["health"] = health - data["color"] = color - - return data -``` - -The `ui_data` proc is what people often find the hardest about tgui, but its -really quite simple! You just need to represent your object as numbers, strings, -and lists, instead of atoms and datums. - -Finally, the `ui_act` proc is called by the interface whenever the user used an -input. The input's `action` and `params` are passed to the proc. - -```dm -/obj/machinery/my_machine/ui_act(action, params) - if(..()) - return - switch(action) - if("change_color") - var/new_color = params["color"] - if(!(color in allowed_coors)) - return - color = new_color - . = TRUE - update_icon() -``` - -The `..()` (parent call) is very important here, as it is how we check that the -user is allowed to use this interface (to avoid so-called href exploits). It is -also very important to clamp and sanitize all input here. Always assume the user -is attempting to exploit the game. - -Also note the use of `. = TRUE` (or `FALSE`), which is used to notify the UI -that this input caused an update. This is especially important for UIs that do -not auto-update, as otherwise the user will never see their change. - -### Frontend - -Finally, you have to make a UI component. This is also a source of -confusion for many new users. If you got some basic javascript and HTML -knowledge, that should ease the learning process, although we recommend -getting yourself introduced to -[React and JSX](https://reactjs.org/docs/introducing-jsx.html). - -A component is not a regular HTML. A component is a pure function, which -accepts a `props` object (it contains properties passed to a component), -and outputs an HTML-like structure consisting of regular HTML elements and -other UI components. - -Interface component will always receive 1 prop which is called `state`. -This object contains a few special values: - -- `config` is always the same and is part of core tgui -(it will be explained later), -- `data` is the data returned from `ui_data` - -```jsx -import { Section, LabeledList } from '../components'; - -const SampleInterface = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - return ( -
        - - - {data.health} - - - {data.color} - - -
        - ); -}; -``` - -This syntax can be very confusing at first, but it is very important to -realize that this is just a natural extension of javascript. Here's a few -examples of this syntax: - -Return a different element based on a condition: - -```jsx -if (condition) { - return ; -} -return ; -``` - -Conditionally render a element inside of another element: - -```jsx - - {showProgress && ( - - )} - -``` - -Looping over the array to make an element for each item: - -```jsx - - {items.map(item => ( - - {item.content} - - ))} - -``` - -### Routing table - -Once you finished creating your interface, you need to add a route entry to -the large `ROUTES` object, otherwise tgui won't know when and how to render -your interface. Key of this `ROUTES` object corresponds to the interface -name you use in DM code. - -```js -import { SampleInterface } from './interfaces/SampleInterface'; - -const ROUTES = { - sample_interface: { - component: () => SampleInterface, - scrollable: true, - }, -}; -``` - -## Copypasta - -We all do it, even the best of us. If you just want to make a tgui **fast**, -here's what you need (note that you'll probably be forced to clean your shit up -upon code review): - -```dm -/obj/copypasta/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state) // Remember to use the appropriate state. - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "copypasta", name, 300, 300, master_ui, state) - ui.open() - -/obj/copypasta/ui_data(mob/user) - var/list/data = list() - data["var"] = var - return data - -/obj/copypasta/ui_act(action, params) - if(..()) - return - if(action == "copypasta") - var/newvar = params["var"] - // A demo of proper input sanitation. - var = CLAMP(newvar, min_val, max_val) - return TRUE - update_icon() // Not applicable to all objects. -``` - -And the template: - -```jsx -import { Section, LabeledList } from '../components'; - -const SampleInterface = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - return ( -
        - - - {data.var} - - -
        - ); -}; -``` diff --git a/tgui-next/package.json b/tgui-next/package.json deleted file mode 100644 index 9b7253e131..0000000000 --- a/tgui-next/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "private": true, - "name": "tgui-next", - "version": "0.1.0", - "workspaces": [ - "packages/*" - ], - "scripts": { - "build": "eslint packages && cd packages/tgui && npx webpack --mode=production", - "watch": "cd packages/tgui-dev-server && node --experimental-modules index.js", - "analyze": "cd packages/tgui && npx webpack --mode=production --env.analyze=1", - "lint": "eslint packages" - }, - "dependencies": { - "babel-eslint": "^10.0.3", - "eslint": "^6.7.2", - "eslint-plugin-react": "^7.17.0" - } -} diff --git a/tgui-next/packages/common/math.js b/tgui-next/packages/common/math.js deleted file mode 100644 index a33b9aa214..0000000000 --- a/tgui-next/packages/common/math.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Limits a number to the range between 'min' and 'max'. - */ -export const clamp = (value, min = 0, max = 1) => { - return Math.max(min, Math.min(value, max)); -}; - -/** - * Returns a rounded number. - * TODO: Replace this native rounding function with a more robust one. - */ -export const round = value => Math.round(value); - -/** - * Returns a string representing a number in fixed point notation. - */ -export const toFixed = (value, fractionDigits = 0) => { - return Number(value).toFixed(fractionDigits); -}; diff --git a/tgui-next/packages/tgui/backend.js b/tgui-next/packages/tgui/backend.js deleted file mode 100644 index cdaf89fc6b..0000000000 --- a/tgui-next/packages/tgui/backend.js +++ /dev/null @@ -1,95 +0,0 @@ -import { UI_DISABLED, UI_INTERACTIVE } from './constants'; -import { tridentVersion, act as _act } from './byond'; - -/** - * This file provides a clear separation layer between backend updates - * and what state our React app sees. - * - * Sometimes backend can response without a "data" field, but our final - * state will still contain previous "data" because we are merging - * the response with already existing state. - */ - -/** - * Creates a backend update action. - */ -export const backendUpdate = state => ({ - type: 'backendUpdate', - payload: state, -}); - -/** - * Precisely defines state changes. - */ -export const backendReducer = (state, action) => { - const { type, payload } = action; - - if (type === 'backendUpdate') { - // Merge config - const config = { - ...state.config, - ...payload.config, - }; - // Merge data - const data = { - ...state.data, - ...payload.static_data, - ...payload.data, - }; - // Calculate our own fields - const visible = config.status !== UI_DISABLED; - const interactive = config.status === UI_INTERACTIVE; - // Return new state - return { - ...state, - config, - data, - visible, - interactive, - }; - } - - return state; -}; - -/** - * @typedef BackendState - * @type {{ - * config: { - * title: string, - * status: number, - * screen: string, - * style: string, - * interface: string, - * fancy: number, - * locked: number, - * observer: number, - * window: string, - * ref: string, - * }, - * data: any, - * visible: boolean, - * interactive: boolean, - * }} - */ - -/** - * A React hook (sort of) for getting tgui state and related functions. - * - * This is supposed to be replaced with a real React Hook, which can only - * be used in functional components. DO NOT use it in class-based components! - * - * @return {BackendState & { - * act: (action: string, params?: object) => void, - * }} - */ -export const useBackend = props => { - // TODO: Dispatch "act" calls as Redux actions - const { state, dispatch } = props; - const ref = state.config.ref; - const act = (action, params = {}) => _act(ref, action, params); - return { - ...state, - act, - }; -}; diff --git a/tgui-next/packages/tgui/byond.js b/tgui-next/packages/tgui/byond.js deleted file mode 100644 index 2b7d3ff772..0000000000 --- a/tgui-next/packages/tgui/byond.js +++ /dev/null @@ -1,84 +0,0 @@ -import { buildQueryString } from 'common/string'; - -/** - * Version of Trident engine used in Internet Explorer. - * - * - IE 8 - Trident 4.0 - * - IE 11 - Trident 7.0 - * - * @return An integer number or 'null' if this is not a trident engine. - */ -export const tridentVersion = (() => { - const { userAgent } = navigator; - const groups = userAgent.match(/Trident\/(\d+).+?;/i); - const majorVersion = groups[1]; - if (!majorVersion) { - return null; - } - return parseInt(majorVersion, 10); -})(); - -/** - * Helper to generate a BYOND href given 'params' as an object - * (with an optional 'url' for eg winset). - */ -const href = (url, params = {}) => { - return 'byond://' + url + '?' + buildQueryString(params); -}; - -export const callByond = (url, params = {}) => { - window.location.href = href(url, params); -}; - -/** - * A high-level abstraction of BYJAX. Makes a call to BYOND and returns - * a promise, which (if endpoint has a callback parameter) resolves - * with the return value of that call. - */ -export const callByondAsync = (url, params = {}) => { - // Create a callback array if it doesn't exist yet - window.__callbacks__ = window.__callbacks__ || []; - // Create a Promise and push its resolve function into callback array - const callbackIndex = window.__callbacks__.length; - const promise = new Promise(resolve => { - // TODO: Fix a potential memory leak - window.__callbacks__.push(resolve); - }); - // Call BYOND client - window.location.href = href(url, { - ...params, - callback: `__callbacks__[${callbackIndex}]`, - }); - return promise; -}; - -/** - * Literally types a command on the client. - */ -export const runCommand = command => callByond('winset', { command }); - -/** - * Helper to make a BYOND ui_act() call on the UI 'src' given an 'action' - * and optional 'params'. - */ -export const act = (src, action, params = {}) => { - return callByond('', { src, action, ...params }); -}; - -/** - * Calls 'winget' on window, retrieving value by the 'key'. - */ -export const winget = async (win, key) => { - const obj = await callByondAsync('winget', { - id: win, - property: key, - }); - return obj[key]; -}; - -/** - * Calls 'winset' on window, setting 'key' to 'value'. - */ -export const winset = (win, key, value) => callByond('winset', { - [`${win}.${key}`]: value, -}); diff --git a/tgui-next/packages/tgui/components/ColorBox.js b/tgui-next/packages/tgui/components/ColorBox.js deleted file mode 100644 index 0bfe368d82..0000000000 --- a/tgui-next/packages/tgui/components/ColorBox.js +++ /dev/null @@ -1,19 +0,0 @@ -import { classes, pureComponentHooks } from 'common/react'; -import { Box } from './Box'; - -export const ColorBox = props => { - const { color, content, className, ...rest } = props; - return ( - - ); -}; - -ColorBox.defaultHooks = pureComponentHooks; diff --git a/tgui-next/packages/tgui/components/Dimmer.js b/tgui-next/packages/tgui/components/Dimmer.js deleted file mode 100644 index 9d3ead0549..0000000000 --- a/tgui-next/packages/tgui/components/Dimmer.js +++ /dev/null @@ -1,19 +0,0 @@ -import { Box } from './Box'; - -export const Dimmer = props => { - const { style, ...rest } = props; - return ( - - ); -}; diff --git a/tgui-next/packages/tgui/components/NoticeBox.js b/tgui-next/packages/tgui/components/NoticeBox.js deleted file mode 100644 index f57e4d9082..0000000000 --- a/tgui-next/packages/tgui/components/NoticeBox.js +++ /dev/null @@ -1,16 +0,0 @@ -import { classes, pureComponentHooks } from 'common/react'; -import { Box } from './Box'; - -export const NoticeBox = props => { - const { className, ...rest } = props; - return ( - - ); -}; - -NoticeBox.defaultHooks = pureComponentHooks; diff --git a/tgui-next/packages/tgui/components/ProgressBar.js b/tgui-next/packages/tgui/components/ProgressBar.js deleted file mode 100644 index e58bfa3869..0000000000 --- a/tgui-next/packages/tgui/components/ProgressBar.js +++ /dev/null @@ -1,50 +0,0 @@ -import { classes, pureComponentHooks } from 'common/react'; -import { clamp, toFixed } from 'common/math'; - -export const ProgressBar = props => { - const { - value, - minValue = 0, - maxValue = 1, - ranges = {}, - content, - children, - } = props; - const scaledValue = (value - minValue) / (maxValue - minValue); - const hasContent = content !== undefined || children !== undefined; - let { color } = props; - // Cycle through ranges in key order to determine progressbar color. - if (!color) { - for (let rangeName of Object.keys(ranges)) { - const range = ranges[rangeName]; - if (range && value >= range[0] && value <= range[1]) { - color = rangeName; - break; - } - } - } - // Default color - if (!color) { - color = 'default'; - } - return ( -
        -
        -
        - {hasContent && content} - {hasContent && children} - {!hasContent && toFixed(scaledValue * 100) + '%'} -
        -
        - ); -}; - -ProgressBar.defaultHooks = pureComponentHooks; diff --git a/tgui-next/packages/tgui/components/Tabs.js b/tgui-next/packages/tgui/components/Tabs.js deleted file mode 100644 index b3d02ef820..0000000000 --- a/tgui-next/packages/tgui/components/Tabs.js +++ /dev/null @@ -1,135 +0,0 @@ -import { classes, normalizeChildren } from 'common/react'; -import { Component } from 'inferno'; -import { Box } from './Box'; -import { Button } from './Button'; - -// A magic value for enforcing type safety -const TAB_MAGIC_TYPE = 'Tab'; - -const validateTabs = tabs => { - for (let tab of tabs) { - if (!tab.props || tab.props.__type__ !== TAB_MAGIC_TYPE) { - const json = JSON.stringify(tab, null, 2); - throw new Error(' only accepts children of type .' - + 'This is what we received: ' + json); - } - } -}; - -export class Tabs extends Component { - constructor(props) { - super(props); - this.state = { - activeTabKey: null, - }; - } - - getActiveTab() { - const { state, props } = this; - const tabs = normalizeChildren(props.children); - validateTabs(tabs); - // Get active tab - let activeTabKey = props.activeTab || state.activeTabKey; - // Verify that active tab exists - let activeTab = tabs - .find(tab => { - const key = tab.key || tab.props.label; - return key === activeTabKey; - }); - // Set first tab as the active tab - if (!activeTab) { - activeTab = tabs[0]; - activeTabKey = activeTab && (activeTab.key || activeTab.props.label); - } - return { - tabs, - activeTab, - activeTabKey, - }; - } - - render() { - const { props } = this; - const { - className, - vertical, - children, - ...rest - } = props; - const { - tabs, - activeTab, - activeTabKey, - } = this.getActiveTab(); - // Retrieve tab content - let content = null; - if (activeTab) { - content = activeTab.props.content || activeTab.props.children; - } - // Get children by calling a wrapper function - if (typeof content === 'function') { - content = content(activeTabKey); - } - return ( - -
        - {tabs.map(tab => { - const { - className, - label, - content, // ignored - children, // ignored - onClick, - highlight, - ...rest - } = tab.props; - const key = tab.key || tab.props.label; - const active = tab.active || key === activeTabKey; - return ( - - ); - })} -
        -
        - {content || null} -
        -
        - ); - } -} - -/** - * A dummy component, which is used for carrying props for the - * tab container. - */ -export const Tab = props => null; - -Tab.defaultProps = { - __type__: TAB_MAGIC_TYPE, -}; - -Tabs.Tab = Tab; diff --git a/tgui-next/packages/tgui/components/TitleBar.js b/tgui-next/packages/tgui/components/TitleBar.js deleted file mode 100644 index f0a5040500..0000000000 --- a/tgui-next/packages/tgui/components/TitleBar.js +++ /dev/null @@ -1,51 +0,0 @@ -import { classes, pureComponentHooks } from 'common/react'; -import { toTitleCase } from 'common/string'; -import { tridentVersion } from '../byond'; -import { UI_DISABLED, UI_INTERACTIVE, UI_UPDATE } from '../constants'; -import { Icon } from './Icon'; - -const statusToColor = status => { - switch (status) { - case UI_INTERACTIVE: - return 'good'; - case UI_UPDATE: - return 'average'; - case UI_DISABLED: - default: - return 'bad'; - } -}; - -export const TitleBar = props => { - const { className, title, status, fancy, onDragStart, onClose } = props; - return ( -
        - -
        - {title === title.toLowerCase() ? toTitleCase(title) : title} -
        -
        fancy && onDragStart(e)} /> - {!!fancy && ( -
        - {tridentVersion <= 4 ? 'x' : '×'} -
        - )} -
        - ); -}; - -TitleBar.defaultHooks = pureComponentHooks; diff --git a/tgui-next/packages/tgui/components/Toast.js b/tgui-next/packages/tgui/components/Toast.js deleted file mode 100644 index d3b9d603de..0000000000 --- a/tgui-next/packages/tgui/components/Toast.js +++ /dev/null @@ -1,57 +0,0 @@ -import { pureComponentHooks } from 'common/react'; - -export const Toast = props => { - const { content, children } = props; - return ( -
        - {content} - {children} -
        - ); -}; - -Toast.defaultHooks = pureComponentHooks; - -let toastTimeout; - -/** - * Shows a toast at the bottom of the screen. - * - * Takes the store's dispatch function, and text as a second argument. - */ -export const showToast = (dispatch, text) => { - if (toastTimeout) { - clearTimeout(toastTimeout); - } - toastTimeout = setTimeout(() => { - toastTimeout = undefined; - dispatch({ - type: 'hideToast', - }); - }, 5000); - dispatch({ - type: 'showToast', - payload: { text }, - }); -}; - -export const toastReducer = (state, action) => { - const { type, payload } = action; - - if (type === 'showToast') { - const { text } = payload; - return { - ...state, - toastText: text, - }; - } - - if (type === 'hideToast') { - return { - ...state, - toastText: null, - }; - } - - return state; -}; diff --git a/tgui-next/packages/tgui/interfaces/Achievements.js b/tgui-next/packages/tgui/interfaces/Achievements.js deleted file mode 100644 index 6e2ad7a599..0000000000 --- a/tgui-next/packages/tgui/interfaces/Achievements.js +++ /dev/null @@ -1,134 +0,0 @@ -import { useBackend } from '../backend'; -import { Box, Icon, Table, Tabs } from '../components'; - -export const Achievement = props => { - const { - name, - desc, - icon_class, - value, - } = props; - return ( - - - - - -

        {name}

        - {desc} - - - - ); -}; - -export const Score = props => { - const { - name, - desc, - icon_class, - value, - } = props; - return ( - - - - - -

        {name}

        - {desc} - 0 ? 'good' : 'bad'} - content={value > 0 ? `Earned ${value} times` : 'Locked'} /> - - - ); -}; - -export const Achievements = props => { - const { data } = useBackend(props); - return ( - - {data.categories.map(category => ( - - - {data.achievements - .filter(x => x.category === category) - .map(achievement => { - if (achievement.score) { - return ( - - ); - } - return ( - - ); - })} - - - ))} - - - {data.highscore.map(highscore => ( - - - - - # - - - Key - - - Score - - - {Object.keys(highscore.scores).map((key, index) => ( - - - {index+1} - - - {index === 0 && ( - - )} - {key} - {index === 0 && ( - - )} - - - {highscore.scores[key]} - - - ))} -
        -
        - ))} -
        -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/AiAirlock.js b/tgui-next/packages/tgui/interfaces/AiAirlock.js deleted file mode 100644 index 55a3cd4a22..0000000000 --- a/tgui-next/packages/tgui/interfaces/AiAirlock.js +++ /dev/null @@ -1,196 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Button, LabeledList, Section } from '../components'; - -export const AiAirlock = props => { - const { act, data } = useBackend(props); - const dangerMap = { - 2: { - color: 'good', - localStatusText: 'Offline', - }, - 1: { - color: 'average', - localStatusText: 'Caution', - }, - 0: { - color: 'bad', - localStatusText: 'Optimal', - }, - }; - const statusMain = dangerMap[data.power.main] || dangerMap[0]; - const statusBackup = dangerMap[data.power.backup] || dangerMap[0]; - const statusElectrify = dangerMap[data.shock] || dangerMap[0]; - return ( - -
        - - act('disrupt-main')} /> - )}> - {data.power.main ? 'Online' : 'Offline'} - {' '} - {(!data.wires.main_1 || !data.wires.main_2) - && '[Wires have been cut!]' - || (data.power.main_timeleft > 0 - && `[${data.power.main_timeleft}s]`)} - - act('disrupt-backup')} /> - )}> - {data.power.backup ? 'Online' : 'Offline'} - {' '} - {(!data.wires.backup_1 || !data.wires.backup_2) - && '[Wires have been cut!]' - || (data.power.backup_timeleft > 0 - && `[${data.power.backup_timeleft}s]`)} - - -
        -
        - - act('idscan-toggle')} /> - )}> - {!data.wires.id_scanner && '[Wires have been cut!]'} - - act('emergency-toggle')} /> - )} /> - - act('bolt-toggle')} /> - )}> - {!data.wires.bolts && '[Wires have been cut!]'} - - act('light-toggle')} /> - )}> - {!data.wires.lights && '[Wires have been cut!]'} - - act('safe-toggle')} /> - )}> - {!data.wires.safe && '[Wires have been cut!]'} - - act('speed-toggle')} /> - )}> - {!data.wires.timing && '[Wires have been cut!]'} - - - act('open-close')} /> - )}> - {!!(data.locked || data.welded) && ( - - [Door is {data.locked ? 'bolted' : ''} - {(data.locked && data.welded) ? ' and ' : ''} - {data.welded ? 'welded' : ''}!] - - )} - - -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/AirlockElectronics.js b/tgui-next/packages/tgui/interfaces/AirlockElectronics.js deleted file mode 100644 index f42afd1de2..0000000000 --- a/tgui-next/packages/tgui/interfaces/AirlockElectronics.js +++ /dev/null @@ -1,138 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Box, Button, LabeledList, Section, Tabs } from '../components'; - -export const AirlockElectronics = props => { - const { act, data } = useBackend(props); - const regions = data.regions || []; - - const diffMap = { - 0: { - icon: 'times-circle', - }, - 1: { - icon: 'stop-circle', - }, - 2: { - icon: 'check-circle', - }, - }; - - const checkAccessIcon = accesses => { - let oneAccess = false; - let oneInaccess = false; - - accesses.forEach(element => { - if (element.req) { - oneAccess = true; - } - else { - oneInaccess = true; - } - }); - - if (!oneAccess && oneInaccess) { - return 0; - } - else if (oneAccess && oneInaccess) { - return 1; - } - else { - return 2; - } - }; - - return ( - -
        - - -
        -
        - - - {regions.map(region => { - const { name } = region; - const accesses = region.accesses || []; - const icon = diffMap[checkAccessIcon(accesses)].icon; - return ( - - {() => accesses.map(access => ( - -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/AtmosAlertConsole.js b/tgui-next/packages/tgui/interfaces/AtmosAlertConsole.js deleted file mode 100644 index 3e8728aab7..0000000000 --- a/tgui-next/packages/tgui/interfaces/AtmosAlertConsole.js +++ /dev/null @@ -1,44 +0,0 @@ -import { useBackend } from '../backend'; -import { Button, Section } from '../components'; - -export const AtmosAlertConsole = props => { - const { act, data } = useBackend(props); - const priorityAlerts = data.priority || []; - const minorAlerts = data.minor || []; - return ( -
        -
          - {priorityAlerts.length > 0 ? ( - priorityAlerts.map(alert => ( -
        • -
        • - )) - ) : ( -
        • - No Priority Alerts -
        • - )} - {minorAlerts.length > 0 ? ( - minorAlerts.map(alert => ( -
        • -
        • - )) - ) : ( -
        • - No Minor Alerts -
        • - )} -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/AtmosControlConsole.js b/tgui-next/packages/tgui/interfaces/AtmosControlConsole.js deleted file mode 100644 index 80c23d434b..0000000000 --- a/tgui-next/packages/tgui/interfaces/AtmosControlConsole.js +++ /dev/null @@ -1,100 +0,0 @@ -import { map } from 'common/collections'; -import { toFixed } from 'common/math'; -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Button, LabeledList, NumberInput, Section } from '../components'; - -export const AtmosControlConsole = props => { - const { act, data } = useBackend(props); - const sensors = data.sensors || []; - return ( - -
        - {sensors.map(sensor => { - const gases = sensor.gases || {}; - return ( -
        - - - {toFixed(sensor.pressure, 2) + ' kPa'} - - {!!sensor.temperature && ( - - {toFixed(sensor.temperature, 2) + ' K'} - - )} - {map((gasPercent, gasId) => { - return ( - - {toFixed(gasPercent, 2) + '%'} - - ); - })(gases)} - -
        - ); - })} -
        - {data.tank && ( -
        act('reconnect')} /> - )}> - - -
        - )} -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/AtmosFilter.js b/tgui-next/packages/tgui/interfaces/AtmosFilter.js deleted file mode 100644 index 35bbf34686..0000000000 --- a/tgui-next/packages/tgui/interfaces/AtmosFilter.js +++ /dev/null @@ -1,52 +0,0 @@ -import { useBackend } from '../backend'; -import { Button, LabeledList, NumberInput, Section } from '../components'; -import { getGasLabel } from '../constants'; - -export const AtmosFilter = props => { - const { act, data } = useBackend(props); - const filterTypes = data.filter_types || []; - return ( -
        - - -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/AtmosMixer.js b/tgui-next/packages/tgui/interfaces/AtmosMixer.js deleted file mode 100644 index a944bfb686..0000000000 --- a/tgui-next/packages/tgui/interfaces/AtmosMixer.js +++ /dev/null @@ -1,66 +0,0 @@ -import { useBackend } from '../backend'; -import { Button, LabeledList, NumberInput, Section } from '../components'; - -export const AtmosMixer = props => { - const { act, data } = useBackend(props); - return ( -
        - - -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/AtmosPump.js b/tgui-next/packages/tgui/interfaces/AtmosPump.js deleted file mode 100644 index 01c50de4d4..0000000000 --- a/tgui-next/packages/tgui/interfaces/AtmosPump.js +++ /dev/null @@ -1,63 +0,0 @@ -import { useBackend } from '../backend'; -import { Button, LabeledList, NumberInput, Section } from '../components'; - -export const AtmosPump = props => { - const { act, data } = useBackend(props); - return ( -
        - - -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/AtmosRelief.js b/tgui-next/packages/tgui/interfaces/AtmosRelief.js deleted file mode 100644 index 4654ec6582..0000000000 --- a/tgui-next/packages/tgui/interfaces/AtmosRelief.js +++ /dev/null @@ -1,54 +0,0 @@ -import { useBackend } from '../backend'; -import { Button, LabeledList, NumberInput, Section } from '../components'; - -export const AtmosRelief = props => { - const { act, data } = useBackend(props); - return ( -
        - - - act('open_pressure', { - open_pressure: value, - })} /> -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/BankMachine.js b/tgui-next/packages/tgui/interfaces/BankMachine.js deleted file mode 100644 index a3d52097ec..0000000000 --- a/tgui-next/packages/tgui/interfaces/BankMachine.js +++ /dev/null @@ -1,33 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Button, LabeledList, NoticeBox, Section } from '../components'; - -export const BankMachine = props => { - const { act, data } = useBackend(props); - const { - current_balance, - siphoning, - station_name, - } = data; - return ( - -
        - - act(siphoning ? 'halt' : 'siphon')} /> - )}> - {current_balance + ' cr'} - - -
        - - Authorized personnel only - -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/Bepis.js b/tgui-next/packages/tgui/interfaces/Bepis.js deleted file mode 100644 index 71ba5c8cb6..0000000000 --- a/tgui-next/packages/tgui/interfaces/Bepis.js +++ /dev/null @@ -1,112 +0,0 @@ -import { multiline } from 'common/string'; -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { Section, LabeledList, Button, NumberInput, Box, Grid } from '../components'; - -export const Bepis = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const { - amount, - } = data; - return ( -
        -
        act(ref, 'toggle_power')} /> - )}> - All you need to know about the B.E.P.I.S. and you! - The B.E.P.I.S. performs hundreds of tests a second - using electrical and financial resources to invent - new products, or discover new technologies otherwise - overlooked for being too risky or too niche to produce! -
        -
        act(ref, 'account_reset')} /> - )}> - Console is currently being operated - by {data.account_owner ? data.account_owner : 'no one'}. -
        - - -
        - - - {data.stored_cash} - - - {data.accuracy_percentage}% - - - {data.positive_cash_offset} - - - {data.negative_cash_offset} - - - act(ref, 'amount', { - amount: value, - })} /> - - -
        - -
        - - - - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/BluespaceArtillery.js b/tgui-next/packages/tgui/interfaces/BluespaceArtillery.js deleted file mode 100644 index b9f07eabe9..0000000000 --- a/tgui-next/packages/tgui/interfaces/BluespaceArtillery.js +++ /dev/null @@ -1,78 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Box, Button, LabeledList, NoticeBox, Section } from '../components'; - -export const BluespaceArtillery = props => { - const { act, data } = useBackend(props); - const { - notice, - connected, - unlocked, - target, - } = data; - return ( - - {!!notice && ( - - {notice} - - )} - {connected ? ( - -
        act('recalibrate')} /> - )}> - - {target || 'No Target Set'} - -
        -
        - {unlocked ? ( - -
        -
        - ) : ( -
        - - -
        - )} -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/BorgPanel.js b/tgui-next/packages/tgui/interfaces/BorgPanel.js deleted file mode 100644 index 7cc4c860e6..0000000000 --- a/tgui-next/packages/tgui/interfaces/BorgPanel.js +++ /dev/null @@ -1,135 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Box, Button, LabeledList, ProgressBar, Section } from '../components'; - -export const BorgPanel = props => { - const { act, data } = useBackend(props); - const borg = data.borg || {}; - const cell = data.cell || {}; - const cellPercent = cell.charge / cell.maxcharge; - const channels = data.channels || []; - const modules = data.modules || []; - const upgrades = data.upgrades || []; - const ais = data.ais || []; - const laws = data.laws || []; - return ( - -
        act('rename')} /> - )}> - - -
        -
        act('toggle_lawupdate')} /> - )}> - {laws.map(law => ( - - {law} - - ))} -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/BrigTimer.js b/tgui-next/packages/tgui/interfaces/BrigTimer.js deleted file mode 100644 index a83d643334..0000000000 --- a/tgui-next/packages/tgui/interfaces/BrigTimer.js +++ /dev/null @@ -1,55 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Button, Section } from '../components'; - -export const BrigTimer = props => { - const { act, data } = useBackend(props); - return ( -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/Canister.js b/tgui-next/packages/tgui/interfaces/Canister.js deleted file mode 100644 index 0e2810e290..0000000000 --- a/tgui-next/packages/tgui/interfaces/Canister.js +++ /dev/null @@ -1,121 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { AnimatedNumber, Box, Button, LabeledList, NoticeBox, ProgressBar, Section } from '../components'; - -export const Canister = props => { - const { act, data } = useBackend(props); - return ( - - - The regulator {data.hasHoldingTank ? 'is' : 'is not'} connected - to a tank. - -
        act('relabel')} /> - )}> - - - kPa - - - {!!data.isPrototype && ( - -
        - -
        - - - - kPa - - - -
        - -
        act('eject')} /> - )}> - {!!data.hasHoldingTank && ( - - - {data.holdingTank.name} - - - kPa - - - )} - {!data.hasHoldingTank && ( - - No Holding Tank - - )} -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/Cargo.js b/tgui-next/packages/tgui/interfaces/Cargo.js deleted file mode 100644 index 85a528d901..0000000000 --- a/tgui-next/packages/tgui/interfaces/Cargo.js +++ /dev/null @@ -1,363 +0,0 @@ -import { map } from 'common/collections'; -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { AnimatedNumber, Box, Button, LabeledList, Section, Tabs } from '../components'; -import { InterfaceLockNoticeBox } from './common/InterfaceLockNoticeBox'; - -export const Cargo = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - const supplies = data.supplies || {}; - const requests = data.requests || []; - const cart = data.cart || []; - - const cartTotalAmount = cart - .reduce((total, entry) => total + entry.cost, 0); - - const cartButtons = !data.requestonly && ( - - - {cart.length === 0 && 'Cart is empty'} - {cart.length === 1 && '1 item'} - {cart.length >= 2 && cart.length + ' items'} - {' '} - {cartTotalAmount > 0 && `(${cartTotalAmount} cr)`} - - - - ))} - - - - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/ChemReactionChamber.js b/tgui-next/packages/tgui/interfaces/ChemReactionChamber.js deleted file mode 100644 index 8c829258ec..0000000000 --- a/tgui-next/packages/tgui/interfaces/ChemReactionChamber.js +++ /dev/null @@ -1,98 +0,0 @@ -import { Component } from 'inferno'; -import { act } from '../byond'; -import { Box, Button, LabeledList, NumberInput, Section, Input } from '../components'; -import { map } from 'common/collections'; -import { classes } from 'common/react'; - - -export class ChemReactionChamber extends Component { - constructor() { - super(); - this.state = { - reagentName: "", - reagentQuantity: 1, - }; - } - - setReagentName(reagentName) { - this.setState({ - reagentName, - }); - } - - setReagentQuantity(reagentQuantity) { - this.setState({ - reagentQuantity, - }); - } - - render() { - const { state } = this.props; - const { config, data } = state; - const { ref } = config; - const emptying = data.emptying; - const reagents = data.reagents || []; - return ( -
        - {emptying ? "Emptying" : "Filling"} - - )} > - - - - this.setReagentName(value)} /> - - - this.setReagentQuantity(value)} /> - -
        - ); - } -} diff --git a/tgui-next/packages/tgui/interfaces/ChemSplitter.js b/tgui-next/packages/tgui/interfaces/ChemSplitter.js deleted file mode 100644 index 8e64c43e0f..0000000000 --- a/tgui-next/packages/tgui/interfaces/ChemSplitter.js +++ /dev/null @@ -1,48 +0,0 @@ -import { toFixed } from 'common/math'; -import { useBackend } from '../backend'; -import { LabeledList, NumberInput, Section } from '../components'; - -export const ChemSplitter = props => { - const { act, data } = useBackend(props); - const { - straight, - side, - max_transfer, - } = data; - return ( -
        - - - toFixed(value, 2)} - step={0.05} - stepPixelSize={4} - onChange={(e, value) => act('set_amount', { - target: 'straight', - amount: value, - })} /> - - - toFixed(value, 2)} - step={0.05} - stepPixelSize={4} - onChange={(e, value) => act('set_amount', { - target: 'side', - amount: value, - })} /> - - -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/ChemSynthesizer.js b/tgui-next/packages/tgui/interfaces/ChemSynthesizer.js deleted file mode 100644 index df56dfdc07..0000000000 --- a/tgui-next/packages/tgui/interfaces/ChemSynthesizer.js +++ /dev/null @@ -1,42 +0,0 @@ -import { toFixed } from 'common/math'; -import { useBackend } from '../backend'; -import { Box, Button, Section } from '../components'; - -export const ChemSynthesizer = props => { - const { act, data } = useBackend(props); - const { - amount, - current_reagent, - chemicals = [], - possible_amounts = [], - } = data; - return ( -
        - - {possible_amounts.map(possible_amount => ( -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/CodexGigas.js b/tgui-next/packages/tgui/interfaces/CodexGigas.js deleted file mode 100644 index f96ce9380b..0000000000 --- a/tgui-next/packages/tgui/interfaces/CodexGigas.js +++ /dev/null @@ -1,98 +0,0 @@ -import { useBackend } from '../backend'; -import { Button, LabeledList, Section } from '../components'; - -// TODO: refactor the backend of this it's a trainwreck -export const CodexGigas = props => { - const { act, data } = useBackend(props); - const prefixes = [ - "Dark", - "Hellish", - "Fallen", - "Fiery", - "Sinful", - "Blood", - "Fluffy", - ]; - const titles = [ - "Lord", - "Prelate", - "Count", - "Viscount", - "Vizier", - "Elder", - "Adept", - ]; - const names = [ - "hal", - "ve", - "odr", - "neit", - "ci", - "quon", - "mya", - "folth", - "wren", - "geyr", - "hil", - "niet", - "twou", - "phi", - "coa", - ]; - const suffixes = [ - "the Red", - "the Soulless", - "the Master", - "the Lord of all things", - "Jr.", - ]; - return ( -
        - {data.name} - - - {prefixes.map(prefix => ( -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/ComputerFabricator.js b/tgui-next/packages/tgui/interfaces/ComputerFabricator.js deleted file mode 100644 index 87366f6f73..0000000000 --- a/tgui-next/packages/tgui/interfaces/ComputerFabricator.js +++ /dev/null @@ -1,403 +0,0 @@ -import { multiline } from 'common/string'; -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Box, Button, Grid, Section, Table, Tooltip } from '../components'; - -export const ComputerFabricator = props => { - const { state } = props; - const { act, data } = useBackend(props); - return ( - -
        - Your perfect device, only three steps away... -
        - {data.state !== 0 && ( - - - - )} -
        - - {programs.map(program => ( - - -
        -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/NtosNetChat.js b/tgui-next/packages/tgui/interfaces/NtosNetChat.js deleted file mode 100644 index e6b2ff5f9d..0000000000 --- a/tgui-next/packages/tgui/interfaces/NtosNetChat.js +++ /dev/null @@ -1,170 +0,0 @@ -import { useBackend } from '../backend'; -import { AnimatedNumber, Box, Button, Grid, LabeledList, ProgressBar, Section, Input, Table, Icon, Flex } from '../components'; -import { Fragment } from 'inferno'; -import { createLogger } from '../logging'; - -const logger = createLogger('ntos chat'); - -export const NtosNetChat = props => { - const { act, data } = useBackend(props); - - const { - can_admin, - adminmode, - authed, - username, - active_channel, - is_operator, - all_channels = [], - clients = [], - messages = [], - } = data; - - const in_channel = (active_channel !== null); - const authorized = (authed || adminmode); - - return ( -
        - - - - - act('PRG_newchannel', { - new_channel_name: value, - })} /> - {all_channels.map(channel => ( -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/NtosWrapper.js b/tgui-next/packages/tgui/interfaces/NtosWrapper.js deleted file mode 100644 index b342883e79..0000000000 --- a/tgui-next/packages/tgui/interfaces/NtosWrapper.js +++ /dev/null @@ -1,109 +0,0 @@ -import { useBackend } from '../backend'; -import { Box, Button } from '../components'; -import { refocusLayout } from '../refocus'; - -export const NtosWrapper = props => { - const { children } = props; - const { act, data } = useBackend(props); - const { - PC_batteryicon, - PC_showbatteryicon, - PC_batterypercent, - PC_ntneticon, - PC_apclinkicon, - PC_stationtime, - PC_programheaders = [], - PC_showexitprogram, - } = data; - return ( -
        -
        { - refocusLayout(); - }}> -
        - - {PC_stationtime} - - - NtOS - -
        -
        - {PC_programheaders.map(header => ( - - - - ))} - - {PC_ntneticon && ( - - )} - - {!!PC_showbatteryicon && PC_batteryicon && ( - - {PC_batteryicon && ( - - )} - {PC_batterypercent && ( - PC_batterypercent - )} - - )} - {PC_apclinkicon && ( - - - - )} - {!!PC_showexitprogram && ( -
        -
        -
        - {children} -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/NuclearBomb.js b/tgui-next/packages/tgui/interfaces/NuclearBomb.js deleted file mode 100644 index 419fa7473e..0000000000 --- a/tgui-next/packages/tgui/interfaces/NuclearBomb.js +++ /dev/null @@ -1,121 +0,0 @@ -import { classes } from 'common/react'; -import { useBackend } from '../backend'; -import { Box, Button, Flex, Grid, Icon } from '../components'; - -// This ui is so many manual overrides and !important tags -// and hand made width sets that changing pretty much anything -// is going to require a lot of tweaking it get it looking correct again -// I'm sorry, but it looks bangin -const NukeKeypad = props => { - const { act } = useBackend(props); - const keypadKeys = [ - ['1', '4', '7', 'C'], - ['2', '5', '8', '0'], - ['3', '6', '9', 'E'], - ]; - return ( - - - {keypadKeys.map(keyColumn => ( - - {keyColumn.map(key => ( - - - - {data.sheets} - {(data.sheets >= 1) && ( - - )} - - - - - - {data.current_heat < 100 ? ( - Nominal - ) : ( - data.current_heat < 200 ? ( - Caution - ) : ( - DANGER - ) - )} - - - -
        - - - {data.power_output} - - - - - - - - {data.connected ? data.power_available : "Unconnected"} - - - -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/Radio.js b/tgui-next/packages/tgui/interfaces/Radio.js deleted file mode 100644 index e335cf1cac..0000000000 --- a/tgui-next/packages/tgui/interfaces/Radio.js +++ /dev/null @@ -1,108 +0,0 @@ -import { map } from 'common/collections'; -import { toFixed } from 'common/math'; -import { useBackend } from '../backend'; -import { Box, Button, LabeledList, NumberInput, Section } from '../components'; -import { RADIO_CHANNELS } from '../constants'; - -export const Radio = props => { - const { act, data } = useBackend(props); - const { - freqlock, - frequency, - minFrequency, - maxFrequency, - listening, - broadcasting, - command, - useCommand, - subspace, - subspaceSwitchable, - } = data; - const tunedChannel = RADIO_CHANNELS - .find(channel => channel.freq === frequency); - const channels = map((value, key) => ({ - name: key, - status: !!value, - }))(data.channels); - return ( -
        - - - {freqlock && ( - - {toFixed(frequency / 10, 1) + ' kHz'} - - ) || ( - toFixed(value, 1)} - onDrag={(e, value) => act('frequency', { - adjust: (value - frequency / 10), - })} /> - )} - {tunedChannel && ( - - [{tunedChannel.name}] - - )} - - -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/RapidPipeDispenser.js b/tgui-next/packages/tgui/interfaces/RapidPipeDispenser.js deleted file mode 100644 index 17e4fd9d15..0000000000 --- a/tgui-next/packages/tgui/interfaces/RapidPipeDispenser.js +++ /dev/null @@ -1,188 +0,0 @@ -import { classes } from 'common/react'; -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Box, Button, ColorBox, Flex, LabeledList, Section, Tabs } from '../components'; - -const ROOT_CATEGORIES = [ - 'Atmospherics', - 'Disposals', - 'Transit Tubes', -]; - -const ICON_BY_CATEGORY_NAME = { - 'Atmospherics': 'wrench', - 'Disposals': 'trash-alt', - 'Transit Tubes': 'bus', - 'Pipes': 'grip-lines', - 'Disposal Pipes': 'grip-lines', - 'Devices': 'microchip', - 'Heat Exchange': 'thermometer-half', - 'Station Equipment': 'microchip', -}; - -const PAINT_COLORS = { - grey: '#bbbbbb', - amethyst: '#a365ff', - blue: '#4466ff', - brown: '#b26438', - cyan: '#48eae8', - dark: '#808080', - green: '#1edd00', - orange: '#ffa030', - purple: '#b535ea', - red: '#ff3333', - violet: '#6e00f6', - yellow: '#ffce26', -}; - -const TOOLS = [ - { - name: 'Dispense', - bitmask: 1, - }, - { - name: 'Connect', - bitmask: 2, - }, - { - name: 'Destroy', - bitmask: 4, - }, - { - name: 'Paint', - bitmask: 8, - }, -]; - -export const RapidPipeDispenser = props => { - const { act, data } = useBackend(props); - const { - category: rootCategoryIndex, - categories = [], - selected_color, - piping_layer, - mode, - } = data; - const previews = data.preview_rows.flatMap(row => row.previews); - return ( - -
        - - - {ROOT_CATEGORIES.map((categoryName, i) => ( -
        - - -
        - {rootCategoryIndex === 0 && ( - - {[1, 2, 3].map(layer => ( - act('piping_layer', { - piping_layer: layer, - })} /> - ))} - - )} - - {previews.map(preview => ( - - ))} - -
        -
        - -
        - - {categories.map(category => ( - - {() => category.recipes.map(recipe => ( - act('pipe_type', { - pipe_type: recipe.pipe_index, - category: category.cat_name, - })} /> - ))} - - ))} - -
        -
        -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/SatelliteControl.js b/tgui-next/packages/tgui/interfaces/SatelliteControl.js deleted file mode 100644 index 73a7f1ffbb..0000000000 --- a/tgui-next/packages/tgui/interfaces/SatelliteControl.js +++ /dev/null @@ -1,45 +0,0 @@ -import { useBackend } from '../backend'; -import { Button, LabeledList, ProgressBar, Section, Table, Box } from '../components'; -import { Fragment } from 'inferno'; -import { LabeledListItem } from '../components/LabeledList'; - -export const SatelliteControl = props => { - const { act, data } = useBackend(props); - const satellites = data.satellites || []; - return ( - - {data.meteor_shield && ( -
        - - - - - -
        - )} -
        - - {satellites.map(satellite => ( - act('toggle', { - id: satellite.id, - })} - /> - ))} - -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/ShuttleManipulator.js b/tgui-next/packages/tgui/interfaces/ShuttleManipulator.js deleted file mode 100644 index 1cc361bc95..0000000000 --- a/tgui-next/packages/tgui/interfaces/ShuttleManipulator.js +++ /dev/null @@ -1,200 +0,0 @@ -import { map } from 'common/collections'; -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Button, LabeledList, Section, Table, Tabs } from '../components'; - -export const ShuttleManipulator = props => { - const { act, data } = useBackend(props); - const shuttles = data.shuttles || []; - const templateObject = data.templates || {}; - const selected = data.selected || {}; - const existingShuttle = data.existing_shuttle || {}; - return ( - - - {() => ( -
        - - {shuttles.map(shuttle => ( - - -
        -
        - )} -
        - - {() => ( -
        - - {map((template, templateId) => { - const templates = template.templates || []; - return ( - - {templates.map(actualTemplate => { - const isSelected = ( - actualTemplate.shuttle_id === selected.shuttle_id - ); - // Whoever made the structure being sent is an asshole - return ( -
        act('select_template', { - shuttle_id: actualTemplate.shuttle_id, - })} /> - )}> - {(!!actualTemplate.description - || !!actualTemplate.admin_notes - ) && ( - - {!!actualTemplate.description && ( - - {actualTemplate.description} - - )} - {!!actualTemplate.admin_notes && ( - - {actualTemplate.admin_notes} - - )} - - )} -
        - ); - })} -
        - ); - })(templateObject)} -
        -
        - )} -
        - -
        - {selected ? ( - -
        - {(!!selected.description || !!selected.admin_notes) && ( - - {!!selected.description && ( - - {selected.description} - - )} - {!!selected.admin_notes && ( - - {selected.admin_notes} - - )} - - )} -
        - {existingShuttle ? ( -
        - - act('jump_to', { - type: 'mobile', - id: existingShuttle.id, - })} /> - )}> - {existingShuttle.status} - {!!existingShuttle.timer && ( - - ({existingShuttle.timeleft}) - - )} - - -
        - ) : ( -
        - )} -
        -
        - - ) : 'No shuttle selected'} -
        - - - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/Signaler.js b/tgui-next/packages/tgui/interfaces/Signaler.js deleted file mode 100644 index c656613141..0000000000 --- a/tgui-next/packages/tgui/interfaces/Signaler.js +++ /dev/null @@ -1,85 +0,0 @@ -import { Grid, NumberInput, Button, Section } from '../components'; -import { useBackend } from '../backend'; -import { toFixed } from 'common/math'; - -export const Signaler = props => { - const { act, data } = useBackend(props); - const { - code, - frequency, - minFrequency, - maxFrequency, - } = data; - - return ( -
        - - - Frequency: - - - toFixed(value, 1)} - width={13} - onDrag={(e, value) => act('freq', { - freq: value, - })} /> - - -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/SkillPanel.js b/tgui-next/packages/tgui/interfaces/SkillPanel.js deleted file mode 100644 index f4ae1625b3..0000000000 --- a/tgui-next/packages/tgui/interfaces/SkillPanel.js +++ /dev/null @@ -1,121 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Box, Button, LabeledList, ProgressBar, Section } from '../components'; - -export const SkillPanel = props => { - const { act, data } = useBackend(props); - const skills = data.skills || []; - const see_mods = data.see_skill_mods; - const skillgreen = { - color: 'lightgreen', - fontWeight: 'bold', - }; - const skillyellow = { - color: '#FFDB58', - fontWeight: 'bold', - }; - return ( -
        act('toggle_mods')} /> - )}> - - {skills.map(skill => ( - - - {skill.desc} -
        - `Modifiers: ${skill.modifiers}` -
        -
        - {!!skill.level_based && ( - - {see_mods ? ( - - Level: [ - - {skill.lvl_mod} - ] - - ) : ( - - Level: [ - - {skill.lvl_base} - ] - - )} -
        - Total Experience: - {see_mods ? ( - [{skill.value_mod} XP] - ) : ( - [{skill.value_base} XP] - )} -
        - XP To Next Level: - {skill.max_lvl !== (see_mods - ? skill.lvl_mod_num - : skill.lvl_base_num) ? ( - - {see_mods ? ( - {skill.xp_next_lvl_mod} - ) : ( - {skill.xp_next_lvl_base} - )} - - ) : ( - - [MAXXED] - - )} -
        - )} - {see_mods ? ( - {skill.mod_readout} - ) : ( - {skill.base_readout} - )} - {see_mods ? ( - - ) : ( - - )} -
        - {!!data.admin && ( - -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/Sleeper.js b/tgui-next/packages/tgui/interfaces/Sleeper.js deleted file mode 100644 index dabf0f355d..0000000000 --- a/tgui-next/packages/tgui/interfaces/Sleeper.js +++ /dev/null @@ -1,181 +0,0 @@ -import { useBackend } from '../backend'; -import { Box, Section, LabeledList, Button, ProgressBar, Flex, AnimatedNumber } from '../components'; -import { Fragment } from 'inferno'; - -export const Sleeper = props => { - const { act, data } = useBackend(props); - - const { - occupied, - open, - occupant = [], - } = data; - - const preSortChems = data.chems || []; - const chems = preSortChems.sort((a, b) => { - const descA = a.name.toLowerCase(); - const descB = b.name.toLowerCase(); - if (descA < descB) { - return -1; - } - if (descA > descB) { - return 1; - } - return 0; - }); - const preSortSynth = data.synthchems || []; - const synthchems = preSortSynth.sort((a, b) => { - const descA = a.name.toLowerCase(); - const descB = b.name.toLowerCase(); - if (descA < descB) { - return -1; - } - if (descA > descB) { - return 1; - } - return 0; - }); - - const damageTypes = [ - { - label: 'Brute', - type: 'bruteLoss', - }, - { - label: 'Burn', - type: 'fireLoss', - }, - { - label: 'Toxin', - type: 'toxLoss', - }, - { - label: 'Oxygen', - type: 'oxyLoss', - }, - ]; - - return ( - -
        - {occupant.stat} - - )}> - {!!occupied && ( - - - - - {damageTypes.map(type => ( - - - - ))} - - - - - {data.blood_status} - - - {occupant.cloneLoss ? 'Damaged' : 'Healthy'} - - - {occupant.brainLoss ? 'Abnormal' : 'Healthy'} - - - - )} -
        -
        - - {data.chemical_list.map(specificChem => ( - - {specificChem.volume} units of {specificChem.name} - - ), - )} - -
        -
        act('door')} /> - )}> - {chems.map(chem => ( -
        -
        - {synthchems.map(chem => ( -
        -
        - {chems.map(chem => ( -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/SmartVend.js b/tgui-next/packages/tgui/interfaces/SmartVend.js deleted file mode 100644 index d0c13ad259..0000000000 --- a/tgui-next/packages/tgui/interfaces/SmartVend.js +++ /dev/null @@ -1,61 +0,0 @@ -import { map } from 'common/collections'; -import { useBackend } from '../backend'; -import { Button, NoticeBox, Section, Table } from '../components'; - -export const SmartVend = props => { - const { act, data } = useBackend(props); - return ( -
        act('Dry')}> - {data.drying ? 'Stop drying' : 'Dry'} - - )}> - {data.contents.length === 0 && ( - - Unfortunately, this {data.name} is empty. - - ) || ( - - - - Item - - - - {data.verb ? data.verb : 'Dispense'} - - - {map((value, key) => ( - - - {value.name} - - - {value.amount} - - -
        - )} -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/Smes.js b/tgui-next/packages/tgui/interfaces/Smes.js deleted file mode 100644 index 7479af5894..0000000000 --- a/tgui-next/packages/tgui/interfaces/Smes.js +++ /dev/null @@ -1,176 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Box, Button, NumberInput, LabeledList, ProgressBar, Section } from '../components'; - -export const Smes = props => { - const { act, data } = useBackend(props); - - let inputState; - if (data.capacityPercent >= 100) { - inputState = 'good'; - } - else if (data.inputting) { - inputState = 'average'; - } - else { - inputState = 'bad'; - } - let outputState; - if (data.outputting) { - outputState = 'good'; - } - else if (data.charge > 0) { - outputState = 'average'; - } - else { - outputState = 'bad'; - } - - return ( - -
        - -
        -
        - - act('tryinput')}> - {data.inputAttempt ? 'Auto' : 'Off'} - - }> - - {data.capacityPercent >= 100 - ? 'Fully Charged' - : data.inputting - ? 'Charging' - : 'Not Charging'} - - - - - - -
        -
        - - act('tryoutput')}> - {data.outputAttempt ? 'On' : 'Off'} - - }> - - {data.outputting - ? 'Sending' - : data.charge > 0 - ? 'Not Sending' - : 'No Charge'} - - - - - - -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/SmokeMachine.js b/tgui-next/packages/tgui/interfaces/SmokeMachine.js deleted file mode 100644 index 16ba078910..0000000000 --- a/tgui-next/packages/tgui/interfaces/SmokeMachine.js +++ /dev/null @@ -1,71 +0,0 @@ -import { useBackend } from '../backend'; -import { Fragment } from 'inferno'; -import { AnimatedNumber, Box, Button, LabeledList, ProgressBar, NoticeBox, Section } from '../components'; - -export const SmokeMachine = props => { - const { act, data } = useBackend(props); - const { - TankContents, - isTankLoaded, - TankCurrentVolume, - TankMaxVolume, - active, - setting, - screen, - maxSetting = [], - } = data; - return ( - -
        act('power')} /> - )}> - - - {' / ' + TankMaxVolume} - - - - - { [1, 2, 3, 4, 5].map(amount => ( -
        -
        act('purge')} /> - )}> - {TankContents.map(chemical => ( - - - {' '} - units of {chemical.name} - - ))} -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/SolarControl.js b/tgui-next/packages/tgui/interfaces/SolarControl.js deleted file mode 100644 index 1cfb4800c0..0000000000 --- a/tgui-next/packages/tgui/interfaces/SolarControl.js +++ /dev/null @@ -1,118 +0,0 @@ -import { toFixed } from 'common/math'; -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Box, Button, Grid, LabeledList, NumberInput, ProgressBar, Section } from '../components'; - -export const SolarControl = props => { - const { act, data } = useBackend(props); - const { - generated, - generated_ratio, - azimuth_current, - azimuth_rate, - max_rotation_rate, - tracking_state, - connected_panels, - connected_tracker, - } = data; - return ( - -
        act('refresh')} /> - )}> - - - - - {connected_tracker ? 'OK' : 'N/A'} - - 0 ? 'good' : 'bad'}> - {connected_panels} - - - - - - - - - - - -
        -
        - - -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/SpaceHeater.js b/tgui-next/packages/tgui/interfaces/SpaceHeater.js deleted file mode 100644 index c44f3e9c47..0000000000 --- a/tgui-next/packages/tgui/interfaces/SpaceHeater.js +++ /dev/null @@ -1,104 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Box, Button, LabeledList, NumberInput, ProgressBar, Section } from '../components'; - -export const SpaceHeater = props => { - const { act, data } = useBackend(props); - return ( - -
        -
        -
        - - - 50 - ? 'bad' - : Math.abs(data.targetTemp - data.currentTemp) > 20 - ? 'average' - : 'good'}> - {data.currentTemp}°C - - - - {data.open && ( - act('target', { - target: value, - })} /> - ) || ( - data.targetTemp + '°C' - )} - - - {!data.open && 'Auto' || ( - -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/SpawnersMenu.js b/tgui-next/packages/tgui/interfaces/SpawnersMenu.js deleted file mode 100644 index 27d8b1f9ff..0000000000 --- a/tgui-next/packages/tgui/interfaces/SpawnersMenu.js +++ /dev/null @@ -1,51 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Box, Button, Section } from '../components'; - -export const SpawnersMenu = props => { - const { act, data } = useBackend(props); - const spawners = data.spawners || []; - return ( -
        - {spawners.map(spawner => ( -
        -
        - ))} -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/SuitStorageUnit.js b/tgui-next/packages/tgui/interfaces/SuitStorageUnit.js deleted file mode 100644 index f858505a37..0000000000 --- a/tgui-next/packages/tgui/interfaces/SuitStorageUnit.js +++ /dev/null @@ -1,111 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Box, Button, Icon, LabeledList, NoticeBox, Section } from '../components'; - -export const SuitStorageUnit = props => { - const { act, data } = useBackend(props); - const { - locked, - open, - safeties, - uv_active, - occupied, - suit, - helmet, - mask, - storage, - } = data; - return ( - - {!!(occupied && safeties) && ( - - Biological entity detected in suit chamber. Please remove - before continuing with operation. - - )} - {uv_active && ( - - Contents are currently being decontaminated. Please wait. - - ) || ( -
        - {!open && ( -
        - )} -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/Tank.js b/tgui-next/packages/tgui/interfaces/Tank.js deleted file mode 100644 index f91ff3af99..0000000000 --- a/tgui-next/packages/tgui/interfaces/Tank.js +++ /dev/null @@ -1,53 +0,0 @@ -import { useBackend } from '../backend'; -import { Button, LabeledList, NumberInput, ProgressBar, Section } from '../components'; - -export const Tank = props => { - const { act, data } = useBackend(props); - return ( -
        - - - - - -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/TankDispenser.js b/tgui-next/packages/tgui/interfaces/TankDispenser.js deleted file mode 100644 index de05a5750b..0000000000 --- a/tgui-next/packages/tgui/interfaces/TankDispenser.js +++ /dev/null @@ -1,34 +0,0 @@ -import { useBackend } from '../backend'; -import { Button, LabeledList, Section } from '../components'; - -export const TankDispenser = props => { - const { act, data } = useBackend(props); - return ( -
        - - act('plasma')} /> - )}> - {data.plasma} - - act('oxygen')} /> - )}> - {data.oxygen} - - -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/TelecommsInteraction.js b/tgui-next/packages/tgui/interfaces/TelecommsInteraction.js deleted file mode 100644 index a67bfdf987..0000000000 --- a/tgui-next/packages/tgui/interfaces/TelecommsInteraction.js +++ /dev/null @@ -1,238 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { toFixed } from 'common/math'; -import { RADIO_CHANNELS } from '../constants'; -import { Button, LabeledList, NumberInput, NoticeBox, Section, Input } from '../components'; - -export const TeleInteract = props => { - const { act, data } = useBackend(props); - const { - notice = "", - multitool = false, - multitool_buf = null, - machine = null, - links = [], - freq_listening = [], - } = data; - const { - power = false, - id = "NULL", - network, - prefab = false, - hidden = false, - isrelay = false, - isbus = false, - } = machine; - return ( - - {!!notice && ( - - {notice} - - )} -
        - - -
        -
        - ) : ( - '' - )} -
        - - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/TelecommsLogBrowser.js b/tgui-next/packages/tgui/interfaces/TelecommsLogBrowser.js deleted file mode 100644 index 4b485a5880..0000000000 --- a/tgui-next/packages/tgui/interfaces/TelecommsLogBrowser.js +++ /dev/null @@ -1,174 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Button, LabeledList, NoticeBox, Section, Tabs, Input } from '../components'; - -export const TeleLogBrowser = props => { - const { act, data } = useBackend(props); - const { - notice, - network = "NULL", - servers, - selected = null, - selected_logs, - } = data; - const operational = (selected && selected.status); - return ( - - {!!notice && ( - - {notice} - - )} -
        - - - act('network', { - 'value': value, - })} /> - - -
        - - -
        - {(servers && servers.length) ? ( - - {servers.map(server => { - return ( - act('viewmachine', { - 'value': server.id, - })} /> - )}> - {`${server.name} (${server.id})`} - - ); - })} - - ) : ( - '404 Servers not found. Have you tried scanning the network?' - )} -
        -
        - -
        - {(operational && selected_logs) ? ( - selected_logs.map(logs => { - return ( -
        - - act('delete', { - 'value': logs.ref, - })} /> - )}> - {logs.name} - - - {logs.input_type} - - {logs.source && ( - - {`[${logs.source.name}] (Job: [${logs.source.job}])`} - - )} - {logs.race && ( - - {logs.race} - - )} - - {logs.message} - - -
        - ); - }) - ) : ( - "No server selected!" - )} -
        -
        -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/TelecommsMonitor.js b/tgui-next/packages/tgui/interfaces/TelecommsMonitor.js deleted file mode 100644 index 2b235d584b..0000000000 --- a/tgui-next/packages/tgui/interfaces/TelecommsMonitor.js +++ /dev/null @@ -1,221 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { RADIO_CHANNELS } from '../constants'; -import { Box, Button, LabeledList, NoticeBox, Section, Tabs, Input } from '../components'; - - -export const Telemonitor = props => { - const { act, data } = useBackend(props); - const { - notice, - network = "NULL", - servers, - selected = null, - selected_servers, - } = data; - const operational = (selected && selected.status); - - return ( - - {!!notice && ( - - {notice} - - )} -
        - - - act('network', { - 'value': value, - })} /> - - -
        - - -
        - {(servers && servers.length) ? ( - - {servers.map(server => { - return ( - act('viewmachine', { - 'value': server.id, - })} /> - )}> - {`${server.name} (${server.id})`} - - ); - })} - - ) : ( - '404 Servers not found. Have you tried scanning the network?' - )} -
        -
        - -
        - - - {operational ? ( - 'Running' - ) : ( - 'Server down!' - )} - - - {operational ? ( // Not to be confused to totaltraffic - selected.traffic <= 1024 ? ( - `${Math.max(selected.traffic, 0)} Gigabytes` - ) : ( - `${Math.round(selected.traffic/1024)} Terrabytes` - ) - ) : ( - '0 Gigabytes' - )} - - - {operational ? ( - selected.netspeed <= 1024 ? ( - `${selected.netspeed} Gigabytes/second` - ) : ( - `${Math.round(selected.netspeed/1024)} Terrabytes/second` - ) - ) : ( - '0 Gigabytes/second' - )} - - - {(operational && selected.long_range_link) ? ( - 'true' - ) : ( - 'false' - )} - - - - {operational && selected.freq_listening.map(thing => { - const valid = RADIO_CHANNELS - .find(channel => channel.freq === thing); - return ( - (valid) ? ( - - {`[${thing}] (${valid.name}) `} - - ) : ( - `[${thing}] ` - ) - ); - })} - - - -
        - {(operational && selected_servers) ? ( - - {selected_servers.map(server => { - return ( - act('viewmachine', { - 'value': server.id, - })} /> - )}> - {`${server.name} (${server.id})`} - - ); - })} - - ) : ( - !operational ? ( - "Server currently down! Cannot fetch the buffer list!" - ) : ( - "Buffer is empty!" - ) - )} -
        -
        -
        -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/TelecommsPDALog.js b/tgui-next/packages/tgui/interfaces/TelecommsPDALog.js deleted file mode 100644 index 914e751d05..0000000000 --- a/tgui-next/packages/tgui/interfaces/TelecommsPDALog.js +++ /dev/null @@ -1,420 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { act as _act } from '../byond'; -import { Button, LabeledList, NoticeBox, Section, Tabs, Input } from '../components'; - -export const TelePDALog = props => { - const { act, data } = useBackend(props); - const { - network, - notice = "", - authenticated = false, - canhack = false, - selected = null, - servers = [], - message_logs = [], - recon_logs = [], - } = data; - const fake_message = data.fake_message || { - 'sender': 'System Administrator', - 'job': 'Admin', - 'recepient': null, - 'message': 'This is a test, please ignore', - }; - const prioritycolorMap = { - 'Normal': 'warning', - 'High': 'bad', - 'Extreme': 'bad', - }; - const valid = (selected && selected.status && authenticated); - - if (data.hacking) { - return ( // should have used en -> jp unicode -> other encoding method->utf8 - - -

        - {"INTRN@L ACfES VIOL�TIa█ DEtE₡TED! Ree3ARcinG A█ \ - BAaKUP RdST�RE PbINT [0xcff32ca] - PLfASE aAIT"} -

        -
        - - {data.borg ? ( - - Brute-forcing for server key.
        - It will take 20 seconds for every character that the password has. -
        - In the meantime, this console can reveal your - true intentions if you let someone access it. - Make sure no humans enter the room during that time. -
        - ) : ( - - QnJ1dGUtZm9yY2luZyBmb3Igc2VydmVyIGtleS48YnI+IEl0IHdpbG
        - wgdGFrZSAyMCBzZWNvbmRzIGZvciBldmVyeSBjaGFyYWN0ZXIgdGhh
        - dCB0aGUgcGFzc3dvcmQgaGFzLiBJbiB0aGUgbWVhbnRpbWUsIHRoaX
        - MgY29uc29sZSBjYW4gcmV2ZWFsIHlvdXIgdHJ1ZSBpbnRlbnRpb25z
        - IGlmIHlvdSBsZXQgc29tZW9uZSBhY2Nlc3MgaXQuIE1ha2Ugc3VyZS
        - BubyBodW1hbnMgZW50ZXIgdGhlIHJvb20gZHVyaW5nIHRoYXQgdGltZS4=
        -
        -
        - )} -
        -
        - ); - } - - return ( - - {!!notice && ( - - {notice} - - )} -
        - - - act('network', { - 'value': value, - })} /> - - -
        - - -
        - {(servers && servers.length) ? ( - - {servers.map(server => { - return ( - act('viewmachine', { - 'value': server.id, - })} /> - )}> - {`${server.name} (${server.id})`} - - ); - })} - - ) : ( - '404 Servers not found. Have you tried scanning the network?' - )} -
        -
        - -
        -
        -
        - -
        -
        -
        - -
        -
        -
        -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/Teleporter.js b/tgui-next/packages/tgui/interfaces/Teleporter.js deleted file mode 100644 index a2edfa9739..0000000000 --- a/tgui-next/packages/tgui/interfaces/Teleporter.js +++ /dev/null @@ -1,69 +0,0 @@ -import { useBackend } from '../backend'; -import { Box, Button, LabeledList, Section } from '../components'; - -export const Teleporter = props => { - const { act, data } = useBackend(props); - const { - calibrated, - calibrating, - power_station, - regime_set, - teleporter_hub, - target, - } = data; - return ( -
        - {!power_station && ( - - No power station linked. - - ) || (!teleporter_hub && ( - - No hub linked. - - )) || ( - - act('regimeset')} /> - )}> - {regime_set} - - act('settarget')} /> - )}> - {target} - - act('calibrate')} /> - )}> - {calibrating && ( - - In Progress - - ) || (calibrated && ( - - Optimal - - ) || ( - - Sub-Optimal - - ))} - - - )} -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/ThermoMachine.js b/tgui-next/packages/tgui/interfaces/ThermoMachine.js deleted file mode 100644 index acb31e34d7..0000000000 --- a/tgui-next/packages/tgui/interfaces/ThermoMachine.js +++ /dev/null @@ -1,77 +0,0 @@ -import { toFixed } from 'common/math'; -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { AnimatedNumber, Button, LabeledList, NumberInput, Section } from '../components'; - -export const ThermoMachine = props => { - const { act, data } = useBackend(props); - return ( - -
        - - - toFixed(value, 2)} /> - {' K'} - - - toFixed(value, 2)} /> - {' kPa'} - - -
        -
        act('power')} /> - )}> - - - act('target', { - target: value, - })} /> - - -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/TurbineComputer.js b/tgui-next/packages/tgui/interfaces/TurbineComputer.js deleted file mode 100644 index 4f632cc149..0000000000 --- a/tgui-next/packages/tgui/interfaces/TurbineComputer.js +++ /dev/null @@ -1,64 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Button, LabeledList, Section } from '../components'; - -export const TurbineComputer = props => { - const { act, data } = useBackend(props); - const operational = Boolean(data.compressor - && !data.compressor_broke - && data.turbine - && !data.turbine_broke); - return ( -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/Uplink.js b/tgui-next/packages/tgui/interfaces/Uplink.js deleted file mode 100644 index 4f2b047c9b..0000000000 --- a/tgui-next/packages/tgui/interfaces/Uplink.js +++ /dev/null @@ -1,186 +0,0 @@ -import { decodeHtmlEntities } from 'common/string'; -import { Component, Fragment } from 'inferno'; -import { act } from '../byond'; -import { Box, Button, Input, Section, Table, Tabs } from '../components'; - -// It's a class because we need to store state in the form of the current -// hovered item, and current search terms -export class Uplink extends Component { - constructor() { - super(); - this.state = { - hoveredItem: {}, - currentSearch: '', - }; - } - - setHoveredItem(hoveredItem) { - this.setState({ - hoveredItem, - }); - } - - setSearchText(currentSearch) { - this.setState({ - currentSearch, - }); - } - - render() { - const { state } = this.props; - const { config, data } = state; - const { ref } = config; - const { - compact_mode, - lockable, - telecrystals, - categories = [], - } = data; - const { hoveredItem, currentSearch } = this.state; - return ( -
        0 ? 'good' : 'bad'}> - {telecrystals} TC - - )} - buttons={( - - Search - this.setSearchText(value)} - ml={1} - mr={1} /> -
        - ); - } -} - -const ItemList = props => { - const { - items, - hoveredItem, - telecrystals, - compact, - onBuy, - onBuyMouseOver, - onBuyMouseOut, - } = props; - const hoveredCost = hoveredItem && hoveredItem.cost || 0; - if (compact) { - return ( - - {items.map(item => { - const notSameItem = hoveredItem && hoveredItem.name !== item.name; - const notEnoughHovered = telecrystals - hoveredCost < item.cost; - const disabledDueToHovered = notSameItem && notEnoughHovered; - return ( - - - {decodeHtmlEntities(item.name)} - - -
        - ); - } - return items.map(item => { - const notSameItem = hoveredItem && hoveredItem.name !== item.name; - const notEnoughHovered = telecrystals - hoveredCost < item.cost; - const disabledDueToHovered = notSameItem && notEnoughHovered; - return ( -
        onBuyMouseOver(item)} - onmouseout={() => onBuyMouseOut(item)} - onClick={() => onBuy(item)} /> - )}> - {decodeHtmlEntities(item.desc)} -
        - ); - }); -}; diff --git a/tgui-next/packages/tgui/interfaces/VaultController.js b/tgui-next/packages/tgui/interfaces/VaultController.js deleted file mode 100644 index 64e001d49a..0000000000 --- a/tgui-next/packages/tgui/interfaces/VaultController.js +++ /dev/null @@ -1,32 +0,0 @@ -import { toFixed } from 'common/math'; -import { useBackend } from '../backend'; -import { Button, LabeledList, ProgressBar, Section } from '../components'; - -export const VaultController = props => { - const { act, data } = useBackend(props); - return ( -
        act('togglelock')} /> - )}> - - - - - -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/Vending.js b/tgui-next/packages/tgui/interfaces/Vending.js deleted file mode 100644 index 2965dd97d1..0000000000 --- a/tgui-next/packages/tgui/interfaces/Vending.js +++ /dev/null @@ -1,132 +0,0 @@ -import { Fragment } from 'inferno'; -import { act } from '../byond'; -import { Section, Box, Button, Table } from '../components'; -import { classes } from 'common/react'; - -export const Vending = props => { - const { state } = props; - const { config, data } = state; - const { ref } = config; - let inventory; - let custom = false; - if (data.vending_machine_input) { - inventory = data.vending_machine_input; - custom = true; - } else if (data.extended_inventory) { - inventory = [ - ...data.product_records, - ...data.coin_records, - ...data.hidden_records, - ]; - } else { - inventory = [ - ...data.product_records, - ...data.coin_records, - ]; - } - return ( - - {!!data.onstation && ( -
        - {data.user && ( - - Welcome, {data.user.name}, - {' '} - {data.user.job || "Unemployed"}! -
        - Your balance is {data.user.cash} credits. -
        - ) || ( - - No registered ID card!
        - Please contact your local HoP! -
        - )} -
        - )} -
        - - {inventory.map((product => { - const free = ( - !data.onstation - || product.price === 0 - ); - const to_pay = (!product.premium - ? Math.round(product.price * data.cost_mult) - : product.price - ); - const pay_text = (!product.premium - ? to_pay + ' cr' + data.cost_text - : to_pay + ' cr' - ); - return ( - - - {product.base64 ? ( - - ) : ( - - )} - - - {product.name} - - - - {data.stock[product.name]} in stock - - - - {custom && ( -
        -
        -
        - ); -}; diff --git a/tgui-next/packages/tgui/interfaces/Wires.js b/tgui-next/packages/tgui/interfaces/Wires.js deleted file mode 100644 index f33b261738..0000000000 --- a/tgui-next/packages/tgui/interfaces/Wires.js +++ /dev/null @@ -1,59 +0,0 @@ -import { Fragment } from 'inferno'; -import { useBackend } from '../backend'; -import { Box, Button, LabeledList, Section } from '../components'; - -export const Wires = props => { - const { act, data } = useBackend(props); - const wires = data.wires || []; - const statuses = data.status || []; - return ( - -
        - - {wires.map(wire => ( - -
        - {!!statuses.length && ( -
        - {statuses.map(status => ( - - {status} - - ))} -
        - )} -
        - ); -}; diff --git a/tgui-next/packages/tgui/layout.js b/tgui-next/packages/tgui/layout.js deleted file mode 100644 index dcaba87204..0000000000 --- a/tgui-next/packages/tgui/layout.js +++ /dev/null @@ -1,95 +0,0 @@ -import { classes } from 'common/react'; -import { decodeHtmlEntities } from 'common/string'; -import { Component, Fragment } from 'inferno'; -import { runCommand, winset } from './byond'; -import { Box, TitleBar } from './components'; -import { Toast } from './components/Toast'; -import { UI_DISABLED, UI_INTERACTIVE } from './constants'; -import { dragStartHandler, resizeStartHandler } from './drag'; -import { releaseHeldKeys } from './hotkeys'; -import { createLogger } from './logging'; -import { refocusLayout } from './refocus'; -import { getRoute } from './routes'; - -const logger = createLogger('Layout'); - -export class Layout extends Component { - componentDidMount() { - refocusLayout(); - } - - render() { - const { props } = this; - const { state, dispatch } = props; - const { config } = state; - const route = getRoute(state); - if (!route) { - return `Component for '${config.interface}' was not found.`; - } - const RoutedComponent = route.component(); - const WrapperComponent = route.wrapper && route.wrapper(); - const { scrollable, theme } = route; - // Render content - let contentElement = ( -
        - - - -
        - ); - // Wrap into the wrapper component - if (WrapperComponent) { - contentElement = ( - - {contentElement} - - ); - } - // Determine when to show dimmer - const showDimmer = config.observer - ? config.status < UI_DISABLED - : config.status < UI_INTERACTIVE; - return ( -
        -
        - { - logger.log('pressed close'); - releaseHeldKeys(); - winset(config.window, 'is-visible', false); - runCommand(`uiclose ${config.ref}`); - }} /> - {contentElement} - {showDimmer && ( -
        - )} - {state.toastText && ( - - )} - {config.fancy && scrollable && ( - -
        -
        -
        - - )} -
        -
        - ); - } -} diff --git a/tgui-next/packages/tgui/polyfills.js b/tgui-next/packages/tgui/polyfills.js deleted file mode 100644 index 0c70827679..0000000000 --- a/tgui-next/packages/tgui/polyfills.js +++ /dev/null @@ -1,5 +0,0 @@ -// This one is necessary for Inferno to do complex DOM patching on IE8. -// Not the fastest one or most spec compliant, but hey, it works! -if (!window.Int32Array) { - window.Int32Array = Array; -} diff --git a/tgui-next/packages/tgui/public/tgui-fallback.html b/tgui-next/packages/tgui/public/tgui-fallback.html deleted file mode 100644 index b9757bac48..0000000000 --- a/tgui-next/packages/tgui/public/tgui-fallback.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - -
        -
        - Loading...
        -
        -
        - - - - - - - - - diff --git a/tgui-next/packages/tgui/public/tgui.bundle.css b/tgui-next/packages/tgui/public/tgui.bundle.css deleted file mode 100644 index 26f8010e06..0000000000 --- a/tgui-next/packages/tgui/public/tgui.bundle.css +++ /dev/null @@ -1 +0,0 @@ -body,html{box-sizing:border-box;height:100%;margin:0}html{overflow:hidden;cursor:default}body{overflow:auto;font-family:Verdana,Geneva,sans-serif;font-size:12px}*,:after,:before{box-sizing:inherit}h1,h2,h3,h4,h5,h6{display:block;margin:0;padding:6px 0}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}h4{font-size:12px}td,th{vertical-align:baseline;text-align:left}.candystripe:nth-child(odd){background-color:rgba(0,0,0,.25)}.color-black{color:#0d0d0d!important}.color-white{color:#fff!important}.color-red{color:#d33!important}.color-orange{color:#f37827!important}.color-yellow{color:#fbd814!important}.color-olive{color:#c0d919!important}.color-green{color:#22be47!important}.color-teal{color:#00c5bd!important}.color-blue{color:#238cdc!important}.color-violet{color:#6c3fcc!important}.color-purple{color:#a93bcd!important}.color-pink{color:#e2439c!important}.color-brown{color:#af6d43!important}.color-grey{color:#7d7d7d!important}.color-good{color:#62b62a!important}.color-average{color:#f1951d!important}.color-bad{color:#d33!important}.color-label{color:#8496ab!important}.color-bg-black{background-color:#000!important}.color-bg-white{background-color:#d9d9d9!important}.color-bg-red{background-color:#bd2020!important}.color-bg-orange{background-color:#d95e0c!important}.color-bg-yellow{background-color:#d9b804!important}.color-bg-olive{background-color:#9aad14!important}.color-bg-green{background-color:#1b9638!important}.color-bg-teal{background-color:#009a93!important}.color-bg-blue{background-color:#1c71b1!important}.color-bg-violet{background-color:#552dab!important}.color-bg-purple{background-color:#8b2baa!important}.color-bg-pink{background-color:#cf2082!important}.color-bg-brown{background-color:#8c5836!important}.color-bg-grey{background-color:#646464!important}.color-bg-good{background-color:#4d9121!important}.color-bg-average{background-color:#cd7a0d!important}.color-bg-bad{background-color:#bd2020!important}.color-bg-label{background-color:#657a94!important}.display-none{display:none}.display-block{display:block}.display-inline{display:inline}.display-inline-block{display:inline-block}.m-0{margin:0}.mx-0{margin-left:0;margin-right:0}.my-0{margin-top:0;margin-bottom:0}.ml-0{margin-left:0}.mt-0{margin-top:0}.mr-0{margin-right:0}.mb-0{margin-bottom:0}.m-1{margin:6px}.mx-1{margin-left:6px;margin-right:6px}.my-1{margin-top:6px;margin-bottom:6px}.ml-1{margin-left:6px}.mt-1{margin-top:6px}.mr-1{margin-right:6px}.mb-1{margin-bottom:6px}.m-2{margin:12px}.mx-2{margin-left:12px;margin-right:12px}.my-2{margin-top:12px;margin-bottom:12px}.ml-2{margin-left:12px}.mt-2{margin-top:12px}.mr-2{margin-right:12px}.mb-2{margin-bottom:12px}.position-relative{position:relative}.position-absolute{position:absolute}.position-fixed{position:fixed}.position-sticky{position:sticky}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.text-baseline{text-align:baseline}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-pre{white-space:pre}.text-bold{font-weight:700}.text-italic{font-style:italic}.text-underline{text-decoration:underline}.BlockQuote{color:#8496ab;border-left:2px solid #8496ab;padding-left:6px}.Button{position:relative;display:inline-block;line-height:20px;padding:0 6px;margin-right:2px;white-space:nowrap;outline:0;border-radius:0;margin-bottom:2px;user-select:none;-ms-user-select:none}.Button:last-child{margin-right:0}.Button .fa,.Button .far,.Button .fas{margin-left:-3px;margin-right:-3px;min-width:16px;text-align:center}.Button--hasContent .fa,.Button--hasContent .far,.Button--hasContent .fas{margin-right:3px}.Button--ellipsis{overflow:hidden;text-overflow:ellipsis}.Button--fluid{display:block;margin-left:0;margin-right:0}.Button--color--black{transition:color 50ms,background-color 50ms;background-color:#000;color:#fff}.Button--color--black:hover{transition:color 0ms,background-color 0ms}.Button--color--black:focus{transition:color .1s,background-color .1s}.Button--color--black:focus,.Button--color--black:hover{background-color:#0a0a0a;color:#fff}.Button--color--white{transition:color 50ms,background-color 50ms;background-color:#d9d9d9;color:#000}.Button--color--white:hover{transition:color 0ms,background-color 0ms}.Button--color--white:focus{transition:color .1s,background-color .1s}.Button--color--white:focus,.Button--color--white:hover{background-color:#f3f3f3;color:#000}.Button--color--red{transition:color 50ms,background-color 50ms;background-color:#bd2020;color:#fff}.Button--color--red:hover{transition:color 0ms,background-color 0ms}.Button--color--red:focus{transition:color .1s,background-color .1s}.Button--color--red:focus,.Button--color--red:hover{background-color:#d52b2b;color:#fff}.Button--color--orange{transition:color 50ms,background-color 50ms;background-color:#d95e0c;color:#fff}.Button--color--orange:hover{transition:color 0ms,background-color 0ms}.Button--color--orange:focus{transition:color .1s,background-color .1s}.Button--color--orange:focus,.Button--color--orange:hover{background-color:#ed6f1d;color:#fff}.Button--color--yellow{transition:color 50ms,background-color 50ms;background-color:#d9b804;color:#000}.Button--color--yellow:hover{transition:color 0ms,background-color 0ms}.Button--color--yellow:focus{transition:color .1s,background-color .1s}.Button--color--yellow:focus,.Button--color--yellow:hover{background-color:#f3d00e;color:#000}.Button--color--olive{transition:color 50ms,background-color 50ms;background-color:#9aad14;color:#fff}.Button--color--olive:hover{transition:color 0ms,background-color 0ms}.Button--color--olive:focus{transition:color .1s,background-color .1s}.Button--color--olive:focus,.Button--color--olive:hover{background-color:#afc41f;color:#fff}.Button--color--green{transition:color 50ms,background-color 50ms;background-color:#1b9638;color:#fff}.Button--color--green:hover{transition:color 0ms,background-color 0ms}.Button--color--green:focus{transition:color .1s,background-color .1s}.Button--color--green:focus,.Button--color--green:hover{background-color:#27ab46;color:#fff}.Button--color--teal{transition:color 50ms,background-color 50ms;background-color:#009a93;color:#fff}.Button--color--teal:hover{transition:color 0ms,background-color 0ms}.Button--color--teal:focus{transition:color .1s,background-color .1s}.Button--color--teal:focus,.Button--color--teal:hover{background-color:#0aafa8;color:#fff}.Button--color--blue{transition:color 50ms,background-color 50ms;background-color:#1c71b1;color:#fff}.Button--color--blue:hover{transition:color 0ms,background-color 0ms}.Button--color--blue:focus{transition:color .1s,background-color .1s}.Button--color--blue:focus,.Button--color--blue:hover{background-color:#2883c8;color:#fff}.Button--color--violet{transition:color 50ms,background-color 50ms;background-color:#552dab;color:#fff}.Button--color--violet:hover{transition:color 0ms,background-color 0ms}.Button--color--violet:focus{transition:color .1s,background-color .1s}.Button--color--violet:focus,.Button--color--violet:hover{background-color:#653ac1;color:#fff}.Button--color--purple{transition:color 50ms,background-color 50ms;background-color:#8b2baa;color:#fff}.Button--color--purple:hover{transition:color 0ms,background-color 0ms}.Button--color--purple:focus{transition:color .1s,background-color .1s}.Button--color--purple:focus,.Button--color--purple:hover{background-color:#9e38c1;color:#fff}.Button--color--pink{transition:color 50ms,background-color 50ms;background-color:#cf2082;color:#fff}.Button--color--pink:hover{transition:color 0ms,background-color 0ms}.Button--color--pink:focus{transition:color .1s,background-color .1s}.Button--color--pink:focus,.Button--color--pink:hover{background-color:#dd3794;color:#fff}.Button--color--brown{transition:color 50ms,background-color 50ms;background-color:#8c5836;color:#fff}.Button--color--brown:hover{transition:color 0ms,background-color 0ms}.Button--color--brown:focus{transition:color .1s,background-color .1s}.Button--color--brown:focus,.Button--color--brown:hover{background-color:#a06844;color:#fff}.Button--color--grey{transition:color 50ms,background-color 50ms;background-color:#646464;color:#fff}.Button--color--grey:hover{transition:color 0ms,background-color 0ms}.Button--color--grey:focus{transition:color .1s,background-color .1s}.Button--color--grey:focus,.Button--color--grey:hover{background-color:#757575;color:#fff}.Button--color--good{transition:color 50ms,background-color 50ms;background-color:#4d9121;color:#fff}.Button--color--good:hover{transition:color 0ms,background-color 0ms}.Button--color--good:focus{transition:color .1s,background-color .1s}.Button--color--good:focus,.Button--color--good:hover{background-color:#5da52d;color:#fff}.Button--color--average{transition:color 50ms,background-color 50ms;background-color:#cd7a0d;color:#fff}.Button--color--average:hover{transition:color 0ms,background-color 0ms}.Button--color--average:focus{transition:color .1s,background-color .1s}.Button--color--average:focus,.Button--color--average:hover{background-color:#e68d18;color:#fff}.Button--color--bad{transition:color 50ms,background-color 50ms;background-color:#bd2020;color:#fff}.Button--color--bad:hover{transition:color 0ms,background-color 0ms}.Button--color--bad:focus{transition:color .1s,background-color .1s}.Button--color--bad:focus,.Button--color--bad:hover{background-color:#d52b2b;color:#fff}.Button--color--label{transition:color 50ms,background-color 50ms;background-color:#657a94;color:#fff}.Button--color--label:hover{transition:color 0ms,background-color 0ms}.Button--color--label:focus{transition:color .1s,background-color .1s}.Button--color--label:focus,.Button--color--label:hover{background-color:#7b8da4;color:#fff}.Button--color--default{transition:color 50ms,background-color 50ms;background-color:#3e6189;color:#fff}.Button--color--default:hover{transition:color 0ms,background-color 0ms}.Button--color--default:focus{transition:color .1s,background-color .1s}.Button--color--default:focus,.Button--color--default:hover{background-color:#4c729d;color:#fff}.Button--color--caution{transition:color 50ms,background-color 50ms;background-color:#d9b804;color:#000}.Button--color--caution:hover{transition:color 0ms,background-color 0ms}.Button--color--caution:focus{transition:color .1s,background-color .1s}.Button--color--caution:focus,.Button--color--caution:hover{background-color:#f3d00e;color:#000}.Button--color--danger{transition:color 50ms,background-color 50ms;background-color:#bd2020;color:#fff}.Button--color--danger:hover{transition:color 0ms,background-color 0ms}.Button--color--danger:focus{transition:color .1s,background-color .1s}.Button--color--danger:focus,.Button--color--danger:hover{background-color:#d52b2b;color:#fff}.Button--color--transparent{transition:color 50ms,background-color 50ms;background-color:#252525;color:#fff;background-color:rgba(37,37,37,0);color:hsla(0,0%,100%,.5)}.Button--color--transparent:hover{transition:color 0ms,background-color 0ms}.Button--color--transparent:focus{transition:color .1s,background-color .1s}.Button--color--transparent:focus,.Button--color--transparent:hover{background-color:#323232;color:#fff}.Button--disabled{background-color:#999!important}.Button--selected{transition:color 50ms,background-color 50ms;background-color:#1b9638;color:#fff}.Button--selected:hover{transition:color 0ms,background-color 0ms}.Button--selected:focus{transition:color .1s,background-color .1s}.Button--selected:focus,.Button--selected:hover{background-color:#27ab46;color:#fff}.ColorBox{display:inline-block;width:12px;height:12px;line-height:12px;text-align:center}.Dropdown{position:relative}.Dropdown__control{position:relative;display:inline-block;font-family:Verdana,sans-serif;font-size:12px;width:100px;line-height:17px;user-select:none}.Dropdown__arrow-button{float:right;padding-left:6px;border-left:1px solid #000;border-left:1px solid rgba(0,0,0,.25)}.Dropdown__menu{position:absolute;overflow-y:auto;z-index:5;width:100px;max-height:200px;overflow-y:scroll;border-radius:0 0 2px 2px;background-color:#000;background-color:rgba(0,0,0,.75)}.Dropdown__menuentry{padding:2px 4px;font-family:Verdana,sans-serif;font-size:12px;line-height:17px;transition:background-color .1s}.Dropdown__menuentry:hover{background-color:#444;transition:background-color 0ms}.Dropdown__over{top:auto;bottom:100%}.FatalError{display:block!important;position:absolute;top:0;left:0;right:0;bottom:0;padding:12px;font-size:12px;font-family:Consolas,monospace;color:#fff;background-color:#00d;z-index:1000;overflow:hidden;text-align:center}.FatalError__logo{display:inline-block;text-align:left;font-size:10px;line-height:8px;position:relative;margin-top:12px;top:0;left:0;animation:FatalError__rainbow 2s linear infinite alternate,FatalError__shadow 4s linear infinite alternate,FatalError__tfmX 3s infinite alternate,FatalError__tfmY 4s infinite alternate;white-space:pre-wrap;word-break:break-all}.FatalError__header{margin-top:12px}.FatalError__stack{text-align:left;white-space:pre-wrap;word-break:break-all;margin-top:24px;margin-bottom:24px}.FatalError__footer{margin-bottom:24px}@keyframes FatalError__rainbow{0%{color:#ff0}50%{color:#0ff}to{color:#f0f}}@keyframes FatalError__shadow{0%{left:-2px;text-shadow:4px 0 #f0f}50%{left:0;text-shadow:0 0 #0ff}to{left:2px;text-shadow:-4px 0 #ff0}}@keyframes FatalError__tfmX{0%{left:15px}to{left:-15px}}@keyframes FatalError__tfmY{to{top:-15px}}.Flex{display:-ms-flexbox;display:flex}.Flex--spacing--1{margin:-3px -3px 3px}.Flex--spacing--1>.Flex__item{margin:3px}.Flex--spacing--2{margin:-6px -6px 6px}.Flex--spacing--2>.Flex__item{margin:6px}.LabeledList{display:table;width:100%;width:calc(100% + 12px);border-collapse:collapse;border-spacing:0;margin:-3px -6px 0;padding:0}.LabeledList__row{display:table-row}.LabeledList__row:last-child .LabeledList__cell{padding-bottom:0}.LabeledList__cell{display:table-cell;margin:0;padding:3px 6px;border:0;text-align:left;vertical-align:baseline}.LabeledList__label{width:1%;white-space:nowrap;min-width:60px}.LabeledList__buttons{width:.1%;white-space:nowrap;text-align:right;padding-top:1px;padding-bottom:0}.Layout{bottom:0;right:0;color:#fff;background-color:#252525;background-image:linear-gradient(180deg,#2a2a2a 0,#202020)}.Layout,.Layout__titleBar{position:fixed;top:0;left:0}.Layout__titleBar{z-index:1;width:100%;height:32px}.Layout__content{position:fixed;top:32px;bottom:0;left:0;right:0;overflow-x:hidden;overflow-y:hidden;margin-bottom:-6px;scrollbar-base-color:#1c1c1c;scrollbar-face-color:#3b3b3b;scrollbar-3dlight-color:#252525;scrollbar-highlight-color:#252525;scrollbar-track-color:#1c1c1c;scrollbar-arrow-color:#929292;scrollbar-shadow-color:#3b3b3b}.Layout__content--scrollable{overflow-y:scroll;margin-bottom:0}.Layout__dimmer{top:32px;background-color:rgba(62,62,62,.25);pointer-events:none}.Layout__dimmer,.Layout__toast{position:fixed;bottom:0;left:0;right:0}.Layout__toast{font-size:12px;height:40px;line-height:39px;padding:0 12px;background-color:#131313;color:hsla(0,0%,100%,.8)}.Layout__resizeHandle__se{position:fixed;bottom:0;right:0;width:20px;height:20px;cursor:se-resize}.Layout__resizeHandle__s{position:fixed;bottom:0;left:0;right:0;height:6px;cursor:s-resize}.Layout__resizeHandle__e{position:fixed;top:0;bottom:0;right:0;width:3px;cursor:e-resize}.NoticeBox{padding:4px 6px;margin-bottom:6px;box-shadow:none;font-weight:700;font-style:italic;color:#000;background-color:#bb9b68;background-image:repeating-linear-gradient(-45deg,#bb9b68,#bb9b68 10px,#b1905d 0,#b1905d 20px)}.NtosHeader__left{position:absolute;left:12px}.NtosHeader__right{position:absolute;right:12px}.NtosHeader__icon{margin-top:-9px;margin-bottom:-6px;vertical-align:middle}.NtosWrapper__header{position:absolute;top:32px;left:0;right:0;height:28px;line-height:27px;background-color:rgba(0,0,0,.5);font-family:Consolas,monospace;font-size:14px;user-select:none;-ms-user-select:none}.NtosWrapper__content .Layout__content{margin-top:28px;font-family:Consolas,monospace;font-size:14px}.NuclearBomb__displayBox{background-color:#002003;border:4px inset #e8e4c9;color:#03e017;font-size:24px;font-family:monospace;padding:6px}.NuclearBomb__Button--keypad{background-color:#e8e4c9;border-color:#e8e4c9}.NuclearBomb__Button--keypad:hover{background-color:#f7f6ee!important;border-color:#f7f6ee!important}.NuclearBomb__Button--1{background-color:#d3cfb7!important;border-color:#d3cfb7!important;color:#a9a692!important}.NuclearBomb__Button--E{background-color:#d9b804!important;border-color:#d9b804!important}.NuclearBomb__Button--E:hover{background-color:#f3d00e!important;border-color:#f3d00e!important}.NuclearBomb__Button--C{background-color:#bd2020!important;border-color:#bd2020!important}.NuclearBomb__Button--C:hover{background-color:#d52b2b!important;border-color:#d52b2b!important}.NuclearBomb__NTIcon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMCIgdmlld0JveD0iMCAwIDQyNSAyMDAiIG9wYWNpdHk9Ii4zMyI+PHBhdGggZD0iTTE3OC4wMDQuMDM5SDEwNi44YTYuNzYxIDYuMDI2IDAgMDAtNi43NjEgNi4wMjV2MTg3Ljg3MmE2Ljc2MSA2LjAyNiAwIDAwNi43NjEgNi4wMjVoNTMuMTA3YTYuNzYxIDYuMDI2IDAgMDA2Ljc2Mi02LjAyNVY5Mi4zOTJsNzIuMjE2IDEwNC43YTYuNzYxIDYuMDI2IDAgMDA1Ljc2IDIuODdIMzE4LjJhNi43NjEgNi4wMjYgMCAwMDYuNzYxLTYuMDI2VjYuMDY0QTYuNzYxIDYuMDI2IDAgMDAzMTguMi4wNGgtNTQuNzE3YTYuNzYxIDYuMDI2IDAgMDAtNi43NiA2LjAyNXYxMDIuNjJMMTgzLjc2MyAyLjkwOWE2Ljc2MSA2LjAyNiAwIDAwLTUuNzYtMi44N3pNNC44NDUgMjIuMTA5QTEzLjQxMiAxMi41MDIgMCAwMTEzLjQ3OC4wMzloNjYuMTE4QTUuMzY1IDUgMCAwMTg0Ljk2IDUuMDR2NzkuODh6TTQyMC4xNTUgMTc3Ljg5MWExMy40MTIgMTIuNTAyIDAgMDEtOC42MzMgMjIuMDdoLTY2LjExOGE1LjM2NSA1IDAgMDEtNS4zNjUtNS4wMDF2LTc5Ljg4eiIvPjwvc3ZnPg==);background-size:70%;background-position:50%;background-repeat:no-repeat}.Input{position:relative;display:inline-block;width:120px;border:1px solid #88bfff;border:1px solid rgba(136,191,255,.75);border-radius:2px;color:#fff;background-color:#000;background-color:rgba(0,0,0,.75);padding:0 4px;margin-right:2px;line-height:17px;overflow:visible}.Input--fluid{display:block;width:auto}.Input__baseline{display:inline-block;color:transparent}.Input__input{display:block;position:absolute;top:0;bottom:0;left:0;right:0;border:0;outline:0;width:100%;font-size:12px;line-height:17px;height:17px;margin:0;padding:0 6px;font-family:Verdana,sans-serif;background-color:transparent;color:#fff;color:inherit}.Input__input:-ms-input-placeholder{font-style:italic;color:#777;color:hsla(0,0%,100%,.45)}.NumberInput{position:relative;display:inline-block;border:1px solid #88bfff;border:1px solid rgba(136,191,255,.75);border-radius:2px;color:#88bfff;background-color:#000;background-color:rgba(0,0,0,.75);padding:0 4px;margin-right:2px;line-height:17px;text-align:right;overflow:visible;cursor:n-resize}.NumberInput--fluid{display:block}.NumberInput__content{margin-left:6px}.NumberInput__barContainer{position:absolute;top:2px;bottom:2px;left:2px}.NumberInput__bar{position:absolute;bottom:0;left:0;width:3px;box-sizing:border-box;border-bottom:1px solid #88bfff;background-color:#88bfff}.NumberInput__input{display:block;position:absolute;top:0;bottom:0;left:0;right:0;border:0;outline:0;width:100%;font-size:12px;line-height:17px;height:17px;margin:0;padding:0 6px;font-family:Verdana,sans-serif;background-color:#000;color:#fff;text-align:right}.ProgressBar{display:inline-block;position:relative;width:100%;padding:0 6px;border-radius:0;background-color:transparent;transition:border-color .5s}.ProgressBar__fill{position:absolute;top:0;left:0;bottom:0;transition:background-color .5s,width .5s}.ProgressBar__content{position:relative;line-height:17px;width:100%;text-align:right}.ProgressBar--color--default{border:1px solid #3e6189}.ProgressBar--color--default .ProgressBar__fill{background-color:#3e6189}.ProgressBar--color--black{border:1px solid #000!important}.ProgressBar--color--black .ProgressBar__fill{background-color:#000}.ProgressBar--color--white{border:1px solid #d9d9d9!important}.ProgressBar--color--white .ProgressBar__fill{background-color:#d9d9d9}.ProgressBar--color--red{border:1px solid #bd2020!important}.ProgressBar--color--red .ProgressBar__fill{background-color:#bd2020}.ProgressBar--color--orange{border:1px solid #d95e0c!important}.ProgressBar--color--orange .ProgressBar__fill{background-color:#d95e0c}.ProgressBar--color--yellow{border:1px solid #d9b804!important}.ProgressBar--color--yellow .ProgressBar__fill{background-color:#d9b804}.ProgressBar--color--olive{border:1px solid #9aad14!important}.ProgressBar--color--olive .ProgressBar__fill{background-color:#9aad14}.ProgressBar--color--green{border:1px solid #1b9638!important}.ProgressBar--color--green .ProgressBar__fill{background-color:#1b9638}.ProgressBar--color--teal{border:1px solid #009a93!important}.ProgressBar--color--teal .ProgressBar__fill{background-color:#009a93}.ProgressBar--color--blue{border:1px solid #1c71b1!important}.ProgressBar--color--blue .ProgressBar__fill{background-color:#1c71b1}.ProgressBar--color--violet{border:1px solid #552dab!important}.ProgressBar--color--violet .ProgressBar__fill{background-color:#552dab}.ProgressBar--color--purple{border:1px solid #8b2baa!important}.ProgressBar--color--purple .ProgressBar__fill{background-color:#8b2baa}.ProgressBar--color--pink{border:1px solid #cf2082!important}.ProgressBar--color--pink .ProgressBar__fill{background-color:#cf2082}.ProgressBar--color--brown{border:1px solid #8c5836!important}.ProgressBar--color--brown .ProgressBar__fill{background-color:#8c5836}.ProgressBar--color--grey{border:1px solid #646464!important}.ProgressBar--color--grey .ProgressBar__fill{background-color:#646464}.ProgressBar--color--good{border:1px solid #4d9121!important}.ProgressBar--color--good .ProgressBar__fill{background-color:#4d9121}.ProgressBar--color--average{border:1px solid #cd7a0d!important}.ProgressBar--color--average .ProgressBar__fill{background-color:#cd7a0d}.ProgressBar--color--bad{border:1px solid #bd2020!important}.ProgressBar--color--bad .ProgressBar__fill{background-color:#bd2020}.ProgressBar--color--label{border:1px solid #657a94!important}.ProgressBar--color--label .ProgressBar__fill{background-color:#657a94}.Section{position:relative;margin-bottom:6px;background-color:#1a1a1a;background-color:rgba(0,0,0,.33);box-shadow:inset 0 0 5px rgba(0,0,0,.5);box-sizing:border-box}.Section:last-child{margin-bottom:0}.Section__title{position:relative;padding:6px;border-bottom:2px solid #4972a1}.Section__titleText{font-size:14px;font-weight:700}.Section__buttons{position:absolute;display:inline-block;right:6px;margin-top:-1px}.Section__content{padding:8px 6px}.Section--level--1 .Section__titleText{font-size:14px}.Section--level--2 .Section__titleText{font-size:13px}.Section--level--3 .Section__titleText{font-size:12px}.Section--level--2,.Section--level--3{background-color:transparent;box-shadow:none;margin-left:-6px;margin-right:-6px}.Table{display:table;width:100%;border-collapse:collapse;border-spacing:0;margin:0}.Table--collapsing{width:auto}.Table__row{display:table-row}.Table__cell{display:table-cell;padding:0 3px}.Table__cell:first-child{padding-left:0}.Table__cell:last-child{padding-right:0}.Table__cell--header,.Table__row--header .Table__cell{font-weight:700;padding-bottom:6px}.Table__cell--collapsing{width:1%;white-space:nowrap}.Tabs__content{padding-top:6px;border-top:2px solid hsla(0,0%,100%,.1)}.Tabs--vertical{display:table-row}.Tabs--vertical>.Tabs__content{display:table-cell;width:100%;padding-top:0;padding-left:9px;border-top:0}.Tabs--vertical>.Tabs__tabBox{display:table-cell;border-right:2px solid hsla(0,0%,100%,.1);vertical-align:top}.Tabs--vertical>.Tabs__tabBox>.Tabs__tab{display:block!important;margin-right:0;margin-bottom:0;padding:1px 9px 0 6px;border-bottom:2px solid hsla(0,0%,100%,.1)}.Tabs--vertical>.Tabs__tabBox>.Tabs__tab:last-child{border-bottom:0}.TitleBar{background-color:#363636;border-bottom:1px solid #161616;box-shadow:0 2px 2px rgba(0,0,0,.1);user-select:none;-ms-user-select:none}.TitleBar__clickable{color:hsla(0,0%,100%,.5);background-color:#363636;transition:color .25s,background-color .25s}.TitleBar__clickable:hover{color:#fff;background-color:#c00;transition:color 0ms,background-color 0ms}.TitleBar__title{position:absolute;top:0;left:46px;color:hsla(0,0%,100%,.75);font-size:14px;line-height:31px;white-space:nowrap}.TitleBar__dragZone{position:absolute;top:0;left:0;right:0;height:32px}.TitleBar__statusIcon{position:absolute;top:0;left:12px;transition:color .5s;font-size:20px;line-height:32px!important}.TitleBar__minimize{position:absolute;top:6px;right:46px}.TitleBar__close{position:absolute;top:-1px;right:0;width:45px;height:32px;font-size:20px;line-height:31px;text-align:center}.Tooltip{position:absolute;top:0;left:0;right:0;bottom:0;font-style:normal;font-weight:400}.Tooltip:after{position:absolute;display:block;white-space:nowrap;z-index:2;padding:6px 10px;transform:translateX(-50%);pointer-events:none;visibility:hidden;opacity:0;text-align:left;content:attr(data-tooltip);transition:all .15s;background-color:#000;box-shadow:1px 1px 15px -1px rgba(0,0,0,.5);border-radius:2px}.Tooltip:hover:after{transition:all 70ms;pointer-events:none;visibility:visible;opacity:1}.Tooltip--long:after{width:250px;white-space:normal}.Tooltip--top:after{bottom:100%;left:50%;transform:translateX(-50%) translateY(8px)}.Tooltip--bottom:after,.Tooltip--top:hover:after{transform:translateX(-50%) translateY(-8px)}.Tooltip--bottom:after{top:100%;left:50%}.Tooltip--bottom:hover:after{transform:translateX(-50%) translateY(8px)}.Tooltip--bottom-left:after{top:100%;right:50%;transform:translateX(12px) translateY(-8px)}.Tooltip--bottom-left:hover:after{transform:translateX(12px) translateY(8px)}.Tooltip--bottom-right:after{top:100%;left:50%;transform:translateX(-12px) translateY(-8px)}.Tooltip--bottom-right:hover:after{transform:translateX(-12px) translateY(8px)}.Tooltip--left:after{top:50%;right:100%;transform:translateX(8px) translateY(-50%)}.Tooltip--left:hover:after,.Tooltip--right:after{transform:translateX(-8px) translateY(-50%)}.Tooltip--right:after{top:50%;left:100%}.Tooltip--right:hover:after{transform:translateX(8px) translateY(-50%)}.Layout__content{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMCIgdmlld0JveD0iMCAwIDQyNSAyMDAiIG9wYWNpdHk9Ii4zMyI+PHBhdGggZD0iTTE3OC4wMDQuMDM5SDEwNi44YTYuNzYxIDYuMDI2IDAgMDAtNi43NjEgNi4wMjV2MTg3Ljg3MmE2Ljc2MSA2LjAyNiAwIDAwNi43NjEgNi4wMjVoNTMuMTA3YTYuNzYxIDYuMDI2IDAgMDA2Ljc2Mi02LjAyNVY5Mi4zOTJsNzIuMjE2IDEwNC43YTYuNzYxIDYuMDI2IDAgMDA1Ljc2IDIuODdIMzE4LjJhNi43NjEgNi4wMjYgMCAwMDYuNzYxLTYuMDI2VjYuMDY0QTYuNzYxIDYuMDI2IDAgMDAzMTguMi4wNGgtNTQuNzE3YTYuNzYxIDYuMDI2IDAgMDAtNi43NiA2LjAyNXYxMDIuNjJMMTgzLjc2MyAyLjkwOWE2Ljc2MSA2LjAyNiAwIDAwLTUuNzYtMi44N3pNNC44NDUgMjIuMTA5QTEzLjQxMiAxMi41MDIgMCAwMTEzLjQ3OC4wMzloNjYuMTE4QTUuMzY1IDUgMCAwMTg0Ljk2IDUuMDR2NzkuODh6TTQyMC4xNTUgMTc3Ljg5MWExMy40MTIgMTIuNTAyIDAgMDEtOC42MzMgMjIuMDdoLTY2LjExOGE1LjM2NSA1IDAgMDEtNS4zNjUtNS4wMDF2LTc5Ljg4eiIvPjwvc3ZnPg==);background-size:70%;background-position:50%;background-repeat:no-repeat}.action_test{display:inherit}.theme-cardtable .Button{position:relative;display:inline-block;line-height:20px;padding:0 6px;margin-right:2px;white-space:nowrap;outline:0;border-radius:0;margin-bottom:2px;user-select:none;-ms-user-select:none}.theme-cardtable .Button:last-child{margin-right:0}.theme-cardtable .Button .fa,.theme-cardtable .Button .far,.theme-cardtable .Button .fas{margin-left:-3px;margin-right:-3px;min-width:16px;text-align:center}.theme-cardtable .Button--hasContent .fa,.theme-cardtable .Button--hasContent .far,.theme-cardtable .Button--hasContent .fas{margin-right:3px}.theme-cardtable .Button--ellipsis{overflow:hidden;text-overflow:ellipsis}.theme-cardtable .Button--fluid{display:block;margin-left:0;margin-right:0}.theme-cardtable .Button--color--default{transition:color 50ms,background-color 50ms;background-color:#117039;color:#fff}.theme-cardtable .Button--color--default:hover{transition:color 0ms,background-color 0ms}.theme-cardtable .Button--color--default:focus{transition:color .1s,background-color .1s}.theme-cardtable .Button--color--default:focus,.theme-cardtable .Button--color--default:hover{background-color:#1c8247;color:#fff}.theme-cardtable .Button--color--caution{transition:color 50ms,background-color 50ms;background-color:#be6209;color:#fff}.theme-cardtable .Button--color--caution:hover{transition:color 0ms,background-color 0ms}.theme-cardtable .Button--color--caution:focus{transition:color .1s,background-color .1s}.theme-cardtable .Button--color--caution:focus,.theme-cardtable .Button--color--caution:hover{background-color:#d67313;color:#fff}.theme-cardtable .Button--color--danger{transition:color 50ms,background-color 50ms;background-color:#9a9d00;color:#fff}.theme-cardtable .Button--color--danger:hover{transition:color 0ms,background-color 0ms}.theme-cardtable .Button--color--danger:focus{transition:color .1s,background-color .1s}.theme-cardtable .Button--color--danger:focus,.theme-cardtable .Button--color--danger:hover{background-color:#afb30a;color:#fff}.theme-cardtable .Button--color--transparent{transition:color 50ms,background-color 50ms;background-color:#117039;color:#fff;background-color:rgba(17,112,57,0);color:hsla(0,0%,100%,.5)}.theme-cardtable .Button--color--transparent:hover{transition:color 0ms,background-color 0ms}.theme-cardtable .Button--color--transparent:focus{transition:color .1s,background-color .1s}.theme-cardtable .Button--color--transparent:focus,.theme-cardtable .Button--color--transparent:hover{background-color:#1c8247;color:#fff}.theme-cardtable .Button--disabled{background-color:#363636!important}.theme-cardtable .Button--selected{transition:color 50ms,background-color 50ms;background-color:#9d0808;color:#fff}.theme-cardtable .Button--selected:hover{transition:color 0ms,background-color 0ms}.theme-cardtable .Button--selected:focus{transition:color .1s,background-color .1s}.theme-cardtable .Button--selected:focus,.theme-cardtable .Button--selected:hover{background-color:#b31212;color:#fff}.theme-cardtable .Layout{position:fixed;top:0;bottom:0;left:0;right:0;color:#fff;background-color:#117039;background-image:linear-gradient(180deg,#117039 0,#117039)}.theme-cardtable .Layout__titleBar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px}.theme-cardtable .Layout__content{position:fixed;top:32px;bottom:0;left:0;right:0;overflow-x:hidden;overflow-y:hidden;margin-bottom:-6px;scrollbar-base-color:#0d542b;scrollbar-face-color:#16914a;scrollbar-3dlight-color:#117039;scrollbar-highlight-color:#117039;scrollbar-track-color:#0d542b;scrollbar-arrow-color:#5ae695;scrollbar-shadow-color:#16914a}.theme-cardtable .Layout__content--scrollable{overflow-y:scroll;margin-bottom:0}.theme-cardtable .Layout__dimmer{position:fixed;top:32px;bottom:0;left:0;right:0;background-color:rgba(39,148,85,.25);pointer-events:none}.theme-cardtable .Layout__toast{position:fixed;bottom:0;left:0;right:0;font-size:12px;height:40px;line-height:39px;padding:0 12px;background-color:#09381d;color:hsla(0,0%,100%,.8)}.theme-cardtable .Layout__resizeHandle__se{position:fixed;bottom:0;right:0;width:20px;height:20px;cursor:se-resize}.theme-cardtable .Layout__resizeHandle__s{position:fixed;bottom:0;left:0;right:0;height:6px;cursor:s-resize}.theme-cardtable .Layout__resizeHandle__e{position:fixed;top:0;bottom:0;right:0;width:3px;cursor:e-resize}.theme-cardtable .Input{position:relative;display:inline-block;width:120px;border:1px solid #88bfff;border:1px solid rgba(136,191,255,.75);border-radius:0;color:#fff;background-color:#000;background-color:rgba(0,0,0,.75);padding:0 4px;margin-right:2px;line-height:17px;overflow:visible}.theme-cardtable .Input--fluid{display:block;width:auto}.theme-cardtable .Input__baseline{display:inline-block;color:transparent}.theme-cardtable .Input__input{display:block;position:absolute;top:0;bottom:0;left:0;right:0;border:0;outline:0;width:100%;font-size:12px;line-height:17px;height:17px;margin:0;padding:0 6px;font-family:Verdana,sans-serif;background-color:transparent;color:#fff;color:inherit}.theme-cardtable .Input__input:-ms-input-placeholder{font-style:italic;color:#777;color:hsla(0,0%,100%,.45)}.theme-cardtable .NumberInput{position:relative;display:inline-block;border:1px solid #fff;border:1px solid hsla(0,0%,100%,.75);border-radius:0;color:#fff;background-color:#000;background-color:rgba(0,0,0,.75);padding:0 4px;margin-right:2px;line-height:17px;text-align:right;overflow:visible;cursor:n-resize}.theme-cardtable .NumberInput--fluid{display:block}.theme-cardtable .NumberInput__content{margin-left:6px}.theme-cardtable .NumberInput__barContainer{position:absolute;top:2px;bottom:2px;left:2px}.theme-cardtable .NumberInput__bar{position:absolute;bottom:0;left:0;width:3px;box-sizing:border-box;border-bottom:1px solid #fff;background-color:#fff}.theme-cardtable .NumberInput__input{display:block;position:absolute;top:0;bottom:0;left:0;right:0;border:0;outline:0;width:100%;font-size:12px;line-height:17px;height:17px;margin:0;padding:0 6px;font-family:Verdana,sans-serif;background-color:#000;color:#fff;text-align:right}.theme-cardtable .ProgressBar{display:inline-block;position:relative;width:100%;padding:0 6px;border-radius:0;background-color:rgba(0,0,0,.5);transition:border-color .5s}.theme-cardtable .ProgressBar__fill{position:absolute;top:0;left:0;bottom:0;transition:background-color .5s,width .5s}.theme-cardtable .ProgressBar__content{position:relative;line-height:17px;width:100%;text-align:right}.theme-cardtable .ProgressBar--color--default{border:1px solid #000}.theme-cardtable .ProgressBar--color--default .ProgressBar__fill{background-color:#000}.theme-cardtable .Section{position:relative;margin-bottom:6px;background-color:#1a1a1a;background-color:rgba(0,0,0,.33);box-shadow:inset 0 0 5px rgba(0,0,0,.5);box-sizing:border-box}.theme-cardtable .Section:last-child{margin-bottom:0}.theme-cardtable .Section__title{position:relative;padding:6px;border-bottom:2px solid #000}.theme-cardtable .Section__titleText{font-size:14px;font-weight:700}.theme-cardtable .Section__buttons{position:absolute;display:inline-block;right:6px;margin-top:-1px}.theme-cardtable .Section__content{padding:8px 6px}.theme-cardtable .Section--level--1 .Section__titleText{font-size:14px}.theme-cardtable .Section--level--2 .Section__titleText{font-size:13px}.theme-cardtable .Section--level--3 .Section__titleText{font-size:12px}.theme-cardtable .Section--level--2,.theme-cardtable .Section--level--3{background-color:transparent;box-shadow:none;margin-left:-6px;margin-right:-6px}.theme-cardtable .TitleBar{background-color:#381608;border-bottom:1px solid #161616;box-shadow:0 2px 2px rgba(0,0,0,.1);user-select:none;-ms-user-select:none}.theme-cardtable .TitleBar__clickable{color:hsla(0,0%,100%,.5);background-color:#381608;transition:color .25s,background-color .25s}.theme-cardtable .TitleBar__clickable:hover{color:#fff;background-color:#c00;transition:color 0ms,background-color 0ms}.theme-cardtable .TitleBar__title{position:absolute;top:0;left:46px;color:hsla(0,0%,100%,.75);font-size:14px;line-height:31px;white-space:nowrap}.theme-cardtable .TitleBar__dragZone{position:absolute;top:0;left:0;right:0;height:32px}.theme-cardtable .TitleBar__statusIcon{position:absolute;top:0;left:12px;transition:color .5s;font-size:20px;line-height:32px!important}.theme-cardtable .TitleBar__minimize{position:absolute;top:6px;right:46px}.theme-cardtable .TitleBar__close{position:absolute;top:-1px;right:0;width:45px;height:32px;font-size:20px;line-height:31px;text-align:center}.theme-cardtable .Button{border:2px solid #fff}.theme-ntos .Button{position:relative;display:inline-block;line-height:20px;padding:0 6px;margin-right:2px;white-space:nowrap;outline:0;border-radius:2px;margin-bottom:2px;user-select:none;-ms-user-select:none}.theme-ntos .Button:last-child{margin-right:0}.theme-ntos .Button .fa,.theme-ntos .Button .far,.theme-ntos .Button .fas{margin-left:-3px;margin-right:-3px;min-width:16px;text-align:center}.theme-ntos .Button--hasContent .fa,.theme-ntos .Button--hasContent .far,.theme-ntos .Button--hasContent .fas{margin-right:3px}.theme-ntos .Button--ellipsis{overflow:hidden;text-overflow:ellipsis}.theme-ntos .Button--fluid{display:block;margin-left:0;margin-right:0}.theme-ntos .Button--color--default{transition:color 50ms,background-color 50ms;background-color:#384e68;color:#fff}.theme-ntos .Button--color--default:hover{transition:color 0ms,background-color 0ms}.theme-ntos .Button--color--default:focus{transition:color .1s,background-color .1s}.theme-ntos .Button--color--default:focus,.theme-ntos .Button--color--default:hover{background-color:#465e7a;color:#fff}.theme-ntos .Button--color--caution{transition:color 50ms,background-color 50ms;background-color:#d9b804;color:#000}.theme-ntos .Button--color--caution:hover{transition:color 0ms,background-color 0ms}.theme-ntos .Button--color--caution:focus{transition:color .1s,background-color .1s}.theme-ntos .Button--color--caution:focus,.theme-ntos .Button--color--caution:hover{background-color:#f3d00e;color:#000}.theme-ntos .Button--color--danger{transition:color 50ms,background-color 50ms;background-color:#bd2020;color:#fff}.theme-ntos .Button--color--danger:hover{transition:color 0ms,background-color 0ms}.theme-ntos .Button--color--danger:focus{transition:color .1s,background-color .1s}.theme-ntos .Button--color--danger:focus,.theme-ntos .Button--color--danger:hover{background-color:#d52b2b;color:#fff}.theme-ntos .Button--color--transparent{transition:color 50ms,background-color 50ms;background-color:#1f2b39;color:#fff;background-color:rgba(31,43,57,0);color:rgba(227,240,255,.75)}.theme-ntos .Button--color--transparent:hover{transition:color 0ms,background-color 0ms}.theme-ntos .Button--color--transparent:focus{transition:color .1s,background-color .1s}.theme-ntos .Button--color--transparent:focus,.theme-ntos .Button--color--transparent:hover{background-color:#2b3847;color:#fff}.theme-ntos .Button--disabled{background-color:#999!important}.theme-ntos .Button--selected{transition:color 50ms,background-color 50ms;background-color:#1b9638;color:#fff}.theme-ntos .Button--selected:hover{transition:color 0ms,background-color 0ms}.theme-ntos .Button--selected:focus{transition:color .1s,background-color .1s}.theme-ntos .Button--selected:focus,.theme-ntos .Button--selected:hover{background-color:#27ab46;color:#fff}.theme-ntos .Layout{position:fixed;top:0;bottom:0;left:0;right:0;color:#fff;background-color:#1f2b39;background-image:linear-gradient(180deg,#223040 0,#1b2633)}.theme-ntos .Layout__titleBar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px}.theme-ntos .Layout__content{position:fixed;top:32px;bottom:0;left:0;right:0;overflow-x:hidden;overflow-y:hidden;margin-bottom:-6px;scrollbar-base-color:#17202b;scrollbar-face-color:#2e3f55;scrollbar-3dlight-color:#1f2b39;scrollbar-highlight-color:#1f2b39;scrollbar-track-color:#17202b;scrollbar-arrow-color:#7693b5;scrollbar-shadow-color:#2e3f55}.theme-ntos .Layout__content--scrollable{overflow-y:scroll;margin-bottom:0}.theme-ntos .Layout__dimmer{position:fixed;top:32px;bottom:0;left:0;right:0;background-color:rgba(55,69,85,.25);pointer-events:none}.theme-ntos .Layout__toast{position:fixed;bottom:0;left:0;right:0;font-size:12px;height:40px;line-height:39px;padding:0 12px;background-color:#0f151d;color:hsla(0,0%,100%,.8)}.theme-ntos .Layout__resizeHandle__se{position:fixed;bottom:0;right:0;width:20px;height:20px;cursor:se-resize}.theme-ntos .Layout__resizeHandle__s{position:fixed;bottom:0;left:0;right:0;height:6px;cursor:s-resize}.theme-ntos .Layout__resizeHandle__e{position:fixed;top:0;bottom:0;right:0;width:3px;cursor:e-resize}.theme-ntos .ProgressBar{display:inline-block;position:relative;width:100%;padding:0 6px;border-radius:2px;background-color:rgba(0,0,0,.5);transition:border-color .5s}.theme-ntos .ProgressBar__fill{position:absolute;top:0;left:0;bottom:0;transition:background-color .5s,width .5s}.theme-ntos .ProgressBar__content{position:relative;line-height:17px;width:100%;text-align:right}.theme-ntos .ProgressBar--color--default{border:1px solid #384e68}.theme-ntos .ProgressBar--color--default .ProgressBar__fill{background-color:#384e68}.theme-ntos .Section{position:relative;margin-bottom:6px;background-color:#1a1a1a;background-color:rgba(0,0,0,.33);box-shadow:inset 0 0 5px rgba(0,0,0,.5);box-sizing:border-box}.theme-ntos .Section:last-child{margin-bottom:0}.theme-ntos .Section__title{position:relative;padding:6px;border-bottom:2px solid #4972a1}.theme-ntos .Section__titleText{font-size:14px;font-weight:700}.theme-ntos .Section__buttons{position:absolute;display:inline-block;right:6px;margin-top:-1px}.theme-ntos .Section__content{padding:8px 6px}.theme-ntos .Section--level--1 .Section__titleText{font-size:14px}.theme-ntos .Section--level--2 .Section__titleText{font-size:13px}.theme-ntos .Section--level--3 .Section__titleText{font-size:12px}.theme-ntos .Section--level--2,.theme-ntos .Section--level--3{background-color:transparent;box-shadow:none;margin-left:-6px;margin-right:-6px}.theme-ntos .TitleBar{background-color:#2a3b4e;border-bottom:1px solid #161616;box-shadow:0 2px 2px rgba(0,0,0,.1);user-select:none;-ms-user-select:none}.theme-ntos .TitleBar__clickable{color:hsla(0,0%,100%,.5);background-color:#2a3b4e;transition:color .25s,background-color .25s}.theme-ntos .TitleBar__clickable:hover{color:#fff;background-color:#c00;transition:color 0ms,background-color 0ms}.theme-ntos .TitleBar__title{position:absolute;top:0;left:46px;color:hsla(0,0%,100%,.75);font-size:14px;line-height:31px;white-space:nowrap}.theme-ntos .TitleBar__dragZone{position:absolute;top:0;left:0;right:0;height:32px}.theme-ntos .TitleBar__statusIcon{position:absolute;top:0;left:12px;transition:color .5s;font-size:20px;line-height:32px!important}.theme-ntos .TitleBar__minimize{position:absolute;top:6px;right:46px}.theme-ntos .TitleBar__close{position:absolute;top:-1px;right:0;width:45px;height:32px;font-size:20px;line-height:31px;text-align:center}.theme-hackerman .Button{position:relative;display:inline-block;line-height:20px;padding:0 6px;margin-right:2px;white-space:nowrap;outline:0;border-radius:0;margin-bottom:2px;user-select:none;-ms-user-select:none}.theme-hackerman .Button:last-child{margin-right:0}.theme-hackerman .Button .fa,.theme-hackerman .Button .far,.theme-hackerman .Button .fas{margin-left:-3px;margin-right:-3px;min-width:16px;text-align:center}.theme-hackerman .Button--hasContent .fa,.theme-hackerman .Button--hasContent .far,.theme-hackerman .Button--hasContent .fas{margin-right:3px}.theme-hackerman .Button--ellipsis{overflow:hidden;text-overflow:ellipsis}.theme-hackerman .Button--fluid{display:block;margin-left:0;margin-right:0}.theme-hackerman .Button--color--default{transition:color 50ms,background-color 50ms;background-color:#0f0;color:#000}.theme-hackerman .Button--color--default:hover{transition:color 0ms,background-color 0ms}.theme-hackerman .Button--color--default:focus{transition:color .1s,background-color .1s}.theme-hackerman .Button--color--default:focus,.theme-hackerman .Button--color--default:hover{background-color:#26ff26;color:#000}.theme-hackerman .Button--color--caution{transition:color 50ms,background-color 50ms;background-color:#d9b804;color:#000}.theme-hackerman .Button--color--caution:hover{transition:color 0ms,background-color 0ms}.theme-hackerman .Button--color--caution:focus{transition:color .1s,background-color .1s}.theme-hackerman .Button--color--caution:focus,.theme-hackerman .Button--color--caution:hover{background-color:#f3d00e;color:#000}.theme-hackerman .Button--color--danger{transition:color 50ms,background-color 50ms;background-color:#bd2020;color:#fff}.theme-hackerman .Button--color--danger:hover{transition:color 0ms,background-color 0ms}.theme-hackerman .Button--color--danger:focus{transition:color .1s,background-color .1s}.theme-hackerman .Button--color--danger:focus,.theme-hackerman .Button--color--danger:hover{background-color:#d52b2b;color:#fff}.theme-hackerman .Button--color--transparent{transition:color 50ms,background-color 50ms;background-color:#121b12;color:#fff;background-color:rgba(18,27,18,0);color:hsla(0,0%,100%,.5)}.theme-hackerman .Button--color--transparent:hover{transition:color 0ms,background-color 0ms}.theme-hackerman .Button--color--transparent:focus{transition:color .1s,background-color .1s}.theme-hackerman .Button--color--transparent:focus,.theme-hackerman .Button--color--transparent:hover{background-color:#1d271d;color:#fff}.theme-hackerman .Button--disabled{background-color:#4a6a4a!important}.theme-hackerman .Button--selected{transition:color 50ms,background-color 50ms;background-color:#0f0;color:#000}.theme-hackerman .Button--selected:hover{transition:color 0ms,background-color 0ms}.theme-hackerman .Button--selected:focus{transition:color .1s,background-color .1s}.theme-hackerman .Button--selected:focus,.theme-hackerman .Button--selected:hover{background-color:#26ff26;color:#000}.theme-hackerman .Input{position:relative;display:inline-block;width:120px;border:1px solid #0f0;border:1px solid rgba(0,255,0,.75);border-radius:2px;color:#fff;background-color:#000;background-color:rgba(0,0,0,.75);padding:0 4px;margin-right:2px;line-height:17px;overflow:visible}.theme-hackerman .Input--fluid{display:block;width:auto}.theme-hackerman .Input__baseline{display:inline-block;color:transparent}.theme-hackerman .Input__input{display:block;position:absolute;top:0;bottom:0;left:0;right:0;border:0;outline:0;width:100%;font-size:12px;line-height:17px;height:17px;margin:0;padding:0 6px;font-family:Verdana,sans-serif;background-color:transparent;color:#fff;color:inherit}.theme-hackerman .Input__input:-ms-input-placeholder{font-style:italic;color:#777;color:hsla(0,0%,100%,.45)}.theme-hackerman .Layout{position:fixed;top:0;bottom:0;left:0;right:0;color:#fff;background-color:#121b12;background-image:linear-gradient(180deg,#121b12 0,#121b12)}.theme-hackerman .Layout__titleBar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px}.theme-hackerman .Layout__content{position:fixed;top:32px;bottom:0;left:0;right:0;overflow-x:hidden;overflow-y:hidden;margin-bottom:-6px;scrollbar-base-color:#0e140e;scrollbar-face-color:#253725;scrollbar-3dlight-color:#121b12;scrollbar-highlight-color:#121b12;scrollbar-track-color:#0e140e;scrollbar-arrow-color:#74a274;scrollbar-shadow-color:#253725}.theme-hackerman .Layout__content--scrollable{overflow-y:scroll;margin-bottom:0}.theme-hackerman .Layout__dimmer{position:fixed;top:32px;bottom:0;left:0;right:0;background-color:rgba(40,50,40,.25);pointer-events:none}.theme-hackerman .Layout__toast{position:fixed;bottom:0;left:0;right:0;font-size:12px;height:40px;line-height:39px;padding:0 12px;background-color:#090e09;color:hsla(0,0%,100%,.8)}.theme-hackerman .Layout__resizeHandle__se{position:fixed;bottom:0;right:0;width:20px;height:20px;cursor:se-resize}.theme-hackerman .Layout__resizeHandle__s{position:fixed;bottom:0;left:0;right:0;height:6px;cursor:s-resize}.theme-hackerman .Layout__resizeHandle__e{position:fixed;top:0;bottom:0;right:0;width:3px;cursor:e-resize}.theme-hackerman .Section{position:relative;margin-bottom:6px;background-color:#1a1a1a;background-color:rgba(0,0,0,.33);box-shadow:inset 0 0 5px rgba(0,0,0,.5);box-sizing:border-box}.theme-hackerman .Section:last-child{margin-bottom:0}.theme-hackerman .Section__title{position:relative;padding:6px;border-bottom:2px solid #0f0}.theme-hackerman .Section__titleText{font-size:14px;font-weight:700}.theme-hackerman .Section__buttons{position:absolute;display:inline-block;right:6px;margin-top:-1px}.theme-hackerman .Section__content{padding:8px 6px}.theme-hackerman .Section--level--1 .Section__titleText{font-size:14px}.theme-hackerman .Section--level--2 .Section__titleText{font-size:13px}.theme-hackerman .Section--level--3 .Section__titleText{font-size:12px}.theme-hackerman .Section--level--2,.theme-hackerman .Section--level--3{background-color:transparent;box-shadow:none;margin-left:-6px;margin-right:-6px}.theme-hackerman .TitleBar{background-color:#223d22;border-bottom:1px solid #161616;box-shadow:0 2px 2px rgba(0,0,0,.1);user-select:none;-ms-user-select:none}.theme-hackerman .TitleBar__clickable{color:hsla(0,0%,100%,.5);background-color:#223d22;transition:color .25s,background-color .25s}.theme-hackerman .TitleBar__clickable:hover{color:#fff;background-color:#c00;transition:color 0ms,background-color 0ms}.theme-hackerman .TitleBar__title{position:absolute;top:0;left:46px;color:hsla(0,0%,100%,.75);font-size:14px;line-height:31px;white-space:nowrap}.theme-hackerman .TitleBar__dragZone{position:absolute;top:0;left:0;right:0;height:32px}.theme-hackerman .TitleBar__statusIcon{position:absolute;top:0;left:12px;transition:color .5s;font-size:20px;line-height:32px!important}.theme-hackerman .TitleBar__minimize{position:absolute;top:6px;right:46px}.theme-hackerman .TitleBar__close{position:absolute;top:-1px;right:0;width:45px;height:32px;font-size:20px;line-height:31px;text-align:center}.theme-hackerman .Layout__content{background-image:none}.theme-hackerman .Button{font-family:monospace;border:2px outset #0a0;outline:1px solid #007a00}.theme-hackerman .candystripe:nth-child(odd){background-color:rgba(0,100,0,.5)}.theme-retro .Button{position:relative;display:inline-block;line-height:20px;padding:0 6px;margin-right:2px;white-space:nowrap;outline:0;border-radius:0;margin-bottom:2px;user-select:none;-ms-user-select:none}.theme-retro .Button:last-child{margin-right:0}.theme-retro .Button .fa,.theme-retro .Button .far,.theme-retro .Button .fas{margin-left:-3px;margin-right:-3px;min-width:16px;text-align:center}.theme-retro .Button--hasContent .fa,.theme-retro .Button--hasContent .far,.theme-retro .Button--hasContent .fas{margin-right:3px}.theme-retro .Button--ellipsis{overflow:hidden;text-overflow:ellipsis}.theme-retro .Button--fluid{display:block;margin-left:0;margin-right:0}.theme-retro .Button--color--default{transition:color 50ms,background-color 50ms;background-color:#e8e4c9;color:#000}.theme-retro .Button--color--default:hover{transition:color 0ms,background-color 0ms}.theme-retro .Button--color--default:focus{transition:color .1s,background-color .1s}.theme-retro .Button--color--default:focus,.theme-retro .Button--color--default:hover{background-color:#f7f6ee;color:#000}.theme-retro .Button--color--caution{transition:color 50ms,background-color 50ms;background-color:#be6209;color:#fff}.theme-retro .Button--color--caution:hover{transition:color 0ms,background-color 0ms}.theme-retro .Button--color--caution:focus{transition:color .1s,background-color .1s}.theme-retro .Button--color--caution:focus,.theme-retro .Button--color--caution:hover{background-color:#d67313;color:#fff}.theme-retro .Button--color--danger{transition:color 50ms,background-color 50ms;background-color:#9a9d00;color:#fff}.theme-retro .Button--color--danger:hover{transition:color 0ms,background-color 0ms}.theme-retro .Button--color--danger:focus{transition:color .1s,background-color .1s}.theme-retro .Button--color--danger:focus,.theme-retro .Button--color--danger:hover{background-color:#afb30a;color:#fff}.theme-retro .Button--color--transparent{transition:color 50ms,background-color 50ms;background-color:#e8e4c9;color:#000;background-color:rgba(232,228,201,0);color:hsla(0,0%,100%,.5)}.theme-retro .Button--color--transparent:hover{transition:color 0ms,background-color 0ms}.theme-retro .Button--color--transparent:focus{transition:color .1s,background-color .1s}.theme-retro .Button--color--transparent:focus,.theme-retro .Button--color--transparent:hover{background-color:#f7f6ee;color:#000}.theme-retro .Button--disabled{background-color:#363636!important}.theme-retro .Button--selected{transition:color 50ms,background-color 50ms;background-color:#9d0808;color:#fff}.theme-retro .Button--selected:hover{transition:color 0ms,background-color 0ms}.theme-retro .Button--selected:focus{transition:color .1s,background-color .1s}.theme-retro .Button--selected:focus,.theme-retro .Button--selected:hover{background-color:#b31212;color:#fff}.theme-retro .Layout{position:fixed;top:0;bottom:0;left:0;right:0;color:#fff;background-color:#e8e4c9;background-image:linear-gradient(180deg,#e8e4c9 0,#e8e4c9)}.theme-retro .Layout__titleBar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px}.theme-retro .Layout__content{position:fixed;top:32px;bottom:0;left:0;right:0;overflow-x:hidden;overflow-y:hidden;margin-bottom:-6px;scrollbar-base-color:#c8be7d;scrollbar-face-color:#eae7ce;scrollbar-3dlight-color:#e8e4c9;scrollbar-highlight-color:#e8e4c9;scrollbar-track-color:#c8be7d;scrollbar-arrow-color:#f4f2e4;scrollbar-shadow-color:#eae7ce}.theme-retro .Layout__content--scrollable{overflow-y:scroll;margin-bottom:0}.theme-retro .Layout__dimmer{position:fixed;top:32px;bottom:0;left:0;right:0;background-color:rgba(251,250,246,.25);pointer-events:none}.theme-retro .Layout__toast{position:fixed;bottom:0;left:0;right:0;font-size:12px;height:40px;line-height:39px;padding:0 12px;background-color:#988d41;color:hsla(0,0%,100%,.8)}.theme-retro .Layout__resizeHandle__se{position:fixed;bottom:0;right:0;width:20px;height:20px;cursor:se-resize}.theme-retro .Layout__resizeHandle__s{position:fixed;bottom:0;left:0;right:0;height:6px;cursor:s-resize}.theme-retro .Layout__resizeHandle__e{position:fixed;top:0;bottom:0;right:0;width:3px;cursor:e-resize}.theme-retro .ProgressBar{display:inline-block;position:relative;width:100%;padding:0 6px;border-radius:0;background-color:rgba(0,0,0,.5);transition:border-color .5s}.theme-retro .ProgressBar__fill{position:absolute;top:0;left:0;bottom:0;transition:background-color .5s,width .5s}.theme-retro .ProgressBar__content{position:relative;line-height:17px;width:100%;text-align:right}.theme-retro .ProgressBar--color--default{border:1px solid #000}.theme-retro .ProgressBar--color--default .ProgressBar__fill{background-color:#000}.theme-retro .Section{position:relative;margin-bottom:6px;background-color:#1a1a1a;background-color:rgba(0,0,0,.33);box-shadow:inset 0 0 5px rgba(0,0,0,.5);box-sizing:border-box}.theme-retro .Section:last-child{margin-bottom:0}.theme-retro .Section__title{position:relative;padding:6px;border-bottom:2px solid #000}.theme-retro .Section__titleText{font-size:14px;font-weight:700}.theme-retro .Section__buttons{position:absolute;display:inline-block;right:6px;margin-top:-1px}.theme-retro .Section__content{padding:8px 6px}.theme-retro .Section--level--1 .Section__titleText{font-size:14px}.theme-retro .Section--level--2 .Section__titleText{font-size:13px}.theme-retro .Section--level--3 .Section__titleText{font-size:12px}.theme-retro .Section--level--2,.theme-retro .Section--level--3{background-color:transparent;box-shadow:none;margin-left:-6px;margin-right:-6px}.theme-retro .TitleBar{background-color:#585337;border-bottom:1px solid #161616;box-shadow:0 2px 2px rgba(0,0,0,.1);user-select:none;-ms-user-select:none}.theme-retro .TitleBar__clickable{color:hsla(0,0%,100%,.5);background-color:#585337;transition:color .25s,background-color .25s}.theme-retro .TitleBar__clickable:hover{color:#fff;background-color:#c00;transition:color 0ms,background-color 0ms}.theme-retro .TitleBar__title{position:absolute;top:0;left:46px;color:hsla(0,0%,100%,.75);font-size:14px;line-height:31px;white-space:nowrap}.theme-retro .TitleBar__dragZone{position:absolute;top:0;left:0;right:0;height:32px}.theme-retro .TitleBar__statusIcon{position:absolute;top:0;left:12px;transition:color .5s;font-size:20px;line-height:32px!important}.theme-retro .TitleBar__minimize{position:absolute;top:6px;right:46px}.theme-retro .TitleBar__close{position:absolute;top:-1px;right:0;width:45px;height:32px;font-size:20px;line-height:31px;text-align:center}.theme-retro .Button{font-family:monospace;color:#161613;border:8px outset #e8e4c9;outline:3px solid #161613}.theme-retro .Layout__content{background-image:none}.theme-syndicate .Button{position:relative;display:inline-block;line-height:20px;padding:0 6px;margin-right:2px;white-space:nowrap;outline:0;border-radius:0;margin-bottom:2px;user-select:none;-ms-user-select:none}.theme-syndicate .Button:last-child{margin-right:0}.theme-syndicate .Button .fa,.theme-syndicate .Button .far,.theme-syndicate .Button .fas{margin-left:-3px;margin-right:-3px;min-width:16px;text-align:center}.theme-syndicate .Button--hasContent .fa,.theme-syndicate .Button--hasContent .far,.theme-syndicate .Button--hasContent .fas{margin-right:3px}.theme-syndicate .Button--ellipsis{overflow:hidden;text-overflow:ellipsis}.theme-syndicate .Button--fluid{display:block;margin-left:0;margin-right:0}.theme-syndicate .Button--color--default{transition:color 50ms,background-color 50ms;background-color:#397439;color:#fff}.theme-syndicate .Button--color--default:hover{transition:color 0ms,background-color 0ms}.theme-syndicate .Button--color--default:focus{transition:color .1s,background-color .1s}.theme-syndicate .Button--color--default:focus,.theme-syndicate .Button--color--default:hover{background-color:#478647;color:#fff}.theme-syndicate .Button--color--caution{transition:color 50ms,background-color 50ms;background-color:#be6209;color:#fff}.theme-syndicate .Button--color--caution:hover{transition:color 0ms,background-color 0ms}.theme-syndicate .Button--color--caution:focus{transition:color .1s,background-color .1s}.theme-syndicate .Button--color--caution:focus,.theme-syndicate .Button--color--caution:hover{background-color:#d67313;color:#fff}.theme-syndicate .Button--color--danger{transition:color 50ms,background-color 50ms;background-color:#9a9d00;color:#fff}.theme-syndicate .Button--color--danger:hover{transition:color 0ms,background-color 0ms}.theme-syndicate .Button--color--danger:focus{transition:color .1s,background-color .1s}.theme-syndicate .Button--color--danger:focus,.theme-syndicate .Button--color--danger:hover{background-color:#afb30a;color:#fff}.theme-syndicate .Button--color--transparent{transition:color 50ms,background-color 50ms;background-color:#550202;color:#fff;background-color:rgba(85,2,2,0);color:hsla(0,0%,100%,.5)}.theme-syndicate .Button--color--transparent:hover{transition:color 0ms,background-color 0ms}.theme-syndicate .Button--color--transparent:focus{transition:color .1s,background-color .1s}.theme-syndicate .Button--color--transparent:focus,.theme-syndicate .Button--color--transparent:hover{background-color:#650c0c;color:#fff}.theme-syndicate .Button--disabled{background-color:#363636!important}.theme-syndicate .Button--selected{transition:color 50ms,background-color 50ms;background-color:#9d0808;color:#fff}.theme-syndicate .Button--selected:hover{transition:color 0ms,background-color 0ms}.theme-syndicate .Button--selected:focus{transition:color .1s,background-color .1s}.theme-syndicate .Button--selected:focus,.theme-syndicate .Button--selected:hover{background-color:#b31212;color:#fff}.theme-syndicate .Layout{position:fixed;top:0;bottom:0;left:0;right:0;color:#fff;background-color:#550202;background-image:linear-gradient(180deg,#730303 0,#370101)}.theme-syndicate .Layout__titleBar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px}.theme-syndicate .Layout__content{position:fixed;top:32px;bottom:0;left:0;right:0;overflow-x:hidden;overflow-y:hidden;margin-bottom:-6px;scrollbar-base-color:#400202;scrollbar-face-color:#7e0303;scrollbar-3dlight-color:#550202;scrollbar-highlight-color:#550202;scrollbar-track-color:#400202;scrollbar-arrow-color:#fa3030;scrollbar-shadow-color:#7e0303}.theme-syndicate .Layout__content--scrollable{overflow-y:scroll;margin-bottom:0}.theme-syndicate .Layout__dimmer{position:fixed;top:32px;bottom:0;left:0;right:0;background-color:rgba(117,22,22,.25);pointer-events:none}.theme-syndicate .Layout__toast{position:fixed;bottom:0;left:0;right:0;font-size:12px;height:40px;line-height:39px;padding:0 12px;background-color:#2b0101;color:hsla(0,0%,100%,.8)}.theme-syndicate .Layout__resizeHandle__se{position:fixed;bottom:0;right:0;width:20px;height:20px;cursor:se-resize}.theme-syndicate .Layout__resizeHandle__s{position:fixed;bottom:0;left:0;right:0;height:6px;cursor:s-resize}.theme-syndicate .Layout__resizeHandle__e{position:fixed;top:0;bottom:0;right:0;width:3px;cursor:e-resize}.theme-syndicate .NoticeBox{padding:4px 6px;margin-bottom:6px;box-shadow:none;font-weight:700;font-style:italic;color:#fff;background-color:#750000;background-image:repeating-linear-gradient(-45deg,#750000,#750000 10px,#910101 0,#910101 20px)}.theme-syndicate .Input{position:relative;display:inline-block;width:120px;border:1px solid #87ce87;border:1px solid rgba(135,206,135,.75);border-radius:2px;color:#fff;background-color:#000;background-color:rgba(0,0,0,.75);padding:0 4px;margin-right:2px;line-height:17px;overflow:visible}.theme-syndicate .Input--fluid{display:block;width:auto}.theme-syndicate .Input__baseline{display:inline-block;color:transparent}.theme-syndicate .Input__input{display:block;position:absolute;top:0;bottom:0;left:0;right:0;border:0;outline:0;width:100%;font-size:12px;line-height:17px;height:17px;margin:0;padding:0 6px;font-family:Verdana,sans-serif;background-color:transparent;color:#fff;color:inherit}.theme-syndicate .Input__input:-ms-input-placeholder{font-style:italic;color:#777;color:hsla(0,0%,100%,.45)}.theme-syndicate .NumberInput{position:relative;display:inline-block;border:1px solid #87ce87;border:1px solid rgba(135,206,135,.75);border-radius:2px;color:#87ce87;background-color:#000;background-color:rgba(0,0,0,.75);padding:0 4px;margin-right:2px;line-height:17px;text-align:right;overflow:visible;cursor:n-resize}.theme-syndicate .NumberInput--fluid{display:block}.theme-syndicate .NumberInput__content{margin-left:6px}.theme-syndicate .NumberInput__barContainer{position:absolute;top:2px;bottom:2px;left:2px}.theme-syndicate .NumberInput__bar{position:absolute;bottom:0;left:0;width:3px;box-sizing:border-box;border-bottom:1px solid #87ce87;background-color:#87ce87}.theme-syndicate .NumberInput__input{display:block;position:absolute;top:0;bottom:0;left:0;right:0;border:0;outline:0;width:100%;font-size:12px;line-height:17px;height:17px;margin:0;padding:0 6px;font-family:Verdana,sans-serif;background-color:#000;color:#fff;text-align:right}.theme-syndicate .ProgressBar{display:inline-block;position:relative;width:100%;padding:0 6px;border-radius:0;background-color:rgba(0,0,0,.5);transition:border-color .5s}.theme-syndicate .ProgressBar__fill{position:absolute;top:0;left:0;bottom:0;transition:background-color .5s,width .5s}.theme-syndicate .ProgressBar__content{position:relative;line-height:17px;width:100%;text-align:right}.theme-syndicate .ProgressBar--color--default{border:1px solid #306330}.theme-syndicate .ProgressBar--color--default .ProgressBar__fill{background-color:#306330}.theme-syndicate .Section{position:relative;margin-bottom:6px;background-color:#1a1a1a;background-color:rgba(0,0,0,.33);box-shadow:inset 0 0 5px rgba(0,0,0,.5);box-sizing:border-box}.theme-syndicate .Section:last-child{margin-bottom:0}.theme-syndicate .Section__title{position:relative;padding:6px;border-bottom:2px solid #397439}.theme-syndicate .Section__titleText{font-size:14px;font-weight:700}.theme-syndicate .Section__buttons{position:absolute;display:inline-block;right:6px;margin-top:-1px}.theme-syndicate .Section__content{padding:8px 6px}.theme-syndicate .Section--level--1 .Section__titleText{font-size:14px}.theme-syndicate .Section--level--2 .Section__titleText{font-size:13px}.theme-syndicate .Section--level--3 .Section__titleText{font-size:12px}.theme-syndicate .Section--level--2,.theme-syndicate .Section--level--3{background-color:transparent;box-shadow:none;margin-left:-6px;margin-right:-6px}.theme-syndicate .TitleBar{background-color:#910101;border-bottom:1px solid #161616;box-shadow:0 2px 2px rgba(0,0,0,.1);user-select:none;-ms-user-select:none}.theme-syndicate .TitleBar__clickable{color:hsla(0,0%,100%,.5);background-color:#910101;transition:color .25s,background-color .25s}.theme-syndicate .TitleBar__clickable:hover{color:#fff;background-color:#c00;transition:color 0ms,background-color 0ms}.theme-syndicate .TitleBar__title{position:absolute;top:0;left:46px;color:hsla(0,0%,100%,.75);font-size:14px;line-height:31px;white-space:nowrap}.theme-syndicate .TitleBar__dragZone{position:absolute;top:0;left:0;right:0;height:32px}.theme-syndicate .TitleBar__statusIcon{position:absolute;top:0;left:12px;transition:color .5s;font-size:20px;line-height:32px!important}.theme-syndicate .TitleBar__minimize{position:absolute;top:6px;right:46px}.theme-syndicate .TitleBar__close{position:absolute;top:-1px;right:0;width:45px;height:32px;font-size:20px;line-height:31px;text-align:center}.theme-syndicate .Tooltip{position:absolute;top:0;left:0;right:0;bottom:0;font-style:normal;font-weight:400}.theme-syndicate .Tooltip:after{position:absolute;display:block;white-space:nowrap;z-index:2;padding:6px 10px;transform:translateX(-50%);pointer-events:none;visibility:hidden;opacity:0;text-align:left;content:attr(data-tooltip);transition:all .15s;background-color:#4a0202;box-shadow:1px 1px 15px -1px rgba(0,0,0,.5);border-radius:2px}.theme-syndicate .Tooltip:hover:after{transition:all 70ms;pointer-events:none;visibility:visible;opacity:1}.theme-syndicate .Tooltip--long:after{width:250px;white-space:normal}.theme-syndicate .Tooltip--top:after{bottom:100%;left:50%;transform:translateX(-50%) translateY(8px)}.theme-syndicate .Tooltip--bottom:after,.theme-syndicate .Tooltip--top:hover:after{transform:translateX(-50%) translateY(-8px)}.theme-syndicate .Tooltip--bottom:after{top:100%;left:50%}.theme-syndicate .Tooltip--bottom:hover:after{transform:translateX(-50%) translateY(8px)}.theme-syndicate .Tooltip--bottom-left:after{top:100%;right:50%;transform:translateX(12px) translateY(-8px)}.theme-syndicate .Tooltip--bottom-left:hover:after{transform:translateX(12px) translateY(8px)}.theme-syndicate .Tooltip--bottom-right:after{top:100%;left:50%;transform:translateX(-12px) translateY(-8px)}.theme-syndicate .Tooltip--bottom-right:hover:after{transform:translateX(-12px) translateY(8px)}.theme-syndicate .Tooltip--left:after{top:50%;right:100%;transform:translateX(8px) translateY(-50%)}.theme-syndicate .Tooltip--left:hover:after,.theme-syndicate .Tooltip--right:after{transform:translateX(-8px) translateY(-50%)}.theme-syndicate .Tooltip--right:after{top:50%;left:100%}.theme-syndicate .Tooltip--right:hover:after{transform:translateX(8px) translateY(-50%)}.theme-syndicate .Layout__content{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMCIgdmlld0JveD0iMCAwIDIwMCAyODkuNzQyIiBvcGFjaXR5PSIuMzMiPjxwYXRoIGQ9Ik05My41MzggMGMtMTguMTEzIDAtMzQuMjIgMy4xMTItNDguMzI0IDkuMzM0LTEzLjk2NSA2LjIyMi0yNC42MTIgMTUuMDcyLTMxLjk0IDI2LjU0N0M2LjA4NCA0Ny4yMiAyLjk3MiA2MC42MzEgMi45NzIgNzYuMTE2YzAgMTAuNjQ3IDIuNzI1IDIwLjQ2NSA4LjE3NSAyOS40NTMgNS42MTYgOC45ODcgMTQuMDM5IDE3LjM1MiAyNS4yNyAyNS4wOTQgMTEuMjMgNy42MDYgMjYuNTA3IDE1LjQxOSA0NS44MyAyMy40MzggMTkuOTg0IDguMjk2IDM0Ljg0OSAxNS41NTUgNDQuNTkzIDIxLjc3NiA5Ljc0NCA2LjIyMyAxNi43NjEgMTIuODU5IDIxLjA1NSAxOS45MSA0LjI5NSA3LjA1MiA2LjQ0MiAxNS43NjQgNi40NDIgMjYuMTM0IDAgMTYuMTc4LTUuMjAyIDI4LjQ4My0xNS42MDYgMzYuOTE3LTEwLjI0IDguNDM1LTI1LjAyMiAxMi42NTMtNDQuMzQ1IDEyLjY1My0xNC4wMzkgMC0yNS41MTYtMS42Ni0zNC40MzQtNC45NzgtOC45MTgtMy40NTctMTYuMTg2LTguNzExLTIxLjgtMTUuNzYzLTUuNjE2LTcuMDUyLTEwLjA3Ni0xNi42NjEtMTMuMzc5LTI4LjgyOUgwdjU2LjgyN2MzMy44NTcgNy4zMjggNjMuNzQ5IDEwLjk5NCA4OS42NzggMTAuOTk0IDE2LjAyIDAgMzAuNzItMS4zODMgNDQuMDk4LTQuMTQ4IDEzLjU0Mi0yLjkwNCAyNS4xMDQtNy40NjcgMzQuNjgzLTEzLjY5IDkuNzQ0LTYuMzU5IDE3LjM0LTE0LjUxOSAyMi43OS0yNC40NzQgNS40NS0xMC4wOTMgOC4xNzUtMjIuNCA4LjE3NS0zNi45MTcgMC0xMi45OTctMy4zMDItMjQuMzM1LTkuOTA4LTM0LjAxNC02LjQ0LTkuODE4LTE1LjUyNS0xOC41MjctMjcuMjUxLTI2LjEzMi0xMS41NjEtNy42MDQtMjcuOTExLTE1LjgzMS00OS4wNTEtMjQuNjgtMTcuNTA2LTcuMTktMzAuNzItMTMuNjktMzkuNjM4LTE5LjQ5N1M1NC45NjkgOTMuNzU2IDQ5LjQ3OSA4Ny4zMTZjLTUuNDI2LTYuMzY2LTkuNjU4LTE1LjA3LTkuNjU4LTI0Ljg4NyAwLTkuMjY0IDIuMDc1LTE3LjIxNCA2LjIyMy0yMy44NUM1Ny4xNDIgMjQuMTggODcuMzMxIDM2Ljc4MiA5MS4xMiA2Mi45MjVjNC44NCA2Ljc3NSA4Ljg1IDE2LjI0NyAxMi4wMyAyOC40MTVoMjAuNTMydi01NmMtNC40NzktNS45MjQtOS45NTUtMTAuNjMxLTE1LjkwOS0xNC4zNzMgMS42NC40NzkgMy4xOSAxLjAyMyA0LjYzOSAxLjY0IDYuNDk4IDIuNjI2IDEyLjE2OCA3LjMyNyAxNy4wMDcgMTQuMTAzIDQuODQgNi43NzUgOC44NSAxNi4yNDYgMTIuMDMgMjguNDE0IDAgMCA4LjQ4LS4xMjkgOC40OS0uMDAyLjQxNyA2LjQxNS0xLjc1NCA5LjQ1My00LjEyNCAxMi41NjEtMi40MTcgMy4xNy01LjE0NSA2Ljc5LTQuMDAzIDEzLjAwMyAxLjUwOCA4LjIwMyAxMC4xODQgMTAuNTk3IDE0LjYyMiA5LjMxMi0zLjMxOC0uNS01LjMxOC0xLjc1LTUuMzE4LTEuNzVzMS44NzYuOTk5IDUuNjUtMS4zNmMtMy4yNzYuOTU2LTEwLjcwNC0uNzk3LTExLjgtNi43NjMtLjk1OC01LjIwOC45NDYtNy4yOTUgMy40LTEwLjUxNCAyLjQ1NS0zLjIyIDUuMjg1LTYuOTU5IDQuNjg1LTE0LjQ4OWwuMDAzLjAwMmg4LjkyN3YtNTZjLTE1LjA3Mi0zLjg3MS0yNy42NTMtNi4zNi0zNy43NDctNy40NjVDMTE0LjI3OS41NTIgMTA0LjA0NiAwIDkzLjUzNyAwem03MC4zMjEgMTcuMzA5bC4yMzggNDAuMzA1YzEuMzE4IDEuMjI2IDIuNDQgMi4yNzggMy4zNDEgMy4xMDYgNC44NCA2Ljc3NSA4Ljg1IDE2LjI0NiAxMi4wMyAyOC40MTRIMjAwdi01NmMtNi42NzctNC41OTQtMTkuODM2LTEwLjQ3My0zNi4xNC0xNS44MjV6bS0yOC4xMiA1LjYwNWw4LjU2NSAxNy43MTdjLTExLjk3LTYuNDY3LTEzLjg0Ny05LjcxNy04LjU2NS0xNy43MTd6bTIyLjc5NyAwYzIuNzcxIDggMS43ODcgMTEuMjUtNC40OTQgMTcuNzE3bDQuNDk0LTE3LjcxN3ptMTUuMjIyIDI0LjAwOWw4LjU2NSAxNy43MTZjLTExLjk3LTYuNDY2LTEzLjg0Ny05LjcxNy04LjU2NS0xNy43MTZ6bTIyLjc5NyAwYzIuNzcxIDggMS43ODcgMTEuMjUtNC40OTQgMTcuNzE2bDQuNDk0LTE3LjcxNnpNOTcuNDQgNDkuMTNsOC41NjUgMTcuNzE2Yy0xMS45Ny02LjQ2Ny0xMy44NDctOS43MTctOC41NjUtMTcuNzE2em0yMi43OTUgMGMyLjc3MiA3Ljk5OSAxLjc4OCAxMS4yNS00LjQ5MyAxNy43MTZsNC40OTMtMTcuNzE2eiIvPjwvc3ZnPg==)} \ No newline at end of file diff --git a/tgui-next/packages/tgui/public/tgui.bundle.js b/tgui-next/packages/tgui/public/tgui.bundle.js deleted file mode 100644 index 8a89fd703d..0000000000 --- a/tgui-next/packages/tgui/public/tgui.bundle.js +++ /dev/null @@ -1,3 +0,0 @@ -!function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=169)}([function(e,t,n){"use strict";t.__esModule=!0;var o=n(390);Object.keys(o).forEach((function(e){"default"!==e&&"__esModule"!==e&&(t[e]=o[e])}))},function(e,t,n){"use strict";var o=n(5),r=n(20).f,a=n(30),i=n(22),c=n(90),l=n(125),u=n(62);e.exports=function(e,t){var n,d,s,p,m,f=e.target,h=e.global,C=e.stat;if(n=h?o:C?o[f]||c(f,{}):(o[f]||{}).prototype)for(d in t){if(p=t[d],s=e.noTargetGet?(m=r(n,d))&&m.value:n[d],!u(h?d:f+(C?".":"#")+d,e.forced)&&s!==undefined){if(typeof p==typeof s)continue;l(p,s)}(e.sham||s&&s.sham)&&a(p,"sham",!0),i(n,d,p,e)}}},function(e,t,n){"use strict";t.__esModule=!0,t.Chart=t.Tooltip=t.Toast=t.TitleBar=t.Tabs=t.Table=t.Section=t.ProgressBar=t.NumberInput=t.NoticeBox=t.LabeledList=t.Input=t.Icon=t.Grid=t.Flex=t.Dropdown=t.Dimmer=t.Collapsible=t.ColorBox=t.Button=t.Box=t.BlockQuote=t.AnimatedNumber=void 0;var o=n(162);t.AnimatedNumber=o.AnimatedNumber;var r=n(395);t.BlockQuote=r.BlockQuote;var a=n(19);t.Box=a.Box;var i=n(117);t.Button=i.Button;var c=n(397);t.ColorBox=c.ColorBox;var l=n(398);t.Collapsible=l.Collapsible;var u=n(399);t.Dimmer=u.Dimmer;var d=n(400);t.Dropdown=d.Dropdown;var s=n(401);t.Flex=s.Flex;var p=n(165);t.Grid=p.Grid;var m=n(88);t.Icon=m.Icon;var f=n(164);t.Input=f.Input;var h=n(167);t.LabeledList=h.LabeledList;var C=n(402);t.NoticeBox=C.NoticeBox;var g=n(403);t.NumberInput=g.NumberInput;var b=n(404);t.ProgressBar=b.ProgressBar;var N=n(405);t.Section=N.Section;var v=n(166);t.Table=v.Table;var V=n(406);t.Tabs=V.Tabs;var y=n(407);t.TitleBar=y.TitleBar;var _=n(120);t.Toast=_.Toast;var x=n(163);t.Tooltip=x.Tooltip;var k=n(408);t.Chart=k.Chart},function(e,t,n){"use strict";t.__esModule=!0,t.useBackend=t.backendReducer=t.backendUpdate=void 0;var o=n(33),r=n(16);t.backendUpdate=function(e){return{type:"backendUpdate",payload:e}};t.backendReducer=function(e,t){var n=t.type,r=t.payload;if("backendUpdate"===n){var a=Object.assign({},e.config,r.config),i=Object.assign({},e.data,r.static_data,r.data),c=a.status!==o.UI_DISABLED,l=a.status===o.UI_INTERACTIVE;return Object.assign({},e,{config:a,data:i,visible:c,interactive:l})}return e};t.useBackend=function(e){var t=e.state,n=(e.dispatch,t.config.ref);return Object.assign({},t,{act:function(e,t){return void 0===t&&(t={}),(0,r.act)(n,e,t)}})}},function(e,t,n){"use strict";e.exports=function(e){try{return!!e()}catch(t){return!0}}},function(e,t,n){"use strict";(function(t){var n=function(e){return e&&e.Math==Math&&e};e.exports=n("object"==typeof globalThis&&globalThis)||n("object"==typeof window&&window)||n("object"==typeof self&&self)||n("object"==typeof t&&t)||Function("return this")()}).call(this,n(121))},function(e,t,n){"use strict";e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,t,n){"use strict";var o=n(4);e.exports=!o((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},function(e,t,n){"use strict";var o=n(6);e.exports=function(e){if(!o(e))throw TypeError(String(e)+" is not an object");return e}},function(e,t,n){"use strict";var o,r=n(104),a=n(7),i=n(5),c=n(6),l=n(15),u=n(75),d=n(30),s=n(22),p=n(13).f,m=n(37),f=n(51),h=n(12),C=n(59),g=i.Int8Array,b=g&&g.prototype,N=i.Uint8ClampedArray,v=N&&N.prototype,V=g&&m(g),y=b&&m(b),_=Object.prototype,x=_.isPrototypeOf,k=h("toStringTag"),L=C("TYPED_ARRAY_TAG"),w=r&&!!f&&"Opera"!==u(i.opera),B=!1,S={Int8Array:1,Uint8Array:1,Uint8ClampedArray:1,Int16Array:2,Uint16Array:2,Int32Array:4,Uint32Array:4,Float32Array:4,Float64Array:8},I=function(e){var t=u(e);return"DataView"===t||l(S,t)},T=function(e){return c(e)&&l(S,u(e))};for(o in S)i[o]||(w=!1);if((!w||"function"!=typeof V||V===Function.prototype)&&(V=function(){throw TypeError("Incorrect invocation")},w))for(o in S)i[o]&&f(i[o],V);if((!w||!y||y===_)&&(y=V.prototype,w))for(o in S)i[o]&&f(i[o].prototype,y);if(w&&m(v)!==y&&f(v,y),a&&!l(y,k))for(o in B=!0,p(y,k,{get:function(){return c(this)?this[L]:undefined}}),S)i[o]&&d(i[o],L,o);e.exports={NATIVE_ARRAY_BUFFER_VIEWS:w,TYPED_ARRAY_TAG:B&&L,aTypedArray:function(e){if(T(e))return e;throw TypeError("Target is not a typed array")},aTypedArrayConstructor:function(e){if(f){if(x.call(V,e))return e}else for(var t in S)if(l(S,o)){var n=i[t];if(n&&(e===n||x.call(n,e)))return e}throw TypeError("Target is not a typed array constructor")},exportTypedArrayMethod:function(e,t,n){if(a){if(n)for(var o in S){var r=i[o];r&&l(r.prototype,e)&&delete r.prototype[e]}y[e]&&!n||s(y,e,n?t:w&&b[e]||t)}},exportTypedArrayStaticMethod:function(e,t,n){var o,r;if(a){if(f){if(n)for(o in S)(r=i[o])&&l(r,e)&&delete r[e];if(V[e]&&!n)return;try{return s(V,e,n?t:w&&g[e]||t)}catch(c){}}for(o in S)!(r=i[o])||r[e]&&!n||s(r,e,t)}},isView:I,isTypedArray:T,TypedArray:V,TypedArrayPrototype:y}},function(e,t,n){"use strict";var o=n(31),r=Math.min;e.exports=function(e){return e>0?r(o(e),9007199254740991):0}},function(e,t,n){"use strict";t.__esModule=!0,t.isFalsy=t.pureComponentHooks=t.shallowDiffers=t.normalizeChildren=t.classes=void 0;t.classes=function(e){for(var t="",n=0;n_;_++)if((p||_ in v)&&(b=V(g=v[_],_,N),e))if(t)k[_]=b;else if(b)switch(e){case 3:return!0;case 5:return g;case 6:return _;case 2:l.call(k,g)}else if(d)return!1;return s?-1:u||d?d:k}};e.exports={forEach:u(0),map:u(1),filter:u(2),some:u(3),every:u(4),find:u(5),findIndex:u(6)}},function(e,t,n){"use strict";t.__esModule=!0,t.Box=t.computeBoxProps=t.unit=void 0;var o=n(0),r=n(11),a=n(396),i=n(33);function c(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}var l=function(e){return"string"==typeof e?e:"number"==typeof e?6*e+"px":void 0};t.unit=l;var u=function(e){return"string"==typeof e&&i.CSS_COLORS.includes(e)},d=function(e){return function(t,n){(0,r.isFalsy)(n)||(t[e]=n)}},s=function(e){return function(t,n){(0,r.isFalsy)(n)||(t[e]=l(n))}},p=function(e,t){return function(n,o){(0,r.isFalsy)(o)||(n[e]=t)}},m=function(e,t){return function(n,o){if(!(0,r.isFalsy)(o))for(var a=0;a0&&(t.style=l),t};t.computeBoxProps=C;var g=function(e){var t=e.as,n=void 0===t?"div":t,i=e.className,l=e.content,d=e.children,s=c(e,["as","className","content","children"]),p=e.textColor||e.color,m=e.backgroundColor;if("function"==typeof d)return d(C(e));var f=C(s);return(0,o.createVNode)(a.VNodeFlags.HtmlElement,n,(0,r.classes)([i,u(p)&&"color-"+p,u(m)&&"color-bg-"+m]),l||d,a.ChildFlags.UnknownChildren,f)};t.Box=g,g.defaultHooks=r.pureComponentHooks;var b=function(e){var t=e.children,n=c(e,["children"]);return(0,o.normalizeProps)((0,o.createComponentVNode)(2,g,Object.assign({position:"relative"},n,{children:(0,o.createComponentVNode)(2,g,{fillPositionedParent:!0,children:t})})))};b.defaultHooks=r.pureComponentHooks,g.Forced=b},function(e,t,n){"use strict";var o=n(7),r=n(72),a=n(47),i=n(26),c=n(35),l=n(15),u=n(122),d=Object.getOwnPropertyDescriptor;t.f=o?d:function(e,t){if(e=i(e),t=c(t,!0),u)try{return d(e,t)}catch(n){}if(l(e,t))return a(!r.f.call(e,t),e[t])}},function(e,t,n){"use strict";e.exports=function(e){if(e==undefined)throw TypeError("Can't call method on "+e);return e}},function(e,t,n){"use strict";var o=n(5),r=n(30),a=n(15),i=n(90),c=n(91),l=n(36),u=l.get,d=l.enforce,s=String(String).split("String");(e.exports=function(e,t,n,c){var l=!!c&&!!c.unsafe,u=!!c&&!!c.enumerable,p=!!c&&!!c.noTargetGet;"function"==typeof n&&("string"!=typeof t||a(n,"name")||r(n,"name",t),d(n).source=s.join("string"==typeof t?t:"")),e!==o?(l?!p&&e[t]&&(u=!0):delete e[t],u?e[t]=n:r(e,t,n)):u?e[t]=n:i(t,n)})(Function.prototype,"toString",(function(){return"function"==typeof this&&u(this).source||c(this)}))},function(e,t,n){"use strict";var o=n(7),r=n(4),a=n(15),i=Object.defineProperty,c={},l=function(e){throw e};e.exports=function(e,t){if(a(c,e))return c[e];t||(t={});var n=[][e],u=!!a(t,"ACCESSORS")&&t.ACCESSORS,d=a(t,0)?t[0]:l,s=a(t,1)?t[1]:undefined;return c[e]=!!n&&!r((function(){if(u&&!o)return!0;var e={length:-1};u?i(e,1,{enumerable:!0,get:l}):e[1]=1,n.call(e,d,s)}))}},function(e,t,n){"use strict";function o(e,t){var n;if("undefined"==typeof Symbol||null==e[Symbol.iterator]){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return r(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return r(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var o=0;return function(){return o>=e.length?{done:!0}:{done:!1,value:e[o++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}return(n=e[Symbol.iterator]()).next.bind(n)}function r(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,o=new Array(t);n",apos:"'"};return e.replace(/
        /gi,"\n").replace(/<\/?[a-z0-9-_]+[^>]*>/gi,"").replace(/&(nbsp|amp|quot|lt|gt|apos);/g,(function(e,n){return t[n]})).replace(/&#?([0-9]+);/gi,(function(e,t){var n=parseInt(t,10);return String.fromCharCode(n)})).replace(/&#x?([0-9a-f]+);/gi,(function(e,t){var n=parseInt(t,16);return String.fromCharCode(n)}))};t.buildQueryString=function(e){return Object.keys(e).map((function(t){return encodeURIComponent(t)+"="+encodeURIComponent(e[t])})).join("&")}},function(e,t,n){"use strict";t.__esModule=!0,t.zipWith=t.zip=t.reduce=t.sortBy=t.map=t.toArray=void 0;t.toArray=function(e){if(Array.isArray(e))return e;if("object"==typeof e){var t=Object.prototype.hasOwnProperty,n=[];for(var o in e)t.call(e,o)&&n.push(e[o]);return n}return[]};var o=function(e){return function(t){if(null===t&&t===undefined)return t;if(Array.isArray(t)){for(var n=[],o=0;oc)return 1}return 0};t.sortBy=function(){for(var e=arguments.length,t=new Array(e),n=0;n"+i+""}},function(e,t,n){"use strict";var o=n(4);e.exports=function(e){return o((function(){var t=""[e]('"');return t!==t.toLowerCase()||t.split('"').length>3}))}},function(e,t,n){"use strict";var o=n(7),r=n(13),a=n(47);e.exports=o?function(e,t,n){return r.f(e,t,a(1,n))}:function(e,t,n){return e[t]=n,e}},function(e,t,n){"use strict";var o=Math.ceil,r=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?r:o)(e)}},function(e,t,n){"use strict";e.exports=function(e){if("function"!=typeof e)throw TypeError(String(e)+" is not a function");return e}},function(e,t,n){"use strict";t.__esModule=!0,t.getGasColor=t.getGasLabel=t.RADIO_CHANNELS=t.CSS_COLORS=t.COLORS=t.UI_CLOSE=t.UI_DISABLED=t.UI_UPDATE=t.UI_INTERACTIVE=void 0;t.UI_INTERACTIVE=2;t.UI_UPDATE=1;t.UI_DISABLED=0;t.UI_CLOSE=-1;t.COLORS={department:{captain:"#c06616",security:"#e74c3c",medbay:"#3498db",science:"#9b59b6",engineering:"#f1c40f",cargo:"#f39c12",centcom:"#00c100",other:"#c38312"},damageType:{oxy:"#3498db",toxin:"#2ecc71",burn:"#e67e22",brute:"#e74c3c"}};t.CSS_COLORS=["black","white","red","orange","yellow","olive","green","teal","blue","violet","purple","pink","brown","grey","good","average","bad","label"];t.RADIO_CHANNELS=[{name:"Syndicate",freq:1213,color:"#a52a2a"},{name:"Red Team",freq:1215,color:"#ff4444"},{name:"Blue Team",freq:1217,color:"#3434fd"},{name:"CentCom",freq:1337,color:"#2681a5"},{name:"Supply",freq:1347,color:"#b88646"},{name:"Service",freq:1349,color:"#6ca729"},{name:"Science",freq:1351,color:"#c68cfa"},{name:"Command",freq:1353,color:"#5177ff"},{name:"Medical",freq:1355,color:"#57b8f0"},{name:"Engineering",freq:1357,color:"#f37746"},{name:"Security",freq:1359,color:"#dd3535"},{name:"AI Private",freq:1447,color:"#d65d95"},{name:"Common",freq:1459,color:"#1ecc43"}];var o=[{id:"o2",name:"Oxygen",label:"O\u2082",color:"blue"},{id:"n2",name:"Nitrogen",label:"N\u2082",color:"red"},{id:"co2",name:"Carbon Dioxide",label:"CO\u2082",color:"grey"},{id:"plasma",name:"Plasma",label:"Plasma",color:"pink"},{id:"water_vapor",name:"Water Vapor",label:"H\u2082O",color:"grey"},{id:"nob",name:"Hyper-noblium",label:"Hyper-nob",color:"teal"},{id:"n2o",name:"Nitrous Oxide",label:"N\u2082O",color:"red"},{id:"no2",name:"Nitryl",label:"NO\u2082",color:"brown"},{id:"tritium",name:"Tritium",label:"Tritium",color:"green"},{id:"bz",name:"BZ",label:"BZ",color:"purple"},{id:"stim",name:"Stimulum",label:"Stimulum",color:"purple"},{id:"pluox",name:"Pluoxium",label:"Pluoxium",color:"blue"},{id:"miasma",name:"Miasma",label:"Miasma",color:"olive"}];t.getGasLabel=function(e,t){var n=String(e).toLowerCase(),r=o.find((function(e){return e.id===n||e.name.toLowerCase()===n}));return r&&r.label||t||e};t.getGasColor=function(e){var t=String(e).toLowerCase(),n=o.find((function(e){return e.id===t||e.name.toLowerCase()===t}));return n&&n.color}},function(e,t,n){"use strict";var o={}.toString;e.exports=function(e){return o.call(e).slice(8,-1)}},function(e,t,n){"use strict";var o=n(6);e.exports=function(e,t){if(!o(e))return e;var n,r;if(t&&"function"==typeof(n=e.toString)&&!o(r=n.call(e)))return r;if("function"==typeof(n=e.valueOf)&&!o(r=n.call(e)))return r;if(!t&&"function"==typeof(n=e.toString)&&!o(r=n.call(e)))return r;throw TypeError("Can't convert object to primitive value")}},function(e,t,n){"use strict";var o,r,a,i=n(124),c=n(5),l=n(6),u=n(30),d=n(15),s=n(73),p=n(60),m=c.WeakMap;if(i){var f=new m,h=f.get,C=f.has,g=f.set;o=function(e,t){return g.call(f,e,t),t},r=function(e){return h.call(f,e)||{}},a=function(e){return C.call(f,e)}}else{var b=s("state");p[b]=!0,o=function(e,t){return u(e,b,t),t},r=function(e){return d(e,b)?e[b]:{}},a=function(e){return d(e,b)}}e.exports={set:o,get:r,has:a,enforce:function(e){return a(e)?r(e):o(e,{})},getterFor:function(e){return function(t){var n;if(!l(t)||(n=r(t)).type!==e)throw TypeError("Incompatible receiver, "+e+" required");return n}}}},function(e,t,n){"use strict";var o=n(15),r=n(14),a=n(73),i=n(103),c=a("IE_PROTO"),l=Object.prototype;e.exports=i?Object.getPrototypeOf:function(e){return e=r(e),o(e,c)?e[c]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?l:null}},function(e,t,n){"use strict";var o=n(126),r=n(5),a=function(e){return"function"==typeof e?e:undefined};e.exports=function(e,t){return arguments.length<2?a(o[e])||a(r[e]):o[e]&&o[e][t]||r[e]&&r[e][t]}},function(e,t,n){"use strict";e.exports=!1},function(e,t,n){"use strict";var o=n(4);e.exports=function(e,t){var n=[][e];return!!n&&o((function(){n.call(null,t||function(){throw 1},1)}))}},function(e,t,n){"use strict";var o=n(1),r=n(5),a=n(7),i=n(116),c=n(9),l=n(78),u=n(56),d=n(47),s=n(30),p=n(10),m=n(140),f=n(155),h=n(35),C=n(15),g=n(75),b=n(6),N=n(43),v=n(51),V=n(48).f,y=n(156),_=n(18).forEach,x=n(55),k=n(13),L=n(20),w=n(36),B=n(80),S=w.get,I=w.set,T=k.f,A=L.f,E=Math.round,P=r.RangeError,M=l.ArrayBuffer,O=l.DataView,R=c.NATIVE_ARRAY_BUFFER_VIEWS,F=c.TYPED_ARRAY_TAG,D=c.TypedArray,j=c.TypedArrayPrototype,z=c.aTypedArrayConstructor,H=c.isTypedArray,G=function(e,t){for(var n=0,o=t.length,r=new(z(e))(o);o>n;)r[n]=t[n++];return r},U=function(e,t){T(e,t,{get:function(){return S(this)[t]}})},K=function(e){var t;return e instanceof M||"ArrayBuffer"==(t=g(e))||"SharedArrayBuffer"==t},Y=function(e,t){return H(e)&&"symbol"!=typeof t&&t in e&&String(+t)==String(t)},q=function(e,t){return Y(e,t=h(t,!0))?d(2,e[t]):A(e,t)},W=function(e,t,n){return!(Y(e,t=h(t,!0))&&b(n)&&C(n,"value"))||C(n,"get")||C(n,"set")||n.configurable||C(n,"writable")&&!n.writable||C(n,"enumerable")&&!n.enumerable?T(e,t,n):(e[t]=n.value,e)};a?(R||(L.f=q,k.f=W,U(j,"buffer"),U(j,"byteOffset"),U(j,"byteLength"),U(j,"length")),o({target:"Object",stat:!0,forced:!R},{getOwnPropertyDescriptor:q,defineProperty:W}),e.exports=function(e,t,n){var a=e.match(/\d+$/)[0]/8,c=e+(n?"Clamped":"")+"Array",l="get"+e,d="set"+e,h=r[c],C=h,g=C&&C.prototype,k={},L=function(e,t){T(e,t,{get:function(){return function(e,t){var n=S(e);return n.view[l](t*a+n.byteOffset,!0)}(this,t)},set:function(e){return function(e,t,o){var r=S(e);n&&(o=(o=E(o))<0?0:o>255?255:255&o),r.view[d](t*a+r.byteOffset,o,!0)}(this,t,e)},enumerable:!0})};R?i&&(C=t((function(e,t,n,o){return u(e,C,c),B(b(t)?K(t)?o!==undefined?new h(t,f(n,a),o):n!==undefined?new h(t,f(n,a)):new h(t):H(t)?G(C,t):y.call(C,t):new h(m(t)),e,C)})),v&&v(C,D),_(V(h),(function(e){e in C||s(C,e,h[e])})),C.prototype=g):(C=t((function(e,t,n,o){u(e,C,c);var r,i,l,d=0,s=0;if(b(t)){if(!K(t))return H(t)?G(C,t):y.call(C,t);r=t,s=f(n,a);var h=t.byteLength;if(o===undefined){if(h%a)throw P("Wrong length");if((i=h-s)<0)throw P("Wrong length")}else if((i=p(o)*a)+s>h)throw P("Wrong length");l=i/a}else l=m(t),r=new M(i=l*a);for(I(e,{buffer:r,byteOffset:s,byteLength:i,length:l,view:new O(r)});d"+e+"<\/script>"},f=function(){try{o=document.domain&&new ActiveXObject("htmlfile")}catch(r){}var e,t;f=o?function(e){e.write(m("")),e.close();var t=e.parentWindow.Object;return e=null,t}(o):((t=u("iframe")).style.display="none",l.appendChild(t),t.src=String("javascript:"),(e=t.contentWindow.document).open(),e.write(m("document.F=Object")),e.close(),e.F);for(var n=i.length;n--;)delete f.prototype[i[n]];return f()};c[s]=!0,e.exports=Object.create||function(e,t){var n;return null!==e?(p.prototype=r(e),n=new p,p.prototype=null,n[s]=e):n=f(),t===undefined?n:a(n,t)}},function(e,t,n){"use strict";var o=n(13).f,r=n(15),a=n(12)("toStringTag");e.exports=function(e,t,n){e&&!r(e=n?e:e.prototype,a)&&o(e,a,{configurable:!0,value:t})}},function(e,t,n){"use strict";var o=n(12),r=n(43),a=n(13),i=o("unscopables"),c=Array.prototype;c[i]==undefined&&a.f(c,i,{configurable:!0,value:r(null)}),e.exports=function(e){c[i][e]=!0}},function(e,t,n){"use strict";var o=n(8),r=n(32),a=n(12)("species");e.exports=function(e,t){var n,i=o(e).constructor;return i===undefined||(n=o(i)[a])==undefined?t:r(n)}},function(e,t,n){"use strict";e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t,n){"use strict";var o=n(127),r=n(94).concat("length","prototype");t.f=Object.getOwnPropertyNames||function(e){return o(e,r)}},function(e,t,n){"use strict";var o=n(32);e.exports=function(e,t,n){if(o(e),t===undefined)return e;switch(n){case 0:return function(){return e.call(t)};case 1:return function(n){return e.call(t,n)};case 2:return function(n,o){return e.call(t,n,o)};case 3:return function(n,o,r){return e.call(t,n,o,r)}}return function(){return e.apply(t,arguments)}}},function(e,t,n){"use strict";var o=n(35),r=n(13),a=n(47);e.exports=function(e,t,n){var i=o(t);i in e?r.f(e,i,a(0,n)):e[i]=n}},function(e,t,n){"use strict";var o=n(8),r=n(138);e.exports=Object.setPrototypeOf||("__proto__"in{}?function(){var e,t=!1,n={};try{(e=Object.getOwnPropertyDescriptor(Object.prototype,"__proto__").set).call(n,[]),t=n instanceof Array}catch(a){}return function(n,a){return o(n),r(a),t?e.call(n,a):n.__proto__=a,n}}():undefined)},function(e,t,n){"use strict";var o=n(60),r=n(6),a=n(15),i=n(13).f,c=n(59),l=n(68),u=c("meta"),d=0,s=Object.isExtensible||function(){return!0},p=function(e){i(e,u,{value:{objectID:"O"+ ++d,weakData:{}}})},m=e.exports={REQUIRED:!1,fastKey:function(e,t){if(!r(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!a(e,u)){if(!s(e))return"F";if(!t)return"E";p(e)}return e[u].objectID},getWeakData:function(e,t){if(!a(e,u)){if(!s(e))return!0;if(!t)return!1;p(e)}return e[u].weakData},onFreeze:function(e){return l&&m.REQUIRED&&s(e)&&!a(e,u)&&p(e),e}};o[u]=!0},function(e,t,n){"use strict";t.__esModule=!0,t.createLogger=void 0;n(158);var o=n(16),r=0,a=1,i=2,c=3,l=4,u=function(e,t){for(var n=arguments.length,r=new Array(n>2?n-2:0),a=2;a=i){var c=[t].concat(r).map((function(e){return"string"==typeof e?e:e instanceof Error?e.stack||String(e):JSON.stringify(e)})).filter((function(e){return e})).join(" ")+"\nUser Agent: "+navigator.userAgent;(0,o.act)(window.__ref__,"tgui:log",{log:c})}};t.createLogger=function(e){return{debug:function(){for(var t=arguments.length,n=new Array(t),o=0;od;)if((c=l[d++])!=c)return!0}else for(;u>d;d++)if((e||d in l)&&l[d]===n)return e||d||0;return!e&&-1}};e.exports={includes:i(!0),indexOf:i(!1)}},function(e,t,n){"use strict";var o=n(4),r=/#|\.prototype\./,a=function(e,t){var n=c[i(e)];return n==u||n!=l&&("function"==typeof t?o(t):!!t)},i=a.normalize=function(e){return String(e).replace(r,".").toLowerCase()},c=a.data={},l=a.NATIVE="N",u=a.POLYFILL="P";e.exports=a},function(e,t,n){"use strict";var o=n(127),r=n(94);e.exports=Object.keys||function(e){return o(e,r)}},function(e,t,n){"use strict";var o=n(6),r=n(54),a=n(12)("species");e.exports=function(e,t){var n;return r(e)&&("function"!=typeof(n=e.constructor)||n!==Array&&!r(n.prototype)?o(n)&&null===(n=n[a])&&(n=undefined):n=undefined),new(n===undefined?Array:n)(0===t?0:t)}},function(e,t,n){"use strict";var o=n(4),r=n(12),a=n(97),i=r("species");e.exports=function(e){return a>=51||!o((function(){var t=[];return(t.constructor={})[i]=function(){return{foo:1}},1!==t[e](Boolean).foo}))}},function(e,t,n){"use strict";e.exports={}},function(e,t,n){"use strict";var o=n(22);e.exports=function(e,t,n){for(var r in t)o(e,r,t[r],n);return e}},function(e,t,n){"use strict";var o=n(4);e.exports=!o((function(){return Object.isExtensible(Object.preventExtensions({}))}))},function(e,t,n){"use strict";var o=n(8),r=n(99),a=n(10),i=n(49),c=n(100),l=n(135),u=function(e,t){this.stopped=e,this.result=t};(e.exports=function(e,t,n,d,s){var p,m,f,h,C,g,b,N=i(t,n,d?2:1);if(s)p=e;else{if("function"!=typeof(m=c(e)))throw TypeError("Target is not iterable");if(r(m)){for(f=0,h=a(e.length);h>f;f++)if((C=d?N(o(b=e[f])[0],b[1]):N(e[f]))&&C instanceof u)return C;return new u(!1)}p=m.call(e)}for(g=p.next;!(b=g.call(p)).done;)if("object"==typeof(C=l(p,N,b.value,d))&&C&&C instanceof u)return C;return new u(!1)}).stop=function(e){return new u(!0,e)}},function(e,t,n){"use strict";t.__esModule=!0,t.InterfaceLockNoticeBox=void 0;var o=n(0),r=n(2);t.InterfaceLockNoticeBox=function(e){var t=e.siliconUser,n=e.locked,a=e.onLockStatusChange,i=e.accessText;return t?(0,o.createComponentVNode)(2,r.NoticeBox,{children:(0,o.createComponentVNode)(2,r.Flex,{align:"center",children:[(0,o.createComponentVNode)(2,r.Flex.Item,{children:"Interface lock status:"}),(0,o.createComponentVNode)(2,r.Flex.Item,{grow:1}),(0,o.createComponentVNode)(2,r.Flex.Item,{children:(0,o.createComponentVNode)(2,r.Button,{m:0,color:"gray",icon:n?"lock":"unlock",content:n?"Locked":"Unlocked",onClick:function(){a&&a(!n)}})})]})}):(0,o.createComponentVNode)(2,r.NoticeBox,{children:["Swipe ",i||"an ID card"," ","to ",n?"unlock":"lock"," this interface."]})}},function(e,t,n){"use strict";function o(e,t){var n;if("undefined"==typeof Symbol||null==e[Symbol.iterator]){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return r(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return r(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var o=0;return function(){return o>=e.length?{done:!0}:{done:!1,value:e[o++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}return(n=e[Symbol.iterator]()).next.bind(n)}function r(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,o=new Array(t);n1?r-1:0),c=1;c1?o-1:0),a=1;a=0:s>p;p+=m)p in d&&(l=n(l,d[p],p,u));return l}};e.exports={left:c(!1),right:c(!0)}},function(e,t,n){"use strict";var o=n(5),r=n(7),a=n(104),i=n(30),c=n(67),l=n(4),u=n(56),d=n(31),s=n(10),p=n(140),m=n(222),f=n(37),h=n(51),C=n(48).f,g=n(13).f,b=n(98),N=n(44),v=n(36),V=v.get,y=v.set,_=o.ArrayBuffer,x=_,k=o.DataView,L=k&&k.prototype,w=Object.prototype,B=o.RangeError,S=m.pack,I=m.unpack,T=function(e){return[255&e]},A=function(e){return[255&e,e>>8&255]},E=function(e){return[255&e,e>>8&255,e>>16&255,e>>24&255]},P=function(e){return e[3]<<24|e[2]<<16|e[1]<<8|e[0]},M=function(e){return S(e,23,4)},O=function(e){return S(e,52,8)},R=function(e,t){g(e.prototype,t,{get:function(){return V(this)[t]}})},F=function(e,t,n,o){var r=p(n),a=V(e);if(r+t>a.byteLength)throw B("Wrong index");var i=V(a.buffer).bytes,c=r+a.byteOffset,l=i.slice(c,c+t);return o?l:l.reverse()},D=function(e,t,n,o,r,a){var i=p(n),c=V(e);if(i+t>c.byteLength)throw B("Wrong index");for(var l=V(c.buffer).bytes,u=i+c.byteOffset,d=o(+r),s=0;sG;)(j=H[G++])in x||i(x,j,_[j]);z.constructor=x}h&&f(L)!==w&&h(L,w);var U=new k(new x(2)),K=L.setInt8;U.setInt8(0,2147483648),U.setInt8(1,2147483649),!U.getInt8(0)&&U.getInt8(1)||c(L,{setInt8:function(e,t){K.call(this,e,t<<24>>24)},setUint8:function(e,t){K.call(this,e,t<<24>>24)}},{unsafe:!0})}else x=function(e){u(this,x,"ArrayBuffer");var t=p(e);y(this,{bytes:b.call(new Array(t),0),byteLength:t}),r||(this.byteLength=t)},k=function(e,t,n){u(this,k,"DataView"),u(e,x,"DataView");var o=V(e).byteLength,a=d(t);if(a<0||a>o)throw B("Wrong offset");if(a+(n=n===undefined?o-a:s(n))>o)throw B("Wrong length");y(this,{buffer:e,byteLength:n,byteOffset:a}),r||(this.buffer=e,this.byteLength=n,this.byteOffset=a)},r&&(R(x,"byteLength"),R(k,"buffer"),R(k,"byteLength"),R(k,"byteOffset")),c(k.prototype,{getInt8:function(e){return F(this,1,e)[0]<<24>>24},getUint8:function(e){return F(this,1,e)[0]},getInt16:function(e){var t=F(this,2,e,arguments.length>1?arguments[1]:undefined);return(t[1]<<8|t[0])<<16>>16},getUint16:function(e){var t=F(this,2,e,arguments.length>1?arguments[1]:undefined);return t[1]<<8|t[0]},getInt32:function(e){return P(F(this,4,e,arguments.length>1?arguments[1]:undefined))},getUint32:function(e){return P(F(this,4,e,arguments.length>1?arguments[1]:undefined))>>>0},getFloat32:function(e){return I(F(this,4,e,arguments.length>1?arguments[1]:undefined),23)},getFloat64:function(e){return I(F(this,8,e,arguments.length>1?arguments[1]:undefined),52)},setInt8:function(e,t){D(this,1,e,T,t)},setUint8:function(e,t){D(this,1,e,T,t)},setInt16:function(e,t){D(this,2,e,A,t,arguments.length>2?arguments[2]:undefined)},setUint16:function(e,t){D(this,2,e,A,t,arguments.length>2?arguments[2]:undefined)},setInt32:function(e,t){D(this,4,e,E,t,arguments.length>2?arguments[2]:undefined)},setUint32:function(e,t){D(this,4,e,E,t,arguments.length>2?arguments[2]:undefined)},setFloat32:function(e,t){D(this,4,e,M,t,arguments.length>2?arguments[2]:undefined)},setFloat64:function(e,t){D(this,8,e,O,t,arguments.length>2?arguments[2]:undefined)}});N(x,"ArrayBuffer"),N(k,"DataView"),e.exports={ArrayBuffer:x,DataView:k}},function(e,t,n){"use strict";var o=n(1),r=n(5),a=n(62),i=n(22),c=n(52),l=n(69),u=n(56),d=n(6),s=n(4),p=n(76),m=n(44),f=n(80);e.exports=function(e,t,n){var h=-1!==e.indexOf("Map"),C=-1!==e.indexOf("Weak"),g=h?"set":"add",b=r[e],N=b&&b.prototype,v=b,V={},y=function(e){var t=N[e];i(N,e,"add"==e?function(e){return t.call(this,0===e?0:e),this}:"delete"==e?function(e){return!(C&&!d(e))&&t.call(this,0===e?0:e)}:"get"==e?function(e){return C&&!d(e)?undefined:t.call(this,0===e?0:e)}:"has"==e?function(e){return!(C&&!d(e))&&t.call(this,0===e?0:e)}:function(e,n){return t.call(this,0===e?0:e,n),this})};if(a(e,"function"!=typeof b||!(C||N.forEach&&!s((function(){(new b).entries().next()})))))v=n.getConstructor(t,e,h,g),c.REQUIRED=!0;else if(a(e,!0)){var _=new v,x=_[g](C?{}:-0,1)!=_,k=s((function(){_.has(1)})),L=p((function(e){new b(e)})),w=!C&&s((function(){for(var e=new b,t=5;t--;)e[g](t,t);return!e.has(-0)}));L||((v=t((function(t,n){u(t,v,e);var o=f(new b,t,v);return n!=undefined&&l(n,o[g],o,h),o}))).prototype=N,N.constructor=v),(k||w)&&(y("delete"),y("has"),h&&y("get")),(w||x)&&y(g),C&&N.clear&&delete N.clear}return V[e]=v,o({global:!0,forced:v!=b},V),m(v,e),C||n.setStrong(v,e,h),v}},function(e,t,n){"use strict";var o=n(6),r=n(51);e.exports=function(e,t,n){var a,i;return r&&"function"==typeof(a=t.constructor)&&a!==n&&o(i=a.prototype)&&i!==n.prototype&&r(e,i),e}},function(e,t,n){"use strict";var o=Math.expm1,r=Math.exp;e.exports=!o||o(10)>22025.465794806718||o(10)<22025.465794806718||-2e-17!=o(-2e-17)?function(e){return 0==(e=+e)?e:e>-1e-6&&e<1e-6?e+e*e/2:r(e)-1}:o},function(e,t,n){"use strict";e.exports="\t\n\x0B\f\r \xa0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff"},function(e,t,n){"use strict";var o=n(39),r=n(5),a=n(4);e.exports=o||!a((function(){var e=Math.random();__defineSetter__.call(null,e,(function(){})),delete r[e]}))},function(e,t,n){"use strict";var o=n(8);e.exports=function(){var e=o(this),t="";return e.global&&(t+="g"),e.ignoreCase&&(t+="i"),e.multiline&&(t+="m"),e.dotAll&&(t+="s"),e.unicode&&(t+="u"),e.sticky&&(t+="y"),t}},function(e,t,n){"use strict";var o,r,a=n(84),i=n(110),c=RegExp.prototype.exec,l=String.prototype.replace,u=c,d=(o=/a/,r=/b*/g,c.call(o,"a"),c.call(r,"a"),0!==o.lastIndex||0!==r.lastIndex),s=i.UNSUPPORTED_Y||i.BROKEN_CARET,p=/()??/.exec("")[1]!==undefined;(d||p||s)&&(u=function(e){var t,n,o,r,i=this,u=s&&i.sticky,m=a.call(i),f=i.source,h=0,C=e;return u&&(-1===(m=m.replace("y","")).indexOf("g")&&(m+="g"),C=String(e).slice(i.lastIndex),i.lastIndex>0&&(!i.multiline||i.multiline&&"\n"!==e[i.lastIndex-1])&&(f="(?: "+f+")",C=" "+C,h++),n=new RegExp("^(?:"+f+")",m)),p&&(n=new RegExp("^"+f+"$(?!\\s)",m)),d&&(t=i.lastIndex),o=c.call(u?n:i,C),u?o?(o.input=o.input.slice(h),o[0]=o[0].slice(h),o.index=i.lastIndex,i.lastIndex+=o[0].length):i.lastIndex=0:d&&o&&(i.lastIndex=i.global?o.index+o[0].length:t),p&&o&&o.length>1&&l.call(o[0],n,(function(){for(r=1;r")})),d="$0"==="a".replace(/./,"$0"),s=a("replace"),p=!!/./[s]&&""===/./[s]("a","$0"),m=!r((function(){var e=/(?:)/,t=e.exec;e.exec=function(){return t.apply(this,arguments)};var n="ab".split(e);return 2!==n.length||"a"!==n[0]||"b"!==n[1]}));e.exports=function(e,t,n,s){var f=a(e),h=!r((function(){var t={};return t[f]=function(){return 7},7!=""[e](t)})),C=h&&!r((function(){var t=!1,n=/a/;return"split"===e&&((n={}).constructor={},n.constructor[l]=function(){return n},n.flags="",n[f]=/./[f]),n.exec=function(){return t=!0,null},n[f](""),!t}));if(!h||!C||"replace"===e&&(!u||!d||p)||"split"===e&&!m){var g=/./[f],b=n(f,""[e],(function(e,t,n,o,r){return t.exec===i?h&&!r?{done:!0,value:g.call(t,n,o)}:{done:!0,value:e.call(n,t,o)}:{done:!1}}),{REPLACE_KEEPS_$0:d,REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE:p}),N=b[0],v=b[1];o(String.prototype,e,N),o(RegExp.prototype,f,2==t?function(e,t){return v.call(e,this,t)}:function(e){return v.call(e,this)})}s&&c(RegExp.prototype[f],"sham",!0)}},function(e,t,n){"use strict";var o=n(34),r=n(85);e.exports=function(e,t){var n=e.exec;if("function"==typeof n){var a=n.call(e,t);if("object"!=typeof a)throw TypeError("RegExp exec method returned something other than an Object or null");return a}if("RegExp"!==o(e))throw TypeError("RegExp#exec called on incompatible receiver");return r.call(e,t)}},function(e,t,n){"use strict";t.__esModule=!0,t.Icon=void 0;var o=n(0),r=n(11),a=n(19);var i=/-o$/,c=function(e){var t=e.name,n=e.size,c=e.spin,l=e.className,u=e.style,d=void 0===u?{}:u,s=e.rotation,p=function(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}(e,["name","size","spin","className","style","rotation"]);n&&(d["font-size"]=100*n+"%"),"number"==typeof s&&(d.transform="rotate("+s+"deg)");var m=i.test(t),f=t.replace(i,"");return(0,o.normalizeProps)((0,o.createComponentVNode)(2,a.Box,Object.assign({as:"i",className:(0,r.classes)([l,m?"far":"fas","fa-"+f,c&&"fa-spin"]),style:d},p)))};t.Icon=c,c.defaultHooks=r.pureComponentHooks},function(e,t,n){"use strict";var o=n(5),r=n(6),a=o.document,i=r(a)&&r(a.createElement);e.exports=function(e){return i?a.createElement(e):{}}},function(e,t,n){"use strict";var o=n(5),r=n(30);e.exports=function(e,t){try{r(o,e,t)}catch(n){o[e]=t}return t}},function(e,t,n){"use strict";var o=n(123),r=Function.toString;"function"!=typeof o.inspectSource&&(o.inspectSource=function(e){return r.call(e)}),e.exports=o.inspectSource},function(e,t,n){"use strict";var o=n(39),r=n(123);(e.exports=function(e,t){return r[e]||(r[e]=t!==undefined?t:{})})("versions",[]).push({version:"3.6.5",mode:o?"pure":"global",copyright:"\xa9 2020 Denis Pushkarev (zloirock.ru)"})},function(e,t,n){"use strict";var o=n(38),r=n(48),a=n(95),i=n(8);e.exports=o("Reflect","ownKeys")||function(e){var t=r.f(i(e)),n=a.f;return n?t.concat(n(e)):t}},function(e,t,n){"use strict";e.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},function(e,t,n){"use strict";t.f=Object.getOwnPropertySymbols},function(e,t,n){"use strict";var o=n(4);e.exports=!!Object.getOwnPropertySymbols&&!o((function(){return!String(Symbol())}))},function(e,t,n){"use strict";var o,r,a=n(5),i=n(74),c=a.process,l=c&&c.versions,u=l&&l.v8;u?r=(o=u.split("."))[0]+o[1]:i&&(!(o=i.match(/Edge\/(\d+)/))||o[1]>=74)&&(o=i.match(/Chrome\/(\d+)/))&&(r=o[1]),e.exports=r&&+r},function(e,t,n){"use strict";var o=n(14),r=n(42),a=n(10);e.exports=function(e){for(var t=o(this),n=a(t.length),i=arguments.length,c=r(i>1?arguments[1]:undefined,n),l=i>2?arguments[2]:undefined,u=l===undefined?n:r(l,n);u>c;)t[c++]=e;return t}},function(e,t,n){"use strict";var o=n(12),r=n(66),a=o("iterator"),i=Array.prototype;e.exports=function(e){return e!==undefined&&(r.Array===e||i[a]===e)}},function(e,t,n){"use strict";var o=n(75),r=n(66),a=n(12)("iterator");e.exports=function(e){if(e!=undefined)return e[a]||e["@@iterator"]||r[o(e)]}},function(e,t,n){"use strict";var o={};o[n(12)("toStringTag")]="z",e.exports="[object z]"===String(o)},function(e,t,n){"use strict";var o=n(1),r=n(207),a=n(37),i=n(51),c=n(44),l=n(30),u=n(22),d=n(12),s=n(39),p=n(66),m=n(137),f=m.IteratorPrototype,h=m.BUGGY_SAFARI_ITERATORS,C=d("iterator"),g=function(){return this};e.exports=function(e,t,n,d,m,b,N){r(n,t,d);var v,V,y,_=function(e){if(e===m&&B)return B;if(!h&&e in L)return L[e];switch(e){case"keys":case"values":case"entries":return function(){return new n(this,e)}}return function(){return new n(this)}},x=t+" Iterator",k=!1,L=e.prototype,w=L[C]||L["@@iterator"]||m&&L[m],B=!h&&w||_(m),S="Array"==t&&L.entries||w;if(S&&(v=a(S.call(new e)),f!==Object.prototype&&v.next&&(s||a(v)===f||(i?i(v,f):"function"!=typeof v[C]&&l(v,C,g)),c(v,x,!0,!0),s&&(p[x]=g))),"values"==m&&w&&"values"!==w.name&&(k=!0,B=function(){return w.call(this)}),s&&!N||L[C]===B||l(L,C,B),p[t]=B,m)if(V={values:_("values"),keys:b?B:_("keys"),entries:_("entries")},N)for(y in V)(h||k||!(y in L))&&u(L,y,V[y]);else o({target:t,proto:!0,forced:h||k},V);return V}},function(e,t,n){"use strict";var o=n(4);e.exports=!o((function(){function e(){}return e.prototype.constructor=null,Object.getPrototypeOf(new e)!==e.prototype}))},function(e,t,n){"use strict";e.exports="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof DataView},function(e,t,n){"use strict";var o=n(10),r=n(106),a=n(21),i=Math.ceil,c=function(e){return function(t,n,c){var l,u,d=String(a(t)),s=d.length,p=c===undefined?" ":String(c),m=o(n);return m<=s||""==p?d:(l=m-s,(u=r.call(p,i(l/p.length))).length>l&&(u=u.slice(0,l)),e?d+u:u+d)}};e.exports={start:c(!1),end:c(!0)}},function(e,t,n){"use strict";var o=n(31),r=n(21);e.exports="".repeat||function(e){var t=String(r(this)),n="",a=o(e);if(a<0||a==Infinity)throw RangeError("Wrong number of repetitions");for(;a>0;(a>>>=1)&&(t+=t))1&a&&(n+=t);return n}},function(e,t,n){"use strict";e.exports=Math.sign||function(e){return 0==(e=+e)||e!=e?e:e<0?-1:1}},function(e,t,n){"use strict";var o,r,a,i=n(5),c=n(4),l=n(34),u=n(49),d=n(130),s=n(89),p=n(149),m=i.location,f=i.setImmediate,h=i.clearImmediate,C=i.process,g=i.MessageChannel,b=i.Dispatch,N=0,v={},V=function(e){if(v.hasOwnProperty(e)){var t=v[e];delete v[e],t()}},y=function(e){return function(){V(e)}},_=function(e){V(e.data)},x=function(e){i.postMessage(e+"",m.protocol+"//"+m.host)};f&&h||(f=function(e){for(var t=[],n=1;arguments.length>n;)t.push(arguments[n++]);return v[++N]=function(){("function"==typeof e?e:Function(e)).apply(undefined,t)},o(N),N},h=function(e){delete v[e]},"process"==l(C)?o=function(e){C.nextTick(y(e))}:b&&b.now?o=function(e){b.now(y(e))}:g&&!p?(a=(r=new g).port2,r.port1.onmessage=_,o=u(a.postMessage,a,1)):!i.addEventListener||"function"!=typeof postMessage||i.importScripts||c(x)||"file:"===m.protocol?o="onreadystatechange"in s("script")?function(e){d.appendChild(s("script")).onreadystatechange=function(){d.removeChild(this),V(e)}}:function(e){setTimeout(y(e),0)}:(o=x,i.addEventListener("message",_,!1))),e.exports={set:f,clear:h}},function(e,t,n){"use strict";var o=n(6),r=n(34),a=n(12)("match");e.exports=function(e){var t;return o(e)&&((t=e[a])!==undefined?!!t:"RegExp"==r(e))}},function(e,t,n){"use strict";var o=n(4);function r(e,t){return RegExp(e,t)}t.UNSUPPORTED_Y=o((function(){var e=r("a","y");return e.lastIndex=2,null!=e.exec("abcd")})),t.BROKEN_CARET=o((function(){var e=r("^r","gy");return e.lastIndex=2,null!=e.exec("str")}))},function(e,t,n){"use strict";var o=n(31),r=n(21),a=function(e){return function(t,n){var a,i,c=String(r(t)),l=o(n),u=c.length;return l<0||l>=u?e?"":undefined:(a=c.charCodeAt(l))<55296||a>56319||l+1===u||(i=c.charCodeAt(l+1))<56320||i>57343?e?c.charAt(l):a:e?c.slice(l,l+2):i-56320+(a-55296<<10)+65536}};e.exports={codeAt:a(!1),charAt:a(!0)}},function(e,t,n){"use strict";var o=n(109);e.exports=function(e){if(o(e))throw TypeError("The method doesn't accept regular expressions");return e}},function(e,t,n){"use strict";var o=n(12)("match");e.exports=function(e){var t=/./;try{"/./"[e](t)}catch(n){try{return t[o]=!1,"/./"[e](t)}catch(r){}}return!1}},function(e,t,n){"use strict";var o=n(111).charAt;e.exports=function(e,t,n){return t+(n?o(e,t).length:1)}},function(e,t,n){"use strict";var o=n(4),r=n(82);e.exports=function(e){return o((function(){return!!r[e]()||"\u200b\x85\u180e"!="\u200b\x85\u180e"[e]()||r[e].name!==e}))}},function(e,t,n){"use strict";var o=n(5),r=n(4),a=n(76),i=n(9).NATIVE_ARRAY_BUFFER_VIEWS,c=o.ArrayBuffer,l=o.Int8Array;e.exports=!i||!r((function(){l(1)}))||!r((function(){new l(-1)}))||!a((function(e){new l,new l(null),new l(1.5),new l(e)}),!0)||r((function(){return 1!==new l(new c(2),1,undefined).length}))},function(e,t,n){"use strict";t.__esModule=!0,t.ButtonInput=t.ButtonConfirm=t.ButtonCheckbox=t.Button=void 0;var o=n(0),r=n(11),a=n(16),i=n(118),c=n(53),l=n(119),u=n(19),d=n(88),s=n(163);n(164),n(165);function p(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}function m(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}var f=(0,c.createLogger)("Button"),h=function(e){var t=e.className,n=e.fluid,c=e.icon,p=e.color,h=e.disabled,C=e.selected,g=e.tooltip,b=e.tooltipPosition,N=e.ellipsis,v=e.content,V=e.iconRotation,y=e.iconSpin,_=e.children,x=e.onclick,k=e.onClick,L=m(e,["className","fluid","icon","color","disabled","selected","tooltip","tooltipPosition","ellipsis","content","iconRotation","iconSpin","children","onclick","onClick"]),w=!(!v&&!_);return x&&f.warn("Lowercase 'onclick' is not supported on Button and lowercase prop names are discouraged in general. Please use a camelCase'onClick' instead and read: https://infernojs.org/docs/guides/event-handling"),(0,o.normalizeProps)((0,o.createComponentVNode)(2,u.Box,Object.assign({as:"span",className:(0,r.classes)(["Button",n&&"Button--fluid",h&&"Button--disabled",C&&"Button--selected",w&&"Button--hasContent",N&&"Button--ellipsis",p&&"string"==typeof p?"Button--color--"+p:"Button--color--default",t]),tabIndex:!h&&"0",unselectable:a.tridentVersion<=4,onclick:function(e){(0,l.refocusLayout)(),!h&&k&&k(e)},onKeyDown:function(e){var t=window.event?e.which:e.keyCode;return t===i.KEY_SPACE||t===i.KEY_ENTER?(e.preventDefault(),void(!h&&k&&k(e))):t===i.KEY_ESCAPE?(e.preventDefault(),void(0,l.refocusLayout)()):void 0}},L,{children:[c&&(0,o.createComponentVNode)(2,d.Icon,{name:c,rotation:V,spin:y}),v,_,g&&(0,o.createComponentVNode)(2,s.Tooltip,{content:g,position:b})]})))};t.Button=h,h.defaultHooks=r.pureComponentHooks;var C=function(e){var t=e.checked,n=m(e,["checked"]);return(0,o.normalizeProps)((0,o.createComponentVNode)(2,h,Object.assign({color:"transparent",icon:t?"check-square-o":"square-o",selected:t},n)))};t.ButtonCheckbox=C,h.Checkbox=C;var g=function(e){function t(){var t;return(t=e.call(this)||this).state={clickedOnce:!1},t.handleClick=function(){t.state.clickedOnce&&t.setClickedOnce(!1)},t}p(t,e);var n=t.prototype;return n.setClickedOnce=function(e){var t=this;this.setState({clickedOnce:e}),e?setTimeout((function(){return window.addEventListener("click",t.handleClick)})):window.removeEventListener("click",this.handleClick)},n.render=function(){var e=this,t=this.props,n=t.confirmMessage,r=void 0===n?"Confirm?":n,a=t.confirmColor,i=void 0===a?"bad":a,c=t.color,l=t.content,u=t.onClick,d=m(t,["confirmMessage","confirmColor","color","content","onClick"]);return(0,o.normalizeProps)((0,o.createComponentVNode)(2,h,Object.assign({content:this.state.clickedOnce?r:l,color:this.state.clickedOnce?i:c,onClick:function(){return e.state.clickedOnce?u():e.setClickedOnce(!0)}},d)))},t}(o.Component);t.ButtonConfirm=g,h.Confirm=g;var b=function(e){function t(){var t;return(t=e.call(this)||this).inputRef=(0,o.createRef)(),t.state={inInput:!1},t}p(t,e);var n=t.prototype;return n.setInInput=function(e){if(this.setState({inInput:e}),this.inputRef){var t=this.inputRef.current;if(e){t.value=this.props.currentValue||"";try{t.focus(),t.select()}catch(n){}}}},n.commitResult=function(e){if(this.inputRef){var t=this.inputRef.current;if(""!==t.value)return void this.props.onCommit(e,t.value);if(!this.props.defaultValue)return;this.props.onCommit(e,this.props.defaultValue)}},n.render=function(){var e=this,t=this.props,n=t.fluid,a=t.content,c=t.color,l=void 0===c?"default":c,d=(t.placeholder,t.maxLength,m(t,["fluid","content","color","placeholder","maxLength"]));return(0,o.normalizeProps)((0,o.createComponentVNode)(2,u.Box,Object.assign({className:(0,r.classes)(["Button",n&&"Button--fluid","Button--color--"+l])},d,{onClick:function(){return e.setInInput(!0)},children:[(0,o.createVNode)(1,"div",null,a,0),(0,o.createVNode)(64,"input","NumberInput__input",null,1,{style:{display:this.state.inInput?undefined:"none","text-align":"left"},onBlur:function(t){e.state.inInput&&(e.setInInput(!1),e.commitResult(t))},onKeyDown:function(t){if(t.keyCode===i.KEY_ENTER)return e.setInInput(!1),void e.commitResult(t);t.keyCode===i.KEY_ESCAPE&&e.setInInput(!1)}},null,this.inputRef)]})))},t}(o.Component);t.ButtonInput=b,h.Input=b},function(e,t,n){"use strict";t.__esModule=!0,t.hotKeyReducer=t.hotKeyMiddleware=t.releaseHeldKeys=t.KEY_MINUS=t.KEY_EQUAL=t.KEY_Z=t.KEY_Y=t.KEY_X=t.KEY_W=t.KEY_V=t.KEY_U=t.KEY_T=t.KEY_S=t.KEY_R=t.KEY_Q=t.KEY_P=t.KEY_O=t.KEY_N=t.KEY_M=t.KEY_L=t.KEY_K=t.KEY_J=t.KEY_I=t.KEY_H=t.KEY_G=t.KEY_F=t.KEY_E=t.KEY_D=t.KEY_C=t.KEY_B=t.KEY_A=t.KEY_9=t.KEY_8=t.KEY_7=t.KEY_6=t.KEY_5=t.KEY_4=t.KEY_3=t.KEY_2=t.KEY_1=t.KEY_0=t.KEY_SPACE=t.KEY_ESCAPE=t.KEY_ALT=t.KEY_CTRL=t.KEY_SHIFT=t.KEY_ENTER=t.KEY_TAB=t.KEY_BACKSPACE=void 0;var o=n(53),r=n(16),a=(0,o.createLogger)("hotkeys");t.KEY_BACKSPACE=8;t.KEY_TAB=9;t.KEY_ENTER=13;t.KEY_SHIFT=16;t.KEY_CTRL=17;t.KEY_ALT=18;t.KEY_ESCAPE=27;t.KEY_SPACE=32;t.KEY_0=48;t.KEY_1=49;t.KEY_2=50;t.KEY_3=51;t.KEY_4=52;t.KEY_5=53;t.KEY_6=54;t.KEY_7=55;t.KEY_8=56;t.KEY_9=57;t.KEY_A=65;t.KEY_B=66;t.KEY_C=67;t.KEY_D=68;t.KEY_E=69;t.KEY_F=70;t.KEY_G=71;t.KEY_H=72;t.KEY_I=73;t.KEY_J=74;t.KEY_K=75;t.KEY_L=76;t.KEY_M=77;t.KEY_N=78;t.KEY_O=79;t.KEY_P=80;t.KEY_Q=81;t.KEY_R=82;t.KEY_S=83;t.KEY_T=84;t.KEY_U=85;t.KEY_V=86;t.KEY_W=87;t.KEY_X=88;t.KEY_Y=89;t.KEY_Z=90;t.KEY_EQUAL=187;t.KEY_MINUS=189;var i=[17,18,16],c=[27,13,32,9,17,16],l={},u=function(e,t,n,o){var r="";return e&&(r+="Ctrl+"),t&&(r+="Alt+"),n&&(r+="Shift+"),r+=o>=48&&o<=90?String.fromCharCode(o):"["+o+"]"},d=function(e){var t=window.event?e.which:e.keyCode,n=e.ctrlKey,o=e.altKey,r=e.shiftKey;return{keyCode:t,ctrlKey:n,altKey:o,shiftKey:r,hasModifierKeys:n||o||r,keyString:u(n,o,r,t)}},s=function(){for(var e=0,t=Object.keys(l);e4&&function(e,t){if(!e.defaultPrevented){var n=e.target&&e.target.localName;if("input"!==n&&"textarea"!==n){var o=d(e),i=o.keyCode,u=o.ctrlKey,s=o.shiftKey;u||s||c.includes(i)||("keydown"!==t||l[i]?"keyup"===t&&l[i]&&(a.debug("passthrough",t,o),(0,r.callByond)("",{__keyup:i})):(a.debug("passthrough",t,o),(0,r.callByond)("",{__keydown:i})))}}}(e,t),function(e,t,n){if("keyup"===t){var o=d(e),r=o.ctrlKey,c=o.altKey,l=o.keyCode,u=o.hasModifierKeys,s=o.keyString;u&&!i.includes(l)&&(a.log(s),r&&c&&8===l&&setTimeout((function(){throw new Error("OOPSIE WOOPSIE!! UwU We made a fucky wucky!! A wittle fucko boingo! The code monkeys at our headquarters are working VEWY HAWD to fix this!")})),n({type:"hotKey",payload:o}))}}(e,t,n)},document.addEventListener("keydown",(function(e){var n=window.event?e.which:e.keyCode;t(e,"keydown"),l[n]=!0})),document.addEventListener("keyup",(function(e){var n=window.event?e.which:e.keyCode;t(e,"keyup"),l[n]=!1})),r.tridentVersion>4&&function(e){var t;document.addEventListener("focusout",(function(){t=setTimeout(e)})),document.addEventListener("focusin",(function(){clearTimeout(t)})),window.addEventListener("beforeunload",e)}((function(){s()})),function(e){return function(t){return e(t)}}};t.hotKeyReducer=function(e,t){var n=t.type,o=t.payload;if("hotKey"===n){var r=o.ctrlKey,a=o.altKey,i=o.keyCode;return r&&a&&187===i?Object.assign({},e,{showKitchenSink:!e.showKitchenSink}):e}return e}},function(e,t,n){"use strict";t.__esModule=!0,t.refocusLayout=void 0;var o=n(16);t.refocusLayout=function(){if(!(o.tridentVersion<=4)){var e=document.getElementById("Layout__content");e&&e.focus()}}},function(e,t,n){"use strict";t.__esModule=!0,t.toastReducer=t.showToast=t.Toast=void 0;var o,r=n(0),a=n(11),i=function(e){var t=e.content,n=e.children;return(0,r.createVNode)(1,"div","Layout__toast",[t,n],0)};t.Toast=i,i.defaultHooks=a.pureComponentHooks;t.showToast=function(e,t){o&&clearTimeout(o),o=setTimeout((function(){o=undefined,e({type:"hideToast"})}),5e3),e({type:"showToast",payload:{text:t}})};t.toastReducer=function(e,t){var n=t.type,o=t.payload;if("showToast"===n){var r=o.text;return Object.assign({},e,{toastText:r})}return"hideToast"===n?Object.assign({},e,{toastText:null}):e}},function(e,t,n){"use strict";var o;o=function(){return this}();try{o=o||new Function("return this")()}catch(r){"object"==typeof window&&(o=window)}e.exports=o},function(e,t,n){"use strict";var o=n(7),r=n(4),a=n(89);e.exports=!o&&!r((function(){return 7!=Object.defineProperty(a("div"),"a",{get:function(){return 7}}).a}))},function(e,t,n){"use strict";var o=n(5),r=n(90),a=o["__core-js_shared__"]||r("__core-js_shared__",{});e.exports=a},function(e,t,n){"use strict";var o=n(5),r=n(91),a=o.WeakMap;e.exports="function"==typeof a&&/native code/.test(r(a))},function(e,t,n){"use strict";var o=n(15),r=n(93),a=n(20),i=n(13);e.exports=function(e,t){for(var n=r(t),c=i.f,l=a.f,u=0;ul;)o(c,n=t[l++])&&(~a(u,n)||u.push(n));return u}},function(e,t,n){"use strict";var o=n(96);e.exports=o&&!Symbol.sham&&"symbol"==typeof Symbol.iterator},function(e,t,n){"use strict";var o=n(7),r=n(13),a=n(8),i=n(63);e.exports=o?Object.defineProperties:function(e,t){a(e);for(var n,o=i(t),c=o.length,l=0;c>l;)r.f(e,n=o[l++],t[n]);return e}},function(e,t,n){"use strict";var o=n(38);e.exports=o("document","documentElement")},function(e,t,n){"use strict";var o=n(26),r=n(48).f,a={}.toString,i="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[];e.exports.f=function(e){return i&&"[object Window]"==a.call(e)?function(e){try{return r(e)}catch(t){return i.slice()}}(e):r(o(e))}},function(e,t,n){"use strict";var o=n(12);t.f=o},function(e,t,n){"use strict";var o=n(14),r=n(42),a=n(10),i=Math.min;e.exports=[].copyWithin||function(e,t){var n=o(this),c=a(n.length),l=r(e,c),u=r(t,c),d=arguments.length>2?arguments[2]:undefined,s=i((d===undefined?c:r(d,c))-u,c-l),p=1;for(u0;)u in n?n[l]=n[u]:delete n[l],l+=p,u+=p;return n}},function(e,t,n){"use strict";var o=n(54),r=n(10),a=n(49);e.exports=function i(e,t,n,c,l,u,d,s){for(var p,m=l,f=0,h=!!d&&a(d,s,3);f0&&o(p))m=i(e,t,p,r(p.length),m,u-1)-1;else{if(m>=9007199254740991)throw TypeError("Exceed the acceptable array length");e[m]=p}m++}f++}return m}},function(e,t,n){"use strict";var o=n(8);e.exports=function(e,t,n,r){try{return r?t(o(n)[0],n[1]):t(n)}catch(i){var a=e["return"];throw a!==undefined&&o(a.call(e)),i}}},function(e,t,n){"use strict";var o=n(26),r=n(45),a=n(66),i=n(36),c=n(102),l=i.set,u=i.getterFor("Array Iterator");e.exports=c(Array,"Array",(function(e,t){l(this,{type:"Array Iterator",target:o(e),index:0,kind:t})}),(function(){var e=u(this),t=e.target,n=e.kind,o=e.index++;return!t||o>=t.length?(e.target=undefined,{value:undefined,done:!0}):"keys"==n?{value:o,done:!1}:"values"==n?{value:t[o],done:!1}:{value:[o,t[o]],done:!1}}),"values"),a.Arguments=a.Array,r("keys"),r("values"),r("entries")},function(e,t,n){"use strict";var o,r,a,i=n(37),c=n(30),l=n(15),u=n(12),d=n(39),s=u("iterator"),p=!1;[].keys&&("next"in(a=[].keys())?(r=i(i(a)))!==Object.prototype&&(o=r):p=!0),o==undefined&&(o={}),d||l(o,s)||c(o,s,(function(){return this})),e.exports={IteratorPrototype:o,BUGGY_SAFARI_ITERATORS:p}},function(e,t,n){"use strict";var o=n(6);e.exports=function(e){if(!o(e)&&null!==e)throw TypeError("Can't set "+String(e)+" as a prototype");return e}},function(e,t,n){"use strict";var o=n(26),r=n(31),a=n(10),i=n(40),c=n(23),l=Math.min,u=[].lastIndexOf,d=!!u&&1/[1].lastIndexOf(1,-0)<0,s=i("lastIndexOf"),p=c("indexOf",{ACCESSORS:!0,1:0}),m=d||!s||!p;e.exports=m?function(e){if(d)return u.apply(this,arguments)||0;var t=o(this),n=a(t.length),i=n-1;for(arguments.length>1&&(i=l(i,r(arguments[1]))),i<0&&(i=n+i);i>=0;i--)if(i in t&&t[i]===e)return i||0;return-1}:u},function(e,t,n){"use strict";var o=n(31),r=n(10);e.exports=function(e){if(e===undefined)return 0;var t=o(e),n=r(t);if(t!==n)throw RangeError("Wrong length or index");return n}},function(e,t,n){"use strict";var o=n(32),r=n(6),a=[].slice,i={},c=function(e,t,n){if(!(t in i)){for(var o=[],r=0;r1?arguments[1]:undefined,3);t=t?t.next:n.first;)for(o(t.value,t.key,this);t&&t.removed;)t=t.previous},has:function(e){return!!g(this,e)}}),a(d.prototype,n?{get:function(e){var t=g(this,e);return t&&t.value},set:function(e,t){return C(this,0===e?0:e,t)}}:{add:function(e){return C(this,e=0===e?0:e,e)}}),s&&o(d.prototype,"size",{get:function(){return m(this).size}}),d},setStrong:function(e,t,n){var o=t+" Iterator",r=h(t),a=h(o);u(e,t,(function(e,t){f(this,{type:o,target:e,state:r(e),kind:t,last:undefined})}),(function(){for(var e=a(this),t=e.kind,n=e.last;n&&n.removed;)n=n.previous;return e.target&&(e.last=n=n?n.next:e.state.first)?"keys"==t?{value:n.key,done:!1}:"values"==t?{value:n.value,done:!1}:{value:[n.key,n.value],done:!1}:(e.target=undefined,{value:undefined,done:!0})}),n?"entries":"values",!n,!0),d(t)}}},function(e,t,n){"use strict";var o=Math.log;e.exports=Math.log1p||function(e){return(e=+e)>-1e-8&&e<1e-8?e-e*e/2:o(1+e)}},function(e,t,n){"use strict";var o=n(6),r=Math.floor;e.exports=function(e){return!o(e)&&isFinite(e)&&r(e)===e}},function(e,t,n){"use strict";var o=n(5),r=n(57).trim,a=n(82),i=o.parseInt,c=/^[+-]?0[Xx]/,l=8!==i(a+"08")||22!==i(a+"0x16");e.exports=l?function(e,t){var n=r(String(e));return i(n,t>>>0||(c.test(n)?16:10))}:i},function(e,t,n){"use strict";var o=n(7),r=n(63),a=n(26),i=n(72).f,c=function(e){return function(t){for(var n,c=a(t),l=r(c),u=l.length,d=0,s=[];u>d;)n=l[d++],o&&!i.call(c,n)||s.push(e?[n,c[n]]:c[n]);return s}};e.exports={entries:c(!0),values:c(!1)}},function(e,t,n){"use strict";e.exports=Object.is||function(e,t){return e===t?0!==e||1/e==1/t:e!=e&&t!=t}},function(e,t,n){"use strict";var o=n(5);e.exports=o.Promise},function(e,t,n){"use strict";var o=n(74);e.exports=/(iphone|ipod|ipad).*applewebkit/i.test(o)},function(e,t,n){"use strict";var o,r,a,i,c,l,u,d,s=n(5),p=n(20).f,m=n(34),f=n(108).set,h=n(149),C=s.MutationObserver||s.WebKitMutationObserver,g=s.process,b=s.Promise,N="process"==m(g),v=p(s,"queueMicrotask"),V=v&&v.value;V||(o=function(){var e,t;for(N&&(e=g.domain)&&e.exit();r;){t=r.fn,r=r.next;try{t()}catch(n){throw r?i():a=undefined,n}}a=undefined,e&&e.enter()},N?i=function(){g.nextTick(o)}:C&&!h?(c=!0,l=document.createTextNode(""),new C(o).observe(l,{characterData:!0}),i=function(){l.data=c=!c}):b&&b.resolve?(u=b.resolve(undefined),d=u.then,i=function(){d.call(u,o)}):i=function(){f.call(s,o)}),e.exports=V||function(e){var t={fn:e,next:undefined};a&&(a.next=t),r||(r=t,i()),a=t}},function(e,t,n){"use strict";var o=n(8),r=n(6),a=n(152);e.exports=function(e,t){if(o(e),r(t)&&t.constructor===e)return t;var n=a.f(e);return(0,n.resolve)(t),n.promise}},function(e,t,n){"use strict";var o=n(32),r=function(e){var t,n;this.promise=new e((function(e,o){if(t!==undefined||n!==undefined)throw TypeError("Bad Promise constructor");t=e,n=o})),this.resolve=o(t),this.reject=o(n)};e.exports.f=function(e){return new r(e)}},function(e,t,n){"use strict";var o=n(1),r=n(85);o({target:"RegExp",proto:!0,forced:/./.exec!==r},{exec:r})},function(e,t,n){"use strict";var o=n(74);e.exports=/Version\/10\.\d+(\.\d+)?( Mobile\/\w+)? Safari\//.test(o)},function(e,t,n){"use strict";var o=n(351);e.exports=function(e,t){var n=o(e);if(n%t)throw RangeError("Wrong offset");return n}},function(e,t,n){"use strict";var o=n(14),r=n(10),a=n(100),i=n(99),c=n(49),l=n(9).aTypedArrayConstructor;e.exports=function(e){var t,n,u,d,s,p,m=o(e),f=arguments.length,h=f>1?arguments[1]:undefined,C=h!==undefined,g=a(m);if(g!=undefined&&!i(g))for(p=(s=g.call(m)).next,m=[];!(d=p.call(s)).done;)m.push(d.value);for(C&&f>2&&(h=c(h,arguments[2],2)),n=r(m.length),u=new(l(this))(n),t=0;n>t;t++)u[t]=C?h(m[t],t):m[t];return u}},function(e,t,n){"use strict";var o=n(67),r=n(52).getWeakData,a=n(8),i=n(6),c=n(56),l=n(69),u=n(18),d=n(15),s=n(36),p=s.set,m=s.getterFor,f=u.find,h=u.findIndex,C=0,g=function(e){return e.frozen||(e.frozen=new b)},b=function(){this.entries=[]},N=function(e,t){return f(e.entries,(function(e){return e[0]===t}))};b.prototype={get:function(e){var t=N(this,e);if(t)return t[1]},has:function(e){return!!N(this,e)},set:function(e,t){var n=N(this,e);n?n[1]=t:this.entries.push([e,t])},"delete":function(e){var t=h(this.entries,(function(t){return t[0]===e}));return~t&&this.entries.splice(t,1),!!~t}},e.exports={getConstructor:function(e,t,n,u){var s=e((function(e,o){c(e,s,t),p(e,{type:t,id:C++,frozen:undefined}),o!=undefined&&l(o,e[u],e,n)})),f=m(t),h=function(e,t,n){var o=f(e),i=r(a(t),!0);return!0===i?g(o).set(t,n):i[o.id]=n,e};return o(s.prototype,{"delete":function(e){var t=f(this);if(!i(e))return!1;var n=r(e);return!0===n?g(t)["delete"](e):n&&d(n,t.id)&&delete n[t.id]},has:function(e){var t=f(this);if(!i(e))return!1;var n=r(e);return!0===n?g(t).has(e):n&&d(n,t.id)}}),o(s.prototype,n?{get:function(e){var t=f(this);if(i(e)){var n=r(e);return!0===n?g(t).get(e):n?n[t.id]:undefined}},set:function(e,t){return h(this,e,t)}}:{add:function(e){return h(this,e,!0)}}),s}}},function(e,t,n){"use strict";t.__esModule=!0,t.setupHotReloading=t.sendLogEntry=void 0;t.sendLogEntry=function(e,t){};t.setupHotReloading=function(){0}},function(e,t,n){"use strict";t.__esModule=!0,t.resizeStartHandler=t.dragStartHandler=t.setupDrag=void 0;var o=n(160),r=n(16);function a(e,t,n,o,r,a,i){try{var c=e[a](i),l=c.value}catch(u){return void n(u)}c.done?t(l):Promise.resolve(l).then(o,r)}var i,c,l,u,d,s=(0,n(53).createLogger)("drag"),p=!1,m=!1,f=[0,0],h=function(e){return(0,r.winget)(e,"pos").then((function(e){return[e.x,e.y]}))},C=function(e,t){return(0,r.winset)(e,"pos",t[0]+","+t[1])},g=function(){var e,t=(e=regeneratorRuntime.mark((function n(e){var t,o,r,a;return regeneratorRuntime.wrap((function(n){for(;;)switch(n.prev=n.next){case 0:return s.log("setting up"),i=e.config.window,n.next=4,h(i);case 4:t=n.sent,f=[t[0]-window.screenLeft,t[1]-window.screenTop],o=b(t),r=o[0],a=o[1],r&&C(i,a),s.debug("current state",{ref:i,screenOffset:f});case 9:case"end":return n.stop()}}),n)})),function(){var t=this,n=arguments;return new Promise((function(o,r){var i=e.apply(t,n);function c(e){a(i,o,r,c,l,"next",e)}function l(e){a(i,o,r,c,l,"throw",e)}c(undefined)}))});return function(e){return t.apply(this,arguments)}}();t.setupDrag=g;var b=function(e){var t=e[0],n=e[1],o=!1;return t<0?(t=0,o=!0):t+window.innerWidth>window.screen.availWidth&&(t=window.screen.availWidth-window.innerWidth,o=!0),n<0?(n=0,o=!0):n+window.innerHeight>window.screen.availHeight&&(n=window.screen.availHeight-window.innerHeight,o=!0),[o,[t,n]]};t.dragStartHandler=function(e){s.log("drag start"),p=!0,c=[window.screenLeft-e.screenX,window.screenTop-e.screenY],document.addEventListener("mousemove",v),document.addEventListener("mouseup",N),v(e)};var N=function _(e){s.log("drag end"),v(e),document.removeEventListener("mousemove",v),document.removeEventListener("mouseup",_),p=!1},v=function(e){p&&(e.preventDefault(),C(i,(0,o.vecAdd)([e.screenX,e.screenY],f,c)))};t.resizeStartHandler=function(e,t){return function(n){l=[e,t],s.log("resize start",l),m=!0,c=[window.screenLeft-n.screenX,window.screenTop-n.screenY],u=[window.innerWidth,window.innerHeight],document.addEventListener("mousemove",y),document.addEventListener("mouseup",V),y(n)}};var V=function x(e){s.log("resize end",d),y(e),document.removeEventListener("mousemove",y),document.removeEventListener("mouseup",x),m=!1},y=function(e){m&&(e.preventDefault(),(d=(0,o.vecAdd)(u,(0,o.vecMultiply)(l,(0,o.vecAdd)([e.screenX,e.screenY],(0,o.vecInverse)([window.screenLeft,window.screenTop]),c,[1,1]))))[0]=Math.max(d[0],250),d[1]=Math.max(d[1],120),function(e,t){(0,r.winset)(e,"size",t[0]+","+t[1])}(i,d))}},function(e,t,n){"use strict";t.__esModule=!0,t.vecNormalize=t.vecLength=t.vecInverse=t.vecScale=t.vecDivide=t.vecMultiply=t.vecSubtract=t.vecAdd=t.vecCreate=void 0;var o=n(25);t.vecCreate=function(){for(var e=arguments.length,t=new Array(e),n=0;n35;return(0,o.createVNode)(1,"div",(0,r.classes)(["Tooltip",i&&"Tooltip--long",a&&"Tooltip--"+a]),null,1,{"data-tooltip":t})}},function(e,t,n){"use strict";t.__esModule=!0,t.Input=void 0;var o=n(0),r=n(11),a=n(19);function i(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}var c=function(e){return(0,r.isFalsy)(e)?"":e},l=function(e){var t,n;function l(){var t;return(t=e.call(this)||this).inputRef=(0,o.createRef)(),t.state={editing:!1},t.handleInput=function(e){var n=t.state.editing,o=t.props.onInput;n||t.setEditing(!0),o&&o(e,e.target.value)},t.handleFocus=function(e){t.state.editing||t.setEditing(!0)},t.handleBlur=function(e){var n=t.state.editing,o=t.props.onChange;n&&(t.setEditing(!1),o&&o(e,e.target.value))},t.handleKeyDown=function(e){var n=t.props,o=n.onInput,r=n.onChange,a=n.onEnter;return 13===e.keyCode?(t.setEditing(!1),r&&r(e,e.target.value),o&&o(e,e.target.value),a&&a(e,e.target.value),void(t.props.selfClear?e.target.value="":e.target.blur())):27===e.keyCode?(t.setEditing(!1),e.target.value=c(t.props.value),void e.target.blur()):void 0},t}n=e,(t=l).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n;var u=l.prototype;return u.componentDidMount=function(){var e=this.props.value,t=this.inputRef.current;t&&(t.value=c(e))},u.componentDidUpdate=function(e,t){var n=this.state.editing,o=e.value,r=this.props.value,a=this.inputRef.current;a&&!n&&o!==r&&(a.value=c(r))},u.setEditing=function(e){this.setState({editing:e})},u.render=function(){var e=this.props,t=(e.selfClear,e.onInput,e.onChange,e.onEnter,e.value,e.maxLength),n=e.placeholder,c=i(e,["selfClear","onInput","onChange","onEnter","value","maxLength","placeholder"]),l=c.className,u=c.fluid,d=i(c,["className","fluid"]);return(0,o.normalizeProps)((0,o.createComponentVNode)(2,a.Box,Object.assign({className:(0,r.classes)(["Input",u&&"Input--fluid",l])},d,{children:[(0,o.createVNode)(1,"div","Input__baseline",".",16),(0,o.createVNode)(64,"input","Input__input",null,1,{placeholder:n,onInput:this.handleInput,onFocus:this.handleFocus,onBlur:this.handleBlur,onKeyDown:this.handleKeyDown,maxLength:t},null,this.inputRef)]})))},l}(o.Component);t.Input=l},function(e,t,n){"use strict";t.__esModule=!0,t.GridColumn=t.Grid=void 0;var o=n(0),r=n(166),a=n(11);function i(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}var c=function(e){var t=e.children,n=i(e,["children"]);return(0,o.normalizeProps)((0,o.createComponentVNode)(2,r.Table,Object.assign({},n,{children:(0,o.createComponentVNode)(2,r.Table.Row,{children:t})})))};t.Grid=c,c.defaultHooks=a.pureComponentHooks;var l=function(e){var t=e.size,n=void 0===t?1:t,a=e.style,c=i(e,["size","style"]);return(0,o.normalizeProps)((0,o.createComponentVNode)(2,r.Table.Cell,Object.assign({style:Object.assign({width:n+"%"},a)},c)))};t.GridColumn=l,c.defaultHooks=a.pureComponentHooks,c.Column=l},function(e,t,n){"use strict";t.__esModule=!0,t.TableCell=t.TableRow=t.Table=void 0;var o=n(0),r=n(11),a=n(19);function i(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}var c=function(e){var t=e.collapsing,n=e.className,c=e.content,l=e.children,u=i(e,["collapsing","className","content","children"]);return(0,o.normalizeProps)((0,o.createComponentVNode)(2,a.Box,Object.assign({as:"table",className:(0,r.classes)(["Table",t&&"Table--collapsing",n])},u,{children:(0,o.createVNode)(1,"tbody",null,[c,l],0)})))};t.Table=c,c.defaultHooks=r.pureComponentHooks;var l=function(e){var t=e.className,n=e.header,c=i(e,["className","header"]);return(0,o.normalizeProps)((0,o.createComponentVNode)(2,a.Box,Object.assign({as:"tr",className:(0,r.classes)(["Table__row",n&&"Table__row--header",t])},c)))};t.TableRow=l,l.defaultHooks=r.pureComponentHooks;var u=function(e){var t=e.className,n=e.collapsing,c=e.header,l=i(e,["className","collapsing","header"]);return(0,o.normalizeProps)((0,o.createComponentVNode)(2,a.Box,Object.assign({as:"td",className:(0,r.classes)(["Table__cell",n&&"Table__cell--collapsing",c&&"Table__cell--header",t])},l)))};t.TableCell=u,u.defaultHooks=r.pureComponentHooks,c.Row=l,c.Cell=u},function(e,t,n){"use strict";t.__esModule=!0,t.LabeledListDivider=t.LabeledListItem=t.LabeledList=void 0;var o=n(0),r=n(11),a=n(19),i=function(e){var t=e.children;return(0,o.createVNode)(1,"table","LabeledList",t,0)};t.LabeledList=i,i.defaultHooks=r.pureComponentHooks;var c=function(e){var t=e.className,n=e.label,i=e.labelColor,c=void 0===i?"label":i,l=e.color,u=e.buttons,d=e.content,s=e.children;return(0,o.createVNode)(1,"tr",(0,r.classes)(["LabeledList__row",t]),[(0,o.createComponentVNode)(2,a.Box,{as:"td",color:c,className:(0,r.classes)(["LabeledList__cell","LabeledList__label"]),content:n+":"}),(0,o.createComponentVNode)(2,a.Box,{as:"td",color:l,className:(0,r.classes)(["LabeledList__cell","LabeledList__content"]),colSpan:u?undefined:2,children:[d,s]}),u&&(0,o.createVNode)(1,"td","LabeledList__cell LabeledList__buttons",u,0)],0)};t.LabeledListItem=c,c.defaultHooks=r.pureComponentHooks;var l=function(e){var t=e.size,n=void 0===t?1:t;return(0,o.createVNode)(1,"tr","LabeledList__row",(0,o.createVNode)(1,"td",null,null,1,{style:{"padding-bottom":(0,a.unit)(n)}}),2)};t.LabeledListDivider=l,l.defaultHooks=r.pureComponentHooks,i.Item=c,i.Divider=l},function(e,t,n){"use strict";t.__esModule=!0,t.BeakerContents=void 0;var o=n(0),r=n(2);t.BeakerContents=function(e){var t=e.beakerLoaded,n=e.beakerContents;return(0,o.createComponentVNode)(2,r.Box,{children:[!t&&(0,o.createComponentVNode)(2,r.Box,{color:"label",children:"No beaker loaded."})||0===n.length&&(0,o.createComponentVNode)(2,r.Box,{color:"label",children:"Beaker is empty."}),n.map((function(e){return(0,o.createComponentVNode)(2,r.Box,{color:"label",children:[e.volume," units of ",e.name,", Purity: ",e.purity]},e.name)}))]})}},function(e,t,n){n(170),n(171),n(172),n(173),n(174),n(175),e.exports=n(176)},function(e,t,n){},function(e,t,n){},function(e,t,n){},function(e,t,n){},function(e,t,n){},function(e,t,n){},function(e,t,n){"use strict";n(177),n(178),n(179),n(180),n(181),n(182),n(183),n(184),n(185),n(186),n(187),n(188),n(189),n(190),n(191),n(192),n(193),n(194),n(195),n(196),n(197),n(198),n(199),n(200),n(202),n(204),n(205),n(206),n(136),n(208),n(209),n(210),n(211),n(212),n(213),n(214),n(215),n(216),n(217),n(218),n(219),n(220),n(221),n(223),n(224),n(225),n(226),n(227),n(229),n(230),n(232),n(233),n(234),n(235),n(236),n(237),n(238),n(239),n(240),n(241),n(242),n(243),n(244),n(245),n(247),n(248),n(249),n(250),n(251),n(252),n(253),n(254),n(255),n(256),n(257),n(258),n(259),n(261),n(262),n(263),n(264),n(265),n(266),n(268),n(269),n(271),n(273),n(274),n(275),n(276),n(277),n(278),n(279),n(280),n(281),n(282),n(283),n(284),n(285),n(286),n(287),n(288),n(289),n(290),n(291),n(292),n(293),n(294),n(295),n(297),n(298),n(299),n(302),n(303),n(304),n(305),n(306),n(307),n(308),n(309),n(310),n(311),n(312),n(313),n(314),n(315),n(316),n(153),n(317),n(318),n(319),n(320),n(321),n(322),n(323),n(324),n(325),n(326),n(327),n(328),n(329),n(330),n(331),n(332),n(333),n(334),n(335),n(336),n(337),n(338),n(339),n(340),n(341),n(342),n(343),n(344),n(345),n(346),n(347),n(348),n(349),n(350),n(352),n(353),n(354),n(355),n(356),n(357),n(358),n(359),n(360),n(361),n(362),n(363),n(364),n(365),n(366),n(367),n(368),n(369),n(370),n(371),n(372),n(373),n(374),n(375),n(376),n(377),n(378),n(379),n(380),n(381),n(382),n(383),n(384),n(385),n(386),n(387),n(388),n(389);var o=n(0);n(391),n(392);var r=n(393),a=(n(158),n(3)),i=n(16),c=n(159),l=n(53),u=n(161),d=n(517),s=(0,l.createLogger)(),p=(0,d.createStore)(),m=document.getElementById("react-root"),f=!0,h=!1,C=function(){for(p.subscribe((function(){!function(){if(!h){0;try{var e=p.getState();if(f){if(s.log("initial render",e),!(0,u.getRoute)(e)){if(s.info("loading old tgui"),h=!0,window.update=window.initialize=function(){},i.tridentVersion<=4)return void setTimeout((function(){location.href="tgui-fallback.html?ref="+window.__ref__}),10);document.getElementById("data").textContent=JSON.stringify(e),(0,r.loadCSS)("v4shim.css"),(0,r.loadCSS)("tgui.css");var t=document.getElementsByTagName("head")[0],a=document.createElement("script");return a.type="text/javascript",a.src="tgui.js",void t.appendChild(a)}(0,c.setupDrag)(e)}var l=n(519).Layout,d=(0,o.createComponentVNode)(2,l,{state:e,dispatch:p.dispatch});(0,o.render)(d,m)}catch(C){s.error("rendering error",C)}f&&(f=!1)}}()})),window.update=window.initialize=function(e){var t=function(e){var t=function(e,t){return"object"==typeof t&&null!==t&&t.__number__?parseFloat(t.__number__):t};i.tridentVersion<=4&&(t=undefined);try{return JSON.parse(e,t)}catch(o){s.log(o),s.log("What we got:",e);var n=o&&o.message;throw new Error("JSON parsing error: "+n)}}(e);p.dispatch((0,a.backendUpdate)(t))};;){var e=window.__updateQueue__.shift();if(!e)break;window.update(e)}(0,r.loadCSS)("font-awesome.css")};i.tridentVersion<=4&&"loading"===document.readyState?document.addEventListener("DOMContentLoaded",C):C()},function(e,t,n){"use strict";var o=n(1),r=n(5),a=n(38),i=n(39),c=n(7),l=n(96),u=n(128),d=n(4),s=n(15),p=n(54),m=n(6),f=n(8),h=n(14),C=n(26),g=n(35),b=n(47),N=n(43),v=n(63),V=n(48),y=n(131),_=n(95),x=n(20),k=n(13),L=n(72),w=n(30),B=n(22),S=n(92),I=n(73),T=n(60),A=n(59),E=n(12),P=n(132),M=n(27),O=n(44),R=n(36),F=n(18).forEach,D=I("hidden"),j=E("toPrimitive"),z=R.set,H=R.getterFor("Symbol"),G=Object.prototype,U=r.Symbol,K=a("JSON","stringify"),Y=x.f,q=k.f,W=y.f,$=L.f,Q=S("symbols"),X=S("op-symbols"),Z=S("string-to-symbol-registry"),J=S("symbol-to-string-registry"),ee=S("wks"),te=r.QObject,ne=!te||!te.prototype||!te.prototype.findChild,oe=c&&d((function(){return 7!=N(q({},"a",{get:function(){return q(this,"a",{value:7}).a}})).a}))?function(e,t,n){var o=Y(G,t);o&&delete G[t],q(e,t,n),o&&e!==G&&q(G,t,o)}:q,re=function(e,t){var n=Q[e]=N(U.prototype);return z(n,{type:"Symbol",tag:e,description:t}),c||(n.description=t),n},ae=u?function(e){return"symbol"==typeof e}:function(e){return Object(e)instanceof U},ie=function(e,t,n){e===G&&ie(X,t,n),f(e);var o=g(t,!0);return f(n),s(Q,o)?(n.enumerable?(s(e,D)&&e[D][o]&&(e[D][o]=!1),n=N(n,{enumerable:b(0,!1)})):(s(e,D)||q(e,D,b(1,{})),e[D][o]=!0),oe(e,o,n)):q(e,o,n)},ce=function(e,t){f(e);var n=C(t),o=v(n).concat(pe(n));return F(o,(function(t){c&&!ue.call(n,t)||ie(e,t,n[t])})),e},le=function(e,t){return t===undefined?N(e):ce(N(e),t)},ue=function(e){var t=g(e,!0),n=$.call(this,t);return!(this===G&&s(Q,t)&&!s(X,t))&&(!(n||!s(this,t)||!s(Q,t)||s(this,D)&&this[D][t])||n)},de=function(e,t){var n=C(e),o=g(t,!0);if(n!==G||!s(Q,o)||s(X,o)){var r=Y(n,o);return!r||!s(Q,o)||s(n,D)&&n[D][o]||(r.enumerable=!0),r}},se=function(e){var t=W(C(e)),n=[];return F(t,(function(e){s(Q,e)||s(T,e)||n.push(e)})),n},pe=function(e){var t=e===G,n=W(t?X:C(e)),o=[];return F(n,(function(e){!s(Q,e)||t&&!s(G,e)||o.push(Q[e])})),o};(l||(B((U=function(){if(this instanceof U)throw TypeError("Symbol is not a constructor");var e=arguments.length&&arguments[0]!==undefined?String(arguments[0]):undefined,t=A(e),n=function o(e){this===G&&o.call(X,e),s(this,D)&&s(this[D],t)&&(this[D][t]=!1),oe(this,t,b(1,e))};return c&&ne&&oe(G,t,{configurable:!0,set:n}),re(t,e)}).prototype,"toString",(function(){return H(this).tag})),B(U,"withoutSetter",(function(e){return re(A(e),e)})),L.f=ue,k.f=ie,x.f=de,V.f=y.f=se,_.f=pe,P.f=function(e){return re(E(e),e)},c&&(q(U.prototype,"description",{configurable:!0,get:function(){return H(this).description}}),i||B(G,"propertyIsEnumerable",ue,{unsafe:!0}))),o({global:!0,wrap:!0,forced:!l,sham:!l},{Symbol:U}),F(v(ee),(function(e){M(e)})),o({target:"Symbol",stat:!0,forced:!l},{"for":function(e){var t=String(e);if(s(Z,t))return Z[t];var n=U(t);return Z[t]=n,J[n]=t,n},keyFor:function(e){if(!ae(e))throw TypeError(e+" is not a symbol");if(s(J,e))return J[e]},useSetter:function(){ne=!0},useSimple:function(){ne=!1}}),o({target:"Object",stat:!0,forced:!l,sham:!c},{create:le,defineProperty:ie,defineProperties:ce,getOwnPropertyDescriptor:de}),o({target:"Object",stat:!0,forced:!l},{getOwnPropertyNames:se,getOwnPropertySymbols:pe}),o({target:"Object",stat:!0,forced:d((function(){_.f(1)}))},{getOwnPropertySymbols:function(e){return _.f(h(e))}}),K)&&o({target:"JSON",stat:!0,forced:!l||d((function(){var e=U();return"[null]"!=K([e])||"{}"!=K({a:e})||"{}"!=K(Object(e))}))},{stringify:function(e,t,n){for(var o,r=[e],a=1;arguments.length>a;)r.push(arguments[a++]);if(o=t,(m(t)||e!==undefined)&&!ae(e))return p(t)||(t=function(e,t){if("function"==typeof o&&(t=o.call(this,e,t)),!ae(t))return t}),r[1]=t,K.apply(null,r)}});U.prototype[j]||w(U.prototype,j,U.prototype.valueOf),O(U,"Symbol"),T[D]=!0},function(e,t,n){"use strict";var o=n(1),r=n(7),a=n(5),i=n(15),c=n(6),l=n(13).f,u=n(125),d=a.Symbol;if(r&&"function"==typeof d&&(!("description"in d.prototype)||d().description!==undefined)){var s={},p=function(){var e=arguments.length<1||arguments[0]===undefined?undefined:String(arguments[0]),t=this instanceof p?new d(e):e===undefined?d():d(e);return""===e&&(s[t]=!0),t};u(p,d);var m=p.prototype=d.prototype;m.constructor=p;var f=m.toString,h="Symbol(test)"==String(d("test")),C=/^Symbol\((.*)\)[^)]+$/;l(m,"description",{configurable:!0,get:function(){var e=c(this)?this.valueOf():this,t=f.call(e);if(i(s,e))return"";var n=h?t.slice(7,-1):t.replace(C,"$1");return""===n?undefined:n}}),o({global:!0,forced:!0},{Symbol:p})}},function(e,t,n){"use strict";n(27)("asyncIterator")},function(e,t,n){"use strict";n(27)("hasInstance")},function(e,t,n){"use strict";n(27)("isConcatSpreadable")},function(e,t,n){"use strict";n(27)("iterator")},function(e,t,n){"use strict";n(27)("match")},function(e,t,n){"use strict";n(27)("replace")},function(e,t,n){"use strict";n(27)("search")},function(e,t,n){"use strict";n(27)("species")},function(e,t,n){"use strict";n(27)("split")},function(e,t,n){"use strict";n(27)("toPrimitive")},function(e,t,n){"use strict";n(27)("toStringTag")},function(e,t,n){"use strict";n(27)("unscopables")},function(e,t,n){"use strict";var o=n(1),r=n(4),a=n(54),i=n(6),c=n(14),l=n(10),u=n(50),d=n(64),s=n(65),p=n(12),m=n(97),f=p("isConcatSpreadable"),h=m>=51||!r((function(){var e=[];return e[f]=!1,e.concat()[0]!==e})),C=s("concat"),g=function(e){if(!i(e))return!1;var t=e[f];return t!==undefined?!!t:a(e)};o({target:"Array",proto:!0,forced:!h||!C},{concat:function(e){var t,n,o,r,a,i=c(this),s=d(i,0),p=0;for(t=-1,o=arguments.length;t9007199254740991)throw TypeError("Maximum allowed index exceeded");for(n=0;n=9007199254740991)throw TypeError("Maximum allowed index exceeded");u(s,p++,a)}return s.length=p,s}})},function(e,t,n){"use strict";var o=n(1),r=n(133),a=n(45);o({target:"Array",proto:!0},{copyWithin:r}),a("copyWithin")},function(e,t,n){"use strict";var o=n(1),r=n(18).every,a=n(40),i=n(23),c=a("every"),l=i("every");o({target:"Array",proto:!0,forced:!c||!l},{every:function(e){return r(this,e,arguments.length>1?arguments[1]:undefined)}})},function(e,t,n){"use strict";var o=n(1),r=n(98),a=n(45);o({target:"Array",proto:!0},{fill:r}),a("fill")},function(e,t,n){"use strict";var o=n(1),r=n(18).filter,a=n(65),i=n(23),c=a("filter"),l=i("filter");o({target:"Array",proto:!0,forced:!c||!l},{filter:function(e){return r(this,e,arguments.length>1?arguments[1]:undefined)}})},function(e,t,n){"use strict";var o=n(1),r=n(18).find,a=n(45),i=n(23),c=!0,l=i("find");"find"in[]&&Array(1).find((function(){c=!1})),o({target:"Array",proto:!0,forced:c||!l},{find:function(e){return r(this,e,arguments.length>1?arguments[1]:undefined)}}),a("find")},function(e,t,n){"use strict";var o=n(1),r=n(18).findIndex,a=n(45),i=n(23),c=!0,l=i("findIndex");"findIndex"in[]&&Array(1).findIndex((function(){c=!1})),o({target:"Array",proto:!0,forced:c||!l},{findIndex:function(e){return r(this,e,arguments.length>1?arguments[1]:undefined)}}),a("findIndex")},function(e,t,n){"use strict";var o=n(1),r=n(134),a=n(14),i=n(10),c=n(31),l=n(64);o({target:"Array",proto:!0},{flat:function(){var e=arguments.length?arguments[0]:undefined,t=a(this),n=i(t.length),o=l(t,0);return o.length=r(o,t,t,n,0,e===undefined?1:c(e)),o}})},function(e,t,n){"use strict";var o=n(1),r=n(134),a=n(14),i=n(10),c=n(32),l=n(64);o({target:"Array",proto:!0},{flatMap:function(e){var t,n=a(this),o=i(n.length);return c(e),(t=l(n,0)).length=r(t,n,n,o,0,1,e,arguments.length>1?arguments[1]:undefined),t}})},function(e,t,n){"use strict";var o=n(1),r=n(201);o({target:"Array",proto:!0,forced:[].forEach!=r},{forEach:r})},function(e,t,n){"use strict";var o=n(18).forEach,r=n(40),a=n(23),i=r("forEach"),c=a("forEach");e.exports=i&&c?[].forEach:function(e){return o(this,e,arguments.length>1?arguments[1]:undefined)}},function(e,t,n){"use strict";var o=n(1),r=n(203);o({target:"Array",stat:!0,forced:!n(76)((function(e){Array.from(e)}))},{from:r})},function(e,t,n){"use strict";var o=n(49),r=n(14),a=n(135),i=n(99),c=n(10),l=n(50),u=n(100);e.exports=function(e){var t,n,d,s,p,m,f=r(e),h="function"==typeof this?this:Array,C=arguments.length,g=C>1?arguments[1]:undefined,b=g!==undefined,N=u(f),v=0;if(b&&(g=o(g,C>2?arguments[2]:undefined,2)),N==undefined||h==Array&&i(N))for(n=new h(t=c(f.length));t>v;v++)m=b?g(f[v],v):f[v],l(n,v,m);else for(p=(s=N.call(f)).next,n=new h;!(d=p.call(s)).done;v++)m=b?a(s,g,[d.value,v],!0):d.value,l(n,v,m);return n.length=v,n}},function(e,t,n){"use strict";var o=n(1),r=n(61).includes,a=n(45);o({target:"Array",proto:!0,forced:!n(23)("indexOf",{ACCESSORS:!0,1:0})},{includes:function(e){return r(this,e,arguments.length>1?arguments[1]:undefined)}}),a("includes")},function(e,t,n){"use strict";var o=n(1),r=n(61).indexOf,a=n(40),i=n(23),c=[].indexOf,l=!!c&&1/[1].indexOf(1,-0)<0,u=a("indexOf"),d=i("indexOf",{ACCESSORS:!0,1:0});o({target:"Array",proto:!0,forced:l||!u||!d},{indexOf:function(e){return l?c.apply(this,arguments)||0:r(this,e,arguments.length>1?arguments[1]:undefined)}})},function(e,t,n){"use strict";n(1)({target:"Array",stat:!0},{isArray:n(54)})},function(e,t,n){"use strict";var o=n(137).IteratorPrototype,r=n(43),a=n(47),i=n(44),c=n(66),l=function(){return this};e.exports=function(e,t,n){var u=t+" Iterator";return e.prototype=r(o,{next:a(1,n)}),i(e,u,!1,!0),c[u]=l,e}},function(e,t,n){"use strict";var o=n(1),r=n(58),a=n(26),i=n(40),c=[].join,l=r!=Object,u=i("join",",");o({target:"Array",proto:!0,forced:l||!u},{join:function(e){return c.call(a(this),e===undefined?",":e)}})},function(e,t,n){"use strict";var o=n(1),r=n(139);o({target:"Array",proto:!0,forced:r!==[].lastIndexOf},{lastIndexOf:r})},function(e,t,n){"use strict";var o=n(1),r=n(18).map,a=n(65),i=n(23),c=a("map"),l=i("map");o({target:"Array",proto:!0,forced:!c||!l},{map:function(e){return r(this,e,arguments.length>1?arguments[1]:undefined)}})},function(e,t,n){"use strict";var o=n(1),r=n(4),a=n(50);o({target:"Array",stat:!0,forced:r((function(){function e(){}return!(Array.of.call(e)instanceof e)}))},{of:function(){for(var e=0,t=arguments.length,n=new("function"==typeof this?this:Array)(t);t>e;)a(n,e,arguments[e++]);return n.length=t,n}})},function(e,t,n){"use strict";var o=n(1),r=n(77).left,a=n(40),i=n(23),c=a("reduce"),l=i("reduce",{1:0});o({target:"Array",proto:!0,forced:!c||!l},{reduce:function(e){return r(this,e,arguments.length,arguments.length>1?arguments[1]:undefined)}})},function(e,t,n){"use strict";var o=n(1),r=n(77).right,a=n(40),i=n(23),c=a("reduceRight"),l=i("reduce",{1:0});o({target:"Array",proto:!0,forced:!c||!l},{reduceRight:function(e){return r(this,e,arguments.length,arguments.length>1?arguments[1]:undefined)}})},function(e,t,n){"use strict";var o=n(1),r=n(6),a=n(54),i=n(42),c=n(10),l=n(26),u=n(50),d=n(12),s=n(65),p=n(23),m=s("slice"),f=p("slice",{ACCESSORS:!0,0:0,1:2}),h=d("species"),C=[].slice,g=Math.max;o({target:"Array",proto:!0,forced:!m||!f},{slice:function(e,t){var n,o,d,s=l(this),p=c(s.length),m=i(e,p),f=i(t===undefined?p:t,p);if(a(s)&&("function"!=typeof(n=s.constructor)||n!==Array&&!a(n.prototype)?r(n)&&null===(n=n[h])&&(n=undefined):n=undefined,n===Array||n===undefined))return C.call(s,m,f);for(o=new(n===undefined?Array:n)(g(f-m,0)),d=0;m1?arguments[1]:undefined)}})},function(e,t,n){"use strict";var o=n(1),r=n(32),a=n(14),i=n(4),c=n(40),l=[],u=l.sort,d=i((function(){l.sort(undefined)})),s=i((function(){l.sort(null)})),p=c("sort");o({target:"Array",proto:!0,forced:d||!s||!p},{sort:function(e){return e===undefined?u.call(a(this)):u.call(a(this),r(e))}})},function(e,t,n){"use strict";n(55)("Array")},function(e,t,n){"use strict";var o=n(1),r=n(42),a=n(31),i=n(10),c=n(14),l=n(64),u=n(50),d=n(65),s=n(23),p=d("splice"),m=s("splice",{ACCESSORS:!0,0:0,1:2}),f=Math.max,h=Math.min;o({target:"Array",proto:!0,forced:!p||!m},{splice:function(e,t){var n,o,d,s,p,m,C=c(this),g=i(C.length),b=r(e,g),N=arguments.length;if(0===N?n=o=0:1===N?(n=0,o=g-b):(n=N-2,o=h(f(a(t),0),g-b)),g+n-o>9007199254740991)throw TypeError("Maximum allowed length exceeded");for(d=l(C,o),s=0;sg-o+n;s--)delete C[s-1]}else if(n>o)for(s=g-o;s>b;s--)m=s+n-1,(p=s+o-1)in C?C[m]=C[p]:delete C[m];for(s=0;s>1,h=23===t?r(2,-24)-r(2,-77):0,C=e<0||0===e&&1/e<0?1:0,g=0;for((e=o(e))!=e||e===1/0?(u=e!=e?1:0,l=m):(l=a(i(e)/c),e*(d=r(2,-l))<1&&(l--,d*=2),(e+=l+f>=1?h/d:h*r(2,1-f))*d>=2&&(l++,d/=2),l+f>=m?(u=0,l=m):l+f>=1?(u=(e*d-1)*r(2,t),l+=f):(u=e*r(2,f-1)*r(2,t),l=0));t>=8;s[g++]=255&u,u/=256,t-=8);for(l=l<0;s[g++]=255&l,l/=256,p-=8);return s[--g]|=128*C,s},unpack:function(e,t){var n,o=e.length,a=8*o-t-1,i=(1<>1,l=a-7,u=o-1,d=e[u--],s=127&d;for(d>>=7;l>0;s=256*s+e[u],u--,l-=8);for(n=s&(1<<-l)-1,s>>=-l,l+=t;l>0;n=256*n+e[u],u--,l-=8);if(0===s)s=1-c;else{if(s===i)return n?NaN:d?-1/0:1/0;n+=r(2,t),s-=c}return(d?-1:1)*n*r(2,s-t)}}},function(e,t,n){"use strict";var o=n(1),r=n(9);o({target:"ArrayBuffer",stat:!0,forced:!r.NATIVE_ARRAY_BUFFER_VIEWS},{isView:r.isView})},function(e,t,n){"use strict";var o=n(1),r=n(4),a=n(78),i=n(8),c=n(42),l=n(10),u=n(46),d=a.ArrayBuffer,s=a.DataView,p=d.prototype.slice;o({target:"ArrayBuffer",proto:!0,unsafe:!0,forced:r((function(){return!new d(2).slice(1,undefined).byteLength}))},{slice:function(e,t){if(p!==undefined&&t===undefined)return p.call(i(this),e);for(var n=i(this).byteLength,o=c(e,n),r=c(t===undefined?n:t,n),a=new(u(this,d))(l(r-o)),m=new s(this),f=new s(a),h=0;o9999?"+":"";return n+r(a(e),n?6:4,0)+"-"+r(this.getUTCMonth()+1,2,0)+"-"+r(this.getUTCDate(),2,0)+"T"+r(this.getUTCHours(),2,0)+":"+r(this.getUTCMinutes(),2,0)+":"+r(this.getUTCSeconds(),2,0)+"."+r(t,3,0)+"Z"}:l},function(e,t,n){"use strict";var o=n(1),r=n(4),a=n(14),i=n(35);o({target:"Date",proto:!0,forced:r((function(){return null!==new Date(NaN).toJSON()||1!==Date.prototype.toJSON.call({toISOString:function(){return 1}})}))},{toJSON:function(e){var t=a(this),n=i(t);return"number"!=typeof n||isFinite(n)?t.toISOString():null}})},function(e,t,n){"use strict";var o=n(30),r=n(231),a=n(12)("toPrimitive"),i=Date.prototype;a in i||o(i,a,r)},function(e,t,n){"use strict";var o=n(8),r=n(35);e.exports=function(e){if("string"!==e&&"number"!==e&&"default"!==e)throw TypeError("Incorrect hint");return r(o(this),"number"!==e)}},function(e,t,n){"use strict";var o=n(22),r=Date.prototype,a=r.toString,i=r.getTime;new Date(NaN)+""!="Invalid Date"&&o(r,"toString",(function(){var e=i.call(this);return e==e?a.call(this):"Invalid Date"}))},function(e,t,n){"use strict";n(1)({target:"Function",proto:!0},{bind:n(141)})},function(e,t,n){"use strict";var o=n(6),r=n(13),a=n(37),i=n(12)("hasInstance"),c=Function.prototype;i in c||r.f(c,i,{value:function(e){if("function"!=typeof this||!o(e))return!1;if(!o(this.prototype))return e instanceof this;for(;e=a(e);)if(this.prototype===e)return!0;return!1}})},function(e,t,n){"use strict";var o=n(7),r=n(13).f,a=Function.prototype,i=a.toString,c=/^\s*function ([^ (]*)/;o&&!("name"in a)&&r(a,"name",{configurable:!0,get:function(){try{return i.call(this).match(c)[1]}catch(e){return""}}})},function(e,t,n){"use strict";var o=n(5);n(44)(o.JSON,"JSON",!0)},function(e,t,n){"use strict";var o=n(79),r=n(142);e.exports=o("Map",(function(e){return function(){return e(this,arguments.length?arguments[0]:undefined)}}),r)},function(e,t,n){"use strict";var o=n(1),r=n(143),a=Math.acosh,i=Math.log,c=Math.sqrt,l=Math.LN2;o({target:"Math",stat:!0,forced:!a||710!=Math.floor(a(Number.MAX_VALUE))||a(Infinity)!=Infinity},{acosh:function(e){return(e=+e)<1?NaN:e>94906265.62425156?i(e)+l:r(e-1+c(e-1)*c(e+1))}})},function(e,t,n){"use strict";var o=n(1),r=Math.asinh,a=Math.log,i=Math.sqrt;o({target:"Math",stat:!0,forced:!(r&&1/r(0)>0)},{asinh:function c(e){return isFinite(e=+e)&&0!=e?e<0?-c(-e):a(e+i(e*e+1)):e}})},function(e,t,n){"use strict";var o=n(1),r=Math.atanh,a=Math.log;o({target:"Math",stat:!0,forced:!(r&&1/r(-0)<0)},{atanh:function(e){return 0==(e=+e)?e:a((1+e)/(1-e))/2}})},function(e,t,n){"use strict";var o=n(1),r=n(107),a=Math.abs,i=Math.pow;o({target:"Math",stat:!0},{cbrt:function(e){return r(e=+e)*i(a(e),1/3)}})},function(e,t,n){"use strict";var o=n(1),r=Math.floor,a=Math.log,i=Math.LOG2E;o({target:"Math",stat:!0},{clz32:function(e){return(e>>>=0)?31-r(a(e+.5)*i):32}})},function(e,t,n){"use strict";var o=n(1),r=n(81),a=Math.cosh,i=Math.abs,c=Math.E;o({target:"Math",stat:!0,forced:!a||a(710)===Infinity},{cosh:function(e){var t=r(i(e)-1)+1;return(t+1/(t*c*c))*(c/2)}})},function(e,t,n){"use strict";var o=n(1),r=n(81);o({target:"Math",stat:!0,forced:r!=Math.expm1},{expm1:r})},function(e,t,n){"use strict";n(1)({target:"Math",stat:!0},{fround:n(246)})},function(e,t,n){"use strict";var o=n(107),r=Math.abs,a=Math.pow,i=a(2,-52),c=a(2,-23),l=a(2,127)*(2-c),u=a(2,-126);e.exports=Math.fround||function(e){var t,n,a=r(e),d=o(e);return al||n!=n?d*Infinity:d*n}},function(e,t,n){"use strict";var o=n(1),r=Math.hypot,a=Math.abs,i=Math.sqrt;o({target:"Math",stat:!0,forced:!!r&&r(Infinity,NaN)!==Infinity},{hypot:function(e,t){for(var n,o,r=0,c=0,l=arguments.length,u=0;c0?(o=n/u)*o:n;return u===Infinity?Infinity:u*i(r)}})},function(e,t,n){"use strict";var o=n(1),r=n(4),a=Math.imul;o({target:"Math",stat:!0,forced:r((function(){return-5!=a(4294967295,5)||2!=a.length}))},{imul:function(e,t){var n=+e,o=+t,r=65535&n,a=65535&o;return 0|r*a+((65535&n>>>16)*a+r*(65535&o>>>16)<<16>>>0)}})},function(e,t,n){"use strict";var o=n(1),r=Math.log,a=Math.LOG10E;o({target:"Math",stat:!0},{log10:function(e){return r(e)*a}})},function(e,t,n){"use strict";n(1)({target:"Math",stat:!0},{log1p:n(143)})},function(e,t,n){"use strict";var o=n(1),r=Math.log,a=Math.LN2;o({target:"Math",stat:!0},{log2:function(e){return r(e)/a}})},function(e,t,n){"use strict";n(1)({target:"Math",stat:!0},{sign:n(107)})},function(e,t,n){"use strict";var o=n(1),r=n(4),a=n(81),i=Math.abs,c=Math.exp,l=Math.E;o({target:"Math",stat:!0,forced:r((function(){return-2e-17!=Math.sinh(-2e-17)}))},{sinh:function(e){return i(e=+e)<1?(a(e)-a(-e))/2:(c(e-1)-c(-e-1))*(l/2)}})},function(e,t,n){"use strict";var o=n(1),r=n(81),a=Math.exp;o({target:"Math",stat:!0},{tanh:function(e){var t=r(e=+e),n=r(-e);return t==Infinity?1:n==Infinity?-1:(t-n)/(a(e)+a(-e))}})},function(e,t,n){"use strict";n(44)(Math,"Math",!0)},function(e,t,n){"use strict";var o=n(1),r=Math.ceil,a=Math.floor;o({target:"Math",stat:!0},{trunc:function(e){return(e>0?a:r)(e)}})},function(e,t,n){"use strict";var o=n(7),r=n(5),a=n(62),i=n(22),c=n(15),l=n(34),u=n(80),d=n(35),s=n(4),p=n(43),m=n(48).f,f=n(20).f,h=n(13).f,C=n(57).trim,g=r.Number,b=g.prototype,N="Number"==l(p(b)),v=function(e){var t,n,o,r,a,i,c,l,u=d(e,!1);if("string"==typeof u&&u.length>2)if(43===(t=(u=C(u)).charCodeAt(0))||45===t){if(88===(n=u.charCodeAt(2))||120===n)return NaN}else if(48===t){switch(u.charCodeAt(1)){case 66:case 98:o=2,r=49;break;case 79:case 111:o=8,r=55;break;default:return+u}for(i=(a=u.slice(2)).length,c=0;cr)return NaN;return parseInt(a,o)}return+u};if(a("Number",!g(" 0o1")||!g("0b1")||g("+0x1"))){for(var V,y=function(e){var t=arguments.length<1?0:e,n=this;return n instanceof y&&(N?s((function(){b.valueOf.call(n)})):"Number"!=l(n))?u(new g(v(t)),n,y):v(t)},_=o?m(g):"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger".split(","),x=0;_.length>x;x++)c(g,V=_[x])&&!c(y,V)&&h(y,V,f(g,V));y.prototype=b,b.constructor=y,i(r,"Number",y)}},function(e,t,n){"use strict";n(1)({target:"Number",stat:!0},{EPSILON:Math.pow(2,-52)})},function(e,t,n){"use strict";n(1)({target:"Number",stat:!0},{isFinite:n(260)})},function(e,t,n){"use strict";var o=n(5).isFinite;e.exports=Number.isFinite||function(e){return"number"==typeof e&&o(e)}},function(e,t,n){"use strict";n(1)({target:"Number",stat:!0},{isInteger:n(144)})},function(e,t,n){"use strict";n(1)({target:"Number",stat:!0},{isNaN:function(e){return e!=e}})},function(e,t,n){"use strict";var o=n(1),r=n(144),a=Math.abs;o({target:"Number",stat:!0},{isSafeInteger:function(e){return r(e)&&a(e)<=9007199254740991}})},function(e,t,n){"use strict";n(1)({target:"Number",stat:!0},{MAX_SAFE_INTEGER:9007199254740991})},function(e,t,n){"use strict";n(1)({target:"Number",stat:!0},{MIN_SAFE_INTEGER:-9007199254740991})},function(e,t,n){"use strict";var o=n(1),r=n(267);o({target:"Number",stat:!0,forced:Number.parseFloat!=r},{parseFloat:r})},function(e,t,n){"use strict";var o=n(5),r=n(57).trim,a=n(82),i=o.parseFloat,c=1/i(a+"-0")!=-Infinity;e.exports=c?function(e){var t=r(String(e)),n=i(t);return 0===n&&"-"==t.charAt(0)?-0:n}:i},function(e,t,n){"use strict";var o=n(1),r=n(145);o({target:"Number",stat:!0,forced:Number.parseInt!=r},{parseInt:r})},function(e,t,n){"use strict";var o=n(1),r=n(31),a=n(270),i=n(106),c=n(4),l=1..toFixed,u=Math.floor,d=function s(e,t,n){return 0===t?n:t%2==1?s(e,t-1,n*e):s(e*e,t/2,n)};o({target:"Number",proto:!0,forced:l&&("0.000"!==8e-5.toFixed(3)||"1"!==.9.toFixed(0)||"1.25"!==1.255.toFixed(2)||"1000000000000000128"!==(0xde0b6b3a7640080).toFixed(0))||!c((function(){l.call({})}))},{toFixed:function(e){var t,n,o,c,l=a(this),s=r(e),p=[0,0,0,0,0,0],m="",f="0",h=function(e,t){for(var n=-1,o=t;++n<6;)o+=e*p[n],p[n]=o%1e7,o=u(o/1e7)},C=function(e){for(var t=6,n=0;--t>=0;)n+=p[t],p[t]=u(n/e),n=n%e*1e7},g=function(){for(var e=6,t="";--e>=0;)if(""!==t||0===e||0!==p[e]){var n=String(p[e]);t=""===t?n:t+i.call("0",7-n.length)+n}return t};if(s<0||s>20)throw RangeError("Incorrect fraction digits");if(l!=l)return"NaN";if(l<=-1e21||l>=1e21)return String(l);if(l<0&&(m="-",l=-l),l>1e-21)if(n=(t=function(e){for(var t=0,n=e;n>=4096;)t+=12,n/=4096;for(;n>=2;)t+=1,n/=2;return t}(l*d(2,69,1))-69)<0?l*d(2,-t,1):l/d(2,t,1),n*=4503599627370496,(t=52-t)>0){for(h(0,n),o=s;o>=7;)h(1e7,0),o-=7;for(h(d(10,o,1),0),o=t-1;o>=23;)C(1<<23),o-=23;C(1<0?m+((c=f.length)<=s?"0."+i.call("0",s-c)+f:f.slice(0,c-s)+"."+f.slice(c-s)):m+f}})},function(e,t,n){"use strict";var o=n(34);e.exports=function(e){if("number"!=typeof e&&"Number"!=o(e))throw TypeError("Incorrect invocation");return+e}},function(e,t,n){"use strict";var o=n(1),r=n(272);o({target:"Object",stat:!0,forced:Object.assign!==r},{assign:r})},function(e,t,n){"use strict";var o=n(7),r=n(4),a=n(63),i=n(95),c=n(72),l=n(14),u=n(58),d=Object.assign,s=Object.defineProperty;e.exports=!d||r((function(){if(o&&1!==d({b:1},d(s({},"a",{enumerable:!0,get:function(){s(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var e={},t={},n=Symbol();return e[n]=7,"abcdefghijklmnopqrst".split("").forEach((function(e){t[e]=e})),7!=d({},e)[n]||"abcdefghijklmnopqrst"!=a(d({},t)).join("")}))?function(e,t){for(var n=l(e),r=arguments.length,d=1,s=i.f,p=c.f;r>d;)for(var m,f=u(arguments[d++]),h=s?a(f).concat(s(f)):a(f),C=h.length,g=0;C>g;)m=h[g++],o&&!p.call(f,m)||(n[m]=f[m]);return n}:d},function(e,t,n){"use strict";n(1)({target:"Object",stat:!0,sham:!n(7)},{create:n(43)})},function(e,t,n){"use strict";var o=n(1),r=n(7),a=n(83),i=n(14),c=n(32),l=n(13);r&&o({target:"Object",proto:!0,forced:a},{__defineGetter__:function(e,t){l.f(i(this),e,{get:c(t),enumerable:!0,configurable:!0})}})},function(e,t,n){"use strict";var o=n(1),r=n(7);o({target:"Object",stat:!0,forced:!r,sham:!r},{defineProperties:n(129)})},function(e,t,n){"use strict";var o=n(1),r=n(7);o({target:"Object",stat:!0,forced:!r,sham:!r},{defineProperty:n(13).f})},function(e,t,n){"use strict";var o=n(1),r=n(7),a=n(83),i=n(14),c=n(32),l=n(13);r&&o({target:"Object",proto:!0,forced:a},{__defineSetter__:function(e,t){l.f(i(this),e,{set:c(t),enumerable:!0,configurable:!0})}})},function(e,t,n){"use strict";var o=n(1),r=n(146).entries;o({target:"Object",stat:!0},{entries:function(e){return r(e)}})},function(e,t,n){"use strict";var o=n(1),r=n(68),a=n(4),i=n(6),c=n(52).onFreeze,l=Object.freeze;o({target:"Object",stat:!0,forced:a((function(){l(1)})),sham:!r},{freeze:function(e){return l&&i(e)?l(c(e)):e}})},function(e,t,n){"use strict";var o=n(1),r=n(69),a=n(50);o({target:"Object",stat:!0},{fromEntries:function(e){var t={};return r(e,(function(e,n){a(t,e,n)}),undefined,!0),t}})},function(e,t,n){"use strict";var o=n(1),r=n(4),a=n(26),i=n(20).f,c=n(7),l=r((function(){i(1)}));o({target:"Object",stat:!0,forced:!c||l,sham:!c},{getOwnPropertyDescriptor:function(e,t){return i(a(e),t)}})},function(e,t,n){"use strict";var o=n(1),r=n(7),a=n(93),i=n(26),c=n(20),l=n(50);o({target:"Object",stat:!0,sham:!r},{getOwnPropertyDescriptors:function(e){for(var t,n,o=i(e),r=c.f,u=a(o),d={},s=0;u.length>s;)(n=r(o,t=u[s++]))!==undefined&&l(d,t,n);return d}})},function(e,t,n){"use strict";var o=n(1),r=n(4),a=n(131).f;o({target:"Object",stat:!0,forced:r((function(){return!Object.getOwnPropertyNames(1)}))},{getOwnPropertyNames:a})},function(e,t,n){"use strict";var o=n(1),r=n(4),a=n(14),i=n(37),c=n(103);o({target:"Object",stat:!0,forced:r((function(){i(1)})),sham:!c},{getPrototypeOf:function(e){return i(a(e))}})},function(e,t,n){"use strict";n(1)({target:"Object",stat:!0},{is:n(147)})},function(e,t,n){"use strict";var o=n(1),r=n(4),a=n(6),i=Object.isExtensible;o({target:"Object",stat:!0,forced:r((function(){i(1)}))},{isExtensible:function(e){return!!a(e)&&(!i||i(e))}})},function(e,t,n){"use strict";var o=n(1),r=n(4),a=n(6),i=Object.isFrozen;o({target:"Object",stat:!0,forced:r((function(){i(1)}))},{isFrozen:function(e){return!a(e)||!!i&&i(e)}})},function(e,t,n){"use strict";var o=n(1),r=n(4),a=n(6),i=Object.isSealed;o({target:"Object",stat:!0,forced:r((function(){i(1)}))},{isSealed:function(e){return!a(e)||!!i&&i(e)}})},function(e,t,n){"use strict";var o=n(1),r=n(14),a=n(63);o({target:"Object",stat:!0,forced:n(4)((function(){a(1)}))},{keys:function(e){return a(r(e))}})},function(e,t,n){"use strict";var o=n(1),r=n(7),a=n(83),i=n(14),c=n(35),l=n(37),u=n(20).f;r&&o({target:"Object",proto:!0,forced:a},{__lookupGetter__:function(e){var t,n=i(this),o=c(e,!0);do{if(t=u(n,o))return t.get}while(n=l(n))}})},function(e,t,n){"use strict";var o=n(1),r=n(7),a=n(83),i=n(14),c=n(35),l=n(37),u=n(20).f;r&&o({target:"Object",proto:!0,forced:a},{__lookupSetter__:function(e){var t,n=i(this),o=c(e,!0);do{if(t=u(n,o))return t.set}while(n=l(n))}})},function(e,t,n){"use strict";var o=n(1),r=n(6),a=n(52).onFreeze,i=n(68),c=n(4),l=Object.preventExtensions;o({target:"Object",stat:!0,forced:c((function(){l(1)})),sham:!i},{preventExtensions:function(e){return l&&r(e)?l(a(e)):e}})},function(e,t,n){"use strict";var o=n(1),r=n(6),a=n(52).onFreeze,i=n(68),c=n(4),l=Object.seal;o({target:"Object",stat:!0,forced:c((function(){l(1)})),sham:!i},{seal:function(e){return l&&r(e)?l(a(e)):e}})},function(e,t,n){"use strict";n(1)({target:"Object",stat:!0},{setPrototypeOf:n(51)})},function(e,t,n){"use strict";var o=n(101),r=n(22),a=n(296);o||r(Object.prototype,"toString",a,{unsafe:!0})},function(e,t,n){"use strict";var o=n(101),r=n(75);e.exports=o?{}.toString:function(){return"[object "+r(this)+"]"}},function(e,t,n){"use strict";var o=n(1),r=n(146).values;o({target:"Object",stat:!0},{values:function(e){return r(e)}})},function(e,t,n){"use strict";var o=n(1),r=n(145);o({global:!0,forced:parseInt!=r},{parseInt:r})},function(e,t,n){"use strict";var o,r,a,i,c=n(1),l=n(39),u=n(5),d=n(38),s=n(148),p=n(22),m=n(67),f=n(44),h=n(55),C=n(6),g=n(32),b=n(56),N=n(34),v=n(91),V=n(69),y=n(76),_=n(46),x=n(108).set,k=n(150),L=n(151),w=n(300),B=n(152),S=n(301),I=n(36),T=n(62),A=n(12),E=n(97),P=A("species"),M="Promise",O=I.get,R=I.set,F=I.getterFor(M),D=s,j=u.TypeError,z=u.document,H=u.process,G=d("fetch"),U=B.f,K=U,Y="process"==N(H),q=!!(z&&z.createEvent&&u.dispatchEvent),W=T(M,(function(){if(!(v(D)!==String(D))){if(66===E)return!0;if(!Y&&"function"!=typeof PromiseRejectionEvent)return!0}if(l&&!D.prototype["finally"])return!0;if(E>=51&&/native code/.test(D))return!1;var e=D.resolve(1),t=function(e){e((function(){}),(function(){}))};return(e.constructor={})[P]=t,!(e.then((function(){}))instanceof t)})),$=W||!y((function(e){D.all(e)["catch"]((function(){}))})),Q=function(e){var t;return!(!C(e)||"function"!=typeof(t=e.then))&&t},X=function(e,t,n){if(!t.notified){t.notified=!0;var o=t.reactions;k((function(){for(var r=t.value,a=1==t.state,i=0;o.length>i;){var c,l,u,d=o[i++],s=a?d.ok:d.fail,p=d.resolve,m=d.reject,f=d.domain;try{s?(a||(2===t.rejection&&te(e,t),t.rejection=1),!0===s?c=r:(f&&f.enter(),c=s(r),f&&(f.exit(),u=!0)),c===d.promise?m(j("Promise-chain cycle")):(l=Q(c))?l.call(c,p,m):p(c)):m(r)}catch(h){f&&!u&&f.exit(),m(h)}}t.reactions=[],t.notified=!1,n&&!t.rejection&&J(e,t)}))}},Z=function(e,t,n){var o,r;q?((o=z.createEvent("Event")).promise=t,o.reason=n,o.initEvent(e,!1,!0),u.dispatchEvent(o)):o={promise:t,reason:n},(r=u["on"+e])?r(o):"unhandledrejection"===e&&w("Unhandled promise rejection",n)},J=function(e,t){x.call(u,(function(){var n,o=t.value;if(ee(t)&&(n=S((function(){Y?H.emit("unhandledRejection",o,e):Z("unhandledrejection",e,o)})),t.rejection=Y||ee(t)?2:1,n.error))throw n.value}))},ee=function(e){return 1!==e.rejection&&!e.parent},te=function(e,t){x.call(u,(function(){Y?H.emit("rejectionHandled",e):Z("rejectionhandled",e,t.value)}))},ne=function(e,t,n,o){return function(r){e(t,n,r,o)}},oe=function(e,t,n,o){t.done||(t.done=!0,o&&(t=o),t.value=n,t.state=2,X(e,t,!0))},re=function ae(e,t,n,o){if(!t.done){t.done=!0,o&&(t=o);try{if(e===n)throw j("Promise can't be resolved itself");var r=Q(n);r?k((function(){var o={done:!1};try{r.call(n,ne(ae,e,o,t),ne(oe,e,o,t))}catch(a){oe(e,o,a,t)}})):(t.value=n,t.state=1,X(e,t,!1))}catch(a){oe(e,{done:!1},a,t)}}};W&&(D=function(e){b(this,D,M),g(e),o.call(this);var t=O(this);try{e(ne(re,this,t),ne(oe,this,t))}catch(n){oe(this,t,n)}},(o=function(e){R(this,{type:M,done:!1,notified:!1,parent:!1,reactions:[],rejection:!1,state:0,value:undefined})}).prototype=m(D.prototype,{then:function(e,t){var n=F(this),o=U(_(this,D));return o.ok="function"!=typeof e||e,o.fail="function"==typeof t&&t,o.domain=Y?H.domain:undefined,n.parent=!0,n.reactions.push(o),0!=n.state&&X(this,n,!1),o.promise},"catch":function(e){return this.then(undefined,e)}}),r=function(){var e=new o,t=O(e);this.promise=e,this.resolve=ne(re,e,t),this.reject=ne(oe,e,t)},B.f=U=function(e){return e===D||e===a?new r(e):K(e)},l||"function"!=typeof s||(i=s.prototype.then,p(s.prototype,"then",(function(e,t){var n=this;return new D((function(e,t){i.call(n,e,t)})).then(e,t)}),{unsafe:!0}),"function"==typeof G&&c({global:!0,enumerable:!0,forced:!0},{fetch:function(e){return L(D,G.apply(u,arguments))}}))),c({global:!0,wrap:!0,forced:W},{Promise:D}),f(D,M,!1,!0),h(M),a=d(M),c({target:M,stat:!0,forced:W},{reject:function(e){var t=U(this);return t.reject.call(undefined,e),t.promise}}),c({target:M,stat:!0,forced:l||W},{resolve:function(e){return L(l&&this===a?D:this,e)}}),c({target:M,stat:!0,forced:$},{all:function(e){var t=this,n=U(t),o=n.resolve,r=n.reject,a=S((function(){var n=g(t.resolve),a=[],i=0,c=1;V(e,(function(e){var l=i++,u=!1;a.push(undefined),c++,n.call(t,e).then((function(e){u||(u=!0,a[l]=e,--c||o(a))}),r)})),--c||o(a)}));return a.error&&r(a.value),n.promise},race:function(e){var t=this,n=U(t),o=n.reject,r=S((function(){var r=g(t.resolve);V(e,(function(e){r.call(t,e).then(n.resolve,o)}))}));return r.error&&o(r.value),n.promise}})},function(e,t,n){"use strict";var o=n(5);e.exports=function(e,t){var n=o.console;n&&n.error&&(1===arguments.length?n.error(e):n.error(e,t))}},function(e,t,n){"use strict";e.exports=function(e){try{return{error:!1,value:e()}}catch(t){return{error:!0,value:t}}}},function(e,t,n){"use strict";var o=n(1),r=n(39),a=n(148),i=n(4),c=n(38),l=n(46),u=n(151),d=n(22);o({target:"Promise",proto:!0,real:!0,forced:!!a&&i((function(){a.prototype["finally"].call({then:function(){}},(function(){}))}))},{"finally":function(e){var t=l(this,c("Promise")),n="function"==typeof e;return this.then(n?function(n){return u(t,e()).then((function(){return n}))}:e,n?function(n){return u(t,e()).then((function(){throw n}))}:e)}}),r||"function"!=typeof a||a.prototype["finally"]||d(a.prototype,"finally",c("Promise").prototype["finally"])},function(e,t,n){"use strict";var o=n(1),r=n(38),a=n(32),i=n(8),c=n(4),l=r("Reflect","apply"),u=Function.apply;o({target:"Reflect",stat:!0,forced:!c((function(){l((function(){}))}))},{apply:function(e,t,n){return a(e),i(n),l?l(e,t,n):u.call(e,t,n)}})},function(e,t,n){"use strict";var o=n(1),r=n(38),a=n(32),i=n(8),c=n(6),l=n(43),u=n(141),d=n(4),s=r("Reflect","construct"),p=d((function(){function e(){}return!(s((function(){}),[],e)instanceof e)})),m=!d((function(){s((function(){}))})),f=p||m;o({target:"Reflect",stat:!0,forced:f,sham:f},{construct:function(e,t){a(e),i(t);var n=arguments.length<3?e:a(arguments[2]);if(m&&!p)return s(e,t,n);if(e==n){switch(t.length){case 0:return new e;case 1:return new e(t[0]);case 2:return new e(t[0],t[1]);case 3:return new e(t[0],t[1],t[2]);case 4:return new e(t[0],t[1],t[2],t[3])}var o=[null];return o.push.apply(o,t),new(u.apply(e,o))}var r=n.prototype,d=l(c(r)?r:Object.prototype),f=Function.apply.call(e,d,t);return c(f)?f:d}})},function(e,t,n){"use strict";var o=n(1),r=n(7),a=n(8),i=n(35),c=n(13);o({target:"Reflect",stat:!0,forced:n(4)((function(){Reflect.defineProperty(c.f({},1,{value:1}),1,{value:2})})),sham:!r},{defineProperty:function(e,t,n){a(e);var o=i(t,!0);a(n);try{return c.f(e,o,n),!0}catch(r){return!1}}})},function(e,t,n){"use strict";var o=n(1),r=n(8),a=n(20).f;o({target:"Reflect",stat:!0},{deleteProperty:function(e,t){var n=a(r(e),t);return!(n&&!n.configurable)&&delete e[t]}})},function(e,t,n){"use strict";var o=n(1),r=n(6),a=n(8),i=n(15),c=n(20),l=n(37);o({target:"Reflect",stat:!0},{get:function u(e,t){var n,o,d=arguments.length<3?e:arguments[2];return a(e)===d?e[t]:(n=c.f(e,t))?i(n,"value")?n.value:n.get===undefined?undefined:n.get.call(d):r(o=l(e))?u(o,t,d):void 0}})},function(e,t,n){"use strict";var o=n(1),r=n(7),a=n(8),i=n(20);o({target:"Reflect",stat:!0,sham:!r},{getOwnPropertyDescriptor:function(e,t){return i.f(a(e),t)}})},function(e,t,n){"use strict";var o=n(1),r=n(8),a=n(37);o({target:"Reflect",stat:!0,sham:!n(103)},{getPrototypeOf:function(e){return a(r(e))}})},function(e,t,n){"use strict";n(1)({target:"Reflect",stat:!0},{has:function(e,t){return t in e}})},function(e,t,n){"use strict";var o=n(1),r=n(8),a=Object.isExtensible;o({target:"Reflect",stat:!0},{isExtensible:function(e){return r(e),!a||a(e)}})},function(e,t,n){"use strict";n(1)({target:"Reflect",stat:!0},{ownKeys:n(93)})},function(e,t,n){"use strict";var o=n(1),r=n(38),a=n(8);o({target:"Reflect",stat:!0,sham:!n(68)},{preventExtensions:function(e){a(e);try{var t=r("Object","preventExtensions");return t&&t(e),!0}catch(n){return!1}}})},function(e,t,n){"use strict";var o=n(1),r=n(8),a=n(6),i=n(15),c=n(4),l=n(13),u=n(20),d=n(37),s=n(47);o({target:"Reflect",stat:!0,forced:c((function(){var e=l.f({},"a",{configurable:!0});return!1!==Reflect.set(d(e),"a",1,e)}))},{set:function p(e,t,n){var o,c,m=arguments.length<4?e:arguments[3],f=u.f(r(e),t);if(!f){if(a(c=d(e)))return p(c,t,n,m);f=s(0)}if(i(f,"value")){if(!1===f.writable||!a(m))return!1;if(o=u.f(m,t)){if(o.get||o.set||!1===o.writable)return!1;o.value=n,l.f(m,t,o)}else l.f(m,t,s(0,n));return!0}return f.set!==undefined&&(f.set.call(m,n),!0)}})},function(e,t,n){"use strict";var o=n(1),r=n(8),a=n(138),i=n(51);i&&o({target:"Reflect",stat:!0},{setPrototypeOf:function(e,t){r(e),a(t);try{return i(e,t),!0}catch(n){return!1}}})},function(e,t,n){"use strict";var o=n(7),r=n(5),a=n(62),i=n(80),c=n(13).f,l=n(48).f,u=n(109),d=n(84),s=n(110),p=n(22),m=n(4),f=n(36).set,h=n(55),C=n(12)("match"),g=r.RegExp,b=g.prototype,N=/a/g,v=/a/g,V=new g(N)!==N,y=s.UNSUPPORTED_Y;if(o&&a("RegExp",!V||y||m((function(){return v[C]=!1,g(N)!=N||g(v)==v||"/a/i"!=g(N,"i")})))){for(var _=function(e,t){var n,o=this instanceof _,r=u(e),a=t===undefined;if(!o&&r&&e.constructor===_&&a)return e;V?r&&!a&&(e=e.source):e instanceof _&&(a&&(t=d.call(e)),e=e.source),y&&(n=!!t&&t.indexOf("y")>-1)&&(t=t.replace(/y/g,""));var c=i(V?new g(e,t):g(e,t),o?this:b,_);return y&&n&&f(c,{sticky:n}),c},x=function(e){e in _||c(_,e,{configurable:!0,get:function(){return g[e]},set:function(t){g[e]=t}})},k=l(g),L=0;k.length>L;)x(k[L++]);b.constructor=_,_.prototype=b,p(r,"RegExp",_)}h("RegExp")},function(e,t,n){"use strict";var o=n(7),r=n(13),a=n(84),i=n(110).UNSUPPORTED_Y;o&&("g"!=/./g.flags||i)&&r.f(RegExp.prototype,"flags",{configurable:!0,get:a})},function(e,t,n){"use strict";var o=n(22),r=n(8),a=n(4),i=n(84),c=RegExp.prototype,l=c.toString,u=a((function(){return"/a/b"!=l.call({source:"a",flags:"b"})})),d="toString"!=l.name;(u||d)&&o(RegExp.prototype,"toString",(function(){var e=r(this),t=String(e.source),n=e.flags;return"/"+t+"/"+String(n===undefined&&e instanceof RegExp&&!("flags"in c)?i.call(e):n)}),{unsafe:!0})},function(e,t,n){"use strict";var o=n(79),r=n(142);e.exports=o("Set",(function(e){return function(){return e(this,arguments.length?arguments[0]:undefined)}}),r)},function(e,t,n){"use strict";var o=n(1),r=n(111).codeAt;o({target:"String",proto:!0},{codePointAt:function(e){return r(this,e)}})},function(e,t,n){"use strict";var o,r=n(1),a=n(20).f,i=n(10),c=n(112),l=n(21),u=n(113),d=n(39),s="".endsWith,p=Math.min,m=u("endsWith");r({target:"String",proto:!0,forced:!!(d||m||(o=a(String.prototype,"endsWith"),!o||o.writable))&&!m},{endsWith:function(e){var t=String(l(this));c(e);var n=arguments.length>1?arguments[1]:undefined,o=i(t.length),r=n===undefined?o:p(i(n),o),a=String(e);return s?s.call(t,a,r):t.slice(r-a.length,r)===a}})},function(e,t,n){"use strict";var o=n(1),r=n(42),a=String.fromCharCode,i=String.fromCodePoint;o({target:"String",stat:!0,forced:!!i&&1!=i.length},{fromCodePoint:function(e){for(var t,n=[],o=arguments.length,i=0;o>i;){if(t=+arguments[i++],r(t,1114111)!==t)throw RangeError(t+" is not a valid code point");n.push(t<65536?a(t):a(55296+((t-=65536)>>10),t%1024+56320))}return n.join("")}})},function(e,t,n){"use strict";var o=n(1),r=n(112),a=n(21);o({target:"String",proto:!0,forced:!n(113)("includes")},{includes:function(e){return!!~String(a(this)).indexOf(r(e),arguments.length>1?arguments[1]:undefined)}})},function(e,t,n){"use strict";var o=n(111).charAt,r=n(36),a=n(102),i=r.set,c=r.getterFor("String Iterator");a(String,"String",(function(e){i(this,{type:"String Iterator",string:String(e),index:0})}),(function(){var e,t=c(this),n=t.string,r=t.index;return r>=n.length?{value:undefined,done:!0}:(e=o(n,r),t.index+=e.length,{value:e,done:!1})}))},function(e,t,n){"use strict";var o=n(86),r=n(8),a=n(10),i=n(21),c=n(114),l=n(87);o("match",1,(function(e,t,n){return[function(t){var n=i(this),o=t==undefined?undefined:t[e];return o!==undefined?o.call(t,n):new RegExp(t)[e](String(n))},function(e){var o=n(t,e,this);if(o.done)return o.value;var i=r(e),u=String(this);if(!i.global)return l(i,u);var d=i.unicode;i.lastIndex=0;for(var s,p=[],m=0;null!==(s=l(i,u));){var f=String(s[0]);p[m]=f,""===f&&(i.lastIndex=c(u,a(i.lastIndex),d)),m++}return 0===m?null:p}]}))},function(e,t,n){"use strict";var o=n(1),r=n(105).end;o({target:"String",proto:!0,forced:n(154)},{padEnd:function(e){return r(this,e,arguments.length>1?arguments[1]:undefined)}})},function(e,t,n){"use strict";var o=n(1),r=n(105).start;o({target:"String",proto:!0,forced:n(154)},{padStart:function(e){return r(this,e,arguments.length>1?arguments[1]:undefined)}})},function(e,t,n){"use strict";var o=n(1),r=n(26),a=n(10);o({target:"String",stat:!0},{raw:function(e){for(var t=r(e.raw),n=a(t.length),o=arguments.length,i=[],c=0;n>c;)i.push(String(t[c++])),c]*>)/g,h=/\$([$&'`]|\d\d?)/g;o("replace",2,(function(e,t,n,o){var C=o.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE,g=o.REPLACE_KEEPS_$0,b=C?"$":"$0";return[function(n,o){var r=l(this),a=n==undefined?undefined:n[e];return a!==undefined?a.call(n,r,o):t.call(String(r),n,o)},function(e,o){if(!C&&g||"string"==typeof o&&-1===o.indexOf(b)){var a=n(t,e,this,o);if(a.done)return a.value}var l=r(e),m=String(this),f="function"==typeof o;f||(o=String(o));var h=l.global;if(h){var v=l.unicode;l.lastIndex=0}for(var V=[];;){var y=d(l,m);if(null===y)break;if(V.push(y),!h)break;""===String(y[0])&&(l.lastIndex=u(m,i(l.lastIndex),v))}for(var _,x="",k=0,L=0;L=k&&(x+=m.slice(k,B)+E,k=B+w.length)}return x+m.slice(k)}];function N(e,n,o,r,i,c){var l=o+e.length,u=r.length,d=h;return i!==undefined&&(i=a(i),d=f),t.call(c,d,(function(t,a){var c;switch(a.charAt(0)){case"$":return"$";case"&":return e;case"`":return n.slice(0,o);case"'":return n.slice(l);case"<":c=i[a.slice(1,-1)];break;default:var d=+a;if(0===d)return t;if(d>u){var s=m(d/10);return 0===s?t:s<=u?r[s-1]===undefined?a.charAt(1):r[s-1]+a.charAt(1):t}c=r[d-1]}return c===undefined?"":c}))}}))},function(e,t,n){"use strict";var o=n(86),r=n(8),a=n(21),i=n(147),c=n(87);o("search",1,(function(e,t,n){return[function(t){var n=a(this),o=t==undefined?undefined:t[e];return o!==undefined?o.call(t,n):new RegExp(t)[e](String(n))},function(e){var o=n(t,e,this);if(o.done)return o.value;var a=r(e),l=String(this),u=a.lastIndex;i(u,0)||(a.lastIndex=0);var d=c(a,l);return i(a.lastIndex,u)||(a.lastIndex=u),null===d?-1:d.index}]}))},function(e,t,n){"use strict";var o=n(86),r=n(109),a=n(8),i=n(21),c=n(46),l=n(114),u=n(10),d=n(87),s=n(85),p=n(4),m=[].push,f=Math.min,h=!p((function(){return!RegExp(4294967295,"y")}));o("split",2,(function(e,t,n){var o;return o="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(e,n){var o=String(i(this)),a=n===undefined?4294967295:n>>>0;if(0===a)return[];if(e===undefined)return[o];if(!r(e))return t.call(o,e,a);for(var c,l,u,d=[],p=(e.ignoreCase?"i":"")+(e.multiline?"m":"")+(e.unicode?"u":"")+(e.sticky?"y":""),f=0,h=new RegExp(e.source,p+"g");(c=s.call(h,o))&&!((l=h.lastIndex)>f&&(d.push(o.slice(f,c.index)),c.length>1&&c.index=a));)h.lastIndex===c.index&&h.lastIndex++;return f===o.length?!u&&h.test("")||d.push(""):d.push(o.slice(f)),d.length>a?d.slice(0,a):d}:"0".split(undefined,0).length?function(e,n){return e===undefined&&0===n?[]:t.call(this,e,n)}:t,[function(t,n){var r=i(this),a=t==undefined?undefined:t[e];return a!==undefined?a.call(t,r,n):o.call(String(r),t,n)},function(e,r){var i=n(o,e,this,r,o!==t);if(i.done)return i.value;var s=a(e),p=String(this),m=c(s,RegExp),C=s.unicode,g=(s.ignoreCase?"i":"")+(s.multiline?"m":"")+(s.unicode?"u":"")+(h?"y":"g"),b=new m(h?s:"^(?:"+s.source+")",g),N=r===undefined?4294967295:r>>>0;if(0===N)return[];if(0===p.length)return null===d(b,p)?[p]:[];for(var v=0,V=0,y=[];V1?arguments[1]:undefined,t.length)),o=String(e);return s?s.call(t,o,n):t.slice(n,n+o.length)===o}})},function(e,t,n){"use strict";var o=n(1),r=n(57).trim;o({target:"String",proto:!0,forced:n(115)("trim")},{trim:function(){return r(this)}})},function(e,t,n){"use strict";var o=n(1),r=n(57).end,a=n(115)("trimEnd"),i=a?function(){return r(this)}:"".trimEnd;o({target:"String",proto:!0,forced:a},{trimEnd:i,trimRight:i})},function(e,t,n){"use strict";var o=n(1),r=n(57).start,a=n(115)("trimStart"),i=a?function(){return r(this)}:"".trimStart;o({target:"String",proto:!0,forced:a},{trimStart:i,trimLeft:i})},function(e,t,n){"use strict";var o=n(1),r=n(28);o({target:"String",proto:!0,forced:n(29)("anchor")},{anchor:function(e){return r(this,"a","name",e)}})},function(e,t,n){"use strict";var o=n(1),r=n(28);o({target:"String",proto:!0,forced:n(29)("big")},{big:function(){return r(this,"big","","")}})},function(e,t,n){"use strict";var o=n(1),r=n(28);o({target:"String",proto:!0,forced:n(29)("blink")},{blink:function(){return r(this,"blink","","")}})},function(e,t,n){"use strict";var o=n(1),r=n(28);o({target:"String",proto:!0,forced:n(29)("bold")},{bold:function(){return r(this,"b","","")}})},function(e,t,n){"use strict";var o=n(1),r=n(28);o({target:"String",proto:!0,forced:n(29)("fixed")},{fixed:function(){return r(this,"tt","","")}})},function(e,t,n){"use strict";var o=n(1),r=n(28);o({target:"String",proto:!0,forced:n(29)("fontcolor")},{fontcolor:function(e){return r(this,"font","color",e)}})},function(e,t,n){"use strict";var o=n(1),r=n(28);o({target:"String",proto:!0,forced:n(29)("fontsize")},{fontsize:function(e){return r(this,"font","size",e)}})},function(e,t,n){"use strict";var o=n(1),r=n(28);o({target:"String",proto:!0,forced:n(29)("italics")},{italics:function(){return r(this,"i","","")}})},function(e,t,n){"use strict";var o=n(1),r=n(28);o({target:"String",proto:!0,forced:n(29)("link")},{link:function(e){return r(this,"a","href",e)}})},function(e,t,n){"use strict";var o=n(1),r=n(28);o({target:"String",proto:!0,forced:n(29)("small")},{small:function(){return r(this,"small","","")}})},function(e,t,n){"use strict";var o=n(1),r=n(28);o({target:"String",proto:!0,forced:n(29)("strike")},{strike:function(){return r(this,"strike","","")}})},function(e,t,n){"use strict";var o=n(1),r=n(28);o({target:"String",proto:!0,forced:n(29)("sub")},{sub:function(){return r(this,"sub","","")}})},function(e,t,n){"use strict";var o=n(1),r=n(28);o({target:"String",proto:!0,forced:n(29)("sup")},{sup:function(){return r(this,"sup","","")}})},function(e,t,n){"use strict";n(41)("Float32",(function(e){return function(t,n,o){return e(this,t,n,o)}}))},function(e,t,n){"use strict";var o=n(31);e.exports=function(e){var t=o(e);if(t<0)throw RangeError("The argument can't be less than 0");return t}},function(e,t,n){"use strict";n(41)("Float64",(function(e){return function(t,n,o){return e(this,t,n,o)}}))},function(e,t,n){"use strict";n(41)("Int8",(function(e){return function(t,n,o){return e(this,t,n,o)}}))},function(e,t,n){"use strict";n(41)("Int16",(function(e){return function(t,n,o){return e(this,t,n,o)}}))},function(e,t,n){"use strict";n(41)("Int32",(function(e){return function(t,n,o){return e(this,t,n,o)}}))},function(e,t,n){"use strict";n(41)("Uint8",(function(e){return function(t,n,o){return e(this,t,n,o)}}))},function(e,t,n){"use strict";n(41)("Uint8",(function(e){return function(t,n,o){return e(this,t,n,o)}}),!0)},function(e,t,n){"use strict";n(41)("Uint16",(function(e){return function(t,n,o){return e(this,t,n,o)}}))},function(e,t,n){"use strict";n(41)("Uint32",(function(e){return function(t,n,o){return e(this,t,n,o)}}))},function(e,t,n){"use strict";var o=n(9),r=n(133),a=o.aTypedArray;(0,o.exportTypedArrayMethod)("copyWithin",(function(e,t){return r.call(a(this),e,t,arguments.length>2?arguments[2]:undefined)}))},function(e,t,n){"use strict";var o=n(9),r=n(18).every,a=o.aTypedArray;(0,o.exportTypedArrayMethod)("every",(function(e){return r(a(this),e,arguments.length>1?arguments[1]:undefined)}))},function(e,t,n){"use strict";var o=n(9),r=n(98),a=o.aTypedArray;(0,o.exportTypedArrayMethod)("fill",(function(e){return r.apply(a(this),arguments)}))},function(e,t,n){"use strict";var o=n(9),r=n(18).filter,a=n(46),i=o.aTypedArray,c=o.aTypedArrayConstructor;(0,o.exportTypedArrayMethod)("filter",(function(e){for(var t=r(i(this),e,arguments.length>1?arguments[1]:undefined),n=a(this,this.constructor),o=0,l=t.length,u=new(c(n))(l);l>o;)u[o]=t[o++];return u}))},function(e,t,n){"use strict";var o=n(9),r=n(18).find,a=o.aTypedArray;(0,o.exportTypedArrayMethod)("find",(function(e){return r(a(this),e,arguments.length>1?arguments[1]:undefined)}))},function(e,t,n){"use strict";var o=n(9),r=n(18).findIndex,a=o.aTypedArray;(0,o.exportTypedArrayMethod)("findIndex",(function(e){return r(a(this),e,arguments.length>1?arguments[1]:undefined)}))},function(e,t,n){"use strict";var o=n(9),r=n(18).forEach,a=o.aTypedArray;(0,o.exportTypedArrayMethod)("forEach",(function(e){r(a(this),e,arguments.length>1?arguments[1]:undefined)}))},function(e,t,n){"use strict";var o=n(116);(0,n(9).exportTypedArrayStaticMethod)("from",n(156),o)},function(e,t,n){"use strict";var o=n(9),r=n(61).includes,a=o.aTypedArray;(0,o.exportTypedArrayMethod)("includes",(function(e){return r(a(this),e,arguments.length>1?arguments[1]:undefined)}))},function(e,t,n){"use strict";var o=n(9),r=n(61).indexOf,a=o.aTypedArray;(0,o.exportTypedArrayMethod)("indexOf",(function(e){return r(a(this),e,arguments.length>1?arguments[1]:undefined)}))},function(e,t,n){"use strict";var o=n(5),r=n(9),a=n(136),i=n(12)("iterator"),c=o.Uint8Array,l=a.values,u=a.keys,d=a.entries,s=r.aTypedArray,p=r.exportTypedArrayMethod,m=c&&c.prototype[i],f=!!m&&("values"==m.name||m.name==undefined),h=function(){return l.call(s(this))};p("entries",(function(){return d.call(s(this))})),p("keys",(function(){return u.call(s(this))})),p("values",h,!f),p(i,h,!f)},function(e,t,n){"use strict";var o=n(9),r=o.aTypedArray,a=o.exportTypedArrayMethod,i=[].join;a("join",(function(e){return i.apply(r(this),arguments)}))},function(e,t,n){"use strict";var o=n(9),r=n(139),a=o.aTypedArray;(0,o.exportTypedArrayMethod)("lastIndexOf",(function(e){return r.apply(a(this),arguments)}))},function(e,t,n){"use strict";var o=n(9),r=n(18).map,a=n(46),i=o.aTypedArray,c=o.aTypedArrayConstructor;(0,o.exportTypedArrayMethod)("map",(function(e){return r(i(this),e,arguments.length>1?arguments[1]:undefined,(function(e,t){return new(c(a(e,e.constructor)))(t)}))}))},function(e,t,n){"use strict";var o=n(9),r=n(116),a=o.aTypedArrayConstructor;(0,o.exportTypedArrayStaticMethod)("of",(function(){for(var e=0,t=arguments.length,n=new(a(this))(t);t>e;)n[e]=arguments[e++];return n}),r)},function(e,t,n){"use strict";var o=n(9),r=n(77).left,a=o.aTypedArray;(0,o.exportTypedArrayMethod)("reduce",(function(e){return r(a(this),e,arguments.length,arguments.length>1?arguments[1]:undefined)}))},function(e,t,n){"use strict";var o=n(9),r=n(77).right,a=o.aTypedArray;(0,o.exportTypedArrayMethod)("reduceRight",(function(e){return r(a(this),e,arguments.length,arguments.length>1?arguments[1]:undefined)}))},function(e,t,n){"use strict";var o=n(9),r=o.aTypedArray,a=o.exportTypedArrayMethod,i=Math.floor;a("reverse",(function(){for(var e,t=r(this).length,n=i(t/2),o=0;o1?arguments[1]:undefined,1),n=this.length,o=i(e),c=r(o.length),u=0;if(c+t>n)throw RangeError("Wrong length");for(;ua;)d[a]=n[a++];return d}),a((function(){new Int8Array(1).slice()})))},function(e,t,n){"use strict";var o=n(9),r=n(18).some,a=o.aTypedArray;(0,o.exportTypedArrayMethod)("some",(function(e){return r(a(this),e,arguments.length>1?arguments[1]:undefined)}))},function(e,t,n){"use strict";var o=n(9),r=o.aTypedArray,a=o.exportTypedArrayMethod,i=[].sort;a("sort",(function(e){return i.call(r(this),e)}))},function(e,t,n){"use strict";var o=n(9),r=n(10),a=n(42),i=n(46),c=o.aTypedArray;(0,o.exportTypedArrayMethod)("subarray",(function(e,t){var n=c(this),o=n.length,l=a(e,o);return new(i(n,n.constructor))(n.buffer,n.byteOffset+l*n.BYTES_PER_ELEMENT,r((t===undefined?o:a(t,o))-l))}))},function(e,t,n){"use strict";var o=n(5),r=n(9),a=n(4),i=o.Int8Array,c=r.aTypedArray,l=r.exportTypedArrayMethod,u=[].toLocaleString,d=[].slice,s=!!i&&a((function(){u.call(new i(1))}));l("toLocaleString",(function(){return u.apply(s?d.call(c(this)):c(this),arguments)}),a((function(){return[1,2].toLocaleString()!=new i([1,2]).toLocaleString()}))||!a((function(){i.prototype.toLocaleString.call([1,2])})))},function(e,t,n){"use strict";var o=n(9).exportTypedArrayMethod,r=n(4),a=n(5).Uint8Array,i=a&&a.prototype||{},c=[].toString,l=[].join;r((function(){c.call({})}))&&(c=function(){return l.call(this)});var u=i.toString!=c;o("toString",c,u)},function(e,t,n){"use strict";var o,r=n(5),a=n(67),i=n(52),c=n(79),l=n(157),u=n(6),d=n(36).enforce,s=n(124),p=!r.ActiveXObject&&"ActiveXObject"in r,m=Object.isExtensible,f=function(e){return function(){return e(this,arguments.length?arguments[0]:undefined)}},h=e.exports=c("WeakMap",f,l);if(s&&p){o=l.getConstructor(f,"WeakMap",!0),i.REQUIRED=!0;var C=h.prototype,g=C["delete"],b=C.has,N=C.get,v=C.set;a(C,{"delete":function(e){if(u(e)&&!m(e)){var t=d(this);return t.frozen||(t.frozen=new o),g.call(this,e)||t.frozen["delete"](e)}return g.call(this,e)},has:function(e){if(u(e)&&!m(e)){var t=d(this);return t.frozen||(t.frozen=new o),b.call(this,e)||t.frozen.has(e)}return b.call(this,e)},get:function(e){if(u(e)&&!m(e)){var t=d(this);return t.frozen||(t.frozen=new o),b.call(this,e)?N.call(this,e):t.frozen.get(e)}return N.call(this,e)},set:function(e,t){if(u(e)&&!m(e)){var n=d(this);n.frozen||(n.frozen=new o),b.call(this,e)?v.call(this,e,t):n.frozen.set(e,t)}else v.call(this,e,t);return this}})}},function(e,t,n){"use strict";n(79)("WeakSet",(function(e){return function(){return e(this,arguments.length?arguments[0]:undefined)}}),n(157))},function(e,t,n){"use strict";var o=n(1),r=n(5),a=n(108);o({global:!0,bind:!0,enumerable:!0,forced:!r.setImmediate||!r.clearImmediate},{setImmediate:a.set,clearImmediate:a.clear})},function(e,t,n){"use strict";var o=n(1),r=n(5),a=n(150),i=n(34),c=r.process,l="process"==i(c);o({global:!0,enumerable:!0,noTargetGet:!0},{queueMicrotask:function(e){var t=l&&c.domain;a(t?t.bind(e):e)}})},function(e,t,n){"use strict";var o=n(1),r=n(5),a=n(74),i=[].slice,c=function(e){return function(t,n){var o=arguments.length>2,r=o?i.call(arguments,2):undefined;return e(o?function(){("function"==typeof t?t:Function(t)).apply(this,r)}:t,n)}};o({global:!0,bind:!0,forced:/MSIE .\./.test(a)},{setTimeout:c(r.setTimeout),setInterval:c(r.setInterval)})},function(e,t,n){"use strict";t.__esModule=!0,t._CI=Be,t._HI=R,t._M=Se,t._MCCC=Ee,t._ME=Te,t._MFCC=Pe,t._MP=Le,t._MR=be,t.__render=De,t.createComponentVNode=function(e,t,n,o,r){var i=new S(1,null,null,e=function(e,t){if(12&e)return e;if(t.prototype&&t.prototype.render)return 4;if(t.render)return 32776;return 8}(e,t),o,function(e,t,n){var o=(32768&e?t.render:t).defaultProps;if(a(o))return n;if(a(n))return d(o,null);return w(n,o)}(e,t,n),function(e,t,n){if(4&e)return n;var o=(32768&e?t.render:t).defaultHooks;if(a(o))return n;if(a(n))return o;return w(n,o)}(e,t,r),t);x.createVNode&&x.createVNode(i);return i},t.createFragment=A,t.createPortal=function(e,t){var n=R(e);return I(1024,1024,null,n,0,null,n.key,t)},t.createRef=function(){return{current:null}},t.createRenderer=function(e){return function(t,n,o,r){e||(e=t),je(n,e,o,r)}},t.createTextVNode=T,t.createVNode=I,t.directClone=E,t.findDOMfromVNode=N,t.forwardRef=function(e){return{render:e}},t.getFlagsForElementVnode=function(e){switch(e){case"svg":return 32;case"input":return 64;case"select":return 256;case"textarea":return 128;case"$F":return 8192;default:return 1}},t.linkEvent=function(e,t){if(c(t))return{data:e,event:t};return null},t.normalizeProps=function(e){var t=e.props;if(t){var n=e.flags;481&n&&(void 0!==t.children&&a(e.children)&&O(e,t.children),void 0!==t.className&&(e.className=t.className||null,t.className=undefined)),void 0!==t.key&&(e.key=t.key,t.key=undefined),void 0!==t.ref&&(e.ref=8&n?d(e.ref,t.ref):t.ref,t.ref=undefined)}return e},t.render=je,t.rerender=Ye,t.version=t.options=t.Fragment=t.EMPTY_OBJ=t.Component=void 0;var o=Array.isArray;function r(e){var t=typeof e;return"string"===t||"number"===t}function a(e){return null==e}function i(e){return null===e||!1===e||!0===e||void 0===e}function c(e){return"function"==typeof e}function l(e){return"string"==typeof e}function u(e){return null===e}function d(e,t){var n={};if(e)for(var o in e)n[o]=e[o];if(t)for(var r in t)n[r]=t[r];return n}function s(e){return!u(e)&&"object"==typeof e}var p={};t.EMPTY_OBJ=p;function m(e){return e.substr(2).toLowerCase()}function f(e,t){e.appendChild(t)}function h(e,t,n){u(n)?f(e,t):e.insertBefore(t,n)}function C(e,t){e.removeChild(t)}function g(e){for(var t=0;t0,f=u(p),h=l(p)&&"$"===p[0];m||f||h?(n=n||t.slice(0,d),(m||h)&&(s=E(s)),(f||h)&&(s.key="$"+d),n.push(s)):n&&n.push(s),s.flags|=65536}}a=0===(n=n||t).length?1:8}else(n=t).flags|=65536,81920&t.flags&&(n=E(t)),a=2;return e.children=n,e.childFlags=a,e}function R(e){return i(e)||r(e)?T(e,null):o(e)?A(e,0,null):16384&e.flags?E(e):e}var F="http://www.w3.org/1999/xlink",D="http://www.w3.org/XML/1998/namespace",j={"xlink:actuate":F,"xlink:arcrole":F,"xlink:href":F,"xlink:role":F,"xlink:show":F,"xlink:title":F,"xlink:type":F,"xml:base":D,"xml:lang":D,"xml:space":D};function z(e){return{onClick:e,onDblClick:e,onFocusIn:e,onFocusOut:e,onKeyDown:e,onKeyPress:e,onKeyUp:e,onMouseDown:e,onMouseMove:e,onMouseUp:e,onTouchEnd:e,onTouchMove:e,onTouchStart:e}}var H=z(0),G=z(null),U=z(!0);function K(e,t){var n=t.$EV;return n||(n=t.$EV=z(null)),n[e]||1==++H[e]&&(G[e]=function(e){var t="onClick"===e||"onDblClick"===e?function(e){return function(t){0===t.button?q(t,!0,e,X(t)):t.stopPropagation()}}(e):function(e){return function(t){q(t,!1,e,X(t))}}(e);return document.addEventListener(m(e),t),t}(e)),n}function Y(e,t){var n=t.$EV;n&&n[e]&&(0==--H[e]&&(document.removeEventListener(m(e),G[e]),G[e]=null),n[e]=null)}function q(e,t,n,o){var r=function(e){return c(e.composedPath)?e.composedPath()[0]:e.target}(e);do{if(t&&r.disabled)return;var a=r.$EV;if(a){var i=a[n];if(i&&(o.dom=r,i.event?i.event(i.data,e):i(e),e.cancelBubble))return}r=r.parentNode}while(!u(r))}function W(){this.cancelBubble=!0,this.immediatePropagationStopped||this.stopImmediatePropagation()}function $(){return this.defaultPrevented}function Q(){return this.cancelBubble}function X(e){var t={dom:document};return e.isDefaultPrevented=$,e.isPropagationStopped=Q,e.stopPropagation=W,Object.defineProperty(e,"currentTarget",{configurable:!0,get:function(){return t.dom}}),t}function Z(e,t,n){if(e[t]){var o=e[t];o.event?o.event(o.data,n):o(n)}else{var r=t.toLowerCase();e[r]&&e[r](n)}}function J(e,t){var n=function(n){var o=this.$V;if(o){var r=o.props||p,a=o.dom;if(l(e))Z(r,e,n);else for(var i=0;i-1&&t.options[i]&&(c=t.options[i].value),n&&a(c)&&(c=e.defaultValue),ie(o,c)}}var ue,de,se=J("onInput",me),pe=J("onChange");function me(e,t,n){var o=e.value,r=t.value;if(a(o)){if(n){var i=e.defaultValue;a(i)||i===r||(t.defaultValue=i,t.value=i)}}else r!==o&&(t.defaultValue=o,t.value=o)}function fe(e,t,n,o,r,a){64&e?ae(o,n):256&e?le(o,n,r,t):128&e&&me(o,n,r),a&&(n.$V=t)}function he(e,t,n){64&e?function(e,t){te(t.type)?(ee(e,"change",oe),ee(e,"click",re)):ee(e,"input",ne)}(t,n):256&e?function(e){ee(e,"change",ce)}(t):128&e&&function(e,t){ee(e,"input",se),t.onChange&&ee(e,"change",pe)}(t,n)}function Ce(e){return e.type&&te(e.type)?!a(e.checked):!a(e.value)}function ge(e){e&&!B(e,null)&&e.current&&(e.current=null)}function be(e,t,n){e&&(c(e)||void 0!==e.current)&&n.push((function(){B(e,t)||void 0===e.current||(e.current=t)}))}function Ne(e,t){ve(e),v(e,t)}function ve(e){var t,n=e.flags,o=e.children;if(481&n){t=e.ref;var r=e.props;ge(t);var i=e.childFlags;if(!u(r))for(var l=Object.keys(r),d=0,s=l.length;d0;for(var c in i&&(a=Ce(n))&&he(t,o,n),n)ke(c,null,n[c],o,r,a,null);i&&fe(t,e,o,n,!0,a)}function we(e,t,n){var o=R(e.render(t,e.state,n)),r=n;return c(e.getChildContext)&&(r=d(n,e.getChildContext())),e.$CX=r,o}function Be(e,t,n,o,r,a){var i=new t(n,o),l=i.$N=Boolean(t.getDerivedStateFromProps||i.getSnapshotBeforeUpdate);if(i.$SVG=r,i.$L=a,e.children=i,i.$BS=!1,i.context=o,i.props===p&&(i.props=n),l)i.state=y(i,n,i.state);else if(c(i.componentWillMount)){i.$BR=!0,i.componentWillMount();var d=i.$PS;if(!u(d)){var s=i.state;if(u(s))i.state=d;else for(var m in d)s[m]=d[m];i.$PS=null}i.$BR=!1}return i.$LI=we(i,n,o),i}function Se(e,t,n,o,r,a){var i=e.flags|=16384;481&i?Te(e,t,n,o,r,a):4&i?function(e,t,n,o,r,a){var i=Be(e,e.type,e.props||p,n,o,a);Se(i.$LI,t,i.$CX,o,r,a),Ee(e.ref,i,a)}(e,t,n,o,r,a):8&i?(!function(e,t,n,o,r,a){Se(e.children=R(function(e,t){return 32768&e.flags?e.type.render(e.props||p,e.ref,t):e.type(e.props||p,t)}(e,n)),t,n,o,r,a)}(e,t,n,o,r,a),Pe(e,a)):512&i||16&i?Ie(e,t,r):8192&i?function(e,t,n,o,r,a){var i=e.children,c=e.childFlags;12&c&&0===i.length&&(c=e.childFlags=2,i=e.children=P());2===c?Se(i,n,r,o,r,a):Ae(i,n,t,o,r,a)}(e,n,t,o,r,a):1024&i&&function(e,t,n,o,r){Se(e.children,e.ref,t,!1,null,r);var a=P();Ie(a,n,o),e.dom=a.dom}(e,n,t,r,a)}function Ie(e,t,n){var o=e.dom=document.createTextNode(e.children);u(t)||h(t,o,n)}function Te(e,t,n,o,r,i){var c=e.flags,l=e.props,d=e.className,s=e.children,p=e.childFlags,m=e.dom=function(e,t){return t?document.createElementNS("http://www.w3.org/2000/svg",e):document.createElement(e)}(e.type,o=o||(32&c)>0);if(a(d)||""===d||(o?m.setAttribute("class",d):m.className=d),16===p)k(m,s);else if(1!==p){var f=o&&"foreignObject"!==e.type;2===p?(16384&s.flags&&(e.children=s=E(s)),Se(s,m,n,f,null,i)):8!==p&&4!==p||Ae(s,m,n,f,null,i)}u(t)||h(t,m,r),u(l)||Le(e,c,l,m,o),be(e.ref,m,i)}function Ae(e,t,n,o,r,a){for(var i=0;i0,u!==d){var f=u||p;if((c=d||p)!==p)for(var h in(s=(448&r)>0)&&(m=Ce(c)),c){var C=f[h],g=c[h];C!==g&&ke(h,C,g,l,o,m,e)}if(f!==p)for(var b in f)a(c[b])&&!a(f[b])&&ke(b,f[b],null,l,o,m,e)}var N=t.children,v=t.className;e.className!==v&&(a(v)?l.removeAttribute("class"):o?l.setAttribute("class",v):l.className=v);4096&r?function(e,t){e.textContent!==t&&(e.textContent=t)}(l,N):Oe(e.childFlags,t.childFlags,e.children,N,l,n,o&&"foreignObject"!==t.type,null,e,i);s&&fe(r,t,l,c,!1,m);var V=t.ref,y=e.ref;y!==V&&(ge(y),be(V,l,i))}(e,t,o,r,m,s):4&m?function(e,t,n,o,r,a,i){var l=t.children=e.children;if(u(l))return;l.$L=i;var s=t.props||p,m=t.ref,f=e.ref,h=l.state;if(!l.$N){if(c(l.componentWillReceiveProps)){if(l.$BR=!0,l.componentWillReceiveProps(s,o),l.$UN)return;l.$BR=!1}u(l.$PS)||(h=d(h,l.$PS),l.$PS=null)}Re(l,h,s,n,o,r,!1,a,i),f!==m&&(ge(f),be(m,l,i))}(e,t,n,o,r,l,s):8&m?function(e,t,n,o,r,i,l){var u=!0,d=t.props||p,s=t.ref,m=e.props,f=!a(s),h=e.children;f&&c(s.onComponentShouldUpdate)&&(u=s.onComponentShouldUpdate(m,d));if(!1!==u){f&&c(s.onComponentWillUpdate)&&s.onComponentWillUpdate(m,d);var C=t.type,g=R(32768&t.flags?C.render(d,s,o):C(d,o));Me(h,g,n,o,r,i,l),t.children=g,f&&c(s.onComponentDidUpdate)&&s.onComponentDidUpdate(m,d)}else t.children=h}(e,t,n,o,r,l,s):16&m?function(e,t){var n=t.children,o=t.dom=e.dom;n!==e.children&&(o.nodeValue=n)}(e,t):512&m?t.dom=e.dom:8192&m?function(e,t,n,o,r,a){var i=e.children,c=t.children,l=e.childFlags,u=t.childFlags,d=null;12&u&&0===c.length&&(u=t.childFlags=2,c=t.children=P());var s=0!=(2&u);if(12&l){var p=i.length;(8&l&&8&u||s||!s&&c.length>p)&&(d=N(i[p-1],!1).nextSibling)}Oe(l,u,i,c,n,o,r,d,e,a)}(e,t,n,o,r,s):function(e,t,n,o){var r=e.ref,a=t.ref,c=t.children;if(Oe(e.childFlags,t.childFlags,e.children,c,r,n,!1,null,e,o),t.dom=e.dom,r!==a&&!i(c)){var l=c.dom;C(r,l),f(a,l)}}(e,t,o,s)}function Oe(e,t,n,o,r,a,i,c,l,u){switch(e){case 2:switch(t){case 2:Me(n,o,r,a,i,c,u);break;case 1:Ne(n,r);break;case 16:ve(n),k(r,o);break;default:!function(e,t,n,o,r,a){ve(e),Ae(t,n,o,r,N(e,!0),a),v(e,n)}(n,o,r,a,i,u)}break;case 1:switch(t){case 2:Se(o,r,a,i,c,u);break;case 1:break;case 16:k(r,o);break;default:Ae(o,r,a,i,c,u)}break;case 16:switch(t){case 16:!function(e,t,n){e!==t&&(""!==e?n.firstChild.nodeValue=t:k(n,t))}(n,o,r);break;case 2:ye(r),Se(o,r,a,i,c,u);break;case 1:ye(r);break;default:ye(r),Ae(o,r,a,i,c,u)}break;default:switch(t){case 16:Ve(n),k(r,o);break;case 2:_e(r,l,n),Se(o,r,a,i,c,u);break;case 1:_e(r,l,n);break;default:var d=0|n.length,s=0|o.length;0===d?s>0&&Ae(o,r,a,i,c,u):0===s?_e(r,l,n):8===t&&8===e?function(e,t,n,o,r,a,i,c,l,u){var d,s,p=a-1,m=i-1,f=0,h=e[f],C=t[f];e:{for(;h.key===C.key;){if(16384&C.flags&&(t[f]=C=E(C)),Me(h,C,n,o,r,c,u),e[f]=C,++f>p||f>m)break e;h=e[f],C=t[f]}for(h=e[p],C=t[m];h.key===C.key;){if(16384&C.flags&&(t[m]=C=E(C)),Me(h,C,n,o,r,c,u),e[p]=C,p--,m--,f>p||f>m)break e;h=e[p],C=t[m]}}if(f>p){if(f<=m)for(s=(d=m+1)m)for(;f<=p;)Ne(e[f++],n);else!function(e,t,n,o,r,a,i,c,l,u,d,s,p){var m,f,h,C=0,g=c,b=c,v=a-c+1,y=i-c+1,_=new Int32Array(y+1),x=v===o,k=!1,L=0,w=0;if(r<4||(v|y)<32)for(C=g;C<=a;++C)if(m=e[C],wc?k=!0:L=c,16384&f.flags&&(t[c]=f=E(f)),Me(m,f,l,n,u,d,p),++w;break}!x&&c>i&&Ne(m,l)}else x||Ne(m,l);else{var B={};for(C=b;C<=i;++C)B[t[C].key]=C;for(C=g;C<=a;++C)if(m=e[C],wg;)Ne(e[g++],l);_[c-b]=C+1,L>c?k=!0:L=c,16384&(f=t[c]).flags&&(t[c]=f=E(f)),Me(m,f,l,n,u,d,p),++w}else x||Ne(m,l);else x||Ne(m,l)}if(x)_e(l,s,e),Ae(t,l,n,u,d,p);else if(k){var S=function(e){var t=0,n=0,o=0,r=0,a=0,i=0,c=0,l=e.length;l>Fe&&(Fe=l,ue=new Int32Array(l),de=new Int32Array(l));for(;n>1]]0&&(de[n]=ue[a-1]),ue[a]=n)}a=r+1;var u=new Int32Array(a);i=ue[a-1];for(;a-- >0;)u[a]=i,i=de[i],ue[a]=0;return u}(_);for(c=S.length-1,C=y-1;C>=0;C--)0===_[C]?(16384&(f=t[L=C+b]).flags&&(t[L]=f=E(f)),Se(f,l,n,u,(h=L+1)=0;C--)0===_[C]&&(16384&(f=t[L=C+b]).flags&&(t[L]=f=E(f)),Se(f,l,n,u,(h=L+1)i?i:a,p=0;pi)for(p=s;p=0;--r){var a=this.tryEntries[r],i=a.completion;if("root"===a.tryLoc)return o("end");if(a.tryLoc<=this.prev){var c=n.call(a,"catchLoc"),l=n.call(a,"finallyLoc");if(c&&l){if(this.prev=0;--o){var r=this.tryEntries[o];if(r.tryLoc<=this.prev&&n.call(r,"finallyLoc")&&this.prev=0;--t){var n=this.tryEntries[t];if(n.finallyLoc===e)return this.complete(n.completion,n.afterLoc),V(n),u}},"catch":function(e){for(var t=this.tryEntries.length-1;t>=0;--t){var n=this.tryEntries[t];if(n.tryLoc===e){var o=n.completion;if("throw"===o.type){var r=o.arg;V(n)}return r}}throw new Error("illegal catch attempt")},delegateYield:function(e,t,n){return this.delegate={iterator:_(e),resultName:t,nextLoc:n},"next"===this.method&&(this.arg=void 0),u}},e}(e.exports);try{regeneratorRuntime=o}catch(r){Function("r","regeneratorRuntime = r")(o)}},function(e,t,n){"use strict";window.Int32Array||(window.Int32Array=Array)},function(e,t,n){"use strict";(function(e){ -/*! loadCSS. [c]2017 Filament Group, Inc. MIT License */ -var n;n=void 0!==e?e:void 0,t.loadCSS=function(e,t,o,r){var a,i=n.document,c=i.createElement("link");if(t)a=t;else{var l=(i.body||i.getElementsByTagName("head")[0]).childNodes;a=l[l.length-1]}var u=i.styleSheets;if(r)for(var d in r)r.hasOwnProperty(d)&&c.setAttribute(d,r[d]);c.rel="stylesheet",c.href=e,c.media="only x",function m(e){if(i.body)return e();setTimeout((function(){m(e)}))}((function(){a.parentNode.insertBefore(c,t?a:a.nextSibling)}));var s=function f(e){for(var t=c.href,n=u.length;n--;)if(u[n].href===t)return e();setTimeout((function(){f(e)}))};function p(){c.addEventListener&&c.removeEventListener("load",p),c.media=o||"all"}return c.addEventListener&&c.addEventListener("load",p),c.onloadcssdefined=s,s(p),c}}).call(this,n(121))},function(e,t,n){"use strict";t.__esModule=!0,t.Achievements=t.Score=t.Achievement=void 0;var o=n(0),r=n(3),a=n(2),i=function(e){var t=e.name,n=e.desc,r=e.icon_class,i=e.value;return(0,o.createVNode)(1,"tr",null,[(0,o.createVNode)(1,"td",null,(0,o.createComponentVNode)(2,a.Box,{className:r}),2,{style:{padding:"6px"}}),(0,o.createVNode)(1,"td",null,[(0,o.createVNode)(1,"h1",null,t,0),n,(0,o.createComponentVNode)(2,a.Box,{color:i?"good":"bad",content:i?"Unlocked":"Locked"})],0,{style:{"vertical-align":"top"}})],4,null,t)};t.Achievement=i;var c=function(e){var t=e.name,n=e.desc,r=e.icon_class,i=e.value;return(0,o.createVNode)(1,"tr",null,[(0,o.createVNode)(1,"td",null,(0,o.createComponentVNode)(2,a.Box,{className:r}),2,{style:{padding:"6px"}}),(0,o.createVNode)(1,"td",null,[(0,o.createVNode)(1,"h1",null,t,0),n,(0,o.createComponentVNode)(2,a.Box,{color:i>0?"good":"bad",content:i>0?"Earned "+i+" times":"Locked"})],0,{style:{"vertical-align":"top"}})],4,null,t)};t.Score=c;t.Achievements=function(e){var t=(0,r.useBackend)(e).data;return(0,o.createComponentVNode)(2,a.Tabs,{children:[t.categories.map((function(e){return(0,o.createComponentVNode)(2,a.Tabs.Tab,{label:e,children:(0,o.createComponentVNode)(2,a.Box,{as:"Table",children:t.achievements.filter((function(t){return t.category===e})).map((function(e){return e.score?(0,o.createComponentVNode)(2,c,{name:e.name,desc:e.desc,icon_class:e.icon_class,value:e.value},e.name):(0,o.createComponentVNode)(2,i,{name:e.name,desc:e.desc,icon_class:e.icon_class,value:e.value},e.name)}))})},e)})),(0,o.createComponentVNode)(2,a.Tabs.Tab,{label:"High Scores",children:(0,o.createComponentVNode)(2,a.Tabs,{vertical:!0,children:t.highscore.map((function(e){return(0,o.createComponentVNode)(2,a.Tabs.Tab,{label:e.name,children:(0,o.createComponentVNode)(2,a.Table,{children:[(0,o.createComponentVNode)(2,a.Table.Row,{className:"candystripe",children:[(0,o.createComponentVNode)(2,a.Table.Cell,{color:"label",textAlign:"center",children:"#"}),(0,o.createComponentVNode)(2,a.Table.Cell,{color:"label",textAlign:"center",children:"Key"}),(0,o.createComponentVNode)(2,a.Table.Cell,{color:"label",textAlign:"center",children:"Score"})]}),Object.keys(e.scores).map((function(n,r){return(0,o.createComponentVNode)(2,a.Table.Row,{className:"candystripe",m:2,children:[(0,o.createComponentVNode)(2,a.Table.Cell,{color:"label",textAlign:"center",children:r+1}),(0,o.createComponentVNode)(2,a.Table.Cell,{color:n===t.user_ckey&&"green",textAlign:"center",children:[0===r&&(0,o.createComponentVNode)(2,a.Icon,{name:"crown",color:"gold",mr:2}),n,0===r&&(0,o.createComponentVNode)(2,a.Icon,{name:"crown",color:"gold",ml:2})]}),(0,o.createComponentVNode)(2,a.Table.Cell,{textAlign:"center",children:e.scores[n]})]},n)}))]})},e.name)}))})})]})}},function(e,t,n){"use strict";t.__esModule=!0,t.BlockQuote=void 0;var o=n(0),r=n(11),a=n(19);t.BlockQuote=function(e){var t=e.className,n=function(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}(e,["className"]);return(0,o.normalizeProps)((0,o.createComponentVNode)(2,a.Box,Object.assign({className:(0,r.classes)(["BlockQuote",t])},n)))}},function(e,t,n){"use strict";var o,r;t.__esModule=!0,t.VNodeFlags=t.ChildFlags=void 0,t.VNodeFlags=o,function(e){e[e.HtmlElement=1]="HtmlElement",e[e.ComponentUnknown=2]="ComponentUnknown",e[e.ComponentClass=4]="ComponentClass",e[e.ComponentFunction=8]="ComponentFunction",e[e.Text=16]="Text",e[e.SvgElement=32]="SvgElement",e[e.InputElement=64]="InputElement",e[e.TextareaElement=128]="TextareaElement",e[e.SelectElement=256]="SelectElement",e[e.Void=512]="Void",e[e.Portal=1024]="Portal",e[e.ReCreate=2048]="ReCreate",e[e.ContentEditable=4096]="ContentEditable",e[e.Fragment=8192]="Fragment",e[e.InUse=16384]="InUse",e[e.ForwardRef=32768]="ForwardRef",e[e.Normalized=65536]="Normalized",e[e.ForwardRefComponent=32776]="ForwardRefComponent",e[e.FormElement=448]="FormElement",e[e.Element=481]="Element",e[e.Component=14]="Component",e[e.DOMRef=2033]="DOMRef",e[e.InUseOrNormalized=81920]="InUseOrNormalized",e[e.ClearInUse=-16385]="ClearInUse",e[e.ComponentKnown=12]="ComponentKnown"}(o||(t.VNodeFlags=o={})),t.ChildFlags=r,function(e){e[e.UnknownChildren=0]="UnknownChildren",e[e.HasInvalidChildren=1]="HasInvalidChildren",e[e.HasVNodeChildren=2]="HasVNodeChildren",e[e.HasNonKeyedChildren=4]="HasNonKeyedChildren",e[e.HasKeyedChildren=8]="HasKeyedChildren",e[e.HasTextChildren=16]="HasTextChildren",e[e.MultipleChildren=12]="MultipleChildren"}(r||(t.ChildFlags=r={}))},function(e,t,n){"use strict";t.__esModule=!0,t.ColorBox=void 0;var o=n(0),r=n(11),a=n(19);var i=function(e){var t=e.color,n=e.content,i=e.className,c=function(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}(e,["color","content","className"]);return(0,o.normalizeProps)((0,o.createComponentVNode)(2,a.Box,Object.assign({className:(0,r.classes)(["ColorBox",i]),color:n?null:"transparent",backgroundColor:t,content:n||"."},c)))};t.ColorBox=i,i.defaultHooks=r.pureComponentHooks},function(e,t,n){"use strict";t.__esModule=!0,t.Collapsible=void 0;var o=n(0),r=n(19),a=n(117);var i=function(e){var t,n;function i(t){var n;n=e.call(this,t)||this;var o=t.open;return n.state={open:o||!1},n}return n=e,(t=i).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n,i.prototype.render=function(){var e=this,t=this.props,n=this.state.open,i=t.children,c=t.color,l=void 0===c?"default":c,u=t.title,d=t.buttons,s=function(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}(t,["children","color","title","buttons"]);return(0,o.createComponentVNode)(2,r.Box,{mb:1,children:[(0,o.createVNode)(1,"div","Table",[(0,o.createVNode)(1,"div","Table__cell",(0,o.normalizeProps)((0,o.createComponentVNode)(2,a.Button,Object.assign({fluid:!0,color:l,icon:n?"chevron-down":"chevron-right",onClick:function(){return e.setState({open:!n})}},s,{children:u}))),2),d&&(0,o.createVNode)(1,"div","Table__cell Table__cell--collapsing",d,0)],0),n&&(0,o.createComponentVNode)(2,r.Box,{mt:1,children:i})]})},i}(o.Component);t.Collapsible=i},function(e,t,n){"use strict";t.__esModule=!0,t.Dimmer=void 0;var o=n(0),r=n(19);t.Dimmer=function(e){var t=e.style,n=function(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}(e,["style"]);return(0,o.normalizeProps)((0,o.createComponentVNode)(2,r.Box,Object.assign({style:Object.assign({position:"absolute",top:0,bottom:0,left:0,right:0,"background-color":"rgba(0, 0, 0, 0.75)","z-index":1},t)},n)))}},function(e,t,n){"use strict";t.__esModule=!0,t.Dropdown=void 0;var o=n(0),r=n(11),a=n(19),i=n(88);function c(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}var l=function(e){var t,n;function l(t){var n;return(n=e.call(this,t)||this).state={selected:t.selected,open:!1},n.handleClick=function(){n.state.open&&n.setOpen(!1)},n}n=e,(t=l).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n;var u=l.prototype;return u.componentWillUnmount=function(){window.removeEventListener("click",this.handleClick)},u.setOpen=function(e){var t=this;this.setState({open:e}),e?(setTimeout((function(){return window.addEventListener("click",t.handleClick)})),this.menuRef.focus()):window.removeEventListener("click",this.handleClick)},u.setSelected=function(e){this.setState({selected:e}),this.setOpen(!1),this.props.onSelected(e)},u.buildMenu=function(){var e=this,t=this.props.options,n=(void 0===t?[]:t).map((function(t){return(0,o.createVNode)(1,"div","Dropdown__menuentry",t,0,{onClick:function(n){e.setSelected(t)}},t)}));return n.length?n:"No Options Found"},u.render=function(){var e=this,t=this.props,n=t.color,l=void 0===n?"default":n,u=t.over,d=t.width,s=(t.onClick,t.selected,c(t,["color","over","width","onClick","selected"])),p=s.className,m=c(s,["className"]),f=u?!this.state.open:this.state.open,h=this.state.open?(0,o.createVNode)(1,"div",(0,r.classes)(["Dropdown__menu",u&&"Dropdown__over"]),this.buildMenu(),0,{tabIndex:"-1",style:{width:d}},null,(function(t){e.menuRef=t})):null;return(0,o.createVNode)(1,"div","Dropdown",[(0,o.normalizeProps)((0,o.createComponentVNode)(2,a.Box,Object.assign({width:d,className:(0,r.classes)(["Dropdown__control","Button","Button--color--"+l,p])},m,{onClick:function(t){e.setOpen(!e.state.open)},children:[(0,o.createVNode)(1,"span","Dropdown__selected-text",this.state.selected,0),(0,o.createVNode)(1,"span","Dropdown__arrow-button",(0,o.createComponentVNode)(2,i.Icon,{name:f?"chevron-up":"chevron-down"}),2)]}))),h],0)},l}(o.Component);t.Dropdown=l},function(e,t,n){"use strict";t.__esModule=!0,t.FlexItem=t.computeFlexItemProps=t.Flex=t.computeFlexProps=void 0;var o=n(0),r=n(11),a=n(19);function i(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}var c=function(e){var t=e.className,n=e.direction,o=e.wrap,a=e.align,c=e.justify,l=e.spacing,u=void 0===l?0:l,d=i(e,["className","direction","wrap","align","justify","spacing"]);return Object.assign({className:(0,r.classes)(["Flex",u>0&&"Flex--spacing--"+u,t]),style:Object.assign({},d.style,{"flex-direction":n,"flex-wrap":o,"align-items":a,"justify-content":c})},d)};t.computeFlexProps=c;var l=function(e){return(0,o.normalizeProps)((0,o.createComponentVNode)(2,a.Box,Object.assign({},c(e))))};t.Flex=l,l.defaultHooks=r.pureComponentHooks;var u=function(e){var t=e.className,n=e.grow,o=e.order,a=e.align,c=i(e,["className","grow","order","align"]);return Object.assign({className:(0,r.classes)(["Flex__item",t]),style:Object.assign({},c.style,{"flex-grow":n,order:o,"align-self":a})},c)};t.computeFlexItemProps=u;var d=function(e){return(0,o.normalizeProps)((0,o.createComponentVNode)(2,a.Box,Object.assign({},u(e))))};t.FlexItem=d,d.defaultHooks=r.pureComponentHooks,l.Item=d},function(e,t,n){"use strict";t.__esModule=!0,t.NoticeBox=void 0;var o=n(0),r=n(11),a=n(19);var i=function(e){var t=e.className,n=function(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}(e,["className"]);return(0,o.normalizeProps)((0,o.createComponentVNode)(2,a.Box,Object.assign({className:(0,r.classes)(["NoticeBox",t])},n)))};t.NoticeBox=i,i.defaultHooks=r.pureComponentHooks},function(e,t,n){"use strict";t.__esModule=!0,t.NumberInput=void 0;var o=n(0),r=n(17),a=n(11),i=n(16),c=n(162),l=n(19);var u=function(e){var t,n;function u(t){var n;n=e.call(this,t)||this;var a=t.value;return n.inputRef=(0,o.createRef)(),n.state={value:a,dragging:!1,editing:!1,internalValue:null,origin:null,suppressingFlicker:!1},n.flickerTimer=null,n.suppressFlicker=function(){var e=n.props.suppressFlicker;e>0&&(n.setState({suppressingFlicker:!0}),clearTimeout(n.flickerTimer),n.flickerTimer=setTimeout((function(){return n.setState({suppressingFlicker:!1})}),e))},n.handleDragStart=function(e){var t=n.props.value;n.state.editing||(document.body.style["pointer-events"]="none",n.ref=e.target,n.setState({dragging:!1,origin:e.screenY,value:t,internalValue:t}),n.timer=setTimeout((function(){n.setState({dragging:!0})}),250),n.dragInterval=setInterval((function(){var t=n.state,o=t.dragging,r=t.value,a=n.props.onDrag;o&&a&&a(e,r)}),500),document.addEventListener("mousemove",n.handleDragMove),document.addEventListener("mouseup",n.handleDragEnd))},n.handleDragMove=function(e){var t=n.props,o=t.minValue,a=t.maxValue,i=t.step,c=t.stepPixelSize;n.setState((function(t){var n=Object.assign({},t),l=n.origin-e.screenY;if(t.dragging){var u=Number.isFinite(o)?o%i:0;n.internalValue=(0,r.clamp)(n.internalValue+l*i/c,o-i,a+i),n.value=(0,r.clamp)(n.internalValue-n.internalValue%i+u,o,a),n.origin=e.screenY}else Math.abs(l)>4&&(n.dragging=!0);return n}))},n.handleDragEnd=function(e){var t=n.props,o=t.onChange,r=t.onDrag,a=n.state,i=a.dragging,c=a.value,l=a.internalValue;if(document.body.style["pointer-events"]="auto",clearTimeout(n.timer),clearInterval(n.dragInterval),n.setState({dragging:!1,editing:!i,origin:null}),document.removeEventListener("mousemove",n.handleDragMove),document.removeEventListener("mouseup",n.handleDragEnd),i)n.suppressFlicker(),o&&o(e,c),r&&r(e,c);else if(n.inputRef){var u=n.inputRef.current;u.value=l;try{u.focus(),u.select()}catch(d){}}},n}return n=e,(t=u).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n,u.prototype.render=function(){var e=this,t=this.state,n=t.dragging,u=t.editing,d=t.value,s=t.suppressingFlicker,p=this.props,m=p.className,f=p.fluid,h=p.animated,C=p.value,g=p.unit,b=p.minValue,N=p.maxValue,v=p.height,V=p.width,y=p.lineHeight,_=p.fontSize,x=p.format,k=p.onChange,L=p.onDrag,w=C;(n||s)&&(w=d);var B=function(e){return(0,o.createVNode)(1,"div","NumberInput__content",e+(g?" "+g:""),0,{unselectable:i.tridentVersion<=4})},S=h&&!n&&!s&&(0,o.createComponentVNode)(2,c.AnimatedNumber,{value:w,format:x,children:B})||B(x?x(w):w);return(0,o.createComponentVNode)(2,l.Box,{className:(0,a.classes)(["NumberInput",f&&"NumberInput--fluid",m]),minWidth:V,minHeight:v,lineHeight:y,fontSize:_,onMouseDown:this.handleDragStart,children:[(0,o.createVNode)(1,"div","NumberInput__barContainer",(0,o.createVNode)(1,"div","NumberInput__bar",null,1,{style:{height:(0,r.clamp)((w-b)/(N-b)*100,0,100)+"%"}}),2),S,(0,o.createVNode)(64,"input","NumberInput__input",null,1,{style:{display:u?undefined:"none",height:v,"line-height":y,"font-size":_},onBlur:function(t){if(u){var n=(0,r.clamp)(t.target.value,b,N);isNaN(n)?e.setState({editing:!1}):(e.setState({editing:!1,value:n}),e.suppressFlicker(),k&&k(t,n),L&&L(t,n))}},onKeyDown:function(t){if(13===t.keyCode){var n=(0,r.clamp)(t.target.value,b,N);return isNaN(n)?void e.setState({editing:!1}):(e.setState({editing:!1,value:n}),e.suppressFlicker(),k&&k(t,n),void(L&&L(t,n)))}27!==t.keyCode||e.setState({editing:!1})}},null,this.inputRef)]})},u}(o.Component);t.NumberInput=u,u.defaultHooks=a.pureComponentHooks,u.defaultProps={minValue:-Infinity,maxValue:+Infinity,step:1,stepPixelSize:1,suppressFlicker:50}},function(e,t,n){"use strict";t.__esModule=!0,t.ProgressBar=void 0;var o=n(0),r=n(11),a=n(17),i=function(e){var t=e.value,n=e.minValue,i=void 0===n?0:n,c=e.maxValue,l=void 0===c?1:c,u=e.ranges,d=void 0===u?{}:u,s=e.content,p=e.children,m=(t-i)/(l-i),f=s!==undefined||p!==undefined,h=e.color;if(!h)for(var C=0,g=Object.keys(d);C=N[0]&&t<=N[1]){h=b;break}}return h||(h="default"),(0,o.createVNode)(1,"div",(0,r.classes)(["ProgressBar","ProgressBar--color--"+h]),[(0,o.createVNode)(1,"div","ProgressBar__fill",null,1,{style:{width:100*(0,a.clamp)(m,0,1)+"%"}}),(0,o.createVNode)(1,"div","ProgressBar__content",[f&&s,f&&p,!f&&(0,a.toFixed)(100*m)+"%"],0)],4)};t.ProgressBar=i,i.defaultHooks=r.pureComponentHooks},function(e,t,n){"use strict";t.__esModule=!0,t.Section=void 0;var o=n(0),r=n(11),a=n(19);var i=function(e){var t=e.className,n=e.title,i=e.level,c=void 0===i?1:i,l=e.buttons,u=e.content,d=e.children,s=function(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}(e,["className","title","level","buttons","content","children"]),p=!(0,r.isFalsy)(n)||!(0,r.isFalsy)(l),m=!(0,r.isFalsy)(u)||!(0,r.isFalsy)(d);return(0,o.normalizeProps)((0,o.createComponentVNode)(2,a.Box,Object.assign({className:(0,r.classes)(["Section","Section--level--"+c,t])},s,{children:[p&&(0,o.createVNode)(1,"div","Section__title",[(0,o.createVNode)(1,"span","Section__titleText",n,0),(0,o.createVNode)(1,"div","Section__buttons",l,0)],4),m&&(0,o.createVNode)(1,"div","Section__content",[u,d],0)]})))};t.Section=i,i.defaultHooks=r.pureComponentHooks},function(e,t,n){"use strict";t.__esModule=!0,t.Tab=t.Tabs=void 0;var o=n(0),r=n(11),a=n(19),i=n(117);function c(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}function l(e,t){var n;if("undefined"==typeof Symbol||null==e[Symbol.iterator]){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return u(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return u(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var o=0;return function(){return o>=e.length?{done:!0}:{done:!1,value:e[o++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}return(n=e[Symbol.iterator]()).next.bind(n)}function u(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,o=new Array(t);n only accepts children of type .This is what we received: "+r)}}}(n);var o=t.activeTab||e.activeTabKey,a=n.find((function(e){return(e.key||e.props.label)===o}));return a||(a=n[0],o=a&&(a.key||a.props.label)),{tabs:n,activeTab:a,activeTabKey:o}},d.render=function(){var e=this,t=this.props,n=t.className,l=t.vertical,u=(t.children,c(t,["className","vertical","children"])),d=this.getActiveTab(),s=d.tabs,p=d.activeTab,m=d.activeTabKey,f=null;return p&&(f=p.props.content||p.props.children),"function"==typeof f&&(f=f(m)),(0,o.normalizeProps)((0,o.createComponentVNode)(2,a.Box,Object.assign({className:(0,r.classes)(["Tabs",l&&"Tabs--vertical",n])},u,{children:[(0,o.createVNode)(1,"div","Tabs__tabBox",s.map((function(t){var n=t.props,a=n.className,l=n.label,u=(n.content,n.children,n.onClick),d=n.highlight,s=c(n,["className","label","content","children","onClick","highlight"]),p=t.key||t.props.label,f=t.active||p===m;return(0,o.normalizeProps)((0,o.createComponentVNode)(2,i.Button,Object.assign({className:(0,r.classes)(["Tabs__tab",f&&"Tabs__tab--active",d&&!f&&"color-yellow",a]),selected:f,color:"transparent",onClick:function(n){e.setState({activeTabKey:p}),u&&u(n,t)}},s,{children:l}),p))})),0),(0,o.createVNode)(1,"div","Tabs__content",f||null,0)]})))},u}(o.Component);t.Tabs=d;var s=function(e){return null};t.Tab=s,s.defaultProps={__type__:"Tab"},d.Tab=s},function(e,t,n){"use strict";t.__esModule=!0,t.TitleBar=void 0;var o=n(0),r=n(11),a=n(24),i=n(16),c=n(33),l=n(88),u=function(e){switch(e){case c.UI_INTERACTIVE:return"good";case c.UI_UPDATE:return"average";case c.UI_DISABLED:default:return"bad"}},d=function(e){var t=e.className,n=e.title,c=e.status,d=e.fancy,s=e.onDragStart,p=e.onClose;return(0,o.createVNode)(1,"div",(0,r.classes)(["TitleBar",t]),[(0,o.createComponentVNode)(2,l.Icon,{className:"TitleBar__statusIcon",color:u(c),name:"eye"}),(0,o.createVNode)(1,"div","TitleBar__title",n===n.toLowerCase()?(0,a.toTitleCase)(n):n,0),(0,o.createVNode)(1,"div","TitleBar__dragZone",null,1,{onMousedown:function(e){return d&&s(e)}}),!!d&&(0,o.createVNode)(1,"div","TitleBar__close TitleBar__clickable",i.tridentVersion<=4?"x":"\xd7",0,{onclick:p})],0)};t.TitleBar=d,d.defaultHooks=r.pureComponentHooks},function(e,t,n){"use strict";t.__esModule=!0,t.Chart=void 0;var o=n(0),r=n(25),a=n(19),i=n(11),c=n(16);var l=function(e){var t,n;function i(t){var n;return(n=e.call(this,t)||this).ref=(0,o.createRef)(),n.state={viewBox:[600,200]},n.handleResize=function(){var e=n.ref.current;n.setState({viewBox:[e.offsetWidth,e.offsetHeight]})},n}n=e,(t=i).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n;var c=i.prototype;return c.componentDidMount=function(){window.addEventListener("resize",this.handleResize),this.handleResize()},c.componentWillUnmount=function(){window.removeEventListener("resize",this.handleResize)},c.render=function(){var e=this,t=this.props,n=t.data,i=void 0===n?[]:n,c=t.rangeX,l=t.rangeY,u=t.fillColor,d=void 0===u?"none":u,s=t.strokeColor,p=void 0===s?"#ffffff":s,m=t.strokeWidth,f=void 0===m?2:m,h=function(e,t){if(null==e)return{};var n,o,r={},a=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}(t,["data","rangeX","rangeY","fillColor","strokeColor","strokeWidth"]),C=this.state.viewBox,g=function(e,t,n,o){if(0===e.length)return[];var a=(0,r.zipWith)(Math.min).apply(void 0,e),i=(0,r.zipWith)(Math.max).apply(void 0,e);return n!==undefined&&(a[0]=n[0],i[0]=n[1]),o!==undefined&&(a[1]=o[0],i[1]=o[1]),(0,r.map)((function(e){return(0,r.zipWith)((function(e,t,n,o){return(e-t)/(n-t)*o}))(e,a,i,t)}))(e)}(i,C,c,l);if(g.length>0){var b=g[0],N=g[g.length-1];g.push([C[0]+f,N[1]]),g.push([C[0]+f,-f]),g.push([-f,-f]),g.push([-f,b[1]])}var v=function(e){for(var t="",n=0;n0&&"["+i.power.main_timeleft+"s]":"[Wires have been cut!]"]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Backup",color:u.color,buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"lightbulb-o",disabled:!i.power.backup,content:"Disrupt",onClick:function(){return n("disrupt-backup")}}),children:[i.power.backup?"Online":"Offline"," ",i.wires.backup_1&&i.wires.backup_2?i.power.backup_timeleft>0&&"["+i.power.backup_timeleft+"s]":"[Wires have been cut!]"]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Electrify",color:d.color,buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{icon:"wrench",disabled:!(i.wires.shock&&0===i.shock),content:"Restore",onClick:function(){return n("shock-restore")}}),(0,o.createComponentVNode)(2,a.Button,{icon:"bolt",disabled:!i.wires.shock,content:"Temporary",onClick:function(){return n("shock-temp")}}),(0,o.createComponentVNode)(2,a.Button,{icon:"bolt",disabled:!i.wires.shock,content:"Permanent",onClick:function(){return n("shock-perm")}})],4),children:[2===i.shock?"Safe":"Electrified"," ",(i.wires.shock?i.shock_timeleft>0&&"["+i.shock_timeleft+"s]":"[Wires have been cut!]")||-1===i.shock_timeleft&&"[Permanent]"]})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Access and Door Control",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"ID Scan",color:"bad",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:i.id_scanner?"power-off":"times",content:i.id_scanner?"Enabled":"Disabled",selected:i.id_scanner,disabled:!i.wires.id_scanner,onClick:function(){return n("idscan-toggle")}}),children:!i.wires.id_scanner&&"[Wires have been cut!]"}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Emergency Access",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:i.emergency?"power-off":"times",content:i.emergency?"Enabled":"Disabled",selected:i.emergency,onClick:function(){return n("emergency-toggle")}})}),(0,o.createComponentVNode)(2,a.LabeledList.Divider),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Door Bolts",color:"bad",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:i.locked?"lock":"unlock",content:i.locked?"Lowered":"Raised",selected:i.locked,disabled:!i.wires.bolts,onClick:function(){return n("bolt-toggle")}}),children:!i.wires.bolts&&"[Wires have been cut!]"}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Door Bolt Lights",color:"bad",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:i.lights?"power-off":"times",content:i.lights?"Enabled":"Disabled",selected:i.lights,disabled:!i.wires.lights,onClick:function(){return n("light-toggle")}}),children:!i.wires.lights&&"[Wires have been cut!]"}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Door Force Sensors",color:"bad",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:i.safe?"power-off":"times",content:i.safe?"Enabled":"Disabled",selected:i.safe,disabled:!i.wires.safe,onClick:function(){return n("safe-toggle")}}),children:!i.wires.safe&&"[Wires have been cut!]"}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Door Timing Safety",color:"bad",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:i.speed?"power-off":"times",content:i.speed?"Enabled":"Disabled",selected:i.speed,disabled:!i.wires.timing,onClick:function(){return n("speed-toggle")}}),children:!i.wires.timing&&"[Wires have been cut!]"}),(0,o.createComponentVNode)(2,a.LabeledList.Divider),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Door Control",color:"bad",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:i.opened?"sign-out-alt":"sign-in-alt",content:i.opened?"Open":"Closed",selected:i.opened,disabled:i.locked||i.welded,onClick:function(){return n("open-close")}}),children:!(!i.locked&&!i.welded)&&(0,o.createVNode)(1,"span",null,[(0,o.createTextVNode)("[Door is "),i.locked?"bolted":"",i.locked&&i.welded?" and ":"",i.welded?"welded":"",(0,o.createTextVNode)("!]")],0)})]})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.AirAlarm=void 0;var o=n(0),r=n(17),a=n(24),i=n(3),c=n(2),l=n(33),u=n(70);t.AirAlarm=function(e){var t=e.state,n=(0,i.useBackend)(e),r=n.act,a=n.data,c=a.locked&&!a.siliconUser;return(0,o.createFragment)([(0,o.createComponentVNode)(2,u.InterfaceLockNoticeBox,{siliconUser:a.siliconUser,locked:a.locked,onLockStatusChange:function(){return r("lock")}}),(0,o.createComponentVNode)(2,d,{state:t}),!c&&(0,o.createComponentVNode)(2,p,{state:t})],0)};var d=function(e){var t=(0,i.useBackend)(e).data,n=(t.environment_data||[]).filter((function(e){return e.value>=.01})),a={0:{color:"good",localStatusText:"Optimal"},1:{color:"average",localStatusText:"Caution"},2:{color:"bad",localStatusText:"Danger (Internals Required)"}},l=a[t.danger_level]||a[0];return(0,o.createComponentVNode)(2,c.Section,{title:"Air Status",children:(0,o.createComponentVNode)(2,c.LabeledList,{children:[n.length>0&&(0,o.createFragment)([n.map((function(e){var t=a[e.danger_level]||a[0];return(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:e.name,color:t.color,children:[(0,r.toFixed)(e.value,2),e.unit]},e.name)})),(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Local status",color:l.color,children:l.localStatusText}),(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Area status",color:t.atmos_alarm||t.fire_alarm?"bad":"good",children:(t.atmos_alarm?"Atmosphere Alarm":t.fire_alarm&&"Fire Alarm")||"Nominal"})],0)||(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Warning",color:"bad",children:"Cannot obtain air sample for analysis."}),!!t.emagged&&(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Warning",color:"bad",children:"Safety measures offline. Device may exhibit abnormal behavior."})]})})},s={home:{title:"Air Controls",component:function(){return m}},vents:{title:"Vent Controls",component:function(){return f}},scrubbers:{title:"Scrubber Controls",component:function(){return C}},modes:{title:"Operating Mode",component:function(){return b}},thresholds:{title:"Alarm Thresholds",component:function(){return N}}},p=function(e){var t=e.state,n=(0,i.useBackend)(e),r=n.act,a=n.config,l=s[a.screen]||s.home,u=l.component();return(0,o.createComponentVNode)(2,c.Section,{title:l.title,buttons:"home"!==a.screen&&(0,o.createComponentVNode)(2,c.Button,{icon:"arrow-left",content:"Back",onClick:function(){return r("tgui:view",{screen:"home"})}}),children:(0,o.createComponentVNode)(2,u,{state:t})})},m=function(e){var t=(0,i.useBackend)(e),n=t.act,r=t.data,a=r.mode,l=r.atmos_alarm;return(0,o.createFragment)([(0,o.createComponentVNode)(2,c.Button,{icon:l?"exclamation-triangle":"exclamation",color:l&&"caution",content:"Area Atmosphere Alarm",onClick:function(){return n(l?"reset":"alarm")}}),(0,o.createComponentVNode)(2,c.Box,{mt:1}),(0,o.createComponentVNode)(2,c.Button,{icon:3===a?"exclamation-triangle":"exclamation",color:3===a&&"danger",content:"Panic Siphon",onClick:function(){return n("mode",{mode:3===a?1:3})}}),(0,o.createComponentVNode)(2,c.Box,{mt:2}),(0,o.createComponentVNode)(2,c.Button,{icon:"sign-out-alt",content:"Vent Controls",onClick:function(){return n("tgui:view",{screen:"vents"})}}),(0,o.createComponentVNode)(2,c.Box,{mt:1}),(0,o.createComponentVNode)(2,c.Button,{icon:"filter",content:"Scrubber Controls",onClick:function(){return n("tgui:view",{screen:"scrubbers"})}}),(0,o.createComponentVNode)(2,c.Box,{mt:1}),(0,o.createComponentVNode)(2,c.Button,{icon:"cog",content:"Operating Mode",onClick:function(){return n("tgui:view",{screen:"modes"})}}),(0,o.createComponentVNode)(2,c.Box,{mt:1}),(0,o.createComponentVNode)(2,c.Button,{icon:"chart-bar",content:"Alarm Thresholds",onClick:function(){return n("tgui:view",{screen:"thresholds"})}})],4)},f=function(e){var t=e.state,n=(0,i.useBackend)(e).data.vents;return n&&0!==n.length?n.map((function(e){return(0,o.normalizeProps)((0,o.createComponentVNode)(2,h,Object.assign({state:t},e),e.id_tag))})):"Nothing to show"},h=function(e){var t=e.id_tag,n=e.long_name,r=e.power,l=e.checks,u=e.excheck,d=e.incheck,s=e.direction,p=e.external,m=e.internal,f=e.extdefault,h=e.intdefault,C=(0,i.useBackend)(e).act;return(0,o.createComponentVNode)(2,c.Section,{level:2,title:(0,a.decodeHtmlEntities)(n),buttons:(0,o.createComponentVNode)(2,c.Button,{icon:r?"power-off":"times",selected:r,content:r?"On":"Off",onClick:function(){return C("power",{id_tag:t,val:Number(!r)})}}),children:(0,o.createComponentVNode)(2,c.LabeledList,{children:[(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Mode",children:"release"===s?"Pressurizing":"Releasing"}),(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Pressure Regulator",children:[(0,o.createComponentVNode)(2,c.Button,{icon:"sign-in-alt",content:"Internal",selected:d,onClick:function(){return C("incheck",{id_tag:t,val:l})}}),(0,o.createComponentVNode)(2,c.Button,{icon:"sign-out-alt",content:"External",selected:u,onClick:function(){return C("excheck",{id_tag:t,val:l})}})]}),!!d&&(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Internal Target",children:[(0,o.createComponentVNode)(2,c.NumberInput,{value:Math.round(m),unit:"kPa",width:"75px",minValue:0,step:10,maxValue:5066,onChange:function(e,n){return C("set_internal_pressure",{id_tag:t,value:n})}}),(0,o.createComponentVNode)(2,c.Button,{icon:"undo",disabled:h,content:"Reset",onClick:function(){return C("reset_internal_pressure",{id_tag:t})}})]}),!!u&&(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"External Target",children:[(0,o.createComponentVNode)(2,c.NumberInput,{value:Math.round(p),unit:"kPa",width:"75px",minValue:0,step:10,maxValue:5066,onChange:function(e,n){return C("set_external_pressure",{id_tag:t,value:n})}}),(0,o.createComponentVNode)(2,c.Button,{icon:"undo",disabled:f,content:"Reset",onClick:function(){return C("reset_external_pressure",{id_tag:t})}})]})]})})},C=function(e){var t=e.state,n=(0,i.useBackend)(e).data.scrubbers;return n&&0!==n.length?n.map((function(e){return(0,o.normalizeProps)((0,o.createComponentVNode)(2,g,Object.assign({state:t},e),e.id_tag))})):"Nothing to show"},g=function(e){var t=e.long_name,n=e.power,r=e.scrubbing,u=e.id_tag,d=e.widenet,s=e.filter_types,p=(0,i.useBackend)(e).act;return(0,o.createComponentVNode)(2,c.Section,{level:2,title:(0,a.decodeHtmlEntities)(t),buttons:(0,o.createComponentVNode)(2,c.Button,{icon:n?"power-off":"times",content:n?"On":"Off",selected:n,onClick:function(){return p("power",{id_tag:u,val:Number(!n)})}}),children:(0,o.createComponentVNode)(2,c.LabeledList,{children:[(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Mode",children:[(0,o.createComponentVNode)(2,c.Button,{icon:r?"filter":"sign-in-alt",color:r||"danger",content:r?"Scrubbing":"Siphoning",onClick:function(){return p("scrubbing",{id_tag:u,val:Number(!r)})}}),(0,o.createComponentVNode)(2,c.Button,{icon:d?"expand":"compress",selected:d,content:d?"Expanded range":"Normal range",onClick:function(){return p("widenet",{id_tag:u,val:Number(!d)})}})]}),(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Filters",children:r&&s.map((function(e){return(0,o.createComponentVNode)(2,c.Button,{icon:e.enabled?"check-square-o":"square-o",content:(0,l.getGasLabel)(e.gas_id,e.gas_name),title:e.gas_name,selected:e.enabled,onClick:function(){return p("toggle_filter",{id_tag:u,val:e.gas_id})}},e.gas_id)}))||"N/A"})]})})},b=function(e){var t=(0,i.useBackend)(e),n=t.act,r=t.data.modes;return r&&0!==r.length?r.map((function(e){return(0,o.createFragment)([(0,o.createComponentVNode)(2,c.Button,{icon:e.selected?"check-square-o":"square-o",selected:e.selected,color:e.selected&&e.danger&&"danger",content:e.name,onClick:function(){return n("mode",{mode:e.mode})}}),(0,o.createComponentVNode)(2,c.Box,{mt:1})],4,e.mode)})):"Nothing to show"},N=function(e){var t=(0,i.useBackend)(e),n=t.act,a=t.data.thresholds;return(0,o.createVNode)(1,"table","LabeledList",[(0,o.createVNode)(1,"thead",null,(0,o.createVNode)(1,"tr",null,[(0,o.createVNode)(1,"td"),(0,o.createVNode)(1,"td","color-bad","min2",16),(0,o.createVNode)(1,"td","color-average","min1",16),(0,o.createVNode)(1,"td","color-average","max1",16),(0,o.createVNode)(1,"td","color-bad","max2",16)],4),2),(0,o.createVNode)(1,"tbody",null,a.map((function(e){return(0,o.createVNode)(1,"tr",null,[(0,o.createVNode)(1,"td","LabeledList__label",e.name,0),e.settings.map((function(e){return(0,o.createVNode)(1,"td",null,(0,o.createComponentVNode)(2,c.Button,{content:(0,r.toFixed)(e.selected,2),onClick:function(){return n("threshold",{env:e.env,"var":e.val})}}),2,null,e.val)}))],0,null,e.name)})),0)],4,{style:{width:"100%"}})}},function(e,t,n){"use strict";t.__esModule=!0,t.AirlockElectronics=void 0;var o=n(0),r=n(3),a=n(2);t.AirlockElectronics=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.regions||[],l={0:{icon:"times-circle"},1:{icon:"stop-circle"},2:{icon:"check-circle"}};return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Main",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Access Required",children:(0,o.createComponentVNode)(2,a.Button,{icon:i.oneAccess?"unlock":"lock",content:i.oneAccess?"One":"All",onClick:function(){return n("one_access")}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Mass Modify",children:[(0,o.createComponentVNode)(2,a.Button,{icon:"check-double",content:"Grant All",onClick:function(){return n("grant_all")}}),(0,o.createComponentVNode)(2,a.Button,{icon:"undo",content:"Clear All",onClick:function(){return n("clear_all")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Unrestricted Access",children:[(0,o.createComponentVNode)(2,a.Button,{icon:1&i.unres_direction?"check-square-o":"square-o",content:"North",selected:1&i.unres_direction,onClick:function(){return n("direc_set",{unres_direction:"1"})}}),(0,o.createComponentVNode)(2,a.Button,{icon:2&i.unres_direction?"check-square-o":"square-o",content:"South",selected:2&i.unres_direction,onClick:function(){return n("direc_set",{unres_direction:"2"})}}),(0,o.createComponentVNode)(2,a.Button,{icon:4&i.unres_direction?"check-square-o":"square-o",content:"East",selected:4&i.unres_direction,onClick:function(){return n("direc_set",{unres_direction:"4"})}}),(0,o.createComponentVNode)(2,a.Button,{icon:8&i.unres_direction?"check-square-o":"square-o",content:"West",selected:8&i.unres_direction,onClick:function(){return n("direc_set",{unres_direction:"8"})}})]})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Access",children:(0,o.createComponentVNode)(2,a.Box,{height:"261px",children:(0,o.createComponentVNode)(2,a.Tabs,{vertical:!0,children:c.map((function(e){var t=e.name,r=e.accesses||[],i=l[function(e){var t=!1,n=!1;return e.forEach((function(e){e.req?t=!0:n=!0})),!t&&n?0:t&&n?1:2}(r)].icon;return(0,o.createComponentVNode)(2,a.Tabs.Tab,{icon:i,label:t,children:function(){return r.map((function(e){return(0,o.createComponentVNode)(2,a.Box,{children:(0,o.createComponentVNode)(2,a.Button,{icon:e.req?"check-square-o":"square-o",content:e.name,selected:e.req,onClick:function(){return n("set",{access:e.id})}})},e.id)}))}},t)}))})})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.Apc=void 0;var o=n(0),r=n(3),a=n(2),i=n(70);t.Apc=function(e){var t=(0,r.useBackend)(e),n=t.act,c=t.data,l=c.locked&&!c.siliconUser,u={2:{color:"good",externalPowerText:"External Power",chargingText:"Fully Charged"},1:{color:"average",externalPowerText:"Low External Power",chargingText:"Charging"},0:{color:"bad",externalPowerText:"No External Power",chargingText:"Not Charging"}},d={1:{icon:"terminal",content:"Override Programming",action:"hack"},2:{icon:"caret-square-down",content:"Shunt Core Process",action:"occupy"},3:{icon:"caret-square-left",content:"Return to Main Core",action:"deoccupy"},4:{icon:"caret-square-down",content:"Shunt Core Process",action:"occupy"}},s=u[c.externalPower]||u[0],p=u[c.chargingStatus]||u[0],m=c.powerChannels||[],f=d[c.malfStatus]||d[0],h=c.powerCellStatus/100;return c.failTime>0?(0,o.createComponentVNode)(2,a.NoticeBox,{children:[(0,o.createVNode)(1,"b",null,(0,o.createVNode)(1,"h3",null,"SYSTEM FAILURE",16),2),(0,o.createVNode)(1,"i",null,"I/O regulators malfunction detected! Waiting for system reboot...",16),(0,o.createVNode)(1,"br"),"Automatic reboot in ",c.failTime," seconds...",(0,o.createComponentVNode)(2,a.Button,{icon:"sync",content:"Reboot Now",onClick:function(){return n("reboot")}})]}):(0,o.createFragment)([(0,o.createComponentVNode)(2,i.InterfaceLockNoticeBox,{siliconUser:c.siliconUser,locked:c.locked,onLockStatusChange:function(){return n("lock")}}),(0,o.createComponentVNode)(2,a.Section,{title:"Power Status",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Main Breaker",color:s.color,buttons:(0,o.createComponentVNode)(2,a.Button,{icon:c.isOperating?"power-off":"times",content:c.isOperating?"On":"Off",selected:c.isOperating&&!l,disabled:l,onClick:function(){return n("breaker")}}),children:["[ ",s.externalPowerText," ]"]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Power Cell",children:(0,o.createComponentVNode)(2,a.ProgressBar,{color:"good",value:h})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Charge Mode",color:p.color,buttons:(0,o.createComponentVNode)(2,a.Button,{icon:c.chargeMode?"sync":"close",content:c.chargeMode?"Auto":"Off",disabled:l,onClick:function(){return n("charge")}}),children:["[ ",p.chargingText," ]"]})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Power Channels",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[m.map((function(e){var t=e.topicParams;return(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:e.title,buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Box,{inline:!0,mx:2,color:e.status>=2?"good":"bad",children:e.status>=2?"On":"Off"}),(0,o.createComponentVNode)(2,a.Button,{icon:"sync",content:"Auto",selected:!l&&(1===e.status||3===e.status),disabled:l,onClick:function(){return n("channel",t.auto)}}),(0,o.createComponentVNode)(2,a.Button,{icon:"power-off",content:"On",selected:!l&&2===e.status,disabled:l,onClick:function(){return n("channel",t.on)}}),(0,o.createComponentVNode)(2,a.Button,{icon:"times",content:"Off",selected:!l&&0===e.status,disabled:l,onClick:function(){return n("channel",t.off)}})],4),children:e.powerLoad},e.title)})),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Total Load",children:(0,o.createVNode)(1,"b",null,c.totalLoad,0)})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Misc",buttons:!!c.siliconUser&&(0,o.createFragment)([!!c.malfStatus&&(0,o.createComponentVNode)(2,a.Button,{icon:f.icon,content:f.content,color:"bad",onClick:function(){return n(f.action)}}),(0,o.createComponentVNode)(2,a.Button,{icon:"lightbulb-o",content:"Overload",onClick:function(){return n("overload")}})],0),children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Cover Lock",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:c.coverLocked?"lock":"unlock",content:c.coverLocked?"Engaged":"Disengaged",disabled:l,onClick:function(){return n("cover")}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Emergency Lighting",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"lightbulb-o",content:c.emergencyLights?"Enabled":"Disabled",disabled:l,onClick:function(){return n("emergency_lighting")}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Night Shift Lighting",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"lightbulb-o",content:c.nightshiftLights?"Enabled":"Disabled",disabled:l,onClick:function(){return n("toggle_nightshift")}})})]}),c.hijackable&&(0,o.createComponentVNode)(2,a.Section,{title:"Hijacking",buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{icon:"unlock",content:"Hijack",disabled:c.hijacker,onClick:function(){return n("hijack")}}),(0,o.createComponentVNode)(2,a.Button,{icon:"lock",content:"Lockdown",disabled:!c.lockdownavail,onClick:function(){return n("lockdown")}}),(0,o.createComponentVNode)(2,a.Button,{icon:"lightbulb-o",content:"Drain",disabled:!c.drainavail,onClick:function(){return n("drain")}})],4)})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.AtmosAlertConsole=void 0;var o=n(0),r=n(3),a=n(2);t.AtmosAlertConsole=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.priority||[],l=i.minor||[];return(0,o.createComponentVNode)(2,a.Section,{title:"Alarms",children:(0,o.createVNode)(1,"ul",null,[c.length>0?c.map((function(e){return(0,o.createVNode)(1,"li",null,(0,o.createComponentVNode)(2,a.Button,{icon:"times",content:e,color:"bad",onClick:function(){return n("clear",{zone:e})}}),2,null,e)})):(0,o.createVNode)(1,"li","color-good","No Priority Alerts",16),l.length>0?l.map((function(e){return(0,o.createVNode)(1,"li",null,(0,o.createComponentVNode)(2,a.Button,{icon:"times",content:e,color:"average",onClick:function(){return n("clear",{zone:e})}}),2,null,e)})):(0,o.createVNode)(1,"li","color-good","No Minor Alerts",16)],0)})}},function(e,t,n){"use strict";t.__esModule=!0,t.AtmosControlConsole=void 0;var o=n(0),r=n(25),a=n(17),i=n(3),c=n(2);t.AtmosControlConsole=function(e){var t=(0,i.useBackend)(e),n=t.act,l=t.data,u=l.sensors||[];return(0,o.createFragment)([(0,o.createComponentVNode)(2,c.Section,{title:!!l.tank&&u[0].long_name,children:u.map((function(e){var t=e.gases||{};return(0,o.createComponentVNode)(2,c.Section,{title:!l.tank&&e.long_name,level:2,children:(0,o.createComponentVNode)(2,c.LabeledList,{children:[(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Pressure",children:(0,a.toFixed)(e.pressure,2)+" kPa"}),!!e.temperature&&(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Temperature",children:(0,a.toFixed)(e.temperature,2)+" K"}),(0,r.map)((function(e,t){return(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:t,children:(0,a.toFixed)(e,2)+"%"})}))(t)]})},e.id_tag)}))}),l.tank&&(0,o.createComponentVNode)(2,c.Section,{title:"Controls",buttons:(0,o.createComponentVNode)(2,c.Button,{icon:"undo",content:"Reconnect",onClick:function(){return n("reconnect")}}),children:(0,o.createComponentVNode)(2,c.LabeledList,{children:[(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Input Injector",children:(0,o.createComponentVNode)(2,c.Button,{icon:l.inputting?"power-off":"times",content:l.inputting?"Injecting":"Off",selected:l.inputting,onClick:function(){return n("input")}})}),(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Input Rate",children:(0,o.createComponentVNode)(2,c.NumberInput,{value:l.inputRate,unit:"L/s",width:"63px",minValue:0,maxValue:200,suppressFlicker:2e3,onChange:function(e,t){return n("rate",{rate:t})}})}),(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Output Regulator",children:(0,o.createComponentVNode)(2,c.Button,{icon:l.outputting?"power-off":"times",content:l.outputting?"Open":"Closed",selected:l.outputting,onClick:function(){return n("output")}})}),(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Output Pressure",children:(0,o.createComponentVNode)(2,c.NumberInput,{value:parseFloat(l.outputPressure),unit:"kPa",width:"75px",minValue:0,maxValue:4500,step:10,suppressFlicker:2e3,onChange:function(e,t){return n("pressure",{pressure:t})}})})]})})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.AtmosFilter=void 0;var o=n(0),r=n(3),a=n(2),i=n(33);t.AtmosFilter=function(e){var t=(0,r.useBackend)(e),n=t.act,c=t.data,l=c.filter_types||[];return(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Power",children:(0,o.createComponentVNode)(2,a.Button,{icon:c.on?"power-off":"times",content:c.on?"On":"Off",selected:c.on,onClick:function(){return n("power")}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Transfer Rate",children:[(0,o.createComponentVNode)(2,a.NumberInput,{animated:!0,value:parseFloat(c.rate),width:"63px",unit:"L/s",minValue:0,maxValue:200,onDrag:function(e,t){return n("rate",{rate:t})}}),(0,o.createComponentVNode)(2,a.Button,{ml:1,icon:"plus",content:"Max",disabled:c.rate===c.max_rate,onClick:function(){return n("rate",{rate:"max"})}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Filter",children:l.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{selected:e.selected,content:(0,i.getGasLabel)(e.id,e.name),onClick:function(){return n("filter",{mode:e.id})}},e.id)}))})]})})}},function(e,t,n){"use strict";t.__esModule=!0,t.AtmosMixer=void 0;var o=n(0),r=n(3),a=n(2);t.AtmosMixer=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Power",children:(0,o.createComponentVNode)(2,a.Button,{icon:i.on?"power-off":"times",content:i.on?"On":"Off",selected:i.on,onClick:function(){return n("power")}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Output Pressure",children:[(0,o.createComponentVNode)(2,a.NumberInput,{animated:!0,value:parseFloat(i.set_pressure),unit:"kPa",width:"75px",minValue:0,maxValue:4500,step:10,onChange:function(e,t){return n("pressure",{pressure:t})}}),(0,o.createComponentVNode)(2,a.Button,{ml:1,icon:"plus",content:"Max",disabled:i.set_pressure===i.max_pressure,onClick:function(){return n("pressure",{pressure:"max"})}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Node 1",children:(0,o.createComponentVNode)(2,a.NumberInput,{animated:!0,value:i.node1_concentration,unit:"%",width:"60px",minValue:0,maxValue:100,stepPixelSize:2,onDrag:function(e,t){return n("node1",{concentration:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Node 2",children:(0,o.createComponentVNode)(2,a.NumberInput,{animated:!0,value:i.node2_concentration,unit:"%",width:"60px",minValue:0,maxValue:100,stepPixelSize:2,onDrag:function(e,t){return n("node2",{concentration:t})}})})]})})}},function(e,t,n){"use strict";t.__esModule=!0,t.AtmosPump=void 0;var o=n(0),r=n(3),a=n(2);t.AtmosPump=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Power",children:(0,o.createComponentVNode)(2,a.Button,{icon:i.on?"power-off":"times",content:i.on?"On":"Off",selected:i.on,onClick:function(){return n("power")}})}),i.max_rate?(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Transfer Rate",children:[(0,o.createComponentVNode)(2,a.NumberInput,{animated:!0,value:parseFloat(i.rate),width:"63px",unit:"L/s",minValue:0,maxValue:200,onChange:function(e,t){return n("rate",{rate:t})}}),(0,o.createComponentVNode)(2,a.Button,{ml:1,icon:"plus",content:"Max",disabled:i.rate===i.max_rate,onClick:function(){return n("rate",{rate:"max"})}})]}):(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Output Pressure",children:[(0,o.createComponentVNode)(2,a.NumberInput,{animated:!0,value:parseFloat(i.pressure),unit:"kPa",width:"75px",minValue:0,maxValue:4500,step:10,onChange:function(e,t){return n("pressure",{pressure:t})}}),(0,o.createComponentVNode)(2,a.Button,{ml:1,icon:"plus",content:"Max",disabled:i.pressure===i.max_pressure,onClick:function(){return n("pressure",{pressure:"max"})}})]})]})})}},function(e,t,n){"use strict";t.__esModule=!0,t.BankMachine=void 0;var o=n(0),r=n(3),a=n(2);t.BankMachine=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.current_balance,l=i.siphoning,u=i.station_name;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:u+" Vault",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Current Balance",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:l?"times":"sync",content:l?"Stop Siphoning":"Siphon Credits",selected:l,onClick:function(){return n(l?"halt":"siphon")}}),children:c+" cr"})})}),(0,o.createComponentVNode)(2,a.NoticeBox,{textAlign:"center",children:"Authorized personnel only"})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.BluespaceArtillery=void 0;var o=n(0),r=n(3),a=n(2);t.BluespaceArtillery=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.notice,l=i.connected,u=i.unlocked,d=i.target;return(0,o.createFragment)([!!c&&(0,o.createComponentVNode)(2,a.NoticeBox,{children:c}),l?(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Target",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"crosshairs",disabled:!u,onClick:function(){return n("recalibrate")}}),children:(0,o.createComponentVNode)(2,a.Box,{color:d?"average":"bad",fontSize:"25px",children:d||"No Target Set"})}),(0,o.createComponentVNode)(2,a.Section,{children:u?(0,o.createComponentVNode)(2,a.Box,{style:{margin:"auto"},children:(0,o.createComponentVNode)(2,a.Button,{fluid:!0,content:"FIRE",color:"bad",disabled:!d,fontSize:"30px",textAlign:"center",lineHeight:"46px",onClick:function(){return n("fire")}})}):(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Box,{color:"bad",fontSize:"18px",children:"Bluespace artillery is currently locked."}),(0,o.createComponentVNode)(2,a.Box,{mt:1,children:"Awaiting authorization via keycard reader from at minimum two station heads."})],4)})],4):(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Maintenance",children:(0,o.createComponentVNode)(2,a.Button,{icon:"wrench",content:"Complete Deployment",onClick:function(){return n("build")}})})})})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.Bepis=void 0;var o=n(0),r=(n(24),n(16)),a=n(2);t.Bepis=function(e){var t=e.state,n=t.config,i=t.data,c=n.ref,l=i.amount;return(0,o.createComponentVNode)(2,a.Section,{title:"Business Exploration Protocol Incubation Sink",children:[(0,o.createComponentVNode)(2,a.Section,{title:"Information",backgroundColor:"#450F44",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"power-off",content:i.manual_power?"Off":"On",selected:!i.manual_power,onClick:function(){return(0,r.act)(c,"toggle_power")}}),children:"All you need to know about the B.E.P.I.S. and you! The B.E.P.I.S. performs hundreds of tests a second using electrical and financial resources to invent new products, or discover new technologies otherwise overlooked for being too risky or too niche to produce!"}),(0,o.createComponentVNode)(2,a.Section,{title:"Payer's Account",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"redo-alt",content:"Reset Account",onClick:function(){return(0,r.act)(c,"account_reset")}}),children:["Console is currently being operated by ",i.account_owner?i.account_owner:"no one","."]}),(0,o.createComponentVNode)(2,a.Grid,{children:[(0,o.createComponentVNode)(2,a.Grid.Column,{size:1.5,children:[(0,o.createComponentVNode)(2,a.Section,{title:"Stored Data and Statistics",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Deposited Credits",children:i.stored_cash}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Investment Variability",children:[i.accuracy_percentage,"%"]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Innovation Bonus",children:i.positive_cash_offset}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Risk Offset",color:"bad",children:i.negative_cash_offset}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Deposit Amount",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:l,unit:"Credits",minValue:100,maxValue:3e4,step:100,stepPixelSize:2,onChange:function(e,t){return(0,r.act)(c,"amount",{amount:t})}})})]})}),(0,o.createComponentVNode)(2,a.Box,{children:[(0,o.createComponentVNode)(2,a.Button,{icon:"donate",content:"Deposit Credits",disabled:1===i.manual_power||1===i.silicon_check,onClick:function(){return(0,r.act)(c,"deposit_cash")}}),(0,o.createComponentVNode)(2,a.Button,{icon:"eject",content:"Withdraw Credits",disabled:1===i.manual_power,onClick:function(){return(0,r.act)(c,"withdraw_cash")}})]})]}),(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.Section,{title:"Market Data and Analysis",children:[(0,o.createComponentVNode)(2,a.Box,{children:["Average technology cost: ",i.mean_value]}),(0,o.createComponentVNode)(2,a.Box,{children:["Current chance of Success: Est. ",i.success_estimate,"%"]}),i.error_name&&(0,o.createComponentVNode)(2,a.Box,{color:"bad",children:"Previous Failure Reason: Deposited cash value too low. Please insert more money for future success."}),(0,o.createComponentVNode)(2,a.Box,{m:1}),(0,o.createComponentVNode)(2,a.Button,{icon:"microscope",disabled:1===i.manual_power,onClick:function(){return(0,r.act)(c,"begin_experiment")},content:"Begin Testing"})]})})]})]})}},function(e,t,n){"use strict";t.__esModule=!0,t.BorgPanel=void 0;var o=n(0),r=n(3),a=n(2);t.BorgPanel=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.borg||{},l=i.cell||{},u=l.charge/l.maxcharge,d=i.channels||[],s=i.modules||[],p=i.upgrades||[],m=i.ais||[],f=i.laws||[];return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:c.name,buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"pencil-alt",content:"Rename",onClick:function(){return n("rename")}}),children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Status",children:[(0,o.createComponentVNode)(2,a.Button,{icon:c.emagged?"check-square-o":"square-o",content:"Emagged",selected:c.emagged,onClick:function(){return n("toggle_emagged")}}),(0,o.createComponentVNode)(2,a.Button,{icon:c.lockdown?"check-square-o":"square-o",content:"Locked Down",selected:c.lockdown,onClick:function(){return n("toggle_lockdown")}}),(0,o.createComponentVNode)(2,a.Button,{icon:c.scrambledcodes?"check-square-o":"square-o",content:"Scrambled Codes",selected:c.scrambledcodes,onClick:function(){return n("toggle_scrambledcodes")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Charge",children:[l.missing?(0,o.createVNode)(1,"span","color-bad","No cell installed",16):(0,o.createComponentVNode)(2,a.ProgressBar,{value:u,content:l.charge+" / "+l.maxcharge}),(0,o.createVNode)(1,"br"),(0,o.createComponentVNode)(2,a.Button,{icon:"pencil-alt",content:"Set",onClick:function(){return n("set_charge")}}),(0,o.createComponentVNode)(2,a.Button,{icon:"eject",content:"Change",onClick:function(){return n("change_cell")}}),(0,o.createComponentVNode)(2,a.Button,{icon:"trash",content:"Remove",color:"bad",onClick:function(){return n("remove_cell")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Radio Channels",children:d.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{icon:e.installed?"check-square-o":"square-o",content:e.name,selected:e.installed,onClick:function(){return n("toggle_radio",{channel:e.name})}},e.name)}))}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Module",children:s.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{icon:c.active_module===e.type?"check-square-o":"square-o",content:e.name,selected:c.active_module===e.type,onClick:function(){return n("setmodule",{module:e.type})}},e.type)}))}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Upgrades",children:p.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{icon:e.installed?"check-square-o":"square-o",content:e.name,selected:e.installed,onClick:function(){return n("toggle_upgrade",{upgrade:e.type})}},e.type)}))}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Master AI",children:m.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{icon:e.connected?"check-square-o":"square-o",content:e.name,selected:e.connected,onClick:function(){return n("slavetoai",{slavetoai:e.ref})}},e.ref)}))})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Laws",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:c.lawupdate?"check-square-o":"square-o",content:"Lawsync",selected:c.lawupdate,onClick:function(){return n("toggle_lawupdate")}}),children:f.map((function(e){return(0,o.createComponentVNode)(2,a.Box,{children:e},e)}))})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.BrigTimer=void 0;var o=n(0),r=n(3),a=n(2);t.BrigTimer=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createComponentVNode)(2,a.Section,{title:"Cell Timer",buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{icon:"clock-o",content:i.timing?"Stop":"Start",selected:i.timing,onClick:function(){return n(i.timing?"stop":"start")}}),(0,o.createComponentVNode)(2,a.Button,{icon:"lightbulb-o",content:i.flash_charging?"Recharging":"Flash",disabled:i.flash_charging,onClick:function(){return n("flash")}})],4),children:[(0,o.createComponentVNode)(2,a.Button,{icon:"fast-backward",onClick:function(){return n("time",{adjust:-600})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"backward",onClick:function(){return n("time",{adjust:-100})}})," ",String(i.minutes).padStart(2,"0"),":",String(i.seconds).padStart(2,"0")," ",(0,o.createComponentVNode)(2,a.Button,{icon:"forward",onClick:function(){return n("time",{adjust:100})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"fast-forward",onClick:function(){return n("time",{adjust:600})}}),(0,o.createVNode)(1,"br"),(0,o.createComponentVNode)(2,a.Button,{icon:"hourglass-start",content:"Short",onClick:function(){return n("preset",{preset:"short"})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"hourglass-start",content:"Medium",onClick:function(){return n("preset",{preset:"medium"})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"hourglass-start",content:"Long",onClick:function(){return n("preset",{preset:"long"})}})]})}},function(e,t,n){"use strict";t.__esModule=!0,t.Canvas=void 0;var o=n(0),r=n(3),a=n(2);n(11);var i=function(e){var t,n;function r(t){var n;return(n=e.call(this,t)||this).canvasRef=(0,o.createRef)(),n.onCVClick=t.onCanvasClick,n}n=e,(t=r).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n;var a=r.prototype;return a.componentDidMount=function(){this.drawCanvas(this.props)},a.componentDidUpdate=function(){this.drawCanvas(this.props)},a.drawCanvas=function(e){var t=this.canvasRef.current.getContext("2d"),n=e.value,o=n.length;if(o){var r=n[0].length,a=Math.round(this.canvasRef.current.width/o),i=Math.round(this.canvasRef.current.height/r);t.save(),t.scale(a,i);for(var c=0;c=0||(r[n]=e[n]);return r}(t,["res","value","px_per_unit"]),c=n.length*a,l=0!==c?n[0].length*a:0;return(0,o.normalizeProps)((0,o.createVNode)(1,"canvas",null,"Canvas failed to render.",16,Object.assign({width:c||300,height:l||300},i,{onClick:function(t){return e.clickwrapper(t)}}),null,this.canvasRef))},r}(o.Component);t.Canvas=function(e){var t=(0,r.useBackend)(e),n=t.act,c=t.data;return(0,o.createComponentVNode)(2,a.Box,{textAlign:"center",children:[(0,o.createComponentVNode)(2,i,{value:c.grid,onCanvasClick:function(e,t){return n("paint",{x:e,y:t})}}),(0,o.createComponentVNode)(2,a.Box,{children:[!c.finalized&&(0,o.createComponentVNode)(2,a.Button.Confirm,{onClick:function(){return n("finalize")},content:"Finalize"}),c.name]})]})}},function(e,t,n){"use strict";t.__esModule=!0,t.Canister=void 0;var o=n(0),r=n(3),a=n(2);t.Canister=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.NoticeBox,{children:["The regulator ",i.hasHoldingTank?"is":"is not"," connected to a tank."]}),(0,o.createComponentVNode)(2,a.Section,{title:"Canister",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"pencil-alt",content:"Relabel",onClick:function(){return n("relabel")}}),children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Pressure",children:[(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:i.tankPressure})," kPa"]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Port",color:i.portConnected?"good":"average",content:i.portConnected?"Connected":"Not Connected"}),!!i.isPrototype&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Access",children:(0,o.createComponentVNode)(2,a.Button,{icon:i.restricted?"lock":"unlock",color:"caution",content:i.restricted?"Restricted to Engineering":"Public",onClick:function(){return n("restricted")}})})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Valve",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Release Pressure",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:i.releasePressure/(i.maxReleasePressure-i.minReleasePressure),children:[(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:i.releasePressure})," kPa"]})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Pressure Regulator",children:[(0,o.createComponentVNode)(2,a.Button,{icon:"undo",disabled:i.releasePressure===i.defaultReleasePressure,content:"Reset",onClick:function(){return n("pressure",{pressure:"reset"})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"minus",disabled:i.releasePressure<=i.minReleasePressure,content:"Min",onClick:function(){return n("pressure",{pressure:"min"})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"pencil-alt",content:"Set",onClick:function(){return n("pressure",{pressure:"input"})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"plus",disabled:i.releasePressure>=i.maxReleasePressure,content:"Max",onClick:function(){return n("pressure",{pressure:"max"})}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Valve",children:(0,o.createComponentVNode)(2,a.Button,{icon:i.valveOpen?"unlock":"lock",color:i.valveOpen?i.hasHoldingTank?"caution":"danger":null,content:i.valveOpen?"Open":"Closed",onClick:function(){return n("valve")}})})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Holding Tank",buttons:!!i.hasHoldingTank&&(0,o.createComponentVNode)(2,a.Button,{icon:"eject",color:i.valveOpen&&"danger",content:"Eject",onClick:function(){return n("eject")}}),children:[!!i.hasHoldingTank&&(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Label",children:i.holdingTank.name}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Pressure",children:[(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:i.holdingTank.tankPressure})," kPa"]})]}),!i.hasHoldingTank&&(0,o.createComponentVNode)(2,a.Box,{color:"average",children:"No Holding Tank"})]})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.CargoExpress=t.Cargo=void 0;var o=n(0),r=n(25),a=n(16),i=n(2),c=n(70);t.Cargo=function(e){var t=e.state,n=t.config,r=t.data,c=n.ref,s=r.supplies||{},p=r.requests||[],m=r.cart||[],f=m.reduce((function(e,t){return e+t.cost}),0),h=!r.requestonly&&(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Box,{inline:!0,mx:1,children:[0===m.length&&"Cart is empty",1===m.length&&"1 item",m.length>=2&&m.length+" items"," ",f>0&&"("+f+" cr)"]}),(0,o.createComponentVNode)(2,i.Button,{icon:"times",color:"transparent",content:"Clear",onClick:function(){return(0,a.act)(c,"clear")}})],4);return(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Section,{title:"Cargo",buttons:(0,o.createComponentVNode)(2,i.Box,{inline:!0,bold:!0,children:[(0,o.createComponentVNode)(2,i.AnimatedNumber,{value:Math.round(r.points)})," credits"]}),children:(0,o.createComponentVNode)(2,i.LabeledList,{children:[(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Shuttle",children:r.docked&&!r.requestonly&&(0,o.createComponentVNode)(2,i.Button,{content:r.location,onClick:function(){return(0,a.act)(c,"send")}})||r.location}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"CentCom Message",children:r.message}),r.loan&&!r.requestonly?(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Loan",children:r.loan_dispatched?(0,o.createComponentVNode)(2,i.Box,{color:"bad",children:"Loaned to Centcom"}):(0,o.createComponentVNode)(2,i.Button,{content:"Loan Shuttle",disabled:!(r.away&&r.docked),onClick:function(){return(0,a.act)(c,"loan")}})}):""]})}),(0,o.createComponentVNode)(2,i.Tabs,{mt:2,children:[(0,o.createComponentVNode)(2,i.Tabs.Tab,{label:"Catalog",icon:"list",lineHeight:"23px",children:function(){return(0,o.createComponentVNode)(2,i.Section,{title:"Catalog",buttons:(0,o.createFragment)([h,(0,o.createComponentVNode)(2,i.Button,{ml:1,icon:r.self_paid?"check-square-o":"square-o",content:"Buy Privately",selected:r.self_paid,onClick:function(){return(0,a.act)(c,"toggleprivate")}})],0),children:(0,o.createComponentVNode)(2,l,{state:t,supplies:s})})}},"catalog"),(0,o.createComponentVNode)(2,i.Tabs.Tab,{label:"Requests ("+p.length+")",icon:"envelope",highlight:p.length>0,lineHeight:"23px",children:function(){return(0,o.createComponentVNode)(2,i.Section,{title:"Active Requests",buttons:!r.requestonly&&(0,o.createComponentVNode)(2,i.Button,{icon:"times",content:"Clear",color:"transparent",onClick:function(){return(0,a.act)(c,"denyall")}}),children:(0,o.createComponentVNode)(2,u,{state:t,requests:p})})}},"requests"),!r.requestonly&&(0,o.createComponentVNode)(2,i.Tabs.Tab,{label:"Checkout ("+m.length+")",icon:"shopping-cart",highlight:m.length>0,lineHeight:"23px",children:function(){return(0,o.createComponentVNode)(2,i.Section,{title:"Current Cart",buttons:h,children:(0,o.createComponentVNode)(2,d,{state:t,cart:m})})}},"cart")]})],4)};var l=function(e){var t=e.state,n=e.supplies,c=t.config,l=t.data,u=c.ref,d=function(e){var t=n[e].packs;return(0,o.createVNode)(1,"table","LabeledList",t.map((function(e){return(0,o.createVNode)(1,"tr","LabeledList__row candystripe",[(0,o.createVNode)(1,"td","LabeledList__cell LabeledList__label",[e.name,(0,o.createTextVNode)(":")],0),(0,o.createVNode)(1,"td","LabeledList__cell",!!e.private_goody&&(0,o.createFragment)([(0,o.createTextVNode)("Private Only")],4),0),(0,o.createVNode)(1,"td","LabeledList__cell",!!e.goody&&(0,o.createFragment)([(0,o.createTextVNode)("Small Item")],4),0),(0,o.createVNode)(1,"td","LabeledList__cell",!!e.access&&(0,o.createFragment)([(0,o.createTextVNode)("Restrictions Apply")],4),0),(0,o.createVNode)(1,"td","LabeledList__cell LabeledList__buttons",(0,o.createComponentVNode)(2,i.Button,{fluid:!0,disabled:l.self_paid&&!e.can_private_buy&&!l.emagged,content:(!l.self_paid||e.private_goody||e.goody?e.cost:Math.round(1.1*e.cost))+" cr",tooltip:e.desc,tooltipPosition:"left",onClick:function(){return(0,a.act)(u,"add",{id:e.id})}}),2)],4,null,e.name)})),0)};return(0,o.createComponentVNode)(2,i.Tabs,{vertical:!0,children:(0,r.map)((function(e){var t=e.name;return(0,o.createComponentVNode)(2,i.Tabs.Tab,{label:t,children:d},t)}))(n)})},u=function(e){var t=e.state,n=e.requests,r=t.config,c=t.data,l=r.ref;return 0===n.length?(0,o.createComponentVNode)(2,i.Box,{color:"good",children:"No Requests"}):(0,o.createVNode)(1,"table","LabeledList",n.map((function(e){return(0,o.createFragment)([(0,o.createVNode)(1,"tr","LabeledList__row candystripe",[(0,o.createVNode)(1,"td","LabeledList__cell LabeledList__label",[(0,o.createTextVNode)("#"),e.id,(0,o.createTextVNode)(":")],0),(0,o.createVNode)(1,"td","LabeledList__cell LabeledList__content",e.object,0),(0,o.createVNode)(1,"td","LabeledList__cell",[(0,o.createTextVNode)("By "),(0,o.createVNode)(1,"b",null,e.orderer,0)],4),(0,o.createVNode)(1,"td","LabeledList__cell",(0,o.createVNode)(1,"i",null,e.reason,0),2),(0,o.createVNode)(1,"td","LabeledList__cell LabeledList__buttons",[e.cost,(0,o.createTextVNode)(" credits"),(0,o.createTextVNode)(" "),!c.requestonly&&(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Button,{icon:"check",color:"good",onClick:function(){return(0,a.act)(l,"approve",{id:e.id})}}),(0,o.createComponentVNode)(2,i.Button,{icon:"times",color:"bad",onClick:function(){return(0,a.act)(l,"deny",{id:e.id})}})],4)],0)],4)],4,e.id)})),0)},d=function(e){var t=e.state,n=e.cart,r=t.config,c=t.data,l=r.ref;return(0,o.createFragment)([0===n.length&&"Nothing in cart",n.length>0&&(0,o.createComponentVNode)(2,i.LabeledList,{children:n.map((function(e){return(0,o.createComponentVNode)(2,i.LabeledList.Item,{className:"candystripe",label:"#"+e.id,buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Box,{inline:!0,mx:2,children:[!!e.paid&&(0,o.createVNode)(1,"b",null,"[Paid Privately]",16)," ",e.cost," credits"]}),(0,o.createComponentVNode)(2,i.Button,{icon:"minus",onClick:function(){return(0,a.act)(l,"remove",{id:e.id})}})],4),children:e.object},e.id)}))}),n.length>0&&!c.requestonly&&(0,o.createComponentVNode)(2,i.Box,{mt:2,children:1===c.away&&1===c.docked&&(0,o.createComponentVNode)(2,i.Button,{color:"green",style:{"line-height":"28px",padding:"0 12px"},content:"Confirm the order",onClick:function(){return(0,a.act)(l,"send")}})||(0,o.createComponentVNode)(2,i.Box,{opacity:.5,children:["Shuttle in ",c.location,"."]})})],0)};t.CargoExpress=function(e){var t=e.state,n=t.config,r=t.data,u=n.ref,d=r.supplies||{};return(0,o.createFragment)([(0,o.createComponentVNode)(2,c.InterfaceLockNoticeBox,{siliconUser:r.siliconUser,locked:r.locked,onLockStatusChange:function(){return(0,a.act)(u,"lock")},accessText:"a QM-level ID card"}),!r.locked&&(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Section,{title:"Cargo Express",buttons:(0,o.createComponentVNode)(2,i.Box,{inline:!0,bold:!0,children:[(0,o.createComponentVNode)(2,i.AnimatedNumber,{value:Math.round(r.points)})," credits"]}),children:(0,o.createComponentVNode)(2,i.LabeledList,{children:[(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Landing Location",children:[(0,o.createComponentVNode)(2,i.Button,{content:"Cargo Bay",selected:!r.usingBeacon,onClick:function(){return(0,a.act)(u,"LZCargo")}}),(0,o.createComponentVNode)(2,i.Button,{selected:r.usingBeacon,disabled:!r.hasBeacon,onClick:function(){return(0,a.act)(u,"LZBeacon")},children:[r.beaconzone," (",r.beaconName,")"]}),(0,o.createComponentVNode)(2,i.Button,{content:r.printMsg,disabled:!r.canBuyBeacon,onClick:function(){return(0,a.act)(u,"printBeacon")}})]}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Notice",children:r.message})]})}),(0,o.createComponentVNode)(2,l,{state:t,supplies:d})],4)],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.CellularEmporium=void 0;var o=n(0),r=n(3),a=n(2);t.CellularEmporium=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.abilities;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Genetic Points",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"undo",content:"Readapt",disabled:!i.can_readapt,onClick:function(){return n("readapt")}}),children:i.genetic_points_remaining})})}),(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:c.map((function(e){return(0,o.createComponentVNode)(2,a.LabeledList.Item,{className:"candystripe",label:e.name,buttons:(0,o.createFragment)([e.dna_cost," ",(0,o.createComponentVNode)(2,a.Button,{content:e.owned?"Evolved":"Evolve",selected:e.owned,onClick:function(){return n("evolve",{name:e.name})}})],0),children:[e.desc,(0,o.createComponentVNode)(2,a.Box,{color:"good",children:e.helptext})]},e.name)}))})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.CentcomPodLauncher=void 0;var o=n(0),r=(n(24),n(3)),a=n(2);t.CentcomPodLauncher=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.NoticeBox,{children:"To use this, simply spawn the atoms you want in one of the five Centcom Supplypod Bays. Items in the bay will then be launched inside your supplypod, one turf-full at a time! You can optionally use the following buttons to configure how the supplypod acts."}),(0,o.createComponentVNode)(2,a.Section,{title:"Centcom Pod Customization (To be used against Helen Weinstein)",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Supply Bay",children:[(0,o.createComponentVNode)(2,a.Button,{content:"Bay #1",selected:1===i.bayNumber,onClick:function(){return n("bay1")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Bay #2",selected:2===i.bayNumber,onClick:function(){return n("bay2")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Bay #3",selected:3===i.bayNumber,onClick:function(){return n("bay3")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Bay #4",selected:4===i.bayNumber,onClick:function(){return n("bay4")}}),(0,o.createComponentVNode)(2,a.Button,{content:"ERT Bay",selected:5===i.bayNumber,tooltip:"This bay is located on the western edge of CentCom. Its the\nglass room directly west of where ERT spawn, and south of the\nCentCom ferry. Useful for launching ERT/Deathsquads/etc. onto\nthe station via drop pods.",onClick:function(){return n("bay5")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Teleport to",children:[(0,o.createComponentVNode)(2,a.Button,{content:i.bay,onClick:function(){return n("teleportCentcom")}}),(0,o.createComponentVNode)(2,a.Button,{content:i.oldArea?i.oldArea:"Where you were",disabled:!i.oldArea,onClick:function(){return n("teleportBack")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Clone Mode",children:(0,o.createComponentVNode)(2,a.Button,{content:"Launch Clones",selected:i.launchClone,tooltip:"Choosing this will create a duplicate of the item to be\nlaunched in Centcom, allowing you to send one type of item\nmultiple times. Either way, the atoms are forceMoved into\nthe supplypod after it lands (but before it opens).",onClick:function(){return n("launchClone")}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Launch style",children:[(0,o.createComponentVNode)(2,a.Button,{content:"Ordered",selected:1===i.launchChoice,tooltip:'Instead of launching everything in the bay at once, this\nwill "scan" things (one turf-full at a time) in order, left\nto right and top to bottom. undoing will reset the "scanner"\nto the top-leftmost position.',onClick:function(){return n("launchOrdered")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Random",selected:2===i.launchChoice,tooltip:"Instead of launching everything in the bay at once, this\nwill launch one random turf of items at a time.",onClick:function(){return n("launchRandom")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Explosion",children:[(0,o.createComponentVNode)(2,a.Button,{content:"Custom Size",selected:1===i.explosionChoice,tooltip:"This will cause an explosion of whatever size you like\n(including flame range) to occur as soon as the supplypod\nlands. Dont worry, supply-pods are explosion-proof!",onClick:function(){return n("explosionCustom")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Adminbus",selected:2===i.explosionChoice,tooltip:"This will cause a maxcap explosion (dependent on server\nconfig) to occur as soon as the supplypod lands. Dont worry,\nsupply-pods are explosion-proof!",onClick:function(){return n("explosionBus")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Damage",children:[(0,o.createComponentVNode)(2,a.Button,{content:"Custom Damage",selected:1===i.damageChoice,tooltip:"Anyone caught under the pod when it lands will be dealt\nthis amount of brute damage. Sucks to be them!",onClick:function(){return n("damageCustom")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Gib",selected:2===i.damageChoice,tooltip:"This will attempt to gib any mob caught under the pod when\nit lands, as well as dealing a nice 5000 brute damage. Ya\nknow, just to be sure!",onClick:function(){return n("damageGib")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Effects",children:[(0,o.createComponentVNode)(2,a.Button,{content:"Stun",selected:i.effectStun,tooltip:"Anyone who is on the turf when the supplypod is launched\nwill be stunned until the supplypod lands. They cant get\naway that easy!",onClick:function(){return n("effectStun")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Delimb",selected:i.effectLimb,tooltip:"This will cause anyone caught under the pod to lose a limb,\nexcluding their head.",onClick:function(){return n("effectLimb")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Yeet Organs",selected:i.effectOrgans,tooltip:"This will cause anyone caught under the pod to lose all\ntheir limbs and organs in a spectacular fashion.",onClick:function(){return n("effectOrgans")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Movement",children:[(0,o.createComponentVNode)(2,a.Button,{content:"Bluespace",selected:i.effectBluespace,tooltip:"Gives the supplypod an advanced Bluespace Recyling Device.\nAfter opening, the supplypod will be warped directly to the\nsurface of a nearby NT-designated trash planet (/r/ss13).",onClick:function(){return n("effectBluespace")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Stealth",selected:i.effectStealth,tooltip:'This hides the red target icon from appearing when you\nlaunch the supplypod. Combos well with the "Invisible"\nstyle. Sneak attack, go!',onClick:function(){return n("effectStealth")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Quiet",selected:i.effectQuiet,tooltip:"This will keep the supplypod from making any sounds, except\nfor those specifically set by admins in the Sound section.",onClick:function(){return n("effectQuiet")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Reverse Mode",selected:i.effectReverse,tooltip:"This pod will not send any items. Instead, after landing,\nthe supplypod will close (similar to a normal closet closing),\nand then launch back to the right centcom bay to drop off any\nnew contents.",onClick:function(){return n("effectReverse")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Missile Mode",selected:i.effectMissile,tooltip:"This pod will not send any items. Instead, it will immediately\ndelete after landing (Similar visually to setting openDelay\n& departDelay to 0, but this looks nicer). Useful if you just\nwanna fuck some shit up. Combos well with the Missile style.",onClick:function(){return n("effectMissile")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Any Descent Angle",selected:i.effectCircle,tooltip:"This will make the supplypod come in from any angle. Im not\nsure why this feature exists, but here it is.",onClick:function(){return n("effectCircle")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Machine Gun Mode",selected:i.effectBurst,tooltip:"This will make each click launch 5 supplypods inaccuratly\naround the target turf (a 3x3 area). Combos well with the\nMissile Mode if you dont want shit lying everywhere after.",onClick:function(){return n("effectBurst")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Specific Target",selected:i.effectTarget,tooltip:"This will make the supplypod target a specific atom, instead\nof the mouses position. Smiting does this automatically!",onClick:function(){return n("effectTarget")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Name/Desc",children:[(0,o.createComponentVNode)(2,a.Button,{content:"Custom Name/Desc",selected:i.effectName,tooltip:"Allows you to add a custom name and description.",onClick:function(){return n("effectName")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Alert Ghosts",selected:i.effectAnnounce,tooltip:"Alerts ghosts when a pod is launched. Useful if some dumb\nshit is aboutta come outta the pod.",onClick:function(){return n("effectAnnounce")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Sound",children:[(0,o.createComponentVNode)(2,a.Button,{content:"Custom Falling Sound",selected:i.fallingSound,tooltip:"Choose a sound to play as the pod falls. Note that for this\nto work right you should know the exact length of the sound,\nin seconds.",onClick:function(){return n("fallSound")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Custom Landing Sound",selected:i.landingSound,tooltip:"Choose a sound to play when the pod lands.",onClick:function(){return n("landingSound")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Custom Opening Sound",selected:i.openingSound,tooltip:"Choose a sound to play when the pod opens.",onClick:function(){return n("openingSound")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Custom Leaving Sound",selected:i.leavingSound,tooltip:"Choose a sound to play when the pod departs (whether that be\ndelection in the case of a bluespace pod, or leaving for\ncentcom for a reversing pod).",onClick:function(){return n("leavingSound")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Admin Sound Volume",selected:i.soundVolume,tooltip:"Choose the volume for the sound to play at. Default values\nare between 1 and 100, but hey, do whatever. Im a tooltip,\nnot a cop.",onClick:function(){return n("soundVolume")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Timers",children:[(0,o.createComponentVNode)(2,a.Button,{content:"Custom Falling Duration",selected:4!==i.fallDuration,tooltip:"Set how long the animation for the pod falling lasts. Create\ndramatic, slow falling pods!",onClick:function(){return n("fallDuration")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Custom Landing Time",selected:20!==i.landingDelay,tooltip:"Choose the amount of time it takes for the supplypod to hit\nthe station. By default this value is 0.5 seconds.",onClick:function(){return n("landingDelay")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Custom Opening Time",selected:30!==i.openingDelay,tooltip:"Choose the amount of time it takes for the supplypod to open\nafter landing. Useful for giving whatevers inside the pod a\nnice dramatic entrance! By default this value is 3 seconds.",onClick:function(){return n("openingDelay")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Custom Leaving Time",selected:30!==i.departureDelay,tooltip:"Choose the amount of time it takes for the supplypod to leave\nafter landing. By default this value is 3 seconds.",onClick:function(){return n("departureDelay")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Style",children:[(0,o.createComponentVNode)(2,a.Button,{content:"Standard",selected:1===i.styleChoice,tooltip:"Same color scheme as the normal station-used supplypods",onClick:function(){return n("styleStandard")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Advanced",selected:2===i.styleChoice,tooltip:"The same as the stations upgraded blue-and-white\nBluespace Supplypods",onClick:function(){return n("styleBluespace")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Syndicate",selected:4===i.styleChoice,tooltip:"A menacing black and blood-red. Great for sending meme-ops\nin style!",onClick:function(){return n("styleSyndie")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Deathsquad",selected:5===i.styleChoice,tooltip:"A menacing black and dark blue. Great for sending deathsquads\nin style!",onClick:function(){return n("styleBlue")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Cult Pod",selected:6===i.styleChoice,tooltip:"A blood and rune covered cult pod!",onClick:function(){return n("styleCult")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Missile",selected:7===i.styleChoice,tooltip:"A large missile. Combos well with a missile mode, so the\nmissile doesnt stick around after landing.",onClick:function(){return n("styleMissile")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Syndicate Missile",selected:8===i.styleChoice,tooltip:"A large blood-red missile. Combos well with missile mode,\nso the missile doesnt stick around after landing.",onClick:function(){return n("styleSMissile")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Supply Crate",selected:9===i.styleChoice,tooltip:"A large, dark-green military supply crate.",onClick:function(){return n("styleBox")}}),(0,o.createComponentVNode)(2,a.Button,{content:"HONK",selected:10===i.styleChoice,tooltip:"A colorful, clown inspired look.",onClick:function(){return n("styleHONK")}}),(0,o.createComponentVNode)(2,a.Button,{content:"~Fruit",selected:11===i.styleChoice,tooltip:"For when an orange is angry",onClick:function(){return n("styleFruit")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Invisible",selected:12===i.styleChoice,tooltip:'Makes the supplypod invisible! Useful for when you want to\nuse this feature with a gateway or something. Combos well\nwith the "Stealth" and "Quiet Landing" effects.',onClick:function(){return n("styleInvisible")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Gondola",selected:13===i.styleChoice,tooltip:"This gondola can control when he wants to deliver his supplies\nif he has a smart enough mind, so offer up his body to ghosts\nfor maximum enjoyment. (Make sure to turn off bluespace and\nset a arbitrarily high open-time if you do!",onClick:function(){return n("styleGondola")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Show Contents (See Through Pod)",selected:14===i.styleChoice,tooltip:"By selecting this, the pod will instead look like whatevers\ninside it (as if it were the contents falling by themselves,\nwithout a pod). Useful for launching mechs at the station\nand standing tall as they soar in from the heavens.",onClick:function(){return n("styleSeeThrough")}})]})]})}),(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:i.numObjects+" turfs in "+i.bay,buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{content:"undo Pody Bay",tooltip:"Manually undoes the possible things to launch in the\npod bay.",onClick:function(){return n("undo")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Enter Launch Mode",selected:i.giveLauncher,tooltip:"THE CODEX ASTARTES CALLS THIS MANEUVER: STEEL RAIN",onClick:function(){return n("giveLauncher")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Clear Selected Bay",color:"bad",tooltip:"This will delete all objs and mobs from the selected bay.",tooltipPosition:"left",onClick:function(){return n("clearBay")}})],4)})})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.ChemAcclimator=void 0;var o=n(0),r=n(3),a=n(2);t.ChemAcclimator=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Acclimator",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Current Temperature",children:[i.chem_temp," K"]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Target Temperature",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:i.target_temperature,unit:"K",width:"59px",minValue:0,maxValue:1e3,step:5,stepPixelSize:2,onChange:function(e,t){return n("set_target_temperature",{temperature:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Acceptable Temp. Difference",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:i.allowed_temperature_difference,unit:"K",width:"59px",minValue:1,maxValue:i.target_temperature,stepPixelSize:2,onChange:function(e,t){n("set_allowed_temperature_difference",{temperature:t})}})})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Status",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"power-off",content:i.enabled?"On":"Off",selected:i.enabled,onClick:function(){return n("toggle_power")}}),children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Volume",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:i.max_volume,unit:"u",width:"50px",minValue:i.reagent_volume,maxValue:200,step:2,stepPixelSize:2,onChange:function(e,t){return n("change_volume",{volume:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Current Operation",children:i.acclimate_state}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Current State",children:i.emptying?"Emptying":"Filling"})]})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.ChemDebugSynthesizer=void 0;var o=n(0),r=n(3),a=n(2);t.ChemDebugSynthesizer=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.amount,l=i.beakerCurrentVolume,u=i.beakerMaxVolume,d=i.isBeakerLoaded,s=i.beakerContents,p=void 0===s?[]:s;return(0,o.createComponentVNode)(2,a.Section,{title:"Recipient",buttons:d?(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{icon:"eject",content:"Eject",onClick:function(){return n("ejectBeaker")}}),(0,o.createComponentVNode)(2,a.NumberInput,{value:c,unit:"u",minValue:1,maxValue:u,step:1,stepPixelSize:2,onChange:function(e,t){return n("amount",{amount:t})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"plus",content:"Input",onClick:function(){return n("input")}})],4):(0,o.createComponentVNode)(2,a.Button,{icon:"plus",content:"Create Beaker",onClick:function(){return n("makecup")}}),children:d?(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Box,{children:[(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:l})," / "+u+" u"]}),p.length>0?(0,o.createComponentVNode)(2,a.LabeledList,{children:p.map((function(e){return(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:e.name,children:[e.volume," u"]},e.name)}))}):(0,o.createComponentVNode)(2,a.Box,{color:"bad",children:"Recipient Empty"})],0):(0,o.createComponentVNode)(2,a.Box,{color:"average",children:"No Recipient"})})}},function(e,t,n){"use strict";t.__esModule=!0,t.ChemDispenser=void 0;var o=n(0),r=n(17),a=n(24),i=n(3),c=n(2);t.ChemDispenser=function(e){var t=(0,i.useBackend)(e),n=t.act,l=t.data,u=!!l.recordingRecipe,d=Object.keys(l.recipes).map((function(e){return{name:e,contents:l.recipes[e]}})),s=l.beakerTransferAmounts||[],p=u&&Object.keys(l.recordingRecipe).map((function(e){return{id:e,name:(0,a.toTitleCase)(e.replace(/_/," ")),volume:l.recordingRecipe[e]}}))||l.beakerContents||[];return(0,o.createFragment)([(0,o.createComponentVNode)(2,c.Section,{title:"Status",buttons:u&&(0,o.createComponentVNode)(2,c.Box,{inline:!0,mx:1,color:"red",children:[(0,o.createComponentVNode)(2,c.Icon,{name:"circle",mr:1}),"Recording"]}),children:(0,o.createComponentVNode)(2,c.LabeledList,{children:(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Energy",children:(0,o.createComponentVNode)(2,c.ProgressBar,{value:l.energy/l.maxEnergy,content:(0,r.toFixed)(l.energy)+" units"})})})}),(0,o.createComponentVNode)(2,c.Section,{title:"Recipes",buttons:(0,o.createFragment)([!u&&(0,o.createComponentVNode)(2,c.Box,{inline:!0,mx:1,children:(0,o.createComponentVNode)(2,c.Button,{color:"transparent",content:"Clear recipes",onClick:function(){return n("clear_recipes")}})}),!u&&(0,o.createComponentVNode)(2,c.Button,{icon:"circle",disabled:!l.isBeakerLoaded,content:"Record",onClick:function(){return n("record_recipe")}}),u&&(0,o.createComponentVNode)(2,c.Button,{icon:"ban",color:"transparent",content:"Discard",onClick:function(){return n("cancel_recording")}}),u&&(0,o.createComponentVNode)(2,c.Button,{icon:"save",color:"green",content:"Save",onClick:function(){return n("save_recording")}})],0),children:(0,o.createComponentVNode)(2,c.Box,{mr:-1,children:[d.map((function(e){return(0,o.createComponentVNode)(2,c.Button,{icon:"tint",width:"129.5px",lineHeight:"21px",content:e.name,onClick:function(){return n("dispense_recipe",{recipe:e.name})}},e.name)})),0===d.length&&(0,o.createComponentVNode)(2,c.Box,{color:"light-gray",children:"No recipes."})]})}),(0,o.createComponentVNode)(2,c.Section,{title:"Dispense",buttons:s.map((function(e){return(0,o.createComponentVNode)(2,c.Button,{icon:"plus",selected:e===l.amount,content:e,onClick:function(){return n("amount",{target:e})}},e)})),children:(0,o.createComponentVNode)(2,c.Box,{mr:-1,children:l.chemicals.map((function(e){return(0,o.createComponentVNode)(2,c.Button,{icon:"tint",width:"129.5px",lineHeight:"21px",content:e.title,onClick:function(){return n("dispense",{reagent:e.id})}},e.id)}))})}),(0,o.createComponentVNode)(2,c.Section,{title:"Beaker",buttons:s.map((function(e){return(0,o.createComponentVNode)(2,c.Button,{icon:"minus",disabled:u,content:e,onClick:function(){return n("remove",{amount:e})}},e)})),children:(0,o.createComponentVNode)(2,c.LabeledList,{children:[(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Beaker",buttons:!!l.isBeakerLoaded&&(0,o.createComponentVNode)(2,c.Button,{icon:"eject",content:"Eject",disabled:!l.isBeakerLoaded,onClick:function(){return n("eject")}}),children:(u?"Virtual beaker":l.isBeakerLoaded&&(0,o.createFragment)([(0,o.createComponentVNode)(2,c.AnimatedNumber,{initial:0,value:l.beakerCurrentVolume}),(0,o.createTextVNode)("/"),l.beakerMaxVolume,(0,o.createTextVNode)(" units, "),l.beakerCurrentpH,(0,o.createTextVNode)(" pH")],0))||"No beaker"}),(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Contents",children:[(0,o.createComponentVNode)(2,c.Box,{color:"label",children:l.isBeakerLoaded||u?0===p.length&&"Nothing":"N/A"}),p.map((function(e){return(0,o.createComponentVNode)(2,c.Box,{color:"label",children:[(0,o.createComponentVNode)(2,c.AnimatedNumber,{initial:0,value:e.volume})," ","units of ",e.name]},e.name)}))]})]})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.ChemFilter=t.ChemFilterPane=void 0;var o=n(0),r=n(3),a=n(2);var i=function(e){var t=(0,r.useBackend)(e).act,n=e.title,i=e.list,c=e.reagentName,l=e.onReagentInput,u=n.toLowerCase();return(0,o.createComponentVNode)(2,a.Section,{title:n,minHeight:40,ml:.5,mr:.5,buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Input,{placeholder:"Reagent",width:"140px",onInput:function(e,t){return l(t)}}),(0,o.createComponentVNode)(2,a.Button,{icon:"plus",onClick:function(){return t("add",{which:u,name:c})}})],4),children:i.map((function(e){return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:"minus",content:e,onClick:function(){return t("remove",{which:u,reagent:e})}})],4,e)}))})};t.ChemFilterPane=i;var c=function(e){var t,n;function r(){var t;return(t=e.call(this)||this).state={leftReagentName:"",rightReagentName:""},t}n=e,(t=r).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n;var c=r.prototype;return c.setLeftReagentName=function(e){this.setState({leftReagentName:e})},c.setRightReagentName=function(e){this.setState({rightReagentName:e})},c.render=function(){var e=this,t=this.props.state,n=t.data,r=n.left,c=void 0===r?[]:r,l=n.right,u=void 0===l?[]:l;return(0,o.createComponentVNode)(2,a.Grid,{children:[(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,i,{title:"Left",list:c,reagentName:this.state.leftReagentName,onReagentInput:function(t){return e.setLeftReagentName(t)},state:t})}),(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,i,{title:"Right",list:u,reagentName:this.state.rightReagentName,onReagentInput:function(t){return e.setRightReagentName(t)},state:t})})]})},r}(o.Component);t.ChemFilter=c},function(e,t,n){"use strict";t.__esModule=!0,t.ChemHeater=void 0;var o=n(0),r=n(17),a=n(3),i=n(2),c=n(168);t.ChemHeater=function(e){var t=(0,a.useBackend)(e),n=t.act,l=t.data,u=l.targetTemp,d=l.isActive,s=l.isBeakerLoaded,p=l.currentTemp,m=l.currentpH,f=l.beakerCurrentVolume,h=l.beakerMaxVolume,C=l.beakerContents,g=void 0===C?[]:C;return(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Section,{title:"Thermostat",buttons:(0,o.createComponentVNode)(2,i.Button,{icon:d?"power-off":"times",selected:d,content:d?"On":"Off",onClick:function(){return n("power")}}),children:(0,o.createComponentVNode)(2,i.LabeledList,{children:[(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Target",children:(0,o.createComponentVNode)(2,i.NumberInput,{width:"65px",unit:"K",step:2,stepPixelSize:1,value:(0,r.round)(u),minValue:0,maxValue:1e3,onDrag:function(e,t){return n("temperature",{target:t})}})}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Temperature",children:(0,o.createComponentVNode)(2,i.Box,{width:"60px",textAlign:"right",children:s&&(0,o.createComponentVNode)(2,i.AnimatedNumber,{value:p,format:function(e){return(0,r.toFixed)(e)+" K"}})||"\u2014"})}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"pH",children:(0,o.createComponentVNode)(2,i.Box,{width:"60px",textAlign:"right",children:s&&(0,o.createComponentVNode)(2,i.AnimatedNumber,{value:m,format:function(e){return(0,r.toFixed)(e)+" pH"}})||"-"})})]})}),(0,o.createComponentVNode)(2,i.Section,{title:"Beaker",buttons:!!s&&(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Box,{inline:!0,color:"label",mr:2,children:[f," / ",h," units"]}),(0,o.createComponentVNode)(2,i.Button,{icon:"eject",content:"Eject",onClick:function(){return n("eject")}})],4),children:(0,o.createComponentVNode)(2,c.BeakerContents,{beakerLoaded:s,beakerContents:g})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.ChemMaster=void 0;var o=n(0),r=n(16),a=n(2);t.ChemMaster=function(e){var t=e.state,n=t.config,l=t.data,s=n.ref,p=l.screen,m=l.beakerContents,f=void 0===m?[]:m,h=l.bufferContents,C=void 0===h?[]:h,g=l.beakerCurrentVolume,b=l.beakerMaxVolume,N=l.isBeakerLoaded,v=l.isPillBottleLoaded,V=l.pillBottleCurrentAmount,y=l.pillBottleMaxAmount;return"analyze"===p?(0,o.createComponentVNode)(2,d,{state:t}):(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Beaker",buttons:!!l.isBeakerLoaded&&(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Box,{inline:!0,color:"label",mr:2,children:[(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:g,initial:0})," / "+b+" units"]}),(0,o.createComponentVNode)(2,a.Button,{icon:"eject",content:"Eject",onClick:function(){return(0,r.act)(s,"eject")}})],4),children:[!N&&(0,o.createComponentVNode)(2,a.Box,{color:"label",mt:"3px",mb:"5px",children:"No beaker loaded."}),!!N&&0===f.length&&(0,o.createComponentVNode)(2,a.Box,{color:"label",mt:"3px",mb:"5px",children:"Beaker is empty."}),(0,o.createComponentVNode)(2,i,{children:f.map((function(e){return(0,o.createComponentVNode)(2,c,{state:t,chemical:e,transferTo:"buffer"},e.id)}))})]}),(0,o.createComponentVNode)(2,a.Section,{title:"Buffer",buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Box,{inline:!0,color:"label",mr:1,children:"Mode:"}),(0,o.createComponentVNode)(2,a.Button,{color:l.mode?"good":"bad",icon:l.mode?"exchange-alt":"times",content:l.mode?"Transfer":"Destroy",onClick:function(){return(0,r.act)(s,"toggleMode")}})],4),children:[0===C.length&&(0,o.createComponentVNode)(2,a.Box,{color:"label",mt:"3px",mb:"5px",children:"Buffer is empty."}),(0,o.createComponentVNode)(2,i,{children:C.map((function(e){return(0,o.createComponentVNode)(2,c,{state:t,chemical:e,transferTo:"beaker"},e.id)}))})]}),(0,o.createComponentVNode)(2,a.Section,{title:"Packaging",children:(0,o.createComponentVNode)(2,u,{state:t})}),!!v&&(0,o.createComponentVNode)(2,a.Section,{title:"Pill Bottle",buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Box,{inline:!0,color:"label",mr:2,children:[V," / ",y," pills"]}),(0,o.createComponentVNode)(2,a.Button,{icon:"eject",content:"Eject",onClick:function(){return(0,r.act)(s,"ejectPillBottle")}})],4)})],0)};var i=a.Table,c=function(e){var t=e.state,n=e.chemical,i=e.transferTo,c=t.config.ref;return(0,o.createComponentVNode)(2,a.Table.Row,{children:[(0,o.createComponentVNode)(2,a.Table.Cell,{color:"label",children:[(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:n.volume,initial:0})," units of "+n.name]}),(0,o.createComponentVNode)(2,a.Table.Cell,{collapsing:!0,children:[(0,o.createComponentVNode)(2,a.Button,{content:"1",onClick:function(){return(0,r.act)(c,"transfer",{id:n.id,amount:1,to:i})}}),(0,o.createComponentVNode)(2,a.Button,{content:"5",onClick:function(){return(0,r.act)(c,"transfer",{id:n.id,amount:5,to:i})}}),(0,o.createComponentVNode)(2,a.Button,{content:"10",onClick:function(){return(0,r.act)(c,"transfer",{id:n.id,amount:10,to:i})}}),(0,o.createComponentVNode)(2,a.Button,{content:"All",onClick:function(){return(0,r.act)(c,"transfer",{id:n.id,amount:1e3,to:i})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"ellipsis-h",title:"Custom amount",onClick:function(){return(0,r.act)(c,"transfer",{id:n.id,amount:-1,to:i})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"question",title:"Analyze",onClick:function(){return(0,r.act)(c,"analyze",{id:n.id})}})]})]},n.id)},l=function(e){var t=e.label,n=e.amountUnit,r=e.amount,i=e.onChangeAmount,c=e.onCreate,l=e.sideNote;return(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:t,children:[(0,o.createComponentVNode)(2,a.NumberInput,{width:14,unit:n,step:1,stepPixelSize:15,value:r,minValue:1,maxValue:10,onChange:i}),(0,o.createComponentVNode)(2,a.Button,{ml:1,content:"Create",onClick:c}),(0,o.createComponentVNode)(2,a.Box,{inline:!0,ml:1,color:"label",content:l})]})},u=function(e){var t,n;function i(){var t;return(t=e.call(this)||this).state={pillAmount:1,patchAmount:1,bottleAmount:1,packAmount:1,vialAmount:1,dartAmount:1},t}return n=e,(t=i).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n,i.prototype.render=function(){var e=this,t=(this.state,this.props),n=t.state.config.ref,i=this.state,c=i.pillAmount,u=i.patchAmount,d=i.bottleAmount,s=i.packAmount,p=i.vialAmount,m=i.dartAmount,f=t.state.data,h=f.condi,C=f.chosenPillStyle,g=f.pillStyles,b=void 0===g?[]:g;return(0,o.createComponentVNode)(2,a.LabeledList,{children:[!h&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Pill type",children:b.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{width:5,selected:e.id===C,textAlign:"center",color:"transparent",onClick:function(){return(0,r.act)(n,"pillStyle",{id:e.id})},children:(0,o.createComponentVNode)(2,a.Box,{mx:-1,className:e.className})},e.id)}))}),!h&&(0,o.createComponentVNode)(2,l,{label:"Pills",amount:c,amountUnit:"pills",sideNote:"max 50u",onChangeAmount:function(t,n){return e.setState({pillAmount:n})},onCreate:function(){return(0,r.act)(n,"create",{type:"pill",amount:c,volume:"auto"})}}),!h&&(0,o.createComponentVNode)(2,l,{label:"Patches",amount:u,amountUnit:"patches",sideNote:"max 40u",onChangeAmount:function(t,n){return e.setState({patchAmount:n})},onCreate:function(){return(0,r.act)(n,"create",{type:"patch",amount:u,volume:"auto"})}}),!h&&(0,o.createComponentVNode)(2,l,{label:"Bottles",amount:d,amountUnit:"bottles",sideNote:"max 30u",onChangeAmount:function(t,n){return e.setState({bottleAmount:n})},onCreate:function(){return(0,r.act)(n,"create",{type:"bottle",amount:d,volume:"auto"})}}),!h&&(0,o.createComponentVNode)(2,l,{label:"Hypovials",amount:p,amountUnit:"vials",sideNote:"max 60u",onChangeAmount:function(t,n){return e.setState({vialAmount:n})},onCreate:function(){return(0,r.act)(n,"create",{type:"hypoVial",amount:p,volume:"auto"})}}),!h&&(0,o.createComponentVNode)(2,l,{label:"Smartdarts",amount:m,amountUnit:"darts",sideNote:"max 20u",onChangeAmount:function(t,n){return e.setState({dartAmount:n})},onCreate:function(){return(0,r.act)(n,"create",{type:"smartDart",amount:m,volume:"auto"})}}),!!h&&(0,o.createComponentVNode)(2,l,{label:"Packs",amount:s,amountUnit:"packs",sideNote:"max 10u",onChangeAmount:function(t,n){return e.setState({packAmount:n})},onCreate:function(){return(0,r.act)(n,"create",{type:"condimentPack",amount:s,volume:"auto"})}}),!!h&&(0,o.createComponentVNode)(2,l,{label:"Bottles",amount:d,amountUnit:"bottles",sideNote:"max 50u",onChangeAmount:function(t,n){return e.setState({bottleAmount:n})},onCreate:function(){return(0,r.act)(n,"create",{type:"condimentBottle",amount:d,volume:"auto"})}})]})},i}(o.Component),d=function(e){var t=e.state,n=t.config.ref,i=t.data,c=i.analyzeVars,l=i.fermianalyze;return(0,o.createComponentVNode)(2,a.Section,{title:"Analysis Results",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"arrow-left",content:"Back",onClick:function(){return(0,r.act)(n,"goScreen",{screen:"home"})}}),children:[!l&&(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Name",children:c.name}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"State",children:c.state}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Color",children:[(0,o.createComponentVNode)(2,a.ColorBox,{color:c.color,mr:1}),c.color]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Description",children:c.description}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Metabolization Rate",children:[c.metaRate," u/minute"]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Overdose Threshold",children:c.overD}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Addiction Threshold",children:c.addicD})]}),!!l&&(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Name",children:c.name}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"State",children:c.state}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Color",children:[(0,o.createComponentVNode)(2,a.ColorBox,{color:c.color,mr:1}),c.color]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Description",children:c.description}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Metabolization Rate",children:[c.metaRate," u/minute"]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Overdose Threshold",children:c.overD}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Addiction Threshold",children:c.addicD}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Purity",children:c.purityF}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Inverse Ratio",children:c.inverseRatioF}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Purity E",children:c.purityE}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Lower Optimal Temperature",children:c.minTemp}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Upper Optimal Temperature",children:c.maxTemp}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Explosive Temperature",children:c.eTemp}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"pH Peak",children:c.pHpeak})]})]})}},function(e,t,n){"use strict";t.__esModule=!0,t.ChemPress=void 0;var o=n(0),r=n(3),a=n(2);t.ChemPress=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.pill_size,l=i.pill_name,u=i.pill_style,d=i.pill_styles,s=void 0===d?[]:d;return(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Pill Volume",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:c,unit:"u",width:"43px",minValue:5,maxValue:50,step:1,stepPixelSize:2,onChange:function(e,t){return n("change_pill_size",{volume:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Pill Name",children:(0,o.createComponentVNode)(2,a.Input,{value:l,onChange:function(e,t){return n("change_pill_name",{name:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Pill Style",children:s.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{width:5,selected:e.id===u,textAlign:"center",color:"transparent",onClick:function(){return n("change_pill_style",{id:e.id})},children:(0,o.createComponentVNode)(2,a.Box,{mx:-1,className:e.class_name})},e.id)}))})]})})}},function(e,t,n){"use strict";t.__esModule=!0,t.ChemReactionChamber=void 0;var o=n(0),r=n(16),a=n(2),i=n(25),c=n(11);var l=function(e){var t,n;function l(){var t;return(t=e.call(this)||this).state={reagentName:"",reagentQuantity:1},t}n=e,(t=l).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n;var u=l.prototype;return u.setReagentName=function(e){this.setState({reagentName:e})},u.setReagentQuantity=function(e){this.setState({reagentQuantity:e})},u.render=function(){var e=this,t=this.props.state,n=t.config,l=t.data,u=n.ref,d=l.emptying,s=l.reagents||[];return(0,o.createComponentVNode)(2,a.Section,{title:"Reagents",buttons:(0,o.createComponentVNode)(2,a.Box,{inline:!0,bold:!0,color:d?"bad":"good",children:d?"Emptying":"Filling"}),children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createVNode)(1,"tr","LabledList__row",[(0,o.createVNode)(1,"td","LabeledList__cell",(0,o.createComponentVNode)(2,a.Input,{fluid:!0,value:"",placeholder:"Reagent Name",onInput:function(t,n){return e.setReagentName(n)}}),2,{colSpan:"2"}),(0,o.createVNode)(1,"td",(0,c.classes)(["LabeledList__buttons","LabeledList__cell"]),[(0,o.createComponentVNode)(2,a.NumberInput,{value:this.state.reagentQuantity,minValue:1,maxValue:100,step:1,stepPixelSize:3,width:"39px",onDrag:function(t,n){return e.setReagentQuantity(n)}}),(0,o.createComponentVNode)(2,a.Box,{inline:!0,mr:1}),(0,o.createComponentVNode)(2,a.Button,{icon:"plus",onClick:function(){return(0,r.act)(u,"add",{chem:e.state.reagentName,amount:e.state.reagentQuantity})}})],4)],4),(0,i.map)((function(e,t){return(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:t,buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"minus",color:"bad",onClick:function(){return(0,r.act)(u,"remove",{chem:t})}}),children:e},t)}))(s)]})})},l}(o.Component);t.ChemReactionChamber=l},function(e,t,n){"use strict";t.__esModule=!0,t.ChemSplitter=void 0;var o=n(0),r=n(17),a=n(3),i=n(2);t.ChemSplitter=function(e){var t=(0,a.useBackend)(e),n=t.act,c=t.data,l=c.straight,u=c.side,d=c.max_transfer;return(0,o.createComponentVNode)(2,i.Section,{children:(0,o.createComponentVNode)(2,i.LabeledList,{children:[(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Straight",children:(0,o.createComponentVNode)(2,i.NumberInput,{value:l,unit:"u",width:"55px",minValue:1,maxValue:d,format:function(e){return(0,r.toFixed)(e,2)},step:.05,stepPixelSize:4,onChange:function(e,t){return n("set_amount",{target:"straight",amount:t})}})}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Side",children:(0,o.createComponentVNode)(2,i.NumberInput,{value:u,unit:"u",width:"55px",minValue:1,maxValue:d,format:function(e){return(0,r.toFixed)(e,2)},step:.05,stepPixelSize:4,onChange:function(e,t){return n("set_amount",{target:"side",amount:t})}})})]})})}},function(e,t,n){"use strict";t.__esModule=!0,t.ChemSynthesizer=void 0;var o=n(0),r=n(17),a=n(3),i=n(2);t.ChemSynthesizer=function(e){var t=(0,a.useBackend)(e),n=t.act,c=t.data,l=c.amount,u=c.current_reagent,d=c.chemicals,s=void 0===d?[]:d,p=c.possible_amounts,m=void 0===p?[]:p;return(0,o.createComponentVNode)(2,i.Section,{children:[(0,o.createComponentVNode)(2,i.Box,{children:m.map((function(e){return(0,o.createComponentVNode)(2,i.Button,{icon:"plus",content:(0,r.toFixed)(e,0),selected:e===l,onClick:function(){return n("amount",{target:e})}},(0,r.toFixed)(e,0))}))}),(0,o.createComponentVNode)(2,i.Box,{mt:1,children:s.map((function(e){return(0,o.createComponentVNode)(2,i.Button,{icon:"tint",content:e.title,width:"129px",selected:e.id===u,onClick:function(){return n("select",{reagent:e.id})}},e.id)}))})]})}},function(e,t,n){"use strict";t.__esModule=!0,t.CodexGigas=void 0;var o=n(0),r=n(3),a=n(2);t.CodexGigas=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createComponentVNode)(2,a.Section,{children:[i.name,(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Prefix",children:["Dark","Hellish","Fallen","Fiery","Sinful","Blood","Fluffy"].map((function(e){return(0,o.createComponentVNode)(2,a.Button,{content:e,disabled:1!==i.currentSection,onClick:function(){return n(e+" ")}},e.toLowerCase())}))}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Title",children:["Lord","Prelate","Count","Viscount","Vizier","Elder","Adept"].map((function(e){return(0,o.createComponentVNode)(2,a.Button,{content:e,disabled:i.currentSection>2,onClick:function(){return n(e+" ")}},e.toLowerCase())}))}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Name",children:["hal","ve","odr","neit","ci","quon","mya","folth","wren","geyr","hil","niet","twou","phi","coa"].map((function(e){return(0,o.createComponentVNode)(2,a.Button,{content:e,disabled:i.currentSection>4,onClick:function(){return n(e)}},e.toLowerCase())}))}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Suffix",children:["the Red","the Soulless","the Master","the Lord of all things","Jr."].map((function(e){return(0,o.createComponentVNode)(2,a.Button,{content:e,disabled:4!==i.currentSection,onClick:function(){return n(" "+e)}},e.toLowerCase())}))}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Submit",children:(0,o.createComponentVNode)(2,a.Button,{content:"Search",disabled:i.currentSection<4,onClick:function(){return n("search")}})})]})]})}},function(e,t,n){"use strict";t.__esModule=!0,t.ComputerFabricator=void 0;var o=n(0),r=(n(24),n(3)),a=n(2);t.ComputerFabricator=function(e){var t=e.state,n=(0,r.useBackend)(e),c=n.act,l=n.data;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{italic:!0,fontSize:"20px",children:"Your perfect device, only three steps away..."}),0!==l.state&&(0,o.createComponentVNode)(2,a.Button,{fluid:!0,mb:1,icon:"circle",content:"Clear Order",onClick:function(){return c("clean_order")}}),(0,o.createComponentVNode)(2,i,{state:t})],0)};var i=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return 0===i.state?(0,o.createComponentVNode)(2,a.Section,{title:"Step 1",minHeight:51,children:[(0,o.createComponentVNode)(2,a.Box,{mt:5,bold:!0,textAlign:"center",fontSize:"40px",children:"Choose your Device"}),(0,o.createComponentVNode)(2,a.Box,{mt:3,children:(0,o.createComponentVNode)(2,a.Grid,{width:"100%",children:[(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:"laptop",content:"Laptop",textAlign:"center",fontSize:"30px",lineHeight:"50px",onClick:function(){return n("pick_device",{pick:"1"})}})}),(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:"tablet-alt",content:"Tablet",textAlign:"center",fontSize:"30px",lineHeight:"50px",onClick:function(){return n("pick_device",{pick:"2"})}})})]})})]}):1===i.state?(0,o.createComponentVNode)(2,a.Section,{title:"Step 2: Customize your device",minHeight:47,buttons:(0,o.createComponentVNode)(2,a.Box,{bold:!0,color:"good",children:[i.totalprice," cr"]}),children:[(0,o.createComponentVNode)(2,a.Table,{children:[(0,o.createComponentVNode)(2,a.Table.Row,{children:[(0,o.createComponentVNode)(2,a.Table.Cell,{bold:!0,position:"relative",children:["Battery:",(0,o.createComponentVNode)(2,a.Tooltip,{content:"Allows your device to operate without external utility power\nsource. Advanced batteries increase battery life.",position:"right"})]}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"Standard",selected:1===i.hw_battery,onClick:function(){return n("hw_battery",{battery:"1"})}})}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"Upgraded",selected:2===i.hw_battery,onClick:function(){return n("hw_battery",{battery:"2"})}})}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"Advanced",selected:3===i.hw_battery,onClick:function(){return n("hw_battery",{battery:"3"})}})})]}),(0,o.createComponentVNode)(2,a.Table.Row,{children:[(0,o.createComponentVNode)(2,a.Table.Cell,{bold:!0,position:"relative",children:["Hard Drive:",(0,o.createComponentVNode)(2,a.Tooltip,{content:"Stores file on your device. Advanced drives can store more\nfiles, but use more power, shortening battery life.",position:"right"})]}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"Standard",selected:1===i.hw_disk,onClick:function(){return n("hw_disk",{disk:"1"})}})}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"Upgraded",selected:2===i.hw_disk,onClick:function(){return n("hw_disk",{disk:"2"})}})}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"Advanced",selected:3===i.hw_disk,onClick:function(){return n("hw_disk",{disk:"3"})}})})]}),(0,o.createComponentVNode)(2,a.Table.Row,{children:[(0,o.createComponentVNode)(2,a.Table.Cell,{bold:!0,position:"relative",children:["Network Card:",(0,o.createComponentVNode)(2,a.Tooltip,{content:"Allows your device to wirelessly connect to stationwide NTNet\nnetwork. Basic cards are limited to on-station use, while\nadvanced cards can operate anywhere near the station, which\nincludes asteroid outposts",position:"right"})]}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"None",selected:0===i.hw_netcard,onClick:function(){return n("hw_netcard",{netcard:"0"})}})}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"Standard",selected:1===i.hw_netcard,onClick:function(){return n("hw_netcard",{netcard:"1"})}})}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"Advanced",selected:2===i.hw_netcard,onClick:function(){return n("hw_netcard",{netcard:"2"})}})})]}),(0,o.createComponentVNode)(2,a.Table.Row,{children:[(0,o.createComponentVNode)(2,a.Table.Cell,{bold:!0,position:"relative",children:["Nano Printer:",(0,o.createComponentVNode)(2,a.Tooltip,{content:"A device that allows for various paperwork manipulations,\nsuch as, scanning of documents or printing new ones.\nThis device was certified EcoFriendlyPlus and is capable of\nrecycling existing paper for printing purposes.",position:"right"})]}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"None",selected:0===i.hw_nanoprint,onClick:function(){return n("hw_nanoprint",{print:"0"})}})}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"Standard",selected:1===i.hw_nanoprint,onClick:function(){return n("hw_nanoprint",{print:"1"})}})})]}),(0,o.createComponentVNode)(2,a.Table.Row,{children:[(0,o.createComponentVNode)(2,a.Table.Cell,{bold:!0,position:"relative",children:["Card Reader:",(0,o.createComponentVNode)(2,a.Tooltip,{content:"Adds a slot that allows you to manipulate RFID cards.\nPlease note that this is not necessary to allow the device\nto read your identification, it is just necessary to\nmanipulate other cards.",position:"right"})]}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"None",selected:0===i.hw_card,onClick:function(){return n("hw_card",{card:"0"})}})}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"Standard",selected:1===i.hw_card,onClick:function(){return n("hw_card",{card:"1"})}})})]}),2!==i.devtype&&(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Table.Row,{children:[(0,o.createComponentVNode)(2,a.Table.Cell,{bold:!0,position:"relative",children:["Processor Unit:",(0,o.createComponentVNode)(2,a.Tooltip,{content:"A component critical for your device's functionality.\nIt allows you to run programs from your hard drive.\nAdvanced CPUs use more power, but allow you to run\nmore programs on background at once.",position:"right"})]}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"Standard",selected:1===i.hw_cpu,onClick:function(){return n("hw_cpu",{cpu:"1"})}})}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"Advanced",selected:2===i.hw_cpu,onClick:function(){return n("hw_cpu",{cpu:"2"})}})})]}),(0,o.createComponentVNode)(2,a.Table.Row,{children:[(0,o.createComponentVNode)(2,a.Table.Cell,{bold:!0,position:"relative",children:["Tesla Relay:",(0,o.createComponentVNode)(2,a.Tooltip,{content:"An advanced wireless power relay that allows your device\nto connect to nearby area power controller to provide\nalternative power source. This component is currently\nunavailable on tablet computers due to size restrictions.",position:"right"})]}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"None",selected:0===i.hw_tesla,onClick:function(){return n("hw_tesla",{tesla:"0"})}})}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{content:"Standard",selected:1===i.hw_tesla,onClick:function(){return n("hw_tesla",{tesla:"1"})}})})]})],4)]}),(0,o.createComponentVNode)(2,a.Button,{fluid:!0,mt:3,content:"Confirm Order",color:"good",textAlign:"center",fontSize:"18px",lineHeight:"26px",onClick:function(){return n("confirm_order")}})]}):2===i.state?(0,o.createComponentVNode)(2,a.Section,{title:"Step 3: Payment",minHeight:47,children:[(0,o.createComponentVNode)(2,a.Box,{italic:!0,textAlign:"center",fontSize:"20px",children:"Your device is ready for fabrication..."}),(0,o.createComponentVNode)(2,a.Box,{bold:!0,mt:2,textAlign:"center",fontSize:"16px",children:[(0,o.createComponentVNode)(2,a.Box,{inline:!0,children:"Please insert the required"})," ",(0,o.createComponentVNode)(2,a.Box,{inline:!0,color:"good",children:[i.totalprice," cr"]})]}),(0,o.createComponentVNode)(2,a.Box,{bold:!0,mt:1,textAlign:"center",fontSize:"18px",children:"Current:"}),(0,o.createComponentVNode)(2,a.Box,{bold:!0,mt:.5,textAlign:"center",fontSize:"18px",color:i.credits>=i.totalprice?"good":"bad",children:[i.credits," cr"]}),(0,o.createComponentVNode)(2,a.Button,{fluid:!0,content:"Purchase",disabled:i.credits=10&&e<20?i.COLORS.department.security:e>=20&&e<30?i.COLORS.department.medbay:e>=30&&e<40?i.COLORS.department.science:e>=40&&e<50?i.COLORS.department.engineering:e>=50&&e<60?i.COLORS.department.cargo:e>=200&&e<230?i.COLORS.department.centcom:i.COLORS.department.other},u=function(e){var t=e.type,n=e.value;return(0,o.createComponentVNode)(2,a.Box,{inline:!0,width:4,color:i.COLORS.damageType[t],textAlign:"center",children:n})};t.CrewConsole=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,d=i.sensors||[];return(0,o.createComponentVNode)(2,a.Section,{minHeight:90,children:(0,o.createComponentVNode)(2,a.Table,{children:[(0,o.createComponentVNode)(2,a.Table.Row,{children:[(0,o.createComponentVNode)(2,a.Table.Cell,{bold:!0,children:"Name"}),(0,o.createComponentVNode)(2,a.Table.Cell,{bold:!0,collapsing:!0}),(0,o.createComponentVNode)(2,a.Table.Cell,{bold:!0,collapsing:!0,textAlign:"center",children:"Vitals"}),(0,o.createComponentVNode)(2,a.Table.Cell,{bold:!0,children:"Position"}),!!i.link_allowed&&(0,o.createComponentVNode)(2,a.Table.Cell,{bold:!0,collapsing:!0,children:"Tracking"})]}),d.map((function(e){return(0,o.createComponentVNode)(2,a.Table.Row,{children:[(0,o.createComponentVNode)(2,a.Table.Cell,{bold:(f=e.ijob,f%10==0),color:l(e.ijob),children:[e.name," (",e.assignment,")"]}),(0,o.createComponentVNode)(2,a.Table.Cell,{collapsing:!0,textAlign:"center",children:(0,o.createComponentVNode)(2,a.ColorBox,{color:(t=e.oxydam,r=e.toxdam,d=e.burndam,s=e.brutedam,p=t+r+d+s,m=Math.min(Math.max(Math.ceil(p/25),0),5),c[m])})}),(0,o.createComponentVNode)(2,a.Table.Cell,{collapsing:!0,textAlign:"center",children:null!==e.oxydam?(0,o.createComponentVNode)(2,a.Box,{inline:!0,children:[(0,o.createComponentVNode)(2,u,{type:"oxy",value:e.oxydam}),"/",(0,o.createComponentVNode)(2,u,{type:"toxin",value:e.toxdam}),"/",(0,o.createComponentVNode)(2,u,{type:"burn",value:e.burndam}),"/",(0,o.createComponentVNode)(2,u,{type:"brute",value:e.brutedam})]}):e.life_status?"Alive":"Dead"}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:null!==e.pos_x?e.area:"N/A"}),!!i.link_allowed&&(0,o.createComponentVNode)(2,a.Table.Cell,{collapsing:!0,children:(0,o.createComponentVNode)(2,a.Button,{content:"Track",disabled:!e.can_track,onClick:function(){return n("select_person",{name:e.name})}})})]},e.name);var t,r,d,s,p,m,f}))]})})}},function(e,t,n){"use strict";t.__esModule=!0,t.Cryo=void 0;var o=n(0),r=n(3),a=n(2),i=n(168);t.Cryo=function(e){var t=(0,r.useBackend)(e),n=t.act,c=t.data;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Occupant",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Occupant",content:c.occupant.name?c.occupant.name:"No Occupant"}),!!c.hasOccupant&&(0,o.createFragment)([(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"State",content:c.occupant.stat,color:c.occupant.statstate}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Temperature",color:c.occupant.temperaturestatus,children:[(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:c.occupant.bodyTemperature})," K"]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Health",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:c.occupant.health/c.occupant.maxHealth,color:c.occupant.health>0?"good":"average",children:(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:c.occupant.health})})}),[{label:"Brute",type:"bruteLoss"},{label:"Respiratory",type:"oxyLoss"},{label:"Toxin",type:"toxLoss"},{label:"Burn",type:"fireLoss"}].map((function(e){return(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:e.label,children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:c.occupant[e.type]/100,children:(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:c.occupant[e.type]})})},e.id)}))],0)]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Cell",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Power",content:(0,o.createComponentVNode)(2,a.Button,{icon:c.isOperating?"power-off":"times",disabled:c.isOpen,onClick:function(){return n("power")},color:c.isOperating&&"green",children:c.isOperating?"On":"Off"})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Temperature",children:[(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:c.cellTemperature})," K"]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Door",children:[(0,o.createComponentVNode)(2,a.Button,{icon:c.isOpen?"unlock":"lock",onClick:function(){return n("door")},content:c.isOpen?"Open":"Closed"}),(0,o.createComponentVNode)(2,a.Button,{icon:c.autoEject?"sign-out-alt":"sign-in-alt",onClick:function(){return n("autoeject")},content:c.autoEject?"Auto":"Manual"})]})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Beaker",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"eject",disabled:!c.isBeakerLoaded,onClick:function(){return n("ejectbeaker")},content:"Eject"}),children:(0,o.createComponentVNode)(2,i.BeakerContents,{beakerLoaded:c.isBeakerLoaded,beakerContents:c.beakerContents})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.PersonalCrafting=void 0;var o=n(0),r=n(25),a=n(3),i=n(2),c=function(e){var t=e.craftables,n=void 0===t?[]:t,r=(0,a.useBackend)(e),c=r.act,l=r.data,u=l.craftability,d=void 0===u?{}:u,s=l.display_compact,p=l.display_craftable_only;return n.map((function(e){return p&&!d[e.ref]?null:s?(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:e.name,className:"candystripe",buttons:(0,o.createComponentVNode)(2,i.Button,{icon:"cog",content:"Craft",disabled:!d[e.ref],tooltip:e.tool_text&&"Tools needed: "+e.tool_text,tooltipPosition:"left",onClick:function(){return c("make",{recipe:e.ref})}}),children:e.req_text},e.name):(0,o.createComponentVNode)(2,i.Section,{title:e.name,level:2,buttons:(0,o.createComponentVNode)(2,i.Button,{icon:"cog",content:"Craft",disabled:!d[e.ref],onClick:function(){return c("make",{recipe:e.ref})}}),children:(0,o.createComponentVNode)(2,i.LabeledList,{children:[!!e.req_text&&(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Required",children:e.req_text}),!!e.catalyst_text&&(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Catalyst",children:e.catalyst_text}),!!e.tool_text&&(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Tools",children:e.tool_text})]})},e.name)}))};t.PersonalCrafting=function(e){var t=e.state,n=(0,a.useBackend)(e),l=n.act,u=n.data,d=u.busy,s=u.display_craftable_only,p=u.display_compact,m=(0,r.map)((function(e,t){return{category:t,subcategory:e,hasSubcats:"has_subcats"in e,firstSubcatName:Object.keys(e).find((function(e){return"has_subcats"!==e}))}}))(u.crafting_recipes||{}),f=!!d&&(0,o.createComponentVNode)(2,i.Dimmer,{fontSize:"40px",textAlign:"center",children:(0,o.createComponentVNode)(2,i.Box,{mt:30,children:[(0,o.createComponentVNode)(2,i.Icon,{name:"cog",spin:1})," Crafting..."]})});return(0,o.createFragment)([f,(0,o.createComponentVNode)(2,i.Section,{title:"Personal Crafting",buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Button,{icon:p?"check-square-o":"square-o",content:"Compact",selected:p,onClick:function(){return l("toggle_compact")}}),(0,o.createComponentVNode)(2,i.Button,{icon:s?"check-square-o":"square-o",content:"Craftable Only",selected:s,onClick:function(){return l("toggle_recipes")}})],4),children:(0,o.createComponentVNode)(2,i.Tabs,{children:m.map((function(e){return(0,o.createComponentVNode)(2,i.Tabs.Tab,{label:e.category,onClick:function(){return l("set_category",{category:e.category,subcategory:e.firstSubcatName})},children:function(){return!e.hasSubcats&&(0,o.createComponentVNode)(2,c,{craftables:e.subcategory,state:t})||(0,o.createComponentVNode)(2,i.Tabs,{vertical:!0,children:(0,r.map)((function(e,n){if("has_subcats"!==n)return(0,o.createComponentVNode)(2,i.Tabs.Tab,{label:n,onClick:function(){return l("set_category",{subcategory:n})},children:function(){return(0,o.createComponentVNode)(2,c,{craftables:e,state:t})}})}))(e.subcategory)})}},e.category)}))})})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.DecalPainter=void 0;var o=n(0),r=n(3),a=n(2);t.DecalPainter=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.decal_list||[],l=i.color_list||[],u=i.dir_list||[];return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Decal Type",children:c.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{content:e.name,selected:e.decal===i.decal_style,onClick:function(){return n("select decal",{decals:e.decal})}},e.decal)}))}),(0,o.createComponentVNode)(2,a.Section,{title:"Decal Color",children:l.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{content:"red"===e.colors?"Red":"white"===e.colors?"White":"Yellow",selected:e.colors===i.decal_color,onClick:function(){return n("select color",{colors:e.colors})}},e.colors)}))}),(0,o.createComponentVNode)(2,a.Section,{title:"Decal Direction",children:u.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{content:1===e.dirs?"North":2===e.dirs?"South":4===e.dirs?"East":"West",selected:e.dirs===i.decal_direction,onClick:function(){return n("selected direction",{dirs:e.dirs})}},e.dirs)}))})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.DisposalUnit=void 0;var o=n(0),r=n(3),a=n(2);t.DisposalUnit=function(e){var t,n,i=(0,r.useBackend)(e),c=i.act,l=i.data;return l.full_pressure?(t="good",n="Ready"):l.panel_open?(t="bad",n="Power Disabled"):l.pressure_charging?(t="average",n="Pressurizing"):(t="bad",n="Off"),(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"State",color:t,children:n}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Pressure",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:l.per,color:"good"})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Handle",children:(0,o.createComponentVNode)(2,a.Button,{icon:l.flush?"toggle-on":"toggle-off",disabled:l.isai||l.panel_open,content:l.flush?"Disengage":"Engage",onClick:function(){return c(l.flush?"handle-0":"handle-1")}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Eject",children:(0,o.createComponentVNode)(2,a.Button,{icon:"sign-out-alt",disabled:l.isai,content:"Eject Contents",onClick:function(){return c("eject")}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Power",children:(0,o.createComponentVNode)(2,a.Button,{icon:"power-off",disabled:l.panel_open,selected:l.pressure_charging,onClick:function(){return c(l.pressure_charging?"pump-0":"pump-1")}})})]})})}},function(e,t,n){"use strict";t.__esModule=!0,t.DnaVault=void 0;var o=n(0),r=n(3),a=n(2);t.DnaVault=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.completed,l=i.used,u=i.choiceA,d=i.choiceB,s=i.dna,p=i.dna_max,m=i.plants,f=i.plants_max,h=i.animals,C=i.animals_max;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"DNA Vault Database",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Human DNA",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:s/p,content:s+" / "+p+" Samples"})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Plant DNA",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:m/f,content:m+" / "+f+" Samples"})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Animal DNA",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:h/h,content:h+" / "+C+" Samples"})})]})}),!(!c||l)&&(0,o.createComponentVNode)(2,a.Section,{title:"Personal Gene Therapy",children:[(0,o.createComponentVNode)(2,a.Box,{bold:!0,textAlign:"center",mb:1,children:"Applicable Gene Therapy Treatments"}),(0,o.createComponentVNode)(2,a.Grid,{children:[(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.Button,{fluid:!0,bold:!0,content:u,textAlign:"center",onClick:function(){return n("gene",{choice:u})}})}),(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.Button,{fluid:!0,bold:!0,content:d,textAlign:"center",onClick:function(){return n("gene",{choice:d})}})})]})]})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.EightBallVote=void 0;var o=n(0),r=n(3),a=n(2),i=n(24);t.EightBallVote=function(e){var t=(0,r.useBackend)(e),n=t.act,c=t.data,l=c.question,u=c.shaking,d=c.answers,s=void 0===d?[]:d;return u?(0,o.createComponentVNode)(2,a.Section,{children:[(0,o.createComponentVNode)(2,a.Box,{bold:!0,textAlign:"center",fontSize:"16px",m:1,children:['"',l,'"']}),(0,o.createComponentVNode)(2,a.Grid,{children:s.map((function(e){return(0,o.createComponentVNode)(2,a.Grid.Column,{children:[(0,o.createComponentVNode)(2,a.Button,{fluid:!0,bold:!0,content:(0,i.toTitleCase)(e.answer),selected:e.selected,fontSize:"16px",lineHeight:"24px",textAlign:"center",mb:1,onClick:function(){return n("vote",{answer:e.answer})}}),(0,o.createComponentVNode)(2,a.Box,{bold:!0,textAlign:"center",fontSize:"30px",children:e.amount})]},e.answer)}))})]}):(0,o.createComponentVNode)(2,a.NoticeBox,{children:"No question is currently being asked."})}},function(e,t,n){"use strict";t.__esModule=!0,t.EmergencyShuttleConsole=void 0;var o=n(0),r=n(2),a=n(3);t.EmergencyShuttleConsole=function(e){var t=(0,a.useBackend)(e),n=t.act,i=t.data,c=i.timer_str,l=i.enabled,u=i.emagged,d=i.engines_started,s=i.authorizations_remaining,p=i.authorizations,m=void 0===p?[]:p;return(0,o.createComponentVNode)(2,r.Section,{children:[(0,o.createComponentVNode)(2,r.Box,{bold:!0,fontSize:"40px",textAlign:"center",fontFamily:"monospace",children:c}),(0,o.createComponentVNode)(2,r.Box,{textAlign:"center",fontSize:"16px",mb:1,children:[(0,o.createComponentVNode)(2,r.Box,{inline:!0,bold:!0,children:"ENGINES:"}),(0,o.createComponentVNode)(2,r.Box,{inline:!0,color:d?"good":"average",ml:1,children:d?"Online":"Idle"})]}),(0,o.createComponentVNode)(2,r.Section,{title:"Early Launch Authorization",level:2,buttons:(0,o.createComponentVNode)(2,r.Button,{icon:"times",content:"Repeal All",color:"bad",disabled:!l,onClick:function(){return n("abort")}}),children:[(0,o.createComponentVNode)(2,r.Grid,{children:[(0,o.createComponentVNode)(2,r.Grid.Column,{children:(0,o.createComponentVNode)(2,r.Button,{fluid:!0,icon:"exclamation-triangle",color:"good",content:"AUTHORIZE",disabled:!l,onClick:function(){return n("authorize")}})}),(0,o.createComponentVNode)(2,r.Grid.Column,{children:(0,o.createComponentVNode)(2,r.Button,{fluid:!0,icon:"minus",content:"REPEAL",disabled:!l,onClick:function(){return n("repeal")}})})]}),(0,o.createComponentVNode)(2,r.Section,{title:"Authorizations",level:3,minHeight:"150px",buttons:(0,o.createComponentVNode)(2,r.Box,{inline:!0,bold:!0,color:u?"bad":"good",children:u?"ERROR":"Remaining: "+s}),children:[m.length>0?m.map((function(e){return(0,o.createComponentVNode)(2,r.Box,{bold:!0,fontSize:"16px",className:"candystripe",children:[e.name," (",e.job,")"]},e.name)})):(0,o.createComponentVNode)(2,r.Box,{bold:!0,textAlign:"center",fontSize:"16px",color:"average",children:"No Active Authorizations"}),m.map((function(e){return(0,o.createComponentVNode)(2,r.Box,{bold:!0,fontSize:"16px",className:"candystripe",children:[e.name," (",e.job,")"]},e.name)}))]})]})]})}},function(e,t,n){"use strict";t.__esModule=!0,t.EngravedMessage=void 0;var o=n(0),r=n(24),a=n(3),i=n(2);t.EngravedMessage=function(e){var t=(0,a.useBackend)(e),n=t.act,c=t.data,l=c.admin_mode,u=c.creator_key,d=c.creator_name,s=c.has_liked,p=c.has_disliked,m=c.hidden_message,f=c.is_creator,h=c.num_likes,C=c.num_dislikes,g=c.realdate;return(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Section,{children:[(0,o.createComponentVNode)(2,i.Box,{bold:!0,textAlign:"center",fontSize:"20px",mb:2,children:(0,r.decodeHtmlEntities)(m)}),(0,o.createComponentVNode)(2,i.Grid,{children:[(0,o.createComponentVNode)(2,i.Grid.Column,{children:(0,o.createComponentVNode)(2,i.Button,{fluid:!0,icon:"arrow-up",content:" "+h,disabled:f,selected:s,textAlign:"center",fontSize:"16px",lineHeight:"24px",onClick:function(){return n("like")}})}),(0,o.createComponentVNode)(2,i.Grid.Column,{children:(0,o.createComponentVNode)(2,i.Button,{fluid:!0,icon:"circle",disabled:f,selected:!p&&!s,textAlign:"center",fontSize:"16px",lineHeight:"24px",onClick:function(){return n("neutral")}})}),(0,o.createComponentVNode)(2,i.Grid.Column,{children:(0,o.createComponentVNode)(2,i.Button,{fluid:!0,icon:"arrow-down",content:" "+C,disabled:f,selected:p,textAlign:"center",fontSize:"16px",lineHeight:"24px",onClick:function(){return n("dislike")}})})]})]}),(0,o.createComponentVNode)(2,i.Section,{children:(0,o.createComponentVNode)(2,i.LabeledList,{children:(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Created On",children:g})})}),(0,o.createComponentVNode)(2,i.Section),!!l&&(0,o.createComponentVNode)(2,i.Section,{title:"Admin Panel",buttons:(0,o.createComponentVNode)(2,i.Button,{icon:"times",content:"Delete",color:"bad",onClick:function(){return n("delete")}}),children:(0,o.createComponentVNode)(2,i.LabeledList,{children:[(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Creator Ckey",children:u}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Creator Character Name",children:d})]})})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.Gps=void 0;var o=n(0),r=n(25),a=n(71),i=n(17),c=n(160),l=n(3),u=n(2),d=function(e){return(0,r.map)(parseFloat)(e.split(", "))};t.Gps=function(e){var t=(0,l.useBackend)(e),n=t.act,s=t.data,p=s.currentArea,m=s.currentCoords,f=s.globalmode,h=s.power,C=s.tag,g=s.updating,b=(0,a.flow)([(0,r.map)((function(e,t){var n=e.dist&&Math.round((0,c.vecLength)((0,c.vecSubtract)(d(m),d(e.coords))));return Object.assign({},e,{dist:n,index:t})})),(0,r.sortBy)((function(e){return e.dist===undefined}),(function(e){return e.entrytag}))])(s.signals||[]);return(0,o.createFragment)([(0,o.createComponentVNode)(2,u.Section,{title:"Control",buttons:(0,o.createComponentVNode)(2,u.Button,{icon:"power-off",content:h?"On":"Off",selected:h,onClick:function(){return n("power")}}),children:(0,o.createComponentVNode)(2,u.LabeledList,{children:[(0,o.createComponentVNode)(2,u.LabeledList.Item,{label:"Tag",children:(0,o.createComponentVNode)(2,u.Button,{icon:"pencil-alt",content:C,onClick:function(){return n("rename")}})}),(0,o.createComponentVNode)(2,u.LabeledList.Item,{label:"Scan Mode",children:(0,o.createComponentVNode)(2,u.Button,{icon:g?"unlock":"lock",content:g?"AUTO":"MANUAL",color:!g&&"bad",onClick:function(){return n("updating")}})}),(0,o.createComponentVNode)(2,u.LabeledList.Item,{label:"Range",children:(0,o.createComponentVNode)(2,u.Button,{icon:"sync",content:f?"MAXIMUM":"LOCAL",selected:!f,onClick:function(){return n("globalmode")}})})]})}),!!h&&(0,o.createFragment)([(0,o.createComponentVNode)(2,u.Section,{title:"Current Location",children:(0,o.createComponentVNode)(2,u.Box,{fontSize:"18px",children:[p," (",m,")"]})}),(0,o.createComponentVNode)(2,u.Section,{title:"Detected Signals",children:(0,o.createComponentVNode)(2,u.Table,{children:[(0,o.createComponentVNode)(2,u.Table.Row,{bold:!0,children:[(0,o.createComponentVNode)(2,u.Table.Cell,{content:"Name"}),(0,o.createComponentVNode)(2,u.Table.Cell,{collapsing:!0,content:"Direction"}),(0,o.createComponentVNode)(2,u.Table.Cell,{collapsing:!0,content:"Coordinates"})]}),b.map((function(e){return(0,o.createComponentVNode)(2,u.Table.Row,{className:"candystripe",children:[(0,o.createComponentVNode)(2,u.Table.Cell,{bold:!0,color:"label",children:e.entrytag}),(0,o.createComponentVNode)(2,u.Table.Cell,{collapsing:!0,opacity:e.dist!==undefined&&(0,i.clamp)(1.2/Math.log(Math.E+e.dist/20),.4,1),children:[e.degrees!==undefined&&(0,o.createComponentVNode)(2,u.Icon,{mr:1,size:1.2,name:"arrow-up",rotation:e.degrees}),e.dist!==undefined&&e.dist+"m"]}),(0,o.createComponentVNode)(2,u.Table.Cell,{collapsing:!0,children:e.coords})]},e.entrytag+e.coords+e.index)}))]})})],4)],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.GravityGenerator=void 0;var o=n(0),r=n(3),a=n(2);t.GravityGenerator=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.breaker,l=i.charge_count,u=i.charging_state,d=i.on,s=i.operational;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{children:!s&&(0,o.createComponentVNode)(2,a.NoticeBox,{textAlign:"center",children:"No data available"})||(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Breaker",children:(0,o.createComponentVNode)(2,a.Button,{icon:c?"power-off":"times",content:c?"On":"Off",selected:c,disabled:!s,onClick:function(){return n("gentoggle")}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Gravity Charge",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:l/100,ranges:{good:[.7,Infinity],average:[.3,.7],bad:[-Infinity,.3]}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Charge Mode",children:[0===u&&(d&&(0,o.createComponentVNode)(2,a.Box,{color:"good",children:"Fully Charged"})||(0,o.createComponentVNode)(2,a.Box,{color:"bad",children:"Not Charging"})),1===u&&(0,o.createComponentVNode)(2,a.Box,{color:"average",children:"Charging"}),2===u&&(0,o.createComponentVNode)(2,a.Box,{color:"average",children:"Discharging"})]})]})}),s&&0!==u&&(0,o.createComponentVNode)(2,a.NoticeBox,{textAlign:"center",children:"WARNING - Radiation detected"}),s&&0===u&&(0,o.createComponentVNode)(2,a.NoticeBox,{textAlign:"center",children:"No radiation detected"})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.GulagTeleporterConsole=void 0;var o=n(0),r=n(3),a=n(2);t.GulagTeleporterConsole=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.teleporter,l=i.teleporter_lock,u=i.teleporter_state_open,d=i.teleporter_location,s=i.beacon,p=i.beacon_location,m=i.id,f=i.id_name,h=i.can_teleport,C=i.goal,g=void 0===C?0:C,b=i.prisoner,N=void 0===b?{}:b;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Teleporter Console",buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{content:u?"Open":"Closed",disabled:l,selected:u,onClick:function(){return n("toggle_open")}}),(0,o.createComponentVNode)(2,a.Button,{icon:l?"lock":"unlock",content:l?"Locked":"Unlocked",selected:l,disabled:u,onClick:function(){return n("teleporter_lock")}})],4),children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Teleporter Unit",color:c?"good":"bad",buttons:!c&&(0,o.createComponentVNode)(2,a.Button,{content:"Reconnect",onClick:function(){return n("scan_teleporter")}}),children:c?d:"Not Connected"}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Receiver Beacon",color:s?"good":"bad",buttons:!s&&(0,o.createComponentVNode)(2,a.Button,{content:"Reconnect",onClick:function(){return n("scan_beacon")}}),children:s?p:"Not Connected"})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Prisoner Details",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Prisoner ID",children:(0,o.createComponentVNode)(2,a.Button,{fluid:!0,content:m?f:"No ID",onClick:function(){return n("handle_id")}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Point Goal",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:g,width:"48px",minValue:1,maxValue:1e3,onChange:function(e,t){return n("set_goal",{value:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Occupant",children:N.name?N.name:"No Occupant"}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Criminal Status",children:N.crimstat?N.crimstat:"No Status"})]})}),(0,o.createComponentVNode)(2,a.Button,{fluid:!0,content:"Process Prisoner",disabled:!h,textAlign:"center",color:"bad",onClick:function(){return n("teleport")}})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.GulagItemReclaimer=void 0;var o=n(0),r=n(3),a=n(2);t.GulagItemReclaimer=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.mobs||[];return(0,o.createComponentVNode)(2,a.Section,{title:"Stored Items",children:(0,o.createComponentVNode)(2,a.Table,{children:c.map((function(e){return(0,o.createComponentVNode)(2,a.Table.Row,{children:[(0,o.createComponentVNode)(2,a.Table.Cell,{children:e.name}),(0,o.createComponentVNode)(2,a.Table.Cell,{textAlign:"right",children:(0,o.createComponentVNode)(2,a.Button,{content:"Retrieve Items",disabled:!i.can_reclaim,onClick:function(){return n("release_items",{mobref:e.mob})}})})]},e.mob)}))})})}},function(e,t,n){"use strict";t.__esModule=!0,t.Holodeck=void 0;var o=n(0),r=n(3),a=n(2);t.Holodeck=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.can_toggle_safety,l=i.default_programs,u=void 0===l?[]:l,d=i.emag_programs,s=void 0===d?[]:d,p=i.emagged,m=i.program;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Default Programs",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:p?"unlock":"lock",content:"Safeties",color:"bad",disabled:!c,selected:!p,onClick:function(){return n("safety")}}),children:u.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{fluid:!0,content:e.name.substring(11),textAlign:"center",selected:e.type===m,onClick:function(){return n("load_program",{type:e.type})}},e.type)}))}),!!p&&(0,o.createComponentVNode)(2,a.Section,{title:"Dangerous Programs",children:s.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{fluid:!0,content:e.name.substring(11),color:"bad",textAlign:"center",selected:e.type===m,onClick:function(){return n("load_program",{type:e.type})}},e.type)}))})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.HypnoChair=void 0;var o=n(0),r=n(3),a=n(2);t.HypnoChair=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Information",backgroundColor:"#450F44",children:"The Enhanced Interrogation Chamber is designed to induce a deep-rooted trance trigger into the subject. Once the procedure is complete, by using the implanted trigger phrase, the authorities are able to ensure immediate and complete obedience and truthfulness."}),(0,o.createComponentVNode)(2,a.Section,{title:"Occupant Information",textAlign:"center",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Name",children:i.occupant.name?i.occupant.name:"No Occupant"}),!!i.occupied&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Status",color:0===i.occupant.stat?"good":1===i.occupant.stat?"average":"bad",children:0===i.occupant.stat?"Conscious":1===i.occupant.stat?"Unconcious":"Dead"})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Operations",textAlign:"center",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Door",children:(0,o.createComponentVNode)(2,a.Button,{icon:i.open?"unlock":"lock",color:i.open?"default":"red",content:i.open?"Open":"Closed",onClick:function(){return n("door")}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger Phrase",children:(0,o.createComponentVNode)(2,a.Input,{value:i.trigger,onChange:function(e,t){return n("set_phrase",{phrase:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Interrogate Occupant",children:[(0,o.createComponentVNode)(2,a.Button,{icon:"code-branch",content:i.interrogating?"Interrupt Interrogation":"Begin Enhanced Interrogation",onClick:function(){return n("interrogate")}}),1===i.interrogating&&(0,o.createComponentVNode)(2,a.Icon,{name:"cog",color:"orange",spin:!0})]})]})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.ImplantChair=void 0;var o=n(0),r=n(3),a=n(2);t.ImplantChair=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Occupant Information",textAlign:"center",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Name",children:i.occupant.name?i.occupant.name:"No Occupant"}),!!i.occupied&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Status",color:0===i.occupant.stat?"good":1===i.occupant.stat?"average":"bad",children:0===i.occupant.stat?"Conscious":1===i.occupant.stat?"Unconcious":"Dead"})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Operations",textAlign:"center",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Door",children:(0,o.createComponentVNode)(2,a.Button,{icon:i.open?"unlock":"lock",color:i.open?"default":"red",content:i.open?"Open":"Closed",onClick:function(){return n("door")}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Implant Occupant",children:[(0,o.createComponentVNode)(2,a.Button,{icon:"code-branch",content:i.ready?i.special_name||"Implant":"Recharging",onClick:function(){return n("implant")}}),0===i.ready&&(0,o.createComponentVNode)(2,a.Icon,{name:"cog",color:"orange",spin:!0})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Implants Remaining",children:[i.ready_implants,1===i.replenishing&&(0,o.createComponentVNode)(2,a.Icon,{name:"sync",color:"red",spin:!0})]})]})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.Intellicard=void 0;var o=n(0),r=n(3),a=n(2);t.Intellicard=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=u||d,l=i.name,u=i.isDead,d=i.isBraindead,s=i.health,p=i.wireless,m=i.radio,f=i.wiping,h=i.laws,C=void 0===h?[]:h;return(0,o.createComponentVNode)(2,a.Section,{title:l||"Empty Card",buttons:!!l&&(0,o.createComponentVNode)(2,a.Button,{icon:"trash",content:f?"Stop Wiping":"Wipe",disabled:u,onClick:function(){return n("wipe")}}),children:!!l&&(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Status",color:c?"bad":"good",children:c?"Offline":"Operation"}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Software Integrity",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:s,minValue:0,maxValue:100,ranges:{good:[70,Infinity],average:[50,70],bad:[-Infinity,50]}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Settings",children:[(0,o.createComponentVNode)(2,a.Button,{icon:"signal",content:"Wireless Activity",selected:p,onClick:function(){return n("wireless")}}),(0,o.createComponentVNode)(2,a.Button,{icon:"microphone",content:"Subspace Radio",selected:m,onClick:function(){return n("radio")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Laws",children:C.map((function(e){return(0,o.createComponentVNode)(2,a.BlockQuote,{children:e},e)}))})]})})}},function(e,t,n){"use strict";t.__esModule=!0,t.KeycardAuth=void 0;var o=n(0),r=n(3),a=n(2);t.KeycardAuth=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createComponentVNode)(2,a.Section,{children:[(0,o.createComponentVNode)(2,a.Box,{children:1===i.waiting&&(0,o.createVNode)(1,"span",null,"Waiting for another device to confirm your request...",16)}),(0,o.createComponentVNode)(2,a.Box,{children:0===i.waiting&&(0,o.createFragment)([!!i.auth_required&&(0,o.createComponentVNode)(2,a.Button,{icon:"check-square",color:"red",textAlign:"center",lineHeight:"60px",fluid:!0,onClick:function(){return n("auth_swipe")},content:"Authorize"}),0===i.auth_required&&(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{icon:"exclamation-triangle",fluid:!0,onClick:function(){return n("red_alert")},content:"Red Alert"}),(0,o.createComponentVNode)(2,a.Button,{icon:"wrench",fluid:!0,onClick:function(){return n("emergency_maint")},content:"Emergency Maintenance Access"}),(0,o.createComponentVNode)(2,a.Button,{icon:"meteor",fluid:!0,onClick:function(){return n("bsa_unlock")},content:"Bluespace Artillery Unlock"})],4)],0)})]})}},function(e,t,n){"use strict";t.__esModule=!0,t.LaborClaimConsole=void 0;var o=n(0),r=n(24),a=n(3),i=n(2);t.LaborClaimConsole=function(e){var t=(0,a.useBackend)(e),n=t.act,c=t.data,l=c.can_go_home,u=c.id_points,d=c.ores,s=c.status_info,p=c.unclaimed_points;return(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Section,{children:(0,o.createComponentVNode)(2,i.LabeledList,{children:[(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Status",children:s}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Shuttle controls",children:(0,o.createComponentVNode)(2,i.Button,{content:"Move shuttle",disabled:!l,onClick:function(){return n("move_shuttle")}})}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Points",children:u}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Unclaimed points",buttons:(0,o.createComponentVNode)(2,i.Button,{content:"Claim points",disabled:!p,onClick:function(){return n("claim_points")}}),children:p})]})}),(0,o.createComponentVNode)(2,i.Section,{title:"Material values",children:(0,o.createComponentVNode)(2,i.Table,{children:[(0,o.createComponentVNode)(2,i.Table.Row,{header:!0,children:[(0,o.createComponentVNode)(2,i.Table.Cell,{children:"Material"}),(0,o.createComponentVNode)(2,i.Table.Cell,{collapsing:!0,textAlign:"right",children:"Value"})]}),d.map((function(e){return(0,o.createComponentVNode)(2,i.Table.Row,{children:[(0,o.createComponentVNode)(2,i.Table.Cell,{children:(0,r.toTitleCase)(e.ore)}),(0,o.createComponentVNode)(2,i.Table.Cell,{collapsing:!0,textAlign:"right",children:(0,o.createComponentVNode)(2,i.Box,{color:"label",inline:!0,children:e.value})})]},e.ore)}))]})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.LanguageMenu=void 0;var o=n(0),r=n(3),a=n(2);t.LanguageMenu=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.admin_mode,l=i.is_living,u=i.omnitongue,d=i.languages,s=void 0===d?[]:d,p=i.unknown_languages,m=void 0===p?[]:p;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Known Languages",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:s.map((function(e){return(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:e.name,buttons:(0,o.createFragment)([!!l&&(0,o.createComponentVNode)(2,a.Button,{content:e.is_default?"Default Language":"Select as Default",disabled:!e.can_speak,selected:e.is_default,onClick:function(){return n("select_default",{language_name:e.name})}}),!!c&&(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{content:"Grant",onClick:function(){return n("grant_language",{language_name:e.name})}}),(0,o.createComponentVNode)(2,a.Button,{content:"Remove",onClick:function(){return n("remove_language",{language_name:e.name})}})],4)],0),children:[e.desc," ","Key: ,",e.key," ",e.can_understand?"Can understand.":"Cannot understand."," ",e.can_speak?"Can speak.":"Cannot speak."]},e.name)}))})}),!!c&&(0,o.createComponentVNode)(2,a.Section,{title:"Unknown Languages",buttons:(0,o.createComponentVNode)(2,a.Button,{content:"Omnitongue "+(u?"Enabled":"Disabled"),selected:u,onClick:function(){return n("toggle_omnitongue")}}),children:(0,o.createComponentVNode)(2,a.LabeledList,{children:m.map((function(e){return(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:e.name,buttons:(0,o.createComponentVNode)(2,a.Button,{content:"Grant",onClick:function(){return n("grant_language",{language_name:e.name})}}),children:[e.desc," ","Key: ,",e.key," ",e.can_understand?"Can understand.":"Cannot understand."," ",e.can_speak?"Can speak.":"Cannot speak."]},e.name)}))})})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.LaunchpadConsole=t.LaunchpadRemote=t.LaunchpadControl=t.LaunchpadButtonPad=void 0;var o=n(0),r=n(3),a=n(2),i=function(e){var t=(0,r.useBackend)(e).act;return(0,o.createComponentVNode)(2,a.Grid,{width:"1px",children:[(0,o.createComponentVNode)(2,a.Grid.Column,{children:[(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:"arrow-left",iconRotation:45,mb:1,onClick:function(){return t("move_pos",{x:-1,y:1})}}),(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:"arrow-left",mb:1,onClick:function(){return t("move_pos",{x:-1})}}),(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:"arrow-down",iconRotation:45,mb:1,onClick:function(){return t("move_pos",{x:-1,y:-1})}})]}),(0,o.createComponentVNode)(2,a.Grid.Column,{children:[(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:"arrow-up",mb:1,onClick:function(){return t("move_pos",{y:1})}}),(0,o.createComponentVNode)(2,a.Button,{fluid:!0,content:"R",mb:1,onClick:function(){return t("set_pos",{x:0,y:0})}}),(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:"arrow-down",mb:1,onClick:function(){return t("move_pos",{y:-1})}})]}),(0,o.createComponentVNode)(2,a.Grid.Column,{children:[(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:"arrow-up",iconRotation:45,mb:1,onClick:function(){return t("move_pos",{x:1,y:1})}}),(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:"arrow-right",mb:1,onClick:function(){return t("move_pos",{x:1})}}),(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:"arrow-right",iconRotation:45,mb:1,onClick:function(){return t("move_pos",{x:1,y:-1})}})]})]})};t.LaunchpadButtonPad=i;var c=function(e){var t=e.topLevel,n=(0,r.useBackend)(e),c=n.act,l=n.data,u=l.x,d=l.y,s=l.pad_name,p=l.range;return(0,o.createComponentVNode)(2,a.Section,{title:(0,o.createComponentVNode)(2,a.Input,{value:s,width:"170px",onChange:function(e,t){return c("rename",{name:t})}}),level:t?1:2,buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"times",content:"Remove",color:"bad",onClick:function(){return c("remove")}}),children:[(0,o.createComponentVNode)(2,a.Grid,{children:[(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.Section,{title:"Controls",level:2,children:(0,o.createComponentVNode)(2,i,{state:e.state})})}),(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.Section,{title:"Target",level:2,children:(0,o.createComponentVNode)(2,a.Box,{fontSize:"26px",children:[(0,o.createComponentVNode)(2,a.Box,{mb:1,children:[(0,o.createComponentVNode)(2,a.Box,{inline:!0,bold:!0,mr:1,children:"X:"}),(0,o.createComponentVNode)(2,a.NumberInput,{value:u,minValue:-p,maxValue:p,lineHeight:"30px",fontSize:"26px",width:"90px",height:"30px",stepPixelSize:10,onChange:function(e,t){return c("set_pos",{x:t})}})]}),(0,o.createComponentVNode)(2,a.Box,{children:[(0,o.createComponentVNode)(2,a.Box,{inline:!0,bold:!0,mr:1,children:"Y:"}),(0,o.createComponentVNode)(2,a.NumberInput,{value:d,minValue:-p,maxValue:p,stepPixelSize:10,lineHeight:"30px",fontSize:"26px",width:"90px",height:"30px",onChange:function(e,t){return c("set_pos",{y:t})}})]})]})})})]}),(0,o.createComponentVNode)(2,a.Grid,{children:[(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:"upload",content:"Launch",textAlign:"center",onClick:function(){return c("launch")}})}),(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:"download",content:"Pull",textAlign:"center",onClick:function(){return c("pull")}})})]})]})};t.LaunchpadControl=c;t.LaunchpadRemote=function(e){var t=(0,r.useBackend)(e).data,n=t.has_pad,i=t.pad_closed;return n?i?(0,o.createComponentVNode)(2,a.NoticeBox,{children:"Launchpad Closed"}):(0,o.createComponentVNode)(2,c,{topLevel:!0,state:e.state}):(0,o.createComponentVNode)(2,a.NoticeBox,{children:"No Launchpad Connected"})};t.LaunchpadConsole=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,l=i.launchpads,u=void 0===l?[]:l,d=i.selected_id;return u.length<=0?(0,o.createComponentVNode)(2,a.NoticeBox,{children:"No Pads Connected"}):(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.Grid,{children:[(0,o.createComponentVNode)(2,a.Grid.Column,{size:.6,children:(0,o.createComponentVNode)(2,a.Box,{style:{"border-right":"2px solid rgba(255, 255, 255, 0.1)"},minHeight:"190px",mr:1,children:u.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{fluid:!0,content:e.name,selected:d===e.id,color:"transparent",onClick:function(){return n("select_pad",{id:e.id})}},e.name)}))})}),(0,o.createComponentVNode)(2,a.Grid.Column,{children:d?(0,o.createComponentVNode)(2,c,{state:e.state}):(0,o.createComponentVNode)(2,a.Box,{children:"Please select a pad"})})]})})}},function(e,t,n){"use strict";t.__esModule=!0,t.MechBayPowerConsole=void 0;var o=n(0),r=n(3),a=n(2);t.MechBayPowerConsole=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data.recharge_port,c=i&&i.mech,l=c&&c.cell;return(0,o.createComponentVNode)(2,a.Section,{title:"Mech status",textAlign:"center",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"sync",content:"Sync",onClick:function(){return n("reconnect")}}),children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Integrity",children:!i&&(0,o.createComponentVNode)(2,a.NoticeBox,{children:"No power port detected. Please re-sync."})||!c&&(0,o.createComponentVNode)(2,a.NoticeBox,{children:"No mech detected."})||(0,o.createComponentVNode)(2,a.ProgressBar,{value:c.health/c.maxhealth,ranges:{good:[.7,Infinity],average:[.3,.7],bad:[-Infinity,.3]}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Power",children:!i&&(0,o.createComponentVNode)(2,a.NoticeBox,{children:"No power port detected. Please re-sync."})||!c&&(0,o.createComponentVNode)(2,a.NoticeBox,{children:"No mech detected."})||!l&&(0,o.createComponentVNode)(2,a.NoticeBox,{children:"No cell is installed."})||(0,o.createComponentVNode)(2,a.ProgressBar,{value:l.charge/l.maxcharge,ranges:{good:[.7,Infinity],average:[.3,.7],bad:[-Infinity,.3]},children:[(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:l.charge})," / "+l.maxcharge]})})]})})}},function(e,t,n){"use strict";t.__esModule=!0,t.NaniteChamberControl=void 0;var o=n(0),r=n(3),a=n(2);t.NaniteChamberControl=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.status_msg,l=i.locked,u=i.occupant_name,d=i.has_nanites,s=i.nanite_volume,p=i.regen_rate,m=i.safety_threshold,f=i.cloud_id,h=i.scan_level;if(c)return(0,o.createComponentVNode)(2,a.NoticeBox,{textAlign:"center",children:c});var C=i.mob_programs||[];return(0,o.createComponentVNode)(2,a.Section,{title:"Chamber: "+u,buttons:(0,o.createComponentVNode)(2,a.Button,{icon:l?"lock":"lock-open",content:l?"Locked":"Unlocked",color:l?"bad":"default",onClick:function(){return n("toggle_lock")}}),children:d?(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Status",level:2,buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"exclamation-triangle",content:"Destroy Nanites",color:"bad",onClick:function(){return n("remove_nanites")}}),children:(0,o.createComponentVNode)(2,a.Grid,{children:[(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Nanite Volume",children:s}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Growth Rate",children:p})]})}),(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Safety Threshold",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:m,minValue:0,maxValue:500,width:"39px",onChange:function(e,t){return n("set_safety",{value:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Cloud ID",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:f,minValue:0,maxValue:100,step:1,stepPixelSize:3,width:"39px",onChange:function(e,t){return n("set_cloud",{value:t})}})})]})})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Programs",level:2,children:C.map((function(e){var t=e.extra_settings||[],n=e.rules||[];return(0,o.createComponentVNode)(2,a.Collapsible,{title:e.name,children:(0,o.createComponentVNode)(2,a.Section,{children:[(0,o.createComponentVNode)(2,a.Grid,{children:[(0,o.createComponentVNode)(2,a.Grid.Column,{children:e.desc}),h>=2&&(0,o.createComponentVNode)(2,a.Grid.Column,{size:.6,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Activation Status",children:(0,o.createComponentVNode)(2,a.Box,{color:e.activated?"good":"bad",children:e.activated?"Active":"Inactive"})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Nanites Consumed",children:[e.use_rate,"/s"]})]})})]}),h>=2&&(0,o.createComponentVNode)(2,a.Grid,{children:[!!e.can_trigger&&(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.Section,{title:"Triggers",level:2,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger Cost",children:e.trigger_cost}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger Cooldown",children:e.trigger_cooldown}),!!e.timer_trigger_delay&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger Delay",children:[e.timer_trigger_delay," s"]}),!!e.timer_trigger&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger Repeat Timer",children:[e.timer_trigger," s"]})]})})}),!(!e.timer_restart&&!e.timer_shutdown)&&(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[e.timer_restart&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Restart Timer",children:[e.timer_restart," s"]}),e.timer_shutdown&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Shutdown Timer",children:[e.timer_shutdown," s"]})]})})})]}),h>=3&&!!e.has_extra_settings&&(0,o.createComponentVNode)(2,a.Section,{title:"Extra Settings",level:2,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:t.map((function(e){return(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:e.name,children:e.value},e.name)}))})}),h>=4&&(0,o.createComponentVNode)(2,a.Grid,{children:[(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.Section,{title:"Codes",level:2,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[!!e.activation_code&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Activation",children:e.activation_code}),!!e.deactivation_code&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Deactivation",children:e.deactivation_code}),!!e.kill_code&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Kill",children:e.kill_code}),!!e.can_trigger&&!!e.trigger_code&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger",children:e.trigger_code})]})})}),e.has_rules&&(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.Section,{title:"Rules",level:2,children:n.map((function(e){return(0,o.createFragment)([e.display,(0,o.createVNode)(1,"br")],0,e.display)}))})})]})]})},e.name)}))})],4):(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Box,{bold:!0,color:"bad",textAlign:"center",fontSize:"30px",mb:1,children:"No Nanites Detected"}),(0,o.createComponentVNode)(2,a.Button,{fluid:!0,bold:!0,icon:"syringe",content:" Implant Nanites",color:"green",textAlign:"center",fontSize:"30px",lineHeight:"50px",onClick:function(){return n("nanite_injection")}})],4)})}},function(e,t,n){"use strict";t.__esModule=!0,t.NaniteCloudControl=t.NaniteCloudBackupDetails=t.NaniteCloudBackupList=t.NaniteInfoBox=t.NaniteDiskBox=void 0;var o=n(0),r=n(3),a=n(2),i=function(e){var t=e.state.data,n=t.has_disk,r=t.has_program,i=t.disk;return n?r?(0,o.createComponentVNode)(2,c,{program:i}):(0,o.createComponentVNode)(2,a.NoticeBox,{children:"Inserted disk has no program"}):(0,o.createComponentVNode)(2,a.NoticeBox,{children:"No disk inserted"})};t.NaniteDiskBox=i;var c=function(e){var t=e.program,n=t.name,r=t.desc,i=t.activated,c=t.use_rate,l=t.can_trigger,u=t.trigger_cost,d=t.trigger_cooldown,s=t.activation_code,p=t.deactivation_code,m=t.kill_code,f=t.trigger_code,h=t.timer_restart,C=t.timer_shutdown,g=t.timer_trigger,b=t.timer_trigger_delay,N=t.extra_settings||[];return(0,o.createComponentVNode)(2,a.Section,{title:n,level:2,buttons:(0,o.createComponentVNode)(2,a.Box,{inline:!0,bold:!0,color:i?"good":"bad",children:i?"Activated":"Deactivated"}),children:[(0,o.createComponentVNode)(2,a.Grid,{children:[(0,o.createComponentVNode)(2,a.Grid.Column,{mr:1,children:r}),(0,o.createComponentVNode)(2,a.Grid.Column,{size:.5,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Use Rate",children:c}),!!l&&(0,o.createFragment)([(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger Cost",children:u}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger Cooldown",children:d})],4)]})})]}),(0,o.createComponentVNode)(2,a.Grid,{children:[(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.Section,{title:"Codes",level:3,mr:1,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Activation",children:s}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Deactivation",children:p}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Kill",children:m}),!!l&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger",children:f})]})})}),(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.Section,{title:"Delays",level:3,mr:1,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Restart",children:[h," s"]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Shutdown",children:[C," s"]}),!!l&&(0,o.createFragment)([(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger",children:[g," s"]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger Delay",children:[b," s"]})],4)]})})})]}),(0,o.createComponentVNode)(2,a.Section,{title:"Extra Settings",level:3,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:N.map((function(e){var t={number:(0,o.createFragment)([e.value,e.unit],0),text:e.value,type:e.value,boolean:e.value?e.true_text:e.false_text};return(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:e.name,children:t[e.type]},e.name)}))})})]})};t.NaniteInfoBox=c;var l=function(e){var t=(0,r.useBackend)(e),n=t.act;return(t.data.cloud_backups||[]).map((function(e){return(0,o.createComponentVNode)(2,a.Button,{fluid:!0,content:"Backup #"+e.cloud_id,textAlign:"center",onClick:function(){return n("set_view",{view:e.cloud_id})}},e.cloud_id)}))};t.NaniteCloudBackupList=l;var u=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,l=i.current_view,u=i.disk,d=i.has_program,s=i.cloud_backup,p=u&&u.can_rule||!1;if(!s)return(0,o.createComponentVNode)(2,a.NoticeBox,{children:"ERROR: Backup not found"});var m=i.cloud_programs||[];return(0,o.createComponentVNode)(2,a.Section,{title:"Backup #"+l,level:2,buttons:!!d&&(0,o.createComponentVNode)(2,a.Button,{icon:"upload",content:"Upload From Disk",color:"good",onClick:function(){return n("upload_program")}}),children:m.map((function(e){var t=e.rules||[];return(0,o.createComponentVNode)(2,a.Collapsible,{title:e.name,buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"minus-circle",color:"bad",onClick:function(){return n("remove_program",{program_id:e.id})}}),children:(0,o.createComponentVNode)(2,a.Section,{children:[(0,o.createComponentVNode)(2,c,{program:e}),!!p&&(0,o.createComponentVNode)(2,a.Section,{mt:-2,title:"Rules",level:2,buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"plus",content:"Add Rule from Disk",color:"good",onClick:function(){return n("add_rule",{program_id:e.id})}}),children:e.has_rules?t.map((function(t){return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{icon:"minus-circle",color:"bad",onClick:function(){return n("remove_rule",{program_id:e.id,rule_id:t.id})}}),t.display],0,t.display)})):(0,o.createComponentVNode)(2,a.Box,{color:"bad",children:"No Active Rules"})})]})},e.name)}))})};t.NaniteCloudBackupDetails=u;t.NaniteCloudControl=function(e){var t=e.state,n=(0,r.useBackend)(e),c=n.act,d=n.data,s=d.has_disk,p=d.current_view,m=d.new_backup_id;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Program Disk",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"eject",content:"Eject",disabled:!s,onClick:function(){return c("eject")}}),children:(0,o.createComponentVNode)(2,i,{state:t})}),(0,o.createComponentVNode)(2,a.Section,{title:"Cloud Storage",buttons:p?(0,o.createComponentVNode)(2,a.Button,{icon:"arrow-left",content:"Return",onClick:function(){return c("set_view",{view:0})}}):(0,o.createFragment)(["New Backup: ",(0,o.createComponentVNode)(2,a.NumberInput,{value:m,minValue:1,maxValue:100,stepPixelSize:4,width:"39px",onChange:function(e,t){return c("update_new_backup_value",{value:t})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"plus",onClick:function(){return c("create_backup")}})],0),children:d.current_view?(0,o.createComponentVNode)(2,u,{state:t}):(0,o.createComponentVNode)(2,l,{state:t})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.NaniteProgramHub=void 0;var o=n(0),r=n(25),a=n(3),i=n(2);t.NaniteProgramHub=function(e){var t=(0,a.useBackend)(e),n=t.act,c=t.data,l=c.detail_view,u=c.disk,d=c.has_disk,s=c.has_program,p=c.programs,m=void 0===p?{}:p;return(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Section,{title:"Program Disk",buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Button,{icon:"eject",content:"Eject",onClick:function(){return n("eject")}}),(0,o.createComponentVNode)(2,i.Button,{icon:"minus-circle",content:"Delete Program",onClick:function(){return n("clear")}})],4),children:d?s?(0,o.createComponentVNode)(2,i.LabeledList,{children:[(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Program Name",children:u.name}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Description",children:u.desc})]}):(0,o.createComponentVNode)(2,i.NoticeBox,{children:"No Program Installed"}):(0,o.createComponentVNode)(2,i.NoticeBox,{children:"Insert Disk"})}),(0,o.createComponentVNode)(2,i.Section,{title:"Programs",buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Button,{icon:l?"info":"list",content:l?"Detailed":"Compact",onClick:function(){return n("toggle_details")}}),(0,o.createComponentVNode)(2,i.Button,{icon:"sync",content:"Sync Research",onClick:function(){return n("refresh")}})],4),children:null!==m?(0,o.createComponentVNode)(2,i.Tabs,{vertical:!0,children:(0,r.map)((function(e,t){var r=e||[],a=t.substring(0,t.length-8);return(0,o.createComponentVNode)(2,i.Tabs.Tab,{label:a,children:l?r.map((function(e){return(0,o.createComponentVNode)(2,i.Section,{title:e.name,level:2,buttons:(0,o.createComponentVNode)(2,i.Button,{icon:"download",content:"Download",disabled:!d,onClick:function(){return n("download",{program_id:e.id})}}),children:e.desc},e.id)})):(0,o.createComponentVNode)(2,i.LabeledList,{children:r.map((function(e){return(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:e.name,buttons:(0,o.createComponentVNode)(2,i.Button,{icon:"download",content:"Download",disabled:!d,onClick:function(){return n("download",{program_id:e.id})}})},e.id)}))})},t)}))(m)}):(0,o.createComponentVNode)(2,i.NoticeBox,{children:"No nanite programs are currently researched."})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.NaniteProgrammer=t.NaniteExtraBoolean=t.NaniteExtraType=t.NaniteExtraText=t.NaniteExtraNumber=t.NaniteExtraEntry=t.NaniteDelays=t.NaniteCodes=void 0;var o=n(0),r=n(3),a=n(2),i=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createComponentVNode)(2,a.Section,{title:"Codes",level:3,mr:1,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Activation",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:i.activation_code,width:"47px",minValue:0,maxValue:9999,onChange:function(e,t){return n("set_code",{target_code:"activation",code:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Deactivation",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:i.deactivation_code,width:"47px",minValue:0,maxValue:9999,onChange:function(e,t){return n("set_code",{target_code:"deactivation",code:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Kill",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:i.kill_code,width:"47px",minValue:0,maxValue:9999,onChange:function(e,t){return n("set_code",{target_code:"kill",code:t})}})}),!!i.can_trigger&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:i.trigger_code,width:"47px",minValue:0,maxValue:9999,onChange:function(e,t){return n("set_code",{target_code:"trigger",code:t})}})})]})})};t.NaniteCodes=i;var c=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createComponentVNode)(2,a.Section,{title:"Delays",level:3,ml:1,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Restart Timer",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:i.timer_restart,unit:"s",width:"57px",minValue:0,maxValue:3600,onChange:function(e,t){return n("set_restart_timer",{delay:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Shutdown Timer",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:i.timer_shutdown,unit:"s",width:"57px",minValue:0,maxValue:3600,onChange:function(e,t){return n("set_shutdown_timer",{delay:t})}})}),!!i.can_trigger&&(0,o.createFragment)([(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger Repeat Timer",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:i.timer_trigger,unit:"s",width:"57px",minValue:0,maxValue:3600,onChange:function(e,t){return n("set_trigger_timer",{delay:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger Delay",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:i.timer_trigger_delay,unit:"s",width:"57px",minValue:0,maxValue:3600,onChange:function(e,t){return n("set_timer_trigger_delay",{delay:t})}})})],4)]})})};t.NaniteDelays=c;var l=function(e){var t=e.act,n=e.extra_setting,r=n.name,i=n.type,c={number:(0,o.createComponentVNode)(2,u,{act:t,extra_setting:n}),text:(0,o.createComponentVNode)(2,d,{act:t,extra_setting:n}),type:(0,o.createComponentVNode)(2,s,{act:t,extra_setting:n}),boolean:(0,o.createComponentVNode)(2,p,{act:t,extra_setting:n})};return(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:r,children:c[i]})};t.NaniteExtraEntry=l;var u=function(e){var t=e.act,n=e.extra_setting,r=n.name,i=n.value,c=n.min,l=n.max,u=n.unit;return(0,o.createComponentVNode)(2,a.NumberInput,{value:i,width:"64px",minValue:c,maxValue:l,unit:u,onChange:function(e,n){return t("set_extra_setting",{target_setting:r,value:n})}})};t.NaniteExtraNumber=u;var d=function(e){var t=e.act,n=e.extra_setting,r=n.name,i=n.value;return(0,o.createComponentVNode)(2,a.Input,{value:i,width:"200px",onInput:function(e,n){return t("set_extra_setting",{target_setting:r,value:n})}})};t.NaniteExtraText=d;var s=function(e){var t=e.act,n=e.extra_setting,r=n.name,i=n.value,c=n.types;return(0,o.createComponentVNode)(2,a.Dropdown,{over:!0,selected:i,width:"150px",options:c,onSelected:function(e){return t("set_extra_setting",{target_setting:r,value:e})}})};t.NaniteExtraType=s;var p=function(e){var t=e.act,n=e.extra_setting,r=n.name,i=n.value,c=n.true_text,l=n.false_text;return(0,o.createComponentVNode)(2,a.Button.Checkbox,{content:i?c:l,checked:i,onClick:function(){return t("set_extra_setting",{target_setting:r})}})};t.NaniteExtraBoolean=p;t.NaniteProgrammer=function(e){var t=(0,r.useBackend)(e),n=t.act,u=t.data,d=u.has_disk,s=u.has_program,p=u.name,m=u.desc,f=u.use_rate,h=u.can_trigger,C=u.trigger_cost,g=u.trigger_cooldown,b=u.activated,N=u.has_extra_settings,v=u.extra_settings,V=void 0===v?{}:v;return d?s?(0,o.createComponentVNode)(2,a.Section,{title:p,buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"eject",content:"Eject",onClick:function(){return n("eject")}}),children:[(0,o.createComponentVNode)(2,a.Section,{title:"Info",level:2,children:(0,o.createComponentVNode)(2,a.Grid,{children:[(0,o.createComponentVNode)(2,a.Grid.Column,{children:m}),(0,o.createComponentVNode)(2,a.Grid.Column,{size:.7,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Use Rate",children:f}),!!h&&(0,o.createFragment)([(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger Cost",children:C}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Trigger Cooldown",children:g})],4)]})})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Settings",level:2,buttons:(0,o.createComponentVNode)(2,a.Button,{icon:b?"power-off":"times",content:b?"Active":"Inactive",selected:b,color:"bad",bold:!0,onClick:function(){return n("toggle_active")}}),children:[(0,o.createComponentVNode)(2,a.Grid,{children:[(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,i,{state:e.state})}),(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,c,{state:e.state})})]}),!!N&&(0,o.createComponentVNode)(2,a.Section,{title:"Special",level:3,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:V.map((function(e){return(0,o.createComponentVNode)(2,l,{act:n,extra_setting:e},e.name)}))})})]})]}):(0,o.createComponentVNode)(2,a.Section,{title:"Blank Disk",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"eject",content:"Eject",onClick:function(){return n("eject")}})}):(0,o.createComponentVNode)(2,a.NoticeBox,{textAlign:"center",children:"Insert a nanite program disk"})}},function(e,t,n){"use strict";t.__esModule=!0,t.NaniteRemote=void 0;var o=n(0),r=n(3),a=n(2);t.NaniteRemote=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.code,l=i.locked,u=i.mode,d=i.program_name,s=i.relay_code,p=i.comms,m=i.message,f=i.saved_settings,h=void 0===f?[]:f;return l?(0,o.createComponentVNode)(2,a.NoticeBox,{children:"This interface is locked."}):(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Nanite Control",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"lock",content:"Lock Interface",onClick:function(){return n("lock")}}),children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Name",children:[(0,o.createComponentVNode)(2,a.Input,{value:d,maxLength:14,width:"130px",onChange:function(e,t){return n("update_name",{name:t})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"save",content:"Save",onClick:function(){return n("save")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:p?"Comm Code":"Signal Code",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:c,minValue:0,maxValue:9999,width:"47px",step:1,stepPixelSize:2,onChange:function(e,t){return n("set_code",{code:t})}})}),!!p&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Message",children:(0,o.createComponentVNode)(2,a.Input,{value:m,width:"270px",onChange:function(e,t){return n("set_message",{value:t})}})}),"Relay"===u&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Relay Code",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:s,minValue:0,maxValue:9999,width:"47px",step:1,stepPixelSize:2,onChange:function(e,t){return n("set_relay_code",{code:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Signal Mode",children:["Off","Local","Targeted","Area","Relay"].map((function(e){return(0,o.createComponentVNode)(2,a.Button,{content:e,selected:u===e,onClick:function(){return n("select_mode",{mode:e})}},e)}))})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Saved Settings",children:h.length>0?(0,o.createComponentVNode)(2,a.Table,{children:[(0,o.createComponentVNode)(2,a.Table.Row,{header:!0,children:[(0,o.createComponentVNode)(2,a.Table.Cell,{width:"35%",children:"Name"}),(0,o.createComponentVNode)(2,a.Table.Cell,{width:"20%",children:"Mode"}),(0,o.createComponentVNode)(2,a.Table.Cell,{collapsing:!0,children:"Code"}),(0,o.createComponentVNode)(2,a.Table.Cell,{collapsing:!0,children:"Relay"})]}),h.map((function(e){return(0,o.createComponentVNode)(2,a.Table.Row,{className:"candystripe",children:[(0,o.createComponentVNode)(2,a.Table.Cell,{bold:!0,color:"label",children:[e.name,":"]}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:e.mode}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:e.code}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:"Relay"===e.mode&&e.relay_code}),(0,o.createComponentVNode)(2,a.Table.Cell,{textAlign:"right",children:[(0,o.createComponentVNode)(2,a.Button,{icon:"upload",color:"good",onClick:function(){return n("load",{save_id:e.id})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"minus",color:"bad",onClick:function(){return n("remove_save",{save_id:e.id})}})]})]},e.id)}))]}):(0,o.createComponentVNode)(2,a.NoticeBox,{children:"No settings currently saved"})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.Mule=void 0;var o=n(0),r=n(3),a=n(2),i=n(70);t.Mule=function(e){var t=(0,r.useBackend)(e),n=t.act,c=t.data,l=c.locked&&!c.siliconUser,u=c.siliconUser,d=c.on,s=c.cell,p=c.cellPercent,m=c.load,f=c.mode,h=c.modeStatus,C=c.haspai,g=c.autoReturn,b=c.autoPickup,N=c.reportDelivery,v=c.destination,V=c.home,y=c.id,_=c.destinations,x=void 0===_?[]:_;return(0,o.createFragment)([(0,o.createComponentVNode)(2,i.InterfaceLockNoticeBox,{siliconUser:u,locked:l}),(0,o.createComponentVNode)(2,a.Section,{title:"Status",minHeight:"110px",buttons:!l&&(0,o.createComponentVNode)(2,a.Button,{icon:d?"power-off":"times",content:d?"On":"Off",selected:d,onClick:function(){return n("power")}}),children:[(0,o.createComponentVNode)(2,a.ProgressBar,{value:s?p/100:0,color:s?"good":"bad"}),(0,o.createComponentVNode)(2,a.Grid,{mt:1,children:[(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Mode",color:h,children:f})})}),(0,o.createComponentVNode)(2,a.Grid.Column,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Load",color:m?"good":"average",children:m||"None"})})})]})]}),!l&&(0,o.createComponentVNode)(2,a.Section,{title:"Controls",buttons:(0,o.createFragment)([!!m&&(0,o.createComponentVNode)(2,a.Button,{icon:"eject",content:"Unload",onClick:function(){return n("unload")}}),!!C&&(0,o.createComponentVNode)(2,a.Button,{icon:"eject",content:"Eject PAI",onClick:function(){return n("ejectpai")}})],0),children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"ID",children:(0,o.createComponentVNode)(2,a.Input,{value:y,onChange:function(e,t){return n("setid",{value:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Destination",children:[(0,o.createComponentVNode)(2,a.Dropdown,{over:!0,selected:v||"None",options:x,width:"150px",onSelected:function(e){return n("destination",{value:e})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"stop",content:"Stop",onClick:function(){return n("stop")}}),(0,o.createComponentVNode)(2,a.Button,{icon:"play",content:"Go",onClick:function(){return n("go")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Home",children:[(0,o.createComponentVNode)(2,a.Dropdown,{over:!0,selected:V,options:x,width:"150px",onSelected:function(e){return n("destination",{value:e})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"home",content:"Go Home",onClick:function(){return n("home")}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Settings",children:[(0,o.createComponentVNode)(2,a.Button.Checkbox,{checked:g,content:"Auto-Return",onClick:function(){return n("autored")}}),(0,o.createVNode)(1,"br"),(0,o.createComponentVNode)(2,a.Button.Checkbox,{checked:b,content:"Auto-Pickup",onClick:function(){return n("autopick")}}),(0,o.createVNode)(1,"br"),(0,o.createComponentVNode)(2,a.Button.Checkbox,{checked:N,content:"Report Delivery",onClick:function(){return n("report")}})]})]})})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.NotificationPreferences=void 0;var o=n(0),r=n(3),a=n(2);t.NotificationPreferences=function(e){var t=(0,r.useBackend)(e),n=t.act,i=(t.data.ignore||[]).sort((function(e,t){var n=e.desc.toLowerCase(),o=t.desc.toLowerCase();return no?1:0}));return(0,o.createComponentVNode)(2,a.Section,{title:"Ghost Role Notifications",children:i.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:e.enabled?"times":"check",content:e.desc,color:e.enabled?"bad":"good",onClick:function(){return n("toggle_ignore",{key:e.key})}},e.key)}))})}},function(e,t,n){"use strict";t.__esModule=!0,t.NtnetRelay=void 0;var o=n(0),r=n(3),a=n(2);t.NtnetRelay=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.enabled,l=i.dos_capacity,u=i.dos_overload,d=i.dos_crashed;return(0,o.createComponentVNode)(2,a.Section,{title:"Network Buffer",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"power-off",selected:c,content:c?"ENABLED":"DISABLED",onClick:function(){return n("toggle")}}),children:d?(0,o.createComponentVNode)(2,a.Box,{fontFamily:"monospace",children:[(0,o.createComponentVNode)(2,a.Box,{fontSize:"20px",children:"NETWORK BUFFER OVERFLOW"}),(0,o.createComponentVNode)(2,a.Box,{fontSize:"16px",children:"OVERLOAD RECOVERY MODE"}),(0,o.createComponentVNode)(2,a.Box,{children:"This system is suffering temporary outage due to overflow of traffic buffers. Until buffered traffic is processed, all further requests will be dropped. Frequent occurences of this error may indicate insufficient hardware capacity of your network. Please contact your network planning department for instructions on how to resolve this issue."}),(0,o.createComponentVNode)(2,a.Box,{fontSize:"20px",color:"bad",children:"ADMINISTRATOR OVERRIDE"}),(0,o.createComponentVNode)(2,a.Box,{fontSize:"16px",color:"bad",children:"CAUTION - DATA LOSS MAY OCCUR"}),(0,o.createComponentVNode)(2,a.Button,{icon:"signal",content:"PURGE BUFFER",mt:1,color:"bad",onClick:function(){return n("restart")}})]}):(0,o.createComponentVNode)(2,a.ProgressBar,{value:u,minValue:0,maxValue:l,children:[(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:u})," GQ"," / ",l," GQ"]})})}},function(e,t,n){"use strict";t.__esModule=!0,t.NtosArcade=void 0;var o=n(0),r=n(3),a=n(2);t.NtosArcade=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createComponentVNode)(2,a.Section,{title:"Outbomb Cuban Pete Ultra",textAlign:"center",children:[(0,o.createComponentVNode)(2,a.Box,{children:[(0,o.createComponentVNode)(2,a.Grid,{children:[(0,o.createComponentVNode)(2,a.Grid.Column,{size:2,children:[(0,o.createComponentVNode)(2,a.Box,{m:1}),(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Player Health",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:i.PlayerHitpoints,minValue:0,maxValue:30,ranges:{olive:[31,Infinity],good:[20,31],average:[10,20],bad:[-Infinity,10]},children:[i.PlayerHitpoints,"HP"]})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Player Magic",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:i.PlayerMP,minValue:0,maxValue:10,ranges:{purple:[11,Infinity],violet:[3,11],bad:[-Infinity,3]},children:[i.PlayerMP,"MP"]})})]}),(0,o.createComponentVNode)(2,a.Box,{my:1,mx:4}),(0,o.createComponentVNode)(2,a.Section,{backgroundColor:1===i.PauseState?"#1b3622":"#471915",children:i.Status})]}),(0,o.createComponentVNode)(2,a.Grid.Column,{children:[(0,o.createComponentVNode)(2,a.ProgressBar,{value:i.Hitpoints/45,minValue:0,maxValue:45,ranges:{good:[30,Infinity],average:[5,30],bad:[-Infinity,5]},children:[(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:i.Hitpoints}),"HP"]}),(0,o.createComponentVNode)(2,a.Box,{m:1}),(0,o.createComponentVNode)(2,a.Section,{inline:!0,width:26,textAlign:"center",children:(0,o.createVNode)(1,"img",null,null,1,{src:i.BossID})})]})]}),(0,o.createComponentVNode)(2,a.Box,{my:1,mx:4}),(0,o.createComponentVNode)(2,a.Button,{icon:"fist-raised",tooltip:"Go in for the kill!",tooltipPosition:"top",disabled:0===i.GameActive||1===i.PauseState,onClick:function(){return n("Attack")},content:"Attack!"}),(0,o.createComponentVNode)(2,a.Button,{icon:"band-aid",tooltip:"Heal yourself!",tooltipPosition:"top",disabled:0===i.GameActive||1===i.PauseState,onClick:function(){return n("Heal")},content:"Heal!"}),(0,o.createComponentVNode)(2,a.Button,{icon:"magic",tooltip:"Recharge your magic!",tooltipPosition:"top",disabled:0===i.GameActive||1===i.PauseState,onClick:function(){return n("Recharge_Power")},content:"Recharge!"})]}),(0,o.createComponentVNode)(2,a.Box,{children:[(0,o.createComponentVNode)(2,a.Button,{icon:"sync-alt",tooltip:"One more game couldn't hurt.",tooltipPosition:"top",disabled:1===i.GameActive,onClick:function(){return n("Start_Game")},content:"Begin Game"}),(0,o.createComponentVNode)(2,a.Button,{icon:"ticket-alt",tooltip:"Claim at your local Arcade Computer for Prizes!",tooltipPosition:"top",disabled:1===i.GameActive,onClick:function(){return n("Dispense_Tickets")},content:"Claim Tickets"})]}),(0,o.createComponentVNode)(2,a.Box,{color:i.TicketCount>=1?"good":"normal",children:["Earned Tickets: ",i.TicketCount]})]})}},function(e,t,n){"use strict";t.__esModule=!0,t.NtosConfiguration=void 0;var o=n(0),r=n(3),a=n(2);t.NtosConfiguration=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.power_usage,l=i.battery_exists,u=i.battery,d=void 0===u?{}:u,s=i.disk_size,p=i.disk_used,m=i.hardware,f=void 0===m?[]:m;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Power Supply",buttons:(0,o.createComponentVNode)(2,a.Box,{inline:!0,bold:!0,mr:1,children:["Power Draw: ",c,"W"]}),children:(0,o.createComponentVNode)(2,a.LabeledList,{children:(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Battery Status",color:!l&&"average",children:l?(0,o.createComponentVNode)(2,a.ProgressBar,{value:d.charge,minValue:0,maxValue:d.max,ranges:{good:[d.max/2,Infinity],average:[d.max/4,d.max/2],bad:[-Infinity,d.max/4]},children:[d.charge," / ",d.max]}):"Not Available"})})}),(0,o.createComponentVNode)(2,a.Section,{title:"File System",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:p,minValue:0,maxValue:s,color:"good",children:[p," GQ / ",s," GQ"]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Hardware Components",children:f.map((function(e){return(0,o.createComponentVNode)(2,a.Section,{title:e.name,level:2,buttons:(0,o.createFragment)([!e.critical&&(0,o.createComponentVNode)(2,a.Button.Checkbox,{content:"Enabled",checked:e.enabled,mr:1,onClick:function(){return n("PC_toggle_component",{name:e.name})}}),(0,o.createComponentVNode)(2,a.Box,{inline:!0,bold:!0,mr:1,children:["Power Usage: ",e.powerusage,"W"]})],0),children:e.desc},e.name)}))})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.NtosMain=void 0;var o=n(0),r=n(3),a=n(2),i={compconfig:"cog",ntndownloader:"download",filemanager:"folder",smmonitor:"radiation",alarmmonitor:"bell",cardmod:"id-card",arcade:"gamepad",ntnrc_client:"comment-alt",nttransfer:"exchange-alt",powermonitor:"plug"};t.NtosMain=function(e){var t=(0,r.useBackend)(e),n=t.act,c=t.data,l=c.programs,u=void 0===l?[]:l,d=c.has_light,s=c.light_on,p=c.comp_light_color;return(0,o.createFragment)([!!d&&(0,o.createComponentVNode)(2,a.Section,{children:[(0,o.createComponentVNode)(2,a.Button,{width:"144px",icon:"lightbulb",selected:s,onClick:function(){return n("PC_toggle_light")},children:["Flashlight: ",s?"ON":"OFF"]}),(0,o.createComponentVNode)(2,a.Button,{ml:1,onClick:function(){return n("PC_light_color")},children:["Color:",(0,o.createComponentVNode)(2,a.ColorBox,{ml:1,color:p})]})]}),(0,o.createComponentVNode)(2,a.Section,{title:"Programs",children:(0,o.createComponentVNode)(2,a.Table,{children:u.map((function(e){return(0,o.createComponentVNode)(2,a.Table.Row,{children:[(0,o.createComponentVNode)(2,a.Table.Cell,{children:(0,o.createComponentVNode)(2,a.Button,{fluid:!0,lineHeight:"24px",color:"transparent",icon:i[e.name]||"window-maximize-o",content:e.desc,onClick:function(){return n("PC_runprogram",{name:e.name})}})}),(0,o.createComponentVNode)(2,a.Table.Cell,{collapsing:!0,width:3,children:!!e.running&&(0,o.createComponentVNode)(2,a.Button,{lineHeight:"24px",color:"transparent",icon:"times",tooltip:"Close program",tooltipPosition:"left",onClick:function(){return n("PC_killprogram",{name:e.name})}})})]},e.name)}))})})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.NtosNetChat=void 0;var o=n(0),r=n(3),a=n(2);(0,n(53).createLogger)("ntos chat");t.NtosNetChat=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.can_admin,l=i.adminmode,u=i.authed,d=i.username,s=i.active_channel,p=i.is_operator,m=i.all_channels,f=void 0===m?[]:m,h=i.clients,C=void 0===h?[]:h,g=i.messages,b=void 0===g?[]:g,N=null!==s,v=u||l;return(0,o.createComponentVNode)(2,a.Section,{height:"600px",children:(0,o.createComponentVNode)(2,a.Table,{height:"580px",children:(0,o.createComponentVNode)(2,a.Table.Row,{children:[(0,o.createComponentVNode)(2,a.Table.Cell,{verticalAlign:"top",style:{width:"200px"},children:[(0,o.createComponentVNode)(2,a.Box,{height:"537px",overflowY:"scroll",children:[(0,o.createComponentVNode)(2,a.Button.Input,{fluid:!0,content:"New Channel...",onCommit:function(e,t){return n("PRG_newchannel",{new_channel_name:t})}}),f.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{fluid:!0,content:e.chan,selected:e.id===s,color:"transparent",onClick:function(){return n("PRG_joinchannel",{id:e.id})}},e.chan)}))]}),(0,o.createComponentVNode)(2,a.Button.Input,{fluid:!0,mt:1,content:d+"...",currentValue:d,onCommit:function(e,t){return n("PRG_changename",{new_name:t})}}),!!c&&(0,o.createComponentVNode)(2,a.Button,{fluid:!0,bold:!0,content:"ADMIN MODE: "+(l?"ON":"OFF"),color:l?"bad":"good",onClick:function(){return n("PRG_toggleadmin")}})]}),(0,o.createComponentVNode)(2,a.Table.Cell,{children:[(0,o.createComponentVNode)(2,a.Box,{height:"560px",overflowY:"scroll",children:N&&(v?b.map((function(e){return(0,o.createComponentVNode)(2,a.Box,{children:e.msg},e.msg)})):(0,o.createComponentVNode)(2,a.Box,{textAlign:"center",children:[(0,o.createComponentVNode)(2,a.Icon,{name:"exclamation-triangle",mt:4,fontSize:"40px"}),(0,o.createComponentVNode)(2,a.Box,{mt:1,bold:!0,fontSize:"18px",children:"THIS CHANNEL IS PASSWORD PROTECTED"}),(0,o.createComponentVNode)(2,a.Box,{mt:1,children:"INPUT PASSWORD TO ACCESS"})]}))}),(0,o.createComponentVNode)(2,a.Input,{fluid:!0,selfClear:!0,mt:1,onEnter:function(e,t){return n("PRG_speak",{message:t})}})]}),(0,o.createComponentVNode)(2,a.Table.Cell,{verticalAlign:"top",style:{width:"150px"},children:[(0,o.createComponentVNode)(2,a.Box,{height:"477px",overflowY:"scroll",children:C.map((function(e){return(0,o.createComponentVNode)(2,a.Box,{children:e.name},e.name)}))}),N&&v&&(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button.Input,{fluid:!0,content:"Save log...",defaultValue:"new_log",onCommit:function(e,t){return n("PRG_savelog",{log_name:t})}}),(0,o.createComponentVNode)(2,a.Button.Confirm,{fluid:!0,content:"Leave Channel",onClick:function(){return n("PRG_leavechannel")}})],4),!!p&&u&&(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button.Confirm,{fluid:!0,content:"Delete Channel",onClick:function(){return n("PRG_deletechannel")}}),(0,o.createComponentVNode)(2,a.Button.Input,{fluid:!0,content:"Rename Channel...",onCommit:function(e,t){return n("PRG_renamechannel",{new_name:t})}}),(0,o.createComponentVNode)(2,a.Button.Input,{fluid:!0,content:"Set Password...",onCommit:function(e,t){return n("PRG_setpassword",{new_password:t})}})],4)]})]})})})}},function(e,t,n){"use strict";t.__esModule=!0,t.NtosNetDownloader=void 0;var o=n(0),r=n(3),a=n(2);t.NtosNetDownloader=function(e){var t=e.state,n=(0,r.useBackend)(e),c=n.act,l=n.data,u=l.disk_size,d=l.disk_used,s=l.downloadable_programs,p=void 0===s?[]:s,m=l.error,f=l.hacked_programs,h=void 0===f?[]:f,C=l.hackedavailable;return(0,o.createFragment)([!!m&&(0,o.createComponentVNode)(2,a.NoticeBox,{children:[(0,o.createComponentVNode)(2,a.Box,{mb:1,children:m}),(0,o.createComponentVNode)(2,a.Button,{content:"Reset",onClick:function(){return c("PRG_reseterror")}})]}),(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Disk usage",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:d,minValue:0,maxValue:u,children:d+" GQ / "+u+" GQ"})})})}),(0,o.createComponentVNode)(2,a.Section,{children:p.map((function(e){return(0,o.createComponentVNode)(2,i,{state:t,program:e},e.filename)}))}),!!C&&(0,o.createComponentVNode)(2,a.Section,{title:"UNKNOWN Software Repository",children:[(0,o.createComponentVNode)(2,a.NoticeBox,{mb:1,children:"Please note that Nanotrasen does not recommend download of software from non-official servers."}),h.map((function(e){return(0,o.createComponentVNode)(2,i,{state:t,program:e},e.filename)}))]})],0)};var i=function(e){var t=e.program,n=(0,r.useBackend)(e),i=n.act,c=n.data,l=c.disk_size,u=c.disk_used,d=c.downloadcompletion,s=c.downloading,p=c.downloadname,m=c.downloadsize,f=l-u;return(0,o.createComponentVNode)(2,a.Box,{mb:3,children:[(0,o.createComponentVNode)(2,a.Flex,{align:"baseline",children:[(0,o.createComponentVNode)(2,a.Flex.Item,{bold:!0,grow:1,children:t.filedesc}),(0,o.createComponentVNode)(2,a.Flex.Item,{color:"label",nowrap:!0,children:[t.size," GQ"]}),(0,o.createComponentVNode)(2,a.Flex.Item,{ml:2,width:"94px",textAlign:"center",children:t.filename===p&&(0,o.createComponentVNode)(2,a.ProgressBar,{color:"green",minValue:0,maxValue:m,value:d})||(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:"download",content:"Download",disabled:s||t.size>f,onClick:function(){return i("PRG_downloadfile",{filename:t.filename})}})})]}),"Compatible"!==t.compatibility&&(0,o.createComponentVNode)(2,a.Box,{mt:1,italic:!0,fontSize:"12px",position:"relative",children:[(0,o.createComponentVNode)(2,a.Icon,{mx:1,color:"red",name:"times"}),"Incompatible!"]}),t.size>f&&(0,o.createComponentVNode)(2,a.Box,{mt:1,italic:!0,fontSize:"12px",position:"relative",children:[(0,o.createComponentVNode)(2,a.Icon,{mx:1,color:"red",name:"times"}),"Not enough disk space!"]}),(0,o.createComponentVNode)(2,a.Box,{mt:1,italic:!0,color:"label",fontSize:"12px",children:t.fileinfo})]})}},function(e,t,n){"use strict";t.__esModule=!0,t.NtosSupermatterMonitor=void 0;var o=n(0),r=n(25),a=n(71),i=n(17),c=n(3),l=n(2),u=n(33),d=function(e){return Math.log2(16+Math.max(0,e))-4};t.NtosSupermatterMonitor=function(e){var t=e.state,n=(0,c.useBackend)(e),p=n.act,m=n.data,f=m.active,h=m.SM_integrity,C=m.SM_power,g=m.SM_ambienttemp,b=m.SM_ambientpressure;if(!f)return(0,o.createComponentVNode)(2,s,{state:t});var N=(0,a.flow)([function(e){return e.filter((function(e){return e.amount>=.01}))},(0,r.sortBy)((function(e){return-e.amount}))])(m.gases||[]),v=Math.max.apply(Math,[1].concat(N.map((function(e){return e.amount}))));return(0,o.createComponentVNode)(2,l.Flex,{spacing:1,children:[(0,o.createComponentVNode)(2,l.Flex.Item,{width:"270px",children:(0,o.createComponentVNode)(2,l.Section,{title:"Metrics",children:(0,o.createComponentVNode)(2,l.LabeledList,{children:[(0,o.createComponentVNode)(2,l.LabeledList.Item,{label:"Integrity",children:(0,o.createComponentVNode)(2,l.ProgressBar,{value:h/100,ranges:{good:[.9,Infinity],average:[.5,.9],bad:[-Infinity,.5]}})}),(0,o.createComponentVNode)(2,l.LabeledList.Item,{label:"Relative EER",children:(0,o.createComponentVNode)(2,l.ProgressBar,{value:C,minValue:0,maxValue:5e3,ranges:{good:[-Infinity,5e3],average:[5e3,7e3],bad:[7e3,Infinity]},children:(0,i.toFixed)(C)+" MeV/cm3"})}),(0,o.createComponentVNode)(2,l.LabeledList.Item,{label:"Temperature",children:(0,o.createComponentVNode)(2,l.ProgressBar,{value:d(g),minValue:0,maxValue:d(1e4),ranges:{teal:[-Infinity,d(80)],good:[d(80),d(373)],average:[d(373),d(1e3)],bad:[d(1e3),Infinity]},children:(0,i.toFixed)(g)+" K"})}),(0,o.createComponentVNode)(2,l.LabeledList.Item,{label:"Pressure",children:(0,o.createComponentVNode)(2,l.ProgressBar,{value:d(b),minValue:0,maxValue:d(5e4),ranges:{good:[d(1),d(300)],average:[-Infinity,d(1e3)],bad:[d(1e3),+Infinity]},children:(0,i.toFixed)(b)+" kPa"})})]})})}),(0,o.createComponentVNode)(2,l.Flex.Item,{grow:1,children:(0,o.createComponentVNode)(2,l.Section,{title:"Gases",buttons:(0,o.createComponentVNode)(2,l.Button,{icon:"arrow-left",content:"Back",onClick:function(){return p("PRG_clear")}}),children:(0,o.createComponentVNode)(2,l.Box.Forced,{height:24*N.length+"px",children:(0,o.createComponentVNode)(2,l.LabeledList,{children:N.map((function(e){return(0,o.createComponentVNode)(2,l.LabeledList.Item,{label:(0,u.getGasLabel)(e.name),children:(0,o.createComponentVNode)(2,l.ProgressBar,{color:(0,u.getGasColor)(e.name),value:e.amount,minValue:0,maxValue:v,children:(0,i.toFixed)(e.amount,2)+"%"})},e.name)}))})})})})]})};var s=function(e){var t=(0,c.useBackend)(e),n=t.act,r=t.data.supermatters,a=void 0===r?[]:r;return(0,o.createComponentVNode)(2,l.Section,{title:"Detected Supermatters",buttons:(0,o.createComponentVNode)(2,l.Button,{icon:"sync",content:"Refresh",onClick:function(){return n("PRG_refresh")}}),children:(0,o.createComponentVNode)(2,l.Table,{children:a.map((function(e){return(0,o.createComponentVNode)(2,l.Table.Row,{children:[(0,o.createComponentVNode)(2,l.Table.Cell,{children:e.uid+". "+e.area_name}),(0,o.createComponentVNode)(2,l.Table.Cell,{collapsing:!0,color:"label",children:"Integrity:"}),(0,o.createComponentVNode)(2,l.Table.Cell,{collapsing:!0,width:"120px",children:(0,o.createComponentVNode)(2,l.ProgressBar,{value:e.integrity/100,ranges:{good:[.9,Infinity],average:[.5,.9],bad:[-Infinity,.5]}})}),(0,o.createComponentVNode)(2,l.Table.Cell,{collapsing:!0,children:(0,o.createComponentVNode)(2,l.Button,{content:"Details",onClick:function(){return n("PRG_set",{target:e.uid})}})})]},e.uid)}))})})}},function(e,t,n){"use strict";t.__esModule=!0,t.NtosWrapper=void 0;var o=n(0),r=n(3),a=n(2),i=n(119);t.NtosWrapper=function(e){var t=e.children,n=(0,r.useBackend)(e),c=n.act,l=n.data,u=l.PC_batteryicon,d=l.PC_showbatteryicon,s=l.PC_batterypercent,p=l.PC_ntneticon,m=l.PC_apclinkicon,f=l.PC_stationtime,h=l.PC_programheaders,C=void 0===h?[]:h,g=l.PC_showexitprogram;return(0,o.createVNode)(1,"div","NtosWrapper",[(0,o.createVNode)(1,"div","NtosWrapper__header NtosHeader",[(0,o.createVNode)(1,"div","NtosHeader__left",[(0,o.createComponentVNode)(2,a.Box,{inline:!0,bold:!0,mr:2,children:f}),(0,o.createComponentVNode)(2,a.Box,{inline:!0,italic:!0,mr:2,opacity:.33,children:"NtOS"})],4),(0,o.createVNode)(1,"div","NtosHeader__right",[C.map((function(e){return(0,o.createComponentVNode)(2,a.Box,{inline:!0,mr:1,children:(0,o.createVNode)(1,"img","NtosHeader__icon",null,1,{src:e.icon})},e.icon)})),(0,o.createComponentVNode)(2,a.Box,{inline:!0,children:p&&(0,o.createVNode)(1,"img","NtosHeader__icon",null,1,{src:p})}),!!d&&u&&(0,o.createComponentVNode)(2,a.Box,{inline:!0,mr:1,children:[u&&(0,o.createVNode)(1,"img","NtosHeader__icon",null,1,{src:u}),s&&s]}),m&&(0,o.createComponentVNode)(2,a.Box,{inline:!0,mr:1,children:(0,o.createVNode)(1,"img","NtosHeader__icon",null,1,{src:m})}),!!g&&(0,o.createComponentVNode)(2,a.Button,{width:"26px",lineHeight:"22px",textAlign:"center",color:"transparent",icon:"window-minimize-o",tooltip:"Minimize",tooltipPosition:"bottom",onClick:function(){return c("PC_minimize")}}),!!g&&(0,o.createComponentVNode)(2,a.Button,{mr:"-3px",width:"26px",lineHeight:"22px",textAlign:"center",color:"transparent",icon:"window-close-o",tooltip:"Close",tooltipPosition:"bottom-left",onClick:function(){return c("PC_exit")}}),!g&&(0,o.createComponentVNode)(2,a.Button,{mr:"-3px",width:"26px",lineHeight:"22px",textAlign:"center",color:"transparent",icon:"power-off",tooltip:"Power off",tooltipPosition:"bottom-left",onClick:function(){return c("PC_shutdown")}})],0)],4,{onMouseDown:function(){(0,i.refocusLayout)()}}),(0,o.createVNode)(1,"div","NtosWrapper__content",t,0)],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.NuclearBomb=void 0;var o=n(0),r=n(11),a=n(3),i=n(2),c=function(e){var t=(0,a.useBackend)(e).act;return(0,o.createComponentVNode)(2,i.Box,{width:"185px",children:(0,o.createComponentVNode)(2,i.Grid,{width:"1px",children:[["1","4","7","C"],["2","5","8","0"],["3","6","9","E"]].map((function(e){return(0,o.createComponentVNode)(2,i.Grid.Column,{children:e.map((function(e){return(0,o.createComponentVNode)(2,i.Button,{fluid:!0,bold:!0,mb:1,content:e,textAlign:"center",fontSize:"40px",lineHeight:"50px",width:"55px",className:(0,r.classes)(["NuclearBomb__Button","NuclearBomb__Button--keypad","NuclearBomb__Button--"+e]),onClick:function(){return t("keypad",{digit:e})}},e)}))},e[0])}))})})};t.NuclearBomb=function(e){var t=e.state,n=(0,a.useBackend)(e),r=n.act,l=n.data,u=(l.anchored,l.disk_present,l.status1),d=l.status2;return(0,o.createComponentVNode)(2,i.Box,{m:1,children:[(0,o.createComponentVNode)(2,i.Box,{mb:1,className:"NuclearBomb__displayBox",children:u}),(0,o.createComponentVNode)(2,i.Flex,{mb:1.5,children:[(0,o.createComponentVNode)(2,i.Flex.Item,{grow:1,children:(0,o.createComponentVNode)(2,i.Box,{className:"NuclearBomb__displayBox",children:d})}),(0,o.createComponentVNode)(2,i.Flex.Item,{children:(0,o.createComponentVNode)(2,i.Button,{icon:"eject",fontSize:"24px",lineHeight:"23px",textAlign:"center",width:"43px",ml:1,mr:"3px",mt:"3px",className:"NuclearBomb__Button NuclearBomb__Button--keypad",onClick:function(){return r("eject_disk")}})})]}),(0,o.createComponentVNode)(2,i.Flex,{ml:"3px",children:[(0,o.createComponentVNode)(2,i.Flex.Item,{children:(0,o.createComponentVNode)(2,c,{state:t})}),(0,o.createComponentVNode)(2,i.Flex.Item,{ml:1,width:"129px",children:(0,o.createComponentVNode)(2,i.Box,{children:[(0,o.createComponentVNode)(2,i.Button,{fluid:!0,bold:!0,content:"ARM",textAlign:"center",fontSize:"28px",lineHeight:"32px",mb:1,className:"NuclearBomb__Button NuclearBomb__Button--C",onClick:function(){return r("arm")}}),(0,o.createComponentVNode)(2,i.Button,{fluid:!0,bold:!0,content:"ANCHOR",textAlign:"center",fontSize:"28px",lineHeight:"32px",className:"NuclearBomb__Button NuclearBomb__Button--E",onClick:function(){return r("anchor")}}),(0,o.createComponentVNode)(2,i.Box,{textAlign:"center",color:"#9C9987",fontSize:"80px",children:(0,o.createComponentVNode)(2,i.Icon,{name:"radiation"})}),(0,o.createComponentVNode)(2,i.Box,{height:"80px",className:"NuclearBomb__NTIcon"})]})})]})]})}},function(e,t,n){"use strict";t.__esModule=!0,t.OperatingComputer=void 0;var o=n(0),r=n(3),a=n(2);t.OperatingComputer=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.table,l=i.surgeries,u=void 0===l?[]:l,d=i.procedures,s=void 0===d?[]:d,p=i.patient,m=void 0===p?{}:p;return(0,o.createComponentVNode)(2,a.Tabs,{children:[(0,o.createComponentVNode)(2,a.Tabs.Tab,{label:"Patient State",children:[!c&&(0,o.createComponentVNode)(2,a.NoticeBox,{children:"No Table Detected"}),(0,o.createComponentVNode)(2,a.Section,{children:[(0,o.createComponentVNode)(2,a.Section,{title:"Patient State",level:2,children:m?(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"State",color:m.statstate,children:m.stat}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Blood Type",children:m.blood_type}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Health",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:m.health,minValue:m.minHealth,maxValue:m.maxHealth,color:m.health>=0?"good":"average",content:(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:m.health})})}),[{label:"Brute",type:"bruteLoss"},{label:"Burn",type:"fireLoss"},{label:"Toxin",type:"toxLoss"},{label:"Respiratory",type:"oxyLoss"}].map((function(e){return(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:e.label,children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:m[e.type]/m.maxHealth,color:"bad",content:(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:m[e.type]})})},e.type)}))]}):"No Patient Detected"}),(0,o.createComponentVNode)(2,a.Section,{title:"Initiated Procedures",level:2,children:s.length?s.map((function(e){return(0,o.createComponentVNode)(2,a.Section,{title:e.name,level:3,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Next Step",children:[e.next_step,e.chems_needed&&(0,o.createFragment)([(0,o.createVNode)(1,"b",null,"Required Chemicals:",16),(0,o.createVNode)(1,"br"),e.chems_needed],0)]}),!!i.alternative_step&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Alternative Step",children:[e.alternative_step,e.alt_chems_needed&&(0,o.createFragment)([(0,o.createVNode)(1,"b",null,"Required Chemicals:",16),(0,o.createVNode)(1,"br"),e.alt_chems_needed],0)]})]})},e.name)})):"No Active Procedures"})]})]},"state"),(0,o.createComponentVNode)(2,a.Tabs.Tab,{label:"Surgery Procedures",children:(0,o.createComponentVNode)(2,a.Section,{title:"Advanced Surgery Procedures",children:[(0,o.createComponentVNode)(2,a.Button,{icon:"download",content:"Sync Research Database",onClick:function(){return n("sync")}}),u.map((function(e){return(0,o.createComponentVNode)(2,a.Section,{title:e.name,level:2,children:e.desc},e.name)}))]})},"procedures")]})}},function(e,t,n){"use strict";t.__esModule=!0,t.OreBox=void 0;var o=n(0),r=n(24),a=n(16),i=n(2);t.OreBox=function(e){var t=e.state,n=t.config,c=t.data,l=n.ref,u=c.materials;return(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Section,{title:"Ores",buttons:(0,o.createComponentVNode)(2,i.Button,{content:"Empty",onClick:function(){return(0,a.act)(l,"removeall")}}),children:(0,o.createComponentVNode)(2,i.Table,{children:[(0,o.createComponentVNode)(2,i.Table.Row,{header:!0,children:[(0,o.createComponentVNode)(2,i.Table.Cell,{children:"Ore"}),(0,o.createComponentVNode)(2,i.Table.Cell,{collapsing:!0,textAlign:"right",children:"Amount"})]}),u.map((function(e){return(0,o.createComponentVNode)(2,i.Table.Row,{children:[(0,o.createComponentVNode)(2,i.Table.Cell,{children:(0,r.toTitleCase)(e.name)}),(0,o.createComponentVNode)(2,i.Table.Cell,{collapsing:!0,textAlign:"right",children:(0,o.createComponentVNode)(2,i.Box,{color:"label",inline:!0,children:e.amount})})]},e.type)}))]})}),(0,o.createComponentVNode)(2,i.Section,{children:(0,o.createComponentVNode)(2,i.Box,{children:["All ores will be placed in here when you are wearing a mining stachel on your belt or in a pocket while dragging the ore box.",(0,o.createVNode)(1,"br"),"Gibtonite is not accepted."]})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.OreRedemptionMachine=void 0;var o=n(0),r=n(24),a=n(3),i=n(2);t.OreRedemptionMachine=function(e){var t=(0,a.useBackend)(e),n=t.act,r=t.data,l=r.unclaimedPoints,u=r.materials,d=r.alloys,s=r.diskDesigns,p=r.hasDisk;return(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Section,{children:[(0,o.createComponentVNode)(2,i.BlockQuote,{mb:1,children:["This machine only accepts ore.",(0,o.createVNode)(1,"br"),"Gibtonite and Slag are not accepted."]}),(0,o.createComponentVNode)(2,i.Box,{children:[(0,o.createComponentVNode)(2,i.Box,{inline:!0,color:"label",mr:1,children:"Unclaimed points:"}),l,(0,o.createComponentVNode)(2,i.Button,{ml:2,content:"Claim",disabled:0===l,onClick:function(){return n("Claim")}})]})]}),(0,o.createComponentVNode)(2,i.Section,{children:p&&(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Box,{mb:1,children:(0,o.createComponentVNode)(2,i.Button,{icon:"eject",content:"Eject design disk",onClick:function(){return n("diskEject")}})}),(0,o.createComponentVNode)(2,i.Table,{children:s.map((function(e){return(0,o.createComponentVNode)(2,i.Table.Row,{children:[(0,o.createComponentVNode)(2,i.Table.Cell,{children:["File ",e.index,": ",e.name]}),(0,o.createComponentVNode)(2,i.Table.Cell,{collapsing:!0,children:(0,o.createComponentVNode)(2,i.Button,{disabled:!e.canupload,content:"Upload",onClick:function(){return n("diskUpload",{design:e.index})}})})]},e.index)}))})],4)||(0,o.createComponentVNode)(2,i.Button,{icon:"save",content:"Insert design disk",onClick:function(){return n("diskInsert")}})}),(0,o.createComponentVNode)(2,i.Section,{title:"Materials",children:(0,o.createComponentVNode)(2,i.Table,{children:u.map((function(e){return(0,o.createComponentVNode)(2,c,{material:e,onRelease:function(t){return n("Release",{id:e.id,sheets:t})}},e.id)}))})}),(0,o.createComponentVNode)(2,i.Section,{title:"Alloys",children:(0,o.createComponentVNode)(2,i.Table,{children:d.map((function(e){return(0,o.createComponentVNode)(2,c,{material:e,onRelease:function(t){return n("Smelt",{id:e.id,sheets:t})}},e.id)}))})})],4)};var c=function(e){var t,n;function a(){var t;return(t=e.call(this)||this).state={amount:1},t}return n=e,(t=a).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n,a.prototype.render=function(){var e=this,t=this.state.amount,n=this.props,a=n.material,c=n.onRelease,l=Math.floor(a.amount);return(0,o.createComponentVNode)(2,i.Table.Row,{children:[(0,o.createComponentVNode)(2,i.Table.Cell,{children:(0,r.toTitleCase)(a.name).replace("Alloy","")}),(0,o.createComponentVNode)(2,i.Table.Cell,{collapsing:!0,textAlign:"right",children:(0,o.createComponentVNode)(2,i.Box,{mr:2,color:"label",inline:!0,children:a.value&&a.value+" cr"})}),(0,o.createComponentVNode)(2,i.Table.Cell,{collapsing:!0,textAlign:"right",children:(0,o.createComponentVNode)(2,i.Box,{mr:2,color:"label",inline:!0,children:[l," sheets"]})}),(0,o.createComponentVNode)(2,i.Table.Cell,{collapsing:!0,children:[(0,o.createComponentVNode)(2,i.NumberInput,{width:"32px",step:1,stepPixelSize:5,minValue:1,maxValue:50,value:t,onChange:function(t,n){return e.setState({amount:n})}}),(0,o.createComponentVNode)(2,i.Button,{disabled:l<1,content:"Release",onClick:function(){return c(t)}})]})]})},a}(o.Component)},function(e,t,n){"use strict";t.__esModule=!0,t.Pandemic=t.PandemicAntibodyDisplay=t.PandemicSymptomDisplay=t.PandemicDiseaseDisplay=t.PandemicBeakerDisplay=void 0;var o=n(0),r=n(25),a=n(3),i=n(2),c=function(e){var t=(0,a.useBackend)(e),n=t.act,r=t.data,c=r.has_beaker,l=r.beaker_empty,u=r.has_blood,d=r.blood,s=!c||l;return(0,o.createComponentVNode)(2,i.Section,{title:"Beaker",buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Button,{icon:"times",content:"Empty and Eject",color:"bad",disabled:s,onClick:function(){return n("empty_eject_beaker")}}),(0,o.createComponentVNode)(2,i.Button,{icon:"trash",content:"Empty",disabled:s,onClick:function(){return n("empty_beaker")}}),(0,o.createComponentVNode)(2,i.Button,{icon:"eject",content:"Eject",disabled:!c,onClick:function(){return n("eject_beaker")}})],4),children:c?l?(0,o.createComponentVNode)(2,i.Box,{color:"bad",children:"Beaker is empty"}):u?(0,o.createComponentVNode)(2,i.LabeledList,{children:[(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Blood DNA",children:d&&d.dna||"Unknown"}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Blood Type",children:d&&d.type||"Unknown"})]}):(0,o.createComponentVNode)(2,i.Box,{color:"bad",children:"No blood detected"}):(0,o.createComponentVNode)(2,i.NoticeBox,{children:"No beaker loaded"})})};t.PandemicBeakerDisplay=c;var l=function(e){var t=(0,a.useBackend)(e),n=t.act,r=t.data,c=r.is_ready;return(r.viruses||[]).map((function(e){var t=e.symptoms||[];return(0,o.createComponentVNode)(2,i.Section,{title:e.can_rename?(0,o.createComponentVNode)(2,i.Input,{value:e.name,onChange:function(t,o){return n("rename_disease",{index:e.index,name:o})}}):e.name,buttons:(0,o.createComponentVNode)(2,i.Button,{icon:"flask",content:"Create culture bottle",disabled:!c,onClick:function(){return n("create_culture_bottle",{index:e.index})}}),children:[(0,o.createComponentVNode)(2,i.Grid,{children:[(0,o.createComponentVNode)(2,i.Grid.Column,{children:e.description}),(0,o.createComponentVNode)(2,i.Grid.Column,{children:(0,o.createComponentVNode)(2,i.LabeledList,{children:[(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Agent",children:e.agent}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Spread",children:e.spread}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Possible Cure",children:e.cure})]})})]}),!!e.is_adv&&(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Section,{title:"Statistics",level:2,children:(0,o.createComponentVNode)(2,i.Grid,{children:[(0,o.createComponentVNode)(2,i.Grid.Column,{children:(0,o.createComponentVNode)(2,i.LabeledList,{children:[(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Resistance",children:e.resistance}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Stealth",children:e.stealth})]})}),(0,o.createComponentVNode)(2,i.Grid.Column,{children:(0,o.createComponentVNode)(2,i.LabeledList,{children:[(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Stage speed",children:e.stage_speed}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Transmissibility",children:e.transmission})]})})]})}),(0,o.createComponentVNode)(2,i.Section,{title:"Symptoms",level:2,children:t.map((function(e){return(0,o.createComponentVNode)(2,i.Collapsible,{title:e.name,children:(0,o.createComponentVNode)(2,i.Section,{children:(0,o.createComponentVNode)(2,u,{symptom:e})})},e.name)}))})],4)]},e.name)}))};t.PandemicDiseaseDisplay=l;var u=function(e){var t=e.symptom,n=t.name,a=t.desc,c=t.stealth,l=t.resistance,u=t.stage_speed,d=t.transmission,s=t.level,p=t.neutered,m=(0,r.map)((function(e,t){return{desc:e,label:t}}))(t.threshold_desc||{});return(0,o.createComponentVNode)(2,i.Section,{title:n,level:2,buttons:!!p&&(0,o.createComponentVNode)(2,i.Box,{bold:!0,color:"bad",children:"Neutered"}),children:[(0,o.createComponentVNode)(2,i.Grid,{children:[(0,o.createComponentVNode)(2,i.Grid.Column,{size:2,children:a}),(0,o.createComponentVNode)(2,i.Grid.Column,{children:(0,o.createComponentVNode)(2,i.LabeledList,{children:[(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Level",children:s}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Resistance",children:l}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Stealth",children:c}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Stage Speed",children:u}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Transmission",children:d})]})})]}),m.length>0&&(0,o.createComponentVNode)(2,i.Section,{title:"Thresholds",level:3,children:(0,o.createComponentVNode)(2,i.LabeledList,{children:m.map((function(e){return(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:e.label,children:e.desc},e.label)}))})})]})};t.PandemicSymptomDisplay=u;var d=function(e){var t=(0,a.useBackend)(e),n=t.act,r=t.data,c=r.resistances||[];return(0,o.createComponentVNode)(2,i.Section,{title:"Antibodies",children:c.length>0?(0,o.createComponentVNode)(2,i.LabeledList,{children:c.map((function(e){return(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:e.name,children:(0,o.createComponentVNode)(2,i.Button,{icon:"eye-dropper",content:"Create vaccine bottle",disabled:!r.is_ready,onClick:function(){return n("create_vaccine_bottle",{index:e.id})}})},e.name)}))}):(0,o.createComponentVNode)(2,i.Box,{bold:!0,color:"bad",mt:1,children:"No antibodies detected."})})};t.PandemicAntibodyDisplay=d;t.Pandemic=function(e){var t=(0,a.useBackend)(e).data;return(0,o.createFragment)([(0,o.createComponentVNode)(2,c,{state:e.state}),!!t.has_blood&&(0,o.createFragment)([(0,o.createComponentVNode)(2,l,{state:e.state}),(0,o.createComponentVNode)(2,d,{state:e.state})],4)],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.PortableGenerator=void 0;var o=n(0),r=n(3),a=n(2);t.PortableGenerator=function(e){var t,n=(0,r.useBackend)(e),i=n.act,c=n.data;return t=c.stack_percent>50?"good":c.stack_percent>15?"average":"bad",(0,o.createFragment)([!c.anchored&&(0,o.createComponentVNode)(2,a.NoticeBox,{children:"Generator not anchored."}),(0,o.createComponentVNode)(2,a.Section,{title:"Status",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Power switch",children:(0,o.createComponentVNode)(2,a.Button,{icon:c.active?"power-off":"times",onClick:function(){return i("toggle_power")},disabled:!c.ready_to_boot,children:c.active?"On":"Off"})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:c.sheet_name+" sheets",children:[(0,o.createComponentVNode)(2,a.Box,{inline:!0,color:t,children:c.sheets}),c.sheets>=1&&(0,o.createComponentVNode)(2,a.Button,{ml:1,icon:"eject",disabled:c.active,onClick:function(){return i("eject")},children:"Eject"})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Current sheet level",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:c.stack_percent/100,ranges:{good:[.1,Infinity],average:[.01,.1],bad:[-Infinity,.01]}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Heat level",children:c.current_heat<100?(0,o.createComponentVNode)(2,a.Box,{inline:!0,color:"good",children:"Nominal"}):c.current_heat<200?(0,o.createComponentVNode)(2,a.Box,{inline:!0,color:"average",children:"Caution"}):(0,o.createComponentVNode)(2,a.Box,{inline:!0,color:"bad",children:"DANGER"})})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Output",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Current output",children:c.power_output}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Adjust output",children:[(0,o.createComponentVNode)(2,a.Button,{icon:"minus",onClick:function(){return i("lower_power")},children:c.power_generated}),(0,o.createComponentVNode)(2,a.Button,{icon:"plus",onClick:function(){return i("higher_power")},children:c.power_generated})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Power available",children:(0,o.createComponentVNode)(2,a.Box,{inline:!0,color:!c.connected&&"bad",children:c.connected?c.power_available:"Unconnected"})})]})})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.PortableScrubber=t.PortablePump=t.PortableBasicInfo=void 0;var o=n(0),r=n(3),a=n(2),i=n(33),c=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.connected,l=i.holding,u=i.on,d=i.pressure;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Status",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:u?"power-off":"times",content:u?"On":"Off",selected:u,onClick:function(){return n("power")}}),children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Pressure",children:[(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:d})," kPa"]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Port",color:c?"good":"average",children:c?"Connected":"Not Connected"})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Holding Tank",minHeight:"82px",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:"eject",content:"Eject",disabled:!l,onClick:function(){return n("eject")}}),children:l?(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Label",children:l.name}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Pressure",children:[(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:l.pressure})," kPa"]})]}):(0,o.createComponentVNode)(2,a.Box,{color:"average",children:"No holding tank"})})],4)};t.PortableBasicInfo=c;t.PortablePump=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,l=i.direction,u=(i.holding,i.target_pressure),d=i.default_pressure,s=i.min_pressure,p=i.max_pressure;return(0,o.createFragment)([(0,o.createComponentVNode)(2,c,{state:e.state}),(0,o.createComponentVNode)(2,a.Section,{title:"Pump",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:l?"sign-in-alt":"sign-out-alt",content:l?"In":"Out",selected:l,onClick:function(){return n("direction")}}),children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Output",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:u,unit:"kPa",width:"75px",minValue:s,maxValue:p,step:10,onChange:function(e,t){return n("pressure",{pressure:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Presets",children:[(0,o.createComponentVNode)(2,a.Button,{icon:"minus",disabled:u===s,onClick:function(){return n("pressure",{pressure:"min"})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"sync",disabled:u===d,onClick:function(){return n("pressure",{pressure:"reset"})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"plus",disabled:u===p,onClick:function(){return n("pressure",{pressure:"max"})}})]})]})})],4)};t.PortableScrubber=function(e){var t=(0,r.useBackend)(e),n=t.act,l=t.data.filter_types||[];return(0,o.createFragment)([(0,o.createComponentVNode)(2,c,{state:e.state}),(0,o.createComponentVNode)(2,a.Section,{title:"Filters",children:l.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{icon:e.enabled?"check-square-o":"square-o",content:(0,i.getGasLabel)(e.gas_id,e.gas_name),selected:e.enabled,onClick:function(){return n("toggle_filter",{val:e.gas_id})}},e.id)}))})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.PowerMonitor=void 0;var o=n(0),r=n(25),a=n(71),i=n(17),c=n(11),l=n(2);var u=5e5,d=function(e){var t,n;function c(){var t;return(t=e.call(this)||this).state={sortByField:null},t}return n=e,(t=c).prototype=Object.create(n.prototype),t.prototype.constructor=t,t.__proto__=n,c.prototype.render=function(){var e=this,t=this.props.state.data,n=t.history,c=this.state.sortByField,d=n.supply[n.supply.length-1]||0,m=n.demand[n.demand.length-1]||0,f=n.supply.map((function(e,t){return[t,e]})),h=n.demand.map((function(e,t){return[t,e]})),C=Math.max.apply(Math,[u].concat(n.supply,n.demand)),g=(0,a.flow)([(0,r.map)((function(e,t){return Object.assign({},e,{id:e.name+t})})),"name"===c&&(0,r.sortBy)((function(e){return e.name})),"charge"===c&&(0,r.sortBy)((function(e){return-e.charge})),"draw"===c&&(0,r.sortBy)((function(e){return t=e.load,n=String(t.split(" ")[1]).toLowerCase(),-["w","kw","mw","gw"].indexOf(n);var t,n}),(function(e){return-parseFloat(e.load)}))])(t.areas);return(0,o.createFragment)([(0,o.createComponentVNode)(2,l.Flex,{spacing:1,children:[(0,o.createComponentVNode)(2,l.Flex.Item,{width:"200px",children:(0,o.createComponentVNode)(2,l.Section,{children:(0,o.createComponentVNode)(2,l.LabeledList,{children:[(0,o.createComponentVNode)(2,l.LabeledList.Item,{label:"Supply",children:(0,o.createComponentVNode)(2,l.ProgressBar,{value:d,minValue:0,maxValue:C,color:"teal",content:(0,i.toFixed)(d/1e3)+" kW"})}),(0,o.createComponentVNode)(2,l.LabeledList.Item,{label:"Draw",children:(0,o.createComponentVNode)(2,l.ProgressBar,{value:m,minValue:0,maxValue:C,color:"pink",content:(0,i.toFixed)(m/1e3)+" kW"})})]})})}),(0,o.createComponentVNode)(2,l.Flex.Item,{grow:1,children:(0,o.createComponentVNode)(2,l.Section,{position:"relative",height:"100%",children:[(0,o.createComponentVNode)(2,l.Chart.Line,{fillPositionedParent:!0,data:f,rangeX:[0,f.length-1],rangeY:[0,C],strokeColor:"rgba(0, 181, 173, 1)",fillColor:"rgba(0, 181, 173, 0.25)"}),(0,o.createComponentVNode)(2,l.Chart.Line,{fillPositionedParent:!0,data:h,rangeX:[0,h.length-1],rangeY:[0,C],strokeColor:"rgba(224, 57, 151, 1)",fillColor:"rgba(224, 57, 151, 0.25)"})]})})]}),(0,o.createComponentVNode)(2,l.Section,{children:[(0,o.createComponentVNode)(2,l.Box,{mb:1,children:[(0,o.createComponentVNode)(2,l.Box,{inline:!0,mr:2,color:"label",children:"Sort by:"}),(0,o.createComponentVNode)(2,l.Button.Checkbox,{checked:"name"===c,content:"Name",onClick:function(){return e.setState({sortByField:"name"!==c&&"name"})}}),(0,o.createComponentVNode)(2,l.Button.Checkbox,{checked:"charge"===c,content:"Charge",onClick:function(){return e.setState({sortByField:"charge"!==c&&"charge"})}}),(0,o.createComponentVNode)(2,l.Button.Checkbox,{checked:"draw"===c,content:"Draw",onClick:function(){return e.setState({sortByField:"draw"!==c&&"draw"})}})]}),(0,o.createComponentVNode)(2,l.Table,{children:[(0,o.createComponentVNode)(2,l.Table.Row,{header:!0,children:[(0,o.createComponentVNode)(2,l.Table.Cell,{children:"Area"}),(0,o.createComponentVNode)(2,l.Table.Cell,{collapsing:!0,children:"Charge"}),(0,o.createComponentVNode)(2,l.Table.Cell,{textAlign:"right",children:"Draw"}),(0,o.createComponentVNode)(2,l.Table.Cell,{collapsing:!0,title:"Equipment",children:"Eqp"}),(0,o.createComponentVNode)(2,l.Table.Cell,{collapsing:!0,title:"Lighting",children:"Lgt"}),(0,o.createComponentVNode)(2,l.Table.Cell,{collapsing:!0,title:"Environment",children:"Env"})]}),g.map((function(e,t){return(0,o.createVNode)(1,"tr","Table__row candystripe",[(0,o.createVNode)(1,"td",null,e.name,0),(0,o.createVNode)(1,"td","Table__cell text-right text-nowrap",(0,o.createComponentVNode)(2,s,{charging:e.charging,charge:e.charge}),2),(0,o.createVNode)(1,"td","Table__cell text-right text-nowrap",e.load,0),(0,o.createVNode)(1,"td","Table__cell text-center text-nowrap",(0,o.createComponentVNode)(2,p,{status:e.eqp}),2),(0,o.createVNode)(1,"td","Table__cell text-center text-nowrap",(0,o.createComponentVNode)(2,p,{status:e.lgt}),2),(0,o.createVNode)(1,"td","Table__cell text-center text-nowrap",(0,o.createComponentVNode)(2,p,{status:e.env}),2)],4,null,e.id)}))]})]})],4)},c}(o.Component);t.PowerMonitor=d;var s=function(e){var t=e.charging,n=e.charge;return(0,o.createFragment)([(0,o.createComponentVNode)(2,l.Icon,{width:"18px",textAlign:"center",name:0===t&&(n>50?"battery-half":"battery-quarter")||1===t&&"bolt"||2===t&&"battery-full",color:0===t&&(n>50?"yellow":"red")||1===t&&"yellow"||2===t&&"green"}),(0,o.createComponentVNode)(2,l.Box,{inline:!0,width:"36px",textAlign:"right",children:(0,i.toFixed)(n)+"%"})],4)};s.defaultHooks=c.pureComponentHooks;var p=function(e){var t=e.status,n=Boolean(2&t),r=Boolean(1&t),a=(n?"On":"Off")+" ["+(r?"auto":"manual")+"]";return(0,o.createComponentVNode)(2,l.ColorBox,{color:n?"good":"bad",content:r?undefined:"M",title:a})};p.defaultHooks=c.pureComponentHooks},function(e,t,n){"use strict";t.__esModule=!0,t.Radio=void 0;var o=n(0),r=n(25),a=n(17),i=n(3),c=n(2),l=n(33);t.Radio=function(e){var t=(0,i.useBackend)(e),n=t.act,u=t.data,d=u.freqlock,s=u.frequency,p=u.minFrequency,m=u.maxFrequency,f=u.listening,h=u.broadcasting,C=u.command,g=u.useCommand,b=u.subspace,N=u.subspaceSwitchable,v=l.RADIO_CHANNELS.find((function(e){return e.freq===s})),V=(0,r.map)((function(e,t){return{name:t,status:!!e}}))(u.channels);return(0,o.createComponentVNode)(2,c.Section,{children:(0,o.createComponentVNode)(2,c.LabeledList,{children:[(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Frequency",children:[d&&(0,o.createComponentVNode)(2,c.Box,{inline:!0,color:"light-gray",children:(0,a.toFixed)(s/10,1)+" kHz"})||(0,o.createComponentVNode)(2,c.NumberInput,{animate:!0,unit:"kHz",step:.2,stepPixelSize:10,minValue:p/10,maxValue:m/10,value:s/10,format:function(e){return(0,a.toFixed)(e,1)},onDrag:function(e,t){return n("frequency",{adjust:t-s/10})}}),v&&(0,o.createComponentVNode)(2,c.Box,{inline:!0,color:v.color,ml:2,children:["[",v.name,"]"]})]}),(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Audio",children:[(0,o.createComponentVNode)(2,c.Button,{textAlign:"center",width:"37px",icon:f?"volume-up":"volume-mute",selected:f,onClick:function(){return n("listen")}}),(0,o.createComponentVNode)(2,c.Button,{textAlign:"center",width:"37px",icon:h?"microphone":"microphone-slash",selected:h,onClick:function(){return n("broadcast")}}),!!C&&(0,o.createComponentVNode)(2,c.Button,{ml:1,icon:"bullhorn",selected:g,content:"High volume "+(g?"ON":"OFF"),onClick:function(){return n("command")}}),!!N&&(0,o.createComponentVNode)(2,c.Button,{ml:1,icon:"bullhorn",selected:b,content:"Subspace Tx "+(b?"ON":"OFF"),onClick:function(){return n("subspace")}})]}),!!b&&(0,o.createComponentVNode)(2,c.LabeledList.Item,{label:"Channels",children:[0===V.length&&(0,o.createComponentVNode)(2,c.Box,{inline:!0,color:"bad",children:"No encryption keys installed."}),V.map((function(e){return(0,o.createComponentVNode)(2,c.Box,{children:(0,o.createComponentVNode)(2,c.Button,{icon:e.status?"check-square-o":"square-o",selected:e.status,content:e.name,onClick:function(){return n("channel",{channel:e.name})}})},e.name)}))]})]})})}},function(e,t,n){"use strict";t.__esModule=!0,t.RapidPipeDispenser=void 0;var o=n(0),r=n(11),a=n(3),i=n(2),c=["Atmospherics","Disposals","Transit Tubes"],l={Atmospherics:"wrench",Disposals:"trash-alt","Transit Tubes":"bus",Pipes:"grip-lines","Disposal Pipes":"grip-lines",Devices:"microchip","Heat Exchange":"thermometer-half","Station Equipment":"microchip"},u={grey:"#bbbbbb",amethyst:"#a365ff",blue:"#4466ff",brown:"#b26438",cyan:"#48eae8",dark:"#808080",green:"#1edd00",orange:"#ffa030",purple:"#b535ea",red:"#ff3333",violet:"#6e00f6",yellow:"#ffce26"},d=[{name:"Dispense",bitmask:1},{name:"Connect",bitmask:2},{name:"Destroy",bitmask:4},{name:"Paint",bitmask:8}];t.RapidPipeDispenser=function(e){var t=(0,a.useBackend)(e),n=t.act,s=t.data,p=s.category,m=s.categories,f=void 0===m?[]:m,h=s.selected_color,C=s.piping_layer,g=s.mode,b=s.preview_rows.flatMap((function(e){return e.previews}));return(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Section,{children:(0,o.createComponentVNode)(2,i.LabeledList,{children:[(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Category",children:c.map((function(e,t){return(0,o.createComponentVNode)(2,i.Button,{selected:p===t,icon:l[e],color:"transparent",content:e,onClick:function(){return n("category",{category:t})}},e)}))}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Modes",children:d.map((function(e){return(0,o.createComponentVNode)(2,i.Button.Checkbox,{checked:g&e.bitmask,content:e.name,onClick:function(){return n("mode",{mode:e.bitmask})}},e.bitmask)}))}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Color",children:[(0,o.createComponentVNode)(2,i.Box,{inline:!0,width:"64px",color:u[h],content:h}),Object.keys(u).map((function(e){return(0,o.createComponentVNode)(2,i.ColorBox,{ml:1,color:u[e],onClick:function(){return n("color",{paint_color:e})}},e)}))]})]})}),(0,o.createComponentVNode)(2,i.Flex,{m:-.5,children:[(0,o.createComponentVNode)(2,i.Flex.Item,{m:.5,children:(0,o.createComponentVNode)(2,i.Section,{children:[0===p&&(0,o.createComponentVNode)(2,i.Box,{mb:1,children:[1,2,3].map((function(e){return(0,o.createComponentVNode)(2,i.Button.Checkbox,{fluid:!0,checked:e===C,content:"Layer "+e,onClick:function(){return n("piping_layer",{piping_layer:e})}},e)}))}),(0,o.createComponentVNode)(2,i.Box,{width:"108px",children:b.map((function(e){return(0,o.createComponentVNode)(2,i.Button,{title:e.dir_name,selected:e.selected,style:{width:"48px",height:"48px",padding:0},onClick:function(){return n("setdir",{dir:e.dir,flipped:e.flipped})},children:(0,o.createComponentVNode)(2,i.Box,{className:(0,r.classes)(["pipes32x32",e.dir+"-"+e.icon_state]),style:{transform:"scale(1.5) translate(17%, 17%)"}})},e.dir)}))})]})}),(0,o.createComponentVNode)(2,i.Flex.Item,{m:.5,grow:1,children:(0,o.createComponentVNode)(2,i.Section,{children:(0,o.createComponentVNode)(2,i.Tabs,{children:f.map((function(e){return(0,o.createComponentVNode)(2,i.Tabs.Tab,{fluid:!0,icon:l[e.cat_name],label:e.cat_name,children:function(){return e.recipes.map((function(t){return(0,o.createComponentVNode)(2,i.Button.Checkbox,{fluid:!0,ellipsis:!0,checked:t.selected,content:t.pipe_name,title:t.pipe_name,onClick:function(){return n("pipe_type",{pipe_type:t.pipe_index,category:e.cat_name})}},t.pipe_index)}))}},e.cat_name)}))})})})]})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.SatelliteControl=void 0;var o=n(0),r=n(3),a=n(2),i=n(167);t.SatelliteControl=function(e){var t=(0,r.useBackend)(e),n=t.act,c=t.data,l=c.satellites||[];return(0,o.createFragment)([c.meteor_shield&&(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:(0,o.createComponentVNode)(2,i.LabeledListItem,{label:"Coverage",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:c.meteor_shield_coverage/c.meteor_shield_coverage_max,content:100*c.meteor_shield_coverage/c.meteor_shield_coverage_max+"%",ranges:{good:[1,Infinity],average:[.3,1],bad:[-Infinity,.3]}})})})}),(0,o.createComponentVNode)(2,a.Section,{title:"Satellite Controls",children:(0,o.createComponentVNode)(2,a.Box,{mr:-1,children:l.map((function(e){return(0,o.createComponentVNode)(2,a.Button.Checkbox,{checked:e.active,content:"#"+e.id+" "+e.mode,onClick:function(){return n("toggle",{id:e.id})}},e.id)}))})})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.ScannerGate=void 0;var o=n(0),r=n(3),a=n(2),i=n(70),c=["Positive","Harmless","Minor","Medium","Harmful","Dangerous","BIOHAZARD"],l=[{name:"Human",value:"human"},{name:"Lizardperson",value:"lizard"},{name:"Flyperson",value:"fly"},{name:"Felinid",value:"felinid"},{name:"Plasmaman",value:"plasma"},{name:"Mothperson",value:"moth"},{name:"Jellyperson",value:"jelly"},{name:"Podperson",value:"pod"},{name:"Golem",value:"golem"},{name:"Zombie",value:"zombie"}],u=[{name:"Starving",value:150},{name:"Obese",value:600}];t.ScannerGate=function(e){var t=e.state,n=(0,r.useBackend)(e),a=n.act,c=n.data;return(0,o.createFragment)([(0,o.createComponentVNode)(2,i.InterfaceLockNoticeBox,{locked:c.locked,onLockedStatusChange:function(){return a("toggle_lock")}}),!c.locked&&(0,o.createComponentVNode)(2,s,{state:t})],0)};var d={Off:{title:"Scanner Mode: Off",component:function(){return p}},Wanted:{title:"Scanner Mode: Wanted",component:function(){return m}},Guns:{title:"Scanner Mode: Guns",component:function(){return f}},Mindshield:{title:"Scanner Mode: Mindshield",component:function(){return h}},Disease:{title:"Scanner Mode: Disease",component:function(){return C}},Species:{title:"Scanner Mode: Species",component:function(){return g}},Nutrition:{title:"Scanner Mode: Nutrition",component:function(){return b}},Nanites:{title:"Scanner Mode: Nanites",component:function(){return N}}},s=function(e){var t=e.state,n=(0,r.useBackend)(e),i=n.act,c=n.data.scan_mode,l=d[c]||d.off,u=l.component();return(0,o.createComponentVNode)(2,a.Section,{title:l.title,buttons:"Off"!==c&&(0,o.createComponentVNode)(2,a.Button,{icon:"arrow-left",content:"back",onClick:function(){return i("set_mode",{new_mode:"Off"})}}),children:(0,o.createComponentVNode)(2,u,{state:t})})},p=function(e){var t=(0,r.useBackend)(e).act;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Box,{mb:2,children:"Select a scanning mode below."}),(0,o.createComponentVNode)(2,a.Box,{children:[(0,o.createComponentVNode)(2,a.Button,{content:"Wanted",onClick:function(){return t("set_mode",{new_mode:"Wanted"})}}),(0,o.createComponentVNode)(2,a.Button,{content:"Guns",onClick:function(){return t("set_mode",{new_mode:"Guns"})}}),(0,o.createComponentVNode)(2,a.Button,{content:"Mindshield",onClick:function(){return t("set_mode",{new_mode:"Mindshield"})}}),(0,o.createComponentVNode)(2,a.Button,{content:"Disease",onClick:function(){return t("set_mode",{new_mode:"Disease"})}}),(0,o.createComponentVNode)(2,a.Button,{content:"Species",onClick:function(){return t("set_mode",{new_mode:"Species"})}}),(0,o.createComponentVNode)(2,a.Button,{content:"Nutrition",onClick:function(){return t("set_mode",{new_mode:"Nutrition"})}}),(0,o.createComponentVNode)(2,a.Button,{content:"Nanites",onClick:function(){return t("set_mode",{new_mode:"Nanites"})}})]})],4)},m=function(e){var t=e.state,n=(0,r.useBackend)(e).data.reverse;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Box,{mb:2,children:["Trigger if the person scanned ",n?"does not have":"has"," ","any warrants for their arrest."]}),(0,o.createComponentVNode)(2,v,{state:t})],4)},f=function(e){var t=e.state,n=(0,r.useBackend)(e).data.reverse;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Box,{mb:2,children:["Trigger if the person scanned ",n?"does not have":"has"," ","any guns."]}),(0,o.createComponentVNode)(2,v,{state:t})],4)},h=function(e){var t=e.state,n=(0,r.useBackend)(e).data.reverse;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Box,{mb:2,children:["Trigger if the person scanned ",n?"does not have":"has"," ","a mindshield."]}),(0,o.createComponentVNode)(2,v,{state:t})],4)},C=function(e){var t=e.state,n=(0,r.useBackend)(e),i=n.act,l=n.data,u=l.reverse,d=l.disease_threshold;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Box,{mb:2,children:["Trigger if the person scanned ",u?"does not have":"has"," ","a disease equal or worse than ",d,"."]}),(0,o.createComponentVNode)(2,a.Box,{mb:2,children:c.map((function(e){return(0,o.createComponentVNode)(2,a.Button.Checkbox,{checked:e===d,content:e,onClick:function(){return i("set_disease_threshold",{new_threshold:e})}},e)}))}),(0,o.createComponentVNode)(2,v,{state:t})],4)},g=function(e){var t=e.state,n=(0,r.useBackend)(e),i=n.act,c=n.data,u=c.reverse,d=c.target_species,s=l.find((function(e){return e.value===d}));return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Box,{mb:2,children:["Trigger if the person scanned is ",u?"not":""," ","of the ",s.name," species.","zombie"===d&&" All zombie types will be detected, including dormant zombies."]}),(0,o.createComponentVNode)(2,a.Box,{mb:2,children:l.map((function(e){return(0,o.createComponentVNode)(2,a.Button.Checkbox,{checked:e.value===d,content:e.name,onClick:function(){return i("set_target_species",{new_species:e.value})}},e.value)}))}),(0,o.createComponentVNode)(2,v,{state:t})],4)},b=function(e){var t=e.state,n=(0,r.useBackend)(e),i=n.act,c=n.data,l=c.reverse,d=c.target_nutrition,s=u.find((function(e){return e.value===d}));return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Box,{mb:2,children:["Trigger if the person scanned ",l?"does not have":"has"," ","the ",s.name," nutrition level."]}),(0,o.createComponentVNode)(2,a.Box,{mb:2,children:u.map((function(e){return(0,o.createComponentVNode)(2,a.Button.Checkbox,{checked:e.value===d,content:e.name,onClick:function(){return i("set_target_nutrition",{new_nutrition:e.name})}},e.name)}))}),(0,o.createComponentVNode)(2,v,{state:t})],4)},N=function(e){var t=e.state,n=(0,r.useBackend)(e),i=n.act,c=n.data,l=c.reverse,u=c.nanite_cloud;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Box,{mb:2,children:["Trigger if the person scanned ",l?"does not have":"has"," ","nanite cloud ",u,"."]}),(0,o.createComponentVNode)(2,a.Box,{mb:2,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Cloud ID",children:(0,o.createComponentVNode)(2,a.NumberInput,{value:u,width:"65px",minValue:1,maxValue:100,stepPixelSize:2,onChange:function(e,t){return i("set_nanite_cloud",{new_cloud:t})}})})})}),(0,o.createComponentVNode)(2,v,{state:t})],4)},v=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data.reverse;return(0,o.createComponentVNode)(2,a.LabeledList,{children:(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Scanning Mode",children:(0,o.createComponentVNode)(2,a.Button,{content:i?"Inverted":"Default",icon:i?"random":"long-arrow-alt-right",onClick:function(){return n("toggle_reverse")},color:i?"bad":"good"})})})}},function(e,t,n){"use strict";t.__esModule=!0,t.ShuttleManipulator=void 0;var o=n(0),r=n(25),a=n(3),i=n(2);t.ShuttleManipulator=function(e){var t=(0,a.useBackend)(e),n=t.act,c=t.data,l=c.shuttles||[],u=c.templates||{},d=c.selected||{},s=c.existing_shuttle||{};return(0,o.createComponentVNode)(2,i.Tabs,{children:[(0,o.createComponentVNode)(2,i.Tabs.Tab,{label:"Status",children:function(){return(0,o.createComponentVNode)(2,i.Section,{children:(0,o.createComponentVNode)(2,i.Table,{children:l.map((function(e){return(0,o.createComponentVNode)(2,i.Table.Row,{children:[(0,o.createComponentVNode)(2,i.Table.Cell,{children:(0,o.createComponentVNode)(2,i.Button,{content:"JMP",onClick:function(){return n("jump_to",{type:"mobile",id:e.id})}},e.id)}),(0,o.createComponentVNode)(2,i.Table.Cell,{children:(0,o.createComponentVNode)(2,i.Button,{content:"Fly",disabled:!e.can_fly,onClick:function(){return n("fly",{id:e.id})}},e.id)}),(0,o.createComponentVNode)(2,i.Table.Cell,{children:e.name}),(0,o.createComponentVNode)(2,i.Table.Cell,{children:e.id}),(0,o.createComponentVNode)(2,i.Table.Cell,{children:e.status}),(0,o.createComponentVNode)(2,i.Table.Cell,{children:[e.mode,!!e.timer&&(0,o.createFragment)([(0,o.createTextVNode)("("),e.timeleft,(0,o.createTextVNode)(")"),(0,o.createComponentVNode)(2,i.Button,{content:"Fast Travel",disabled:!e.can_fast_travel,onClick:function(){return n("fast_travel",{id:e.id})}},e.id)],0)]})]},e.id)}))})})}},"status"),(0,o.createComponentVNode)(2,i.Tabs.Tab,{label:"Templates",children:function(){return(0,o.createComponentVNode)(2,i.Section,{children:(0,o.createComponentVNode)(2,i.Tabs,{children:(0,r.map)((function(e,t){var r=e.templates||[];return(0,o.createComponentVNode)(2,i.Tabs.Tab,{label:e.port_id,children:r.map((function(e){var t=e.shuttle_id===d.shuttle_id;return(0,o.createComponentVNode)(2,i.Section,{title:e.name,level:2,buttons:(0,o.createComponentVNode)(2,i.Button,{content:t?"Selected":"Select",selected:t,onClick:function(){return n("select_template",{shuttle_id:e.shuttle_id})}}),children:(!!e.description||!!e.admin_notes)&&(0,o.createComponentVNode)(2,i.LabeledList,{children:[!!e.description&&(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Description",children:e.description}),!!e.admin_notes&&(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Admin Notes",children:e.admin_notes})]})},e.shuttle_id)}))},t)}))(u)})})}},"templates"),(0,o.createComponentVNode)(2,i.Tabs.Tab,{label:"Modification",children:(0,o.createComponentVNode)(2,i.Section,{children:d?(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Section,{level:2,title:d.name,children:(!!d.description||!!d.admin_notes)&&(0,o.createComponentVNode)(2,i.LabeledList,{children:[!!d.description&&(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Description",children:d.description}),!!d.admin_notes&&(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Admin Notes",children:d.admin_notes})]})}),s?(0,o.createComponentVNode)(2,i.Section,{level:2,title:"Existing Shuttle: "+s.name,children:(0,o.createComponentVNode)(2,i.LabeledList,{children:(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Status",buttons:(0,o.createComponentVNode)(2,i.Button,{content:"Jump To",onClick:function(){return n("jump_to",{type:"mobile",id:s.id})}}),children:[s.status,!!s.timer&&(0,o.createFragment)([(0,o.createTextVNode)("("),s.timeleft,(0,o.createTextVNode)(")")],0)]})})}):(0,o.createComponentVNode)(2,i.Section,{level:2,title:"Existing Shuttle: None"}),(0,o.createComponentVNode)(2,i.Section,{level:2,title:"Status",children:[(0,o.createComponentVNode)(2,i.Button,{content:"Preview",onClick:function(){return n("preview",{shuttle_id:d.shuttle_id})}}),(0,o.createComponentVNode)(2,i.Button,{content:"Load",color:"bad",onClick:function(){return n("load",{shuttle_id:d.shuttle_id})}})]})],0):"No shuttle selected"})},"modification")]})}},function(e,t,n){"use strict";t.__esModule=!0,t.SkillPanel=void 0;var o=n(0),r=n(3),a=n(2);t.SkillPanel=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.skills||[],l=i.see_skill_mods,u={color:"lightgreen",fontWeight:"bold"},d={color:"#FFDB58",fontWeight:"bold"};return(0,o.createComponentVNode)(2,a.Section,{title:i.playername,buttons:(0,o.createComponentVNode)(2,a.Button,{icon:l?"Enabled":"Disabled",content:l?"Modifiers Shown":"Modifiers Hidden",onClick:function(){return n("toggle_mods")}}),children:(0,o.createComponentVNode)(2,a.LabeledList,{children:c.map((function(e){return(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:e.name,children:[(0,o.createVNode)(1,"span",null,[e.desc,(0,o.createVNode)(1,"br"),(0,o.createTextVNode)("`Modifiers: $"),e.modifiers,(0,o.createTextVNode)("`")],0,{style:d}),(0,o.createVNode)(1,"br"),!!e.level_based&&(0,o.createComponentVNode)(2,a.Box,{children:[l?(0,o.createVNode)(1,"span",null,[(0,o.createTextVNode)("Level: ["),(0,o.createVNode)(1,"span",null,e.lvl_mod,0,{style:e.mod_style}),(0,o.createTextVNode)("]")],4):(0,o.createVNode)(1,"span",null,[(0,o.createTextVNode)("Level: ["),(0,o.createVNode)(1,"span",null,e.lvl_base,0,{style:e.base_style}),(0,o.createTextVNode)("]")],4),(0,o.createVNode)(1,"br"),"Total Experience:",l?(0,o.createVNode)(1,"span",null,[(0,o.createTextVNode)("["),e.value_mod,(0,o.createTextVNode)(" XP]")],0):(0,o.createVNode)(1,"span",null,[(0,o.createTextVNode)("["),e.value_base,(0,o.createTextVNode)(" XP]")],0),(0,o.createVNode)(1,"br"),"XP To Next Level:",e.max_lvl!==(l?e.lvl_mod_num:e.lvl_base_num)?(0,o.createComponentVNode)(2,a.Box,{inline:!0,children:l?(0,o.createVNode)(1,"span",null,e.xp_next_lvl_mod,0):(0,o.createVNode)(1,"span",null,e.xp_next_lvl_base,0)}):(0,o.createVNode)(1,"span",null,"[MAXXED]",16,{style:u})]}),l?(0,o.createVNode)(1,"span",null,e.mod_readout,0):(0,o.createVNode)(1,"span",null,e.base_readout,0),l?(0,o.createComponentVNode)(2,a.ProgressBar,{value:e.percent_mod,color:"good"}):(0,o.createComponentVNode)(2,a.ProgressBar,{value:e.percent_base,color:"good"}),(0,o.createVNode)(1,"br"),!!i.admin&&(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{content:"Adjust Exp",onClick:function(){return n("adj_exp",{skill:e.path})}}),(0,o.createComponentVNode)(2,a.Button,{content:"Set Exp",onClick:function(){return n("set_exp",{skill:e.path})}}),!!e.level_based&&(0,o.createComponentVNode)(2,a.Button,{content:"Set Level",onClick:function(){return n("set_lvl",{skill:e.path})}})],0),(0,o.createVNode)(1,"br"),(0,o.createVNode)(1,"br")]},e.name)}))})})}},function(e,t,n){"use strict";t.__esModule=!0,t.Sleeper=void 0;var o=n(0),r=n(3),a=n(2);t.Sleeper=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.occupied,l=i.open,u=i.occupant,d=void 0===u?[]:u,s=(i.chems||[]).sort((function(e,t){var n=e.name.toLowerCase(),o=t.name.toLowerCase();return no?1:0})),p=(i.synthchems||[]).sort((function(e,t){var n=e.name.toLowerCase(),o=t.name.toLowerCase();return no?1:0}));return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:d.name?d.name:"No Occupant",minHeight:"210px",buttons:!!d.stat&&(0,o.createComponentVNode)(2,a.Box,{inline:!0,bold:!0,color:d.statstate,children:d.stat}),children:!!c&&(0,o.createFragment)([(0,o.createComponentVNode)(2,a.ProgressBar,{value:d.health,minValue:d.minHealth,maxValue:d.maxHealth,ranges:{good:[50,Infinity],average:[0,50],bad:[-Infinity,0]}}),(0,o.createComponentVNode)(2,a.Box,{mt:1}),(0,o.createComponentVNode)(2,a.LabeledList,{children:[[{label:"Brute",type:"bruteLoss"},{label:"Burn",type:"fireLoss"},{label:"Toxin",type:"toxLoss"},{label:"Oxygen",type:"oxyLoss"}].map((function(e){return(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:e.label,children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:d[e.type],minValue:0,maxValue:d.maxHealth,color:"bad"})},e.type)})),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Blood",children:[(0,o.createComponentVNode)(2,a.ProgressBar,{value:i.blood_levels/100,color:"bad",children:(0,o.createComponentVNode)(2,a.AnimatedNumber,{value:i.blood_levels})}),i.blood_status]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Cells",color:d.cloneLoss?"bad":"good",children:d.cloneLoss?"Damaged":"Healthy"}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Brain",color:d.brainLoss?"bad":"good",children:d.brainLoss?"Abnormal":"Healthy"})]})],4)}),(0,o.createComponentVNode)(2,a.Section,{title:"Chemical Analysis",children:(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Chemical Contents",children:i.chemical_list.map((function(e){return(0,o.createComponentVNode)(2,a.Box,{color:"good",children:[e.volume," units of ",e.name]},e.id)}))})}),(0,o.createComponentVNode)(2,a.Section,{title:"Inject Chemicals",minHeight:"105px",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:l?"door-open":"door-closed",content:l?"Open":"Closed",onClick:function(){return n("door")}}),children:s.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{icon:"flask",content:e.name,disabled:!(c&&e.allowed),width:"140px",onClick:function(){return n("inject",{chem:e.id})}},e.name)}))}),(0,o.createComponentVNode)(2,a.Section,{title:"Synthesize Chemicals",children:p.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{content:e.name,width:"140px",onClick:function(){return n("synth",{chem:e.id})}},e.name)}))}),(0,o.createComponentVNode)(2,a.Section,{title:"Purge Chemicals",children:s.map((function(e){return(0,o.createComponentVNode)(2,a.Button,{content:e.name,disabled:!e.allowed,width:"140px",onClick:function(){return n("purge",{chem:e.id})}},e.name)}))})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.SlimeBodySwapper=t.BodyEntry=void 0;var o=n(0),r=n(3),a=n(2),i=function(e){var t=e.body,n=e.swapFunc;return(0,o.createComponentVNode)(2,a.Section,{title:(0,o.createComponentVNode)(2,a.Box,{inline:!0,color:t.htmlcolor,children:t.name}),level:2,buttons:(0,o.createComponentVNode)(2,a.Button,{content:{owner:"You Are Here",stranger:"Occupied",available:"Swap"}[t.occupied],selected:"owner"===t.occupied,color:"stranger"===t.occupied&&"bad",onClick:function(){return n()}}),children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Status",bold:!0,color:{Dead:"bad",Unconscious:"average",Conscious:"good"}[t.status],children:t.status}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Jelly",children:t.exoticblood}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Location",children:t.area})]})})};t.BodyEntry=i;t.SlimeBodySwapper=function(e){var t=(0,r.useBackend)(e),n=t.act,c=t.data.bodies,l=void 0===c?[]:c;return(0,o.createComponentVNode)(2,a.Section,{children:l.map((function(e){return(0,o.createComponentVNode)(2,i,{body:e,swapFunc:function(){return n("swap",{ref:e.ref})}},e.name)}))})}},function(e,t,n){"use strict";t.__esModule=!0,t.Signaler=void 0;var o=n(0),r=n(2),a=n(3),i=n(17);t.Signaler=function(e){var t=(0,a.useBackend)(e),n=t.act,c=t.data,l=c.code,u=c.frequency,d=c.minFrequency,s=c.maxFrequency;return(0,o.createComponentVNode)(2,r.Section,{children:[(0,o.createComponentVNode)(2,r.Grid,{children:[(0,o.createComponentVNode)(2,r.Grid.Column,{size:1.4,color:"label",children:"Frequency:"}),(0,o.createComponentVNode)(2,r.Grid.Column,{children:(0,o.createComponentVNode)(2,r.NumberInput,{animate:!0,unit:"kHz",step:.2,stepPixelSize:6,minValue:d/10,maxValue:s/10,value:u/10,format:function(e){return(0,i.toFixed)(e,1)},width:13,onDrag:function(e,t){return n("freq",{freq:t})}})}),(0,o.createComponentVNode)(2,r.Grid.Column,{children:(0,o.createComponentVNode)(2,r.Button,{ml:1.3,icon:"sync",content:"Reset",onClick:function(){return n("reset",{reset:"freq"})}})})]}),(0,o.createComponentVNode)(2,r.Grid,{mt:.6,children:[(0,o.createComponentVNode)(2,r.Grid.Column,{size:1.4,color:"label",children:"Code:"}),(0,o.createComponentVNode)(2,r.Grid.Column,{children:(0,o.createComponentVNode)(2,r.NumberInput,{animate:!0,step:1,stepPixelSize:6,minValue:1,maxValue:100,value:l,width:13,onDrag:function(e,t){return n("code",{code:t})}})}),(0,o.createComponentVNode)(2,r.Grid.Column,{children:(0,o.createComponentVNode)(2,r.Button,{ml:1.3,icon:"sync",content:"Reset",onClick:function(){return n("reset",{reset:"code"})}})})]}),(0,o.createComponentVNode)(2,r.Grid,{mt:.8,children:(0,o.createComponentVNode)(2,r.Grid.Column,{children:(0,o.createComponentVNode)(2,r.Button,{mb:-.1,fluid:!0,icon:"arrow-up",content:"Send Signal",textAlign:"center",onClick:function(){return n("signal")}})})})]})}},function(e,t,n){"use strict";t.__esModule=!0,t.SmartVend=void 0;var o=n(0),r=n(25),a=n(3),i=n(2);t.SmartVend=function(e){var t=(0,a.useBackend)(e),n=t.act,c=t.data;return(0,o.createComponentVNode)(2,i.Section,{title:"Storage",buttons:!!c.isdryer&&(0,o.createComponentVNode)(2,i.Button,{icon:c.drying?"stop":"tint",onClick:function(){return n("Dry")},children:c.drying?"Stop drying":"Dry"}),children:0===c.contents.length&&(0,o.createComponentVNode)(2,i.NoticeBox,{children:["Unfortunately, this ",c.name," is empty."]})||(0,o.createComponentVNode)(2,i.Table,{children:[(0,o.createComponentVNode)(2,i.Table.Row,{header:!0,children:[(0,o.createComponentVNode)(2,i.Table.Cell,{children:"Item"}),(0,o.createComponentVNode)(2,i.Table.Cell,{collapsing:!0}),(0,o.createComponentVNode)(2,i.Table.Cell,{collapsing:!0,textAlign:"center",children:c.verb?c.verb:"Dispense"})]}),(0,r.map)((function(e,t){return(0,o.createComponentVNode)(2,i.Table.Row,{children:[(0,o.createComponentVNode)(2,i.Table.Cell,{children:e.name}),(0,o.createComponentVNode)(2,i.Table.Cell,{collapsing:!0,textAlign:"right",children:e.amount}),(0,o.createComponentVNode)(2,i.Table.Cell,{collapsing:!0,children:[(0,o.createComponentVNode)(2,i.Button,{content:"One",disabled:e.amount<1,onClick:function(){return n("Release",{name:e.name,amount:1})}}),(0,o.createComponentVNode)(2,i.Button,{content:"Many",disabled:e.amount<=1,onClick:function(){return n("Release",{name:e.name})}})]})]},t)}))(c.contents)]})})}},function(e,t,n){"use strict";t.__esModule=!0,t.Smes=void 0;var o=n(0),r=n(3),a=n(2);t.Smes=function(e){var t,n,i=(0,r.useBackend)(e),c=i.act,l=i.data;return t=l.capacityPercent>=100?"good":l.inputting?"average":"bad",n=l.outputting?"good":l.charge>0?"average":"bad",(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Stored Energy",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:.01*l.capacityPercent,ranges:{good:[.5,Infinity],average:[.15,.5],bad:[-Infinity,.15]}})}),(0,o.createComponentVNode)(2,a.Section,{title:"Input",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Charge Mode",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:l.inputAttempt?"sync-alt":"times",selected:l.inputAttempt,onClick:function(){return c("tryinput")},children:l.inputAttempt?"Auto":"Off"}),children:(0,o.createComponentVNode)(2,a.Box,{color:t,children:l.capacityPercent>=100?"Fully Charged":l.inputting?"Charging":"Not Charging"})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Target Input",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:l.inputLevel/l.inputLevelMax,content:l.inputLevel_text})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Adjust Input",children:[(0,o.createComponentVNode)(2,a.Button,{icon:"fast-backward",disabled:0===l.inputLevel,onClick:function(){return c("input",{target:"min"})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"backward",disabled:0===l.inputLevel,onClick:function(){return c("input",{adjust:-1e4})}}),(0,o.createComponentVNode)(2,a.NumberInput,{value:Math.round(l.inputLevel/1e3),unit:"kW",width:"65px",minValue:0,maxValue:l.inputLevelMax/1e3,onChange:function(e,t){return c("input",{target:1e3*t})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"forward",disabled:l.inputLevel===l.inputLevelMax,onClick:function(){return c("input",{adjust:1e4})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"fast-forward",disabled:l.inputLevel===l.inputLevelMax,onClick:function(){return c("input",{target:"max"})}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Available",children:l.inputAvailable})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Output",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Output Mode",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:l.outputAttempt?"power-off":"times",selected:l.outputAttempt,onClick:function(){return c("tryoutput")},children:l.outputAttempt?"On":"Off"}),children:(0,o.createComponentVNode)(2,a.Box,{color:n,children:l.outputting?"Sending":l.charge>0?"Not Sending":"No Charge"})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Target Output",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:l.outputLevel/l.outputLevelMax,content:l.outputLevel_text})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Adjust Output",children:[(0,o.createComponentVNode)(2,a.Button,{icon:"fast-backward",disabled:0===l.outputLevel,onClick:function(){return c("output",{target:"min"})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"backward",disabled:0===l.outputLevel,onClick:function(){return c("output",{adjust:-1e4})}}),(0,o.createComponentVNode)(2,a.NumberInput,{value:Math.round(l.outputLevel/1e3),unit:"kW",width:"65px",minValue:0,maxValue:l.outputLevelMax/1e3,onChange:function(e,t){return c("output",{target:1e3*t})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"forward",disabled:l.outputLevel===l.outputLevelMax,onClick:function(){return c("output",{adjust:1e4})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"fast-forward",disabled:l.outputLevel===l.outputLevelMax,onClick:function(){return c("output",{target:"max"})}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Outputting",children:l.outputUsed})]})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.SmokeMachine=void 0;var o=n(0),r=n(3),a=n(2);t.SmokeMachine=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.TankContents,l=(i.isTankLoaded,i.TankCurrentVolume),u=i.TankMaxVolume,d=i.active,s=i.setting,p=(i.screen,i.maxSetting),m=void 0===p?[]:p;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Dispersal Tank",buttons:(0,o.createComponentVNode)(2,a.Button,{icon:d?"power-off":"times",selected:d,content:d?"On":"Off",onClick:function(){return n("power")}}),children:[(0,o.createComponentVNode)(2,a.ProgressBar,{value:l/u,ranges:{bad:[-Infinity,.3]},children:[(0,o.createComponentVNode)(2,a.AnimatedNumber,{initial:0,value:l||0})," / "+u]}),(0,o.createComponentVNode)(2,a.Box,{mt:1,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Range",children:[1,2,3,4,5].map((function(e){return(0,o.createComponentVNode)(2,a.Button,{selected:s===e,icon:"plus",content:3*e,disabled:m0?"good":"bad",children:m})]})}),(0,o.createComponentVNode)(2,a.Grid.Column,{size:1.5,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Power output",children:(0,o.createComponentVNode)(2,a.ProgressBar,{ranges:{good:[.66,Infinity],average:[.33,.66],bad:[-Infinity,.33]},minValue:0,maxValue:1,value:l,content:c+" W"})})})})]})}),(0,o.createComponentVNode)(2,a.Section,{title:"Controls",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Tracking",children:[(0,o.createComponentVNode)(2,a.Button,{icon:"times",content:"Off",selected:0===p,onClick:function(){return n("tracking",{mode:0})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"clock-o",content:"Timed",selected:1===p,onClick:function(){return n("tracking",{mode:1})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"sync",content:"Auto",selected:2===p,disabled:!f,onClick:function(){return n("tracking",{mode:2})}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Azimuth",children:[(0===p||1===p)&&(0,o.createComponentVNode)(2,a.NumberInput,{width:"52px",unit:"\xb0",step:1,stepPixelSize:2,minValue:-360,maxValue:720,value:u,onDrag:function(e,t){return n("azimuth",{value:t})}}),1===p&&(0,o.createComponentVNode)(2,a.NumberInput,{width:"80px",unit:"\xb0/m",step:.01,stepPixelSize:1,minValue:-s-.01,maxValue:s+.01,value:d,format:function(e){return(Math.sign(e)>0?"+":"-")+Math.abs(e)},onDrag:function(e,t){return n("azimuth_rate",{value:t})}}),2===p&&(0,o.createComponentVNode)(2,a.Box,{inline:!0,color:"label",mt:"3px",children:[u+" \xb0"," (auto)"]})]})]})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.SpaceHeater=void 0;var o=n(0),r=n(3),a=n(2);t.SpaceHeater=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Power",buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{icon:"eject",content:"Eject Cell",disabled:!i.hasPowercell||!i.open,onClick:function(){return n("eject")}}),(0,o.createComponentVNode)(2,a.Button,{icon:i.on?"power-off":"times",content:i.on?"On":"Off",selected:i.on,disabled:!i.hasPowercell,onClick:function(){return n("power")}})],4),children:(0,o.createComponentVNode)(2,a.LabeledList,{children:(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Cell",color:!i.hasPowercell&&"bad",children:i.hasPowercell&&(0,o.createComponentVNode)(2,a.ProgressBar,{value:i.powerLevel/100,content:i.powerLevel+"%",ranges:{good:[.6,Infinity],average:[.3,.6],bad:[-Infinity,.3]}})||"None"})})}),(0,o.createComponentVNode)(2,a.Section,{title:"Thermostat",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Current Temperature",children:(0,o.createComponentVNode)(2,a.Box,{fontSize:"18px",color:Math.abs(i.targetTemp-i.currentTemp)>50?"bad":Math.abs(i.targetTemp-i.currentTemp)>20?"average":"good",children:[i.currentTemp,"\xb0C"]})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Target Temperature",children:i.open&&(0,o.createComponentVNode)(2,a.NumberInput,{animated:!0,value:parseFloat(i.targetTemp),width:"65px",unit:"\xb0C",minValue:i.minTemp,maxValue:i.maxTemp,onChange:function(e,t){return n("target",{target:t})}})||i.targetTemp+"\xb0C"}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Mode",children:i.open?(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{icon:"thermometer-half",content:"Auto",selected:"auto"===i.mode,onClick:function(){return n("mode",{mode:"auto"})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"fire-alt",content:"Heat",selected:"heat"===i.mode,onClick:function(){return n("mode",{mode:"heat"})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"fan",content:"Cool",selected:"cool"===i.mode,onClick:function(){return n("mode",{mode:"cool"})}})],4):"Auto"}),(0,o.createComponentVNode)(2,a.LabeledList.Divider)]})})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.SpawnersMenu=void 0;var o=n(0),r=n(3),a=n(2);t.SpawnersMenu=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data.spawners||[];return(0,o.createComponentVNode)(2,a.Section,{children:i.map((function(e){return(0,o.createComponentVNode)(2,a.Section,{title:e.name+" ("+e.amount_left+" left)",level:2,buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{content:"Jump",onClick:function(){return n("jump",{name:e.name})}}),(0,o.createComponentVNode)(2,a.Button,{content:"Spawn",onClick:function(){return n("spawn",{name:e.name})}})],4),children:[(0,o.createComponentVNode)(2,a.Box,{bold:!0,mb:1,fontSize:"20px",children:e.short_desc}),(0,o.createComponentVNode)(2,a.Box,{children:e.flavor_text}),!!e.important_info&&(0,o.createComponentVNode)(2,a.Box,{mt:1,bold:!0,color:"bad",fontSize:"26px",children:e.important_info})]},e.name)}))})}},function(e,t,n){"use strict";t.__esModule=!0,t.StationAlertConsole=void 0;var o=n(0),r=n(3),a=n(2);t.StationAlertConsole=function(e){var t=(0,r.useBackend)(e).data.alarms||[],n=t.Fire||[],i=t.Atmosphere||[],c=t.Power||[];return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{title:"Fire Alarms",children:(0,o.createVNode)(1,"ul",null,[0===n.length&&(0,o.createVNode)(1,"li","color-good","Systems Nominal",16),n.map((function(e){return(0,o.createVNode)(1,"li","color-average",e,0,null,e)}))],0)}),(0,o.createComponentVNode)(2,a.Section,{title:"Atmospherics Alarms",children:(0,o.createVNode)(1,"ul",null,[0===i.length&&(0,o.createVNode)(1,"li","color-good","Systems Nominal",16),i.map((function(e){return(0,o.createVNode)(1,"li","color-average",e,0,null,e)}))],0)}),(0,o.createComponentVNode)(2,a.Section,{title:"Power Alarms",children:(0,o.createVNode)(1,"ul",null,[0===c.length&&(0,o.createVNode)(1,"li","color-good","Systems Nominal",16),c.map((function(e){return(0,o.createVNode)(1,"li","color-average",e,0,null,e)}))],0)})],4)}},function(e,t,n){"use strict";t.__esModule=!0,t.SuitStorageUnit=void 0;var o=n(0),r=n(3),a=n(2);t.SuitStorageUnit=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.locked,l=i.open,u=i.safeties,d=i.uv_active,s=i.occupied,p=i.suit,m=i.helmet,f=i.mask,h=i.storage;return(0,o.createFragment)([!(!s||!u)&&(0,o.createComponentVNode)(2,a.NoticeBox,{children:"Biological entity detected in suit chamber. Please remove before continuing with operation."}),d&&(0,o.createComponentVNode)(2,a.NoticeBox,{children:"Contents are currently being decontaminated. Please wait."})||(0,o.createComponentVNode)(2,a.Section,{title:"Storage",minHeight:"260px",buttons:(0,o.createFragment)([!l&&(0,o.createComponentVNode)(2,a.Button,{icon:c?"unlock":"lock",content:c?"Unlock":"Lock",onClick:function(){return n("lock")}}),!c&&(0,o.createComponentVNode)(2,a.Button,{icon:l?"sign-out-alt":"sign-in-alt",content:l?"Close":"Open",onClick:function(){return n("door")}})],0),children:c&&(0,o.createComponentVNode)(2,a.Box,{mt:6,bold:!0,textAlign:"center",fontSize:"40px",children:[(0,o.createComponentVNode)(2,a.Box,{children:"Unit Locked"}),(0,o.createComponentVNode)(2,a.Icon,{name:"lock"})]})||l&&(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Helmet",children:(0,o.createComponentVNode)(2,a.Button,{icon:m?"square":"square-o",content:m||"Empty",disabled:!m,onClick:function(){return n("dispense",{item:"helmet"})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Suit",children:(0,o.createComponentVNode)(2,a.Button,{icon:p?"square":"square-o",content:p||"Empty",disabled:!p,onClick:function(){return n("dispense",{item:"suit"})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Mask",children:(0,o.createComponentVNode)(2,a.Button,{icon:f?"square":"square-o",content:f||"Empty",disabled:!f,onClick:function(){return n("dispense",{item:"mask"})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Storage",children:(0,o.createComponentVNode)(2,a.Button,{icon:h?"square":"square-o",content:h||"Empty",disabled:!h,onClick:function(){return n("dispense",{item:"storage"})}})})]})||(0,o.createComponentVNode)(2,a.Button,{fluid:!0,icon:"recycle",content:"Decontaminate",disabled:s&&u,textAlign:"center",onClick:function(){return n("uv")}})})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.Tank=void 0;var o=n(0),r=n(3),a=n(2);t.Tank=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Pressure",children:(0,o.createComponentVNode)(2,a.ProgressBar,{value:i.tankPressure/1013,content:i.tankPressure+" kPa",ranges:{good:[.35,Infinity],average:[.15,.35],bad:[-Infinity,.15]}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Pressure Regulator",children:[(0,o.createComponentVNode)(2,a.Button,{icon:"fast-backward",disabled:i.ReleasePressure===i.minReleasePressure,onClick:function(){return n("pressure",{pressure:"min"})}}),(0,o.createComponentVNode)(2,a.NumberInput,{animated:!0,value:parseFloat(i.releasePressure),width:"65px",unit:"kPa",minValue:i.minReleasePressure,maxValue:i.maxReleasePressure,onChange:function(e,t){return n("pressure",{pressure:t})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"fast-forward",disabled:i.ReleasePressure===i.maxReleasePressure,onClick:function(){return n("pressure",{pressure:"max"})}}),(0,o.createComponentVNode)(2,a.Button,{icon:"undo",content:"",disabled:i.ReleasePressure===i.defaultReleasePressure,onClick:function(){return n("pressure",{pressure:"reset"})}})]})]})})}},function(e,t,n){"use strict";t.__esModule=!0,t.TeleLogBrowser=void 0;var o=n(0),r=n(3),a=n(2);t.TeleLogBrowser=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.notice,l=i.network,u=void 0===l?"NULL":l,d=i.servers,s=i.selected,p=void 0===s?null:s,m=i.selected_logs,f=p&&p.status;return(0,o.createFragment)([!!c&&(0,o.createComponentVNode)(2,a.NoticeBox,{children:c}),(0,o.createComponentVNode)(2,a.Section,{title:"Network Control",children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Network",children:(0,o.createComponentVNode)(2,a.Input,{value:u,width:"150px",maxLength:15,onChange:function(e,t){return n("network",{value:t})}})}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Memory",buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{content:"Flush Buffer",icon:"minus-circle",disabled:!d.length||!!p,onClick:function(){return n("release")}}),(0,o.createComponentVNode)(2,a.Button,{content:"Probe Network",icon:"sync",disabled:p,onClick:function(){return n("probe")}})],4),children:d?d.length+" currently probed and buffered":"Buffer is empty!"}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Selected Server",buttons:(0,o.createComponentVNode)(2,a.Button,{content:"Disconnect",disabled:!p,onClick:function(){return n("mainmenu")}}),children:p?p.name+" ("+p.id+")":"None (None)"}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Recorded Traffic",children:p?p.traffic<=1024?p.traffic+" Gigabytes":Math.round(p.traffic/1024)+" Terrabytes":"0 Gigabytes"}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Server Status",color:f?"good":"bad",children:f?"Running":"Server down!"})]})}),(0,o.createComponentVNode)(2,a.Tabs,{children:[(0,o.createComponentVNode)(2,a.Tabs.Tab,{label:"Servers",children:(0,o.createComponentVNode)(2,a.Section,{children:d&&d.length?(0,o.createComponentVNode)(2,a.LabeledList,{children:d.map((function(e){return(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:""+e.ref,buttons:(0,o.createComponentVNode)(2,a.Button,{content:"Connect",selected:i.selected&&e.ref===i.selected.ref,onClick:function(){return n("viewmachine",{value:e.id})}}),children:e.name+" ("+e.id+")"},e.name)}))}):"404 Servers not found. Have you tried scanning the network?"})},"servers"),(0,o.createComponentVNode)(2,a.Tabs.Tab,{label:"Messages",disabled:!f,children:(0,o.createComponentVNode)(2,a.Section,{title:"Logs",children:f&&m?m.map((function(e){return(0,o.createComponentVNode)(2,a.Section,{level:4,children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Filename",buttons:(0,o.createComponentVNode)(2,a.Button,{content:"Delete",onClick:function(){return n("delete",{value:e.ref})}}),children:e.name}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Data type",children:e.input_type}),e.source&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Source",children:"["+e.source.name+"] (Job: ["+e.source.job+"])"}),e.race&&(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Class",children:e.race}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Contents",children:e.message})]})},e.ref)})):"No server selected!"})},"messages")]})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.Telemonitor=void 0;var o=n(0),r=n(3),a=n(33),i=n(2);t.Telemonitor=function(e){var t=(0,r.useBackend)(e),n=t.act,c=t.data,l=c.notice,u=c.network,d=void 0===u?"NULL":u,s=c.servers,p=c.selected,m=void 0===p?null:p,f=c.selected_servers,h=m&&m.status;return(0,o.createFragment)([!!l&&(0,o.createComponentVNode)(2,i.NoticeBox,{children:l}),(0,o.createComponentVNode)(2,i.Section,{title:"Network Control",children:(0,o.createComponentVNode)(2,i.LabeledList,{children:[(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Network",children:(0,o.createComponentVNode)(2,i.Input,{value:d,width:"150px",maxLength:15,onChange:function(e,t){return n("network",{value:t})}})}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Memory",buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,i.Button,{content:"Flush Buffer",icon:"minus-circle",disabled:!s.length||!!m,onClick:function(){return n("release")}}),(0,o.createComponentVNode)(2,i.Button,{content:"Probe Network",icon:"sync",disabled:m,onClick:function(){return n("probe")}})],4),children:m?f?f.length+" currently probed and buffered":"Connected devices is empty!":s?s.length+" currently probed and buffered":"Buffer is empty!"}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Selected Entity",buttons:(0,o.createComponentVNode)(2,i.Button,{content:"Disconnect",icon:"minus-circle",disabled:!m,onClick:function(){return n("mainmenu")}}),children:m?m.name+" ("+m.id+")":"None (None)"})]})}),(0,o.createComponentVNode)(2,i.Tabs,{children:[(0,o.createComponentVNode)(2,i.Tabs.Tab,{label:"Network Entities",children:(0,o.createComponentVNode)(2,i.Section,{title:"Detected Network Entities",children:s&&s.length?(0,o.createComponentVNode)(2,i.LabeledList,{children:s.map((function(e){return(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:e.ref,buttons:(0,o.createComponentVNode)(2,i.Button,{content:"Connect",selected:m&&e.ref===m.ref,onClick:function(){return n("viewmachine",{value:e.id})}}),children:e.name+" ("+e.id+")"},e.name)}))}):"404 Servers not found. Have you tried scanning the network?"})}),(0,o.createComponentVNode)(2,i.Tabs.Tab,{label:"Entity Status",disabled:!m,children:(0,o.createComponentVNode)(2,i.Section,{title:"Network Entity Status",children:[(0,o.createComponentVNode)(2,i.LabeledList,{children:[(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Status",color:h?"good":"bad",children:h?"Running":"Server down!"}),(0,o.createComponentVNode)(2,i.LabeledList.Item,{label:"Network Traffic",color:h&&m.netspeed0?"good":"bad",children:[s," TC"]}),buttons:(0,o.createFragment)([(0,o.createTextVNode)("Search"),(0,o.createComponentVNode)(2,i.Input,{value:C,onInput:function(t,n){return e.setSearchText(n)},ml:1,mr:1}),(0,o.createComponentVNode)(2,i.Button,{icon:u?"list":"info",content:u?"Compact":"Detailed",onClick:function(){return(0,a.act)(c,"compact_toggle")}}),!!d&&(0,o.createComponentVNode)(2,i.Button,{icon:"lock",content:"Lock",onClick:function(){return(0,a.act)(c,"lock")}})],0),children:C.length>0?(0,o.createVNode)(1,"table","Table",(0,o.createComponentVNode)(2,l,{compact:!0,items:m.flatMap((function(e){return e.items||[]})).filter((function(e){var t=C.toLowerCase();return String(e.name+e.desc).toLowerCase().includes(t)})),hoveredItem:h,onBuyMouseOver:function(t){return e.setHoveredItem(t)},onBuyMouseOut:function(t){return e.setHoveredItem({})},onBuy:function(e){return(0,a.act)(c,"buy",{item:e.name})}}),2):(0,o.createComponentVNode)(2,i.Tabs,{vertical:!0,children:m.map((function(t){var n=t.name,r=t.items;if(null!==r)return(0,o.createComponentVNode)(2,i.Tabs.Tab,{label:n+" ("+r.length+")",children:function(){return(0,o.createComponentVNode)(2,l,{compact:u,items:r,hoveredItem:h,telecrystals:s,onBuyMouseOver:function(t){return e.setHoveredItem(t)},onBuyMouseOut:function(t){return e.setHoveredItem({})},onBuy:function(e){return(0,a.act)(c,"buy",{item:e.name})}})}},n)}))})})},r}(o.Component);t.Uplink=c;var l=function(e){var t=e.items,n=e.hoveredItem,a=e.telecrystals,c=e.compact,l=e.onBuy,u=e.onBuyMouseOver,d=e.onBuyMouseOut,s=n&&n.cost||0;return c?(0,o.createComponentVNode)(2,i.Table,{children:t.map((function(e){var t=n&&n.name!==e.name,c=a-sl.user.cash),content:t?"FREE":c,onClick:function(){return(0,r.act)(u,"vend",{ref:e.ref})}})})]},e.name)}))})})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.Wires=void 0;var o=n(0),r=n(3),a=n(2);t.Wires=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data,c=i.wires||[],l=i.status||[];return(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:c.map((function(e){return(0,o.createComponentVNode)(2,a.LabeledList.Item,{className:"candystripe",label:e.color,labelColor:e.color,color:e.color,buttons:(0,o.createFragment)([(0,o.createComponentVNode)(2,a.Button,{content:e.cut?"Mend":"Cut",onClick:function(){return n("cut",{wire:e.color})}}),(0,o.createComponentVNode)(2,a.Button,{content:"Pulse",onClick:function(){return n("pulse",{wire:e.color})}}),(0,o.createComponentVNode)(2,a.Button,{content:e.attached?"Detach":"Attach",onClick:function(){return n("attach",{wire:e.color})}})],4),children:!!e.wire&&(0,o.createVNode)(1,"i",null,[(0,o.createTextVNode)("("),e.wire,(0,o.createTextVNode)(")")],0)},e.color)}))})}),!!l.length&&(0,o.createComponentVNode)(2,a.Section,{children:l.map((function(e){return(0,o.createComponentVNode)(2,a.Box,{children:e},e)}))})],0)}},function(e,t,n){"use strict";t.__esModule=!0,t.AtmosRelief=void 0;var o=n(0),r=n(3),a=n(2);t.AtmosRelief=function(e){var t=(0,r.useBackend)(e),n=t.act,i=t.data;return(0,o.createComponentVNode)(2,a.Section,{children:(0,o.createComponentVNode)(2,a.LabeledList,{children:[(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Open Pressure",children:[(0,o.createComponentVNode)(2,a.NumberInput,{animated:!0,value:parseFloat(i.open_pressure),unit:"kPa",width:"75px",minValue:0,maxValue:4500,step:10,onChange:function(e,t){return n("open_pressure",{open_pressure:t})}}),(0,o.createComponentVNode)(2,a.Button,{ml:1,icon:"plus",content:"Max",disabled:i.open_pressure===i.max_pressure,onClick:function(){return n("open_pressure",{open_pressure:"max"})}})]}),(0,o.createComponentVNode)(2,a.LabeledList.Item,{label:"Close Pressure",children:[(0,o.createComponentVNode)(2,a.NumberInput,{animated:!0,value:parseFloat(i.close_pressure),unit:"kPa",width:"75px",minValue:0,maxValue:i.open_pressure,step:10,onChange:function(e,t){return n("close_pressure",{close_pressure:t})}}),(0,o.createComponentVNode)(2,a.Button,{ml:1,icon:"plus",content:"Max",disabled:i.close_pressure===i.open_pressure,onClick:function(){return n("close_pressure",{close_pressure:"max"})}})]})]})})}},function(e,t,n){"use strict";t.__esModule=!0,t.createStore=void 0;var o=n(71),r=n(518),a=n(3),i=n(120),c=n(118);(0,n(53).createLogger)("store");t.createStore=function(){var e=(0,o.flow)([function(e,t){return void 0===e&&(e={}),e},a.backendReducer,i.toastReducer,c.hotKeyReducer]),t=[c.hotKeyMiddleware];return(0,r.createStore)(e,r.applyMiddleware.apply(void 0,t))}},function(e,t,n){"use strict";t.__esModule=!0,t.applyMiddleware=t.createStore=void 0;var o=n(71);t.createStore=function r(e,t){if(t)return t(r)(e);var n,o=[],a=function(t){n=e(n,t),o.forEach((function(e){return e()}))};return a({type:"@@INIT"}),{dispatch:a,subscribe:function(e){o.push(e)},getState:function(){return n}}};t.applyMiddleware=function(){for(var e=arguments.length,t=new Array(e),n=0;n1?r-1:0),i=1;i1?t-1:0),o=1;o { - // IE8: Focus method is seemingly fucked. - if (tridentVersion <= 4) { - return; - } - const element = document.getElementById('Layout__content'); - if (element) { - element.focus(); - } -}; diff --git a/tgui-next/packages/tgui/routes.js b/tgui-next/packages/tgui/routes.js deleted file mode 100644 index eac87c2040..0000000000 --- a/tgui-next/packages/tgui/routes.js +++ /dev/null @@ -1,595 +0,0 @@ -import { Achievements } from './interfaces/Achievements'; -import { AiAirlock } from './interfaces/AiAirlock'; -import { AirAlarm } from './interfaces/AirAlarm'; -import { AirlockElectronics } from './interfaces/AirlockElectronics'; -import { Apc } from './interfaces/Apc'; -import { AtmosAlertConsole } from './interfaces/AtmosAlertConsole'; -import { AtmosControlConsole } from './interfaces/AtmosControlConsole'; -import { AtmosFilter } from './interfaces/AtmosFilter'; -import { AtmosMixer } from './interfaces/AtmosMixer'; -import { AtmosPump } from './interfaces/AtmosPump'; -import { BankMachine } from './interfaces/BankMachine'; -import { BluespaceArtillery } from './interfaces/BluespaceArtillery'; -import { Bepis } from './interfaces/Bepis'; -import { BorgPanel } from './interfaces/BorgPanel'; -import { BrigTimer } from './interfaces/BrigTimer'; -import { Canvas } from './interfaces/Canvas'; -import { Canister } from './interfaces/Canister'; -import { Cargo, CargoExpress } from './interfaces/Cargo'; -import { CellularEmporium } from './interfaces/CellularEmporium'; -import { CentcomPodLauncher } from './interfaces/CentcomPodLauncher'; -import { ChemAcclimator } from './interfaces/ChemAcclimator'; -import { ChemDebugSynthesizer } from './interfaces/ChemDebugSynthesizer'; -import { ChemDispenser } from './interfaces/ChemDispenser'; -import { ChemFilter } from './interfaces/ChemFilter'; -import { ChemHeater } from './interfaces/ChemHeater'; -import { ChemMaster } from './interfaces/ChemMaster'; -import { ChemPress } from './interfaces/ChemPress'; -import { ChemReactionChamber } from './interfaces/ChemReactionChamber'; -import { ChemSplitter } from './interfaces/ChemSplitter'; -import { ChemSynthesizer } from './interfaces/ChemSynthesizer'; -import { CodexGigas } from './interfaces/CodexGigas'; -import { ComputerFabricator } from './interfaces/ComputerFabricator'; -import { Crayon } from './interfaces/Crayon'; -import { CrewConsole } from './interfaces/CrewConsole'; -import { Cryo } from './interfaces/Cryo'; -import { PersonalCrafting } from './interfaces/PersonalCrafting'; -import { DecalPainter } from './interfaces/DecalPainter'; -import { DisposalUnit } from './interfaces/DisposalUnit'; -import { DnaVault } from './interfaces/DnaVault'; -import { EightBallVote } from './interfaces/EightBallVote'; -import { EmergencyShuttleConsole } from './interfaces/EmergencyShuttleConsole'; -import { EngravedMessage } from './interfaces/EngravedMessage'; -import { Gps } from './interfaces/Gps'; -import { GravityGenerator } from './interfaces/GravityGenerator'; -import { GulagTeleporterConsole } from './interfaces/GulagTeleporterConsole'; -import { GulagItemReclaimer } from './interfaces/GulagItemReclaimer'; -import { Holodeck } from './interfaces/Holodeck'; -import { HypnoChair } from './interfaces/HypnoChair'; -import { ImplantChair } from './interfaces/ImplantChair'; -import { Intellicard } from './interfaces/Intellicard'; -import { KeycardAuth } from './interfaces/KeycardAuth'; -import { LaborClaimConsole } from './interfaces/LaborClaimConsole'; -import { LanguageMenu } from './interfaces/LanguageMenu'; -import { LaunchpadConsole, LaunchpadRemote } from './interfaces/Launchpad'; -import { MechBayPowerConsole } from './interfaces/MechBayPowerConsole'; -import { NaniteChamberControl } from './interfaces/NaniteChamberControl'; -import { NaniteCloudControl } from './interfaces/NaniteCloudControl'; -import { NaniteProgramHub } from './interfaces/NaniteProgramHub'; -import { NaniteProgrammer } from './interfaces/NaniteProgrammer'; -import { NaniteRemote } from './interfaces/NaniteRemote'; -import { Mule } from './interfaces/Mule'; -import { NotificationPreferences } from './interfaces/NotificationPreferences'; -import { NtnetRelay } from './interfaces/NtnetRelay'; -import { NtosArcade } from './interfaces/NtosArcade'; -import { NtosConfiguration } from './interfaces/NtosConfiguration'; -import { NtosMain } from './interfaces/NtosMain'; -import { NtosNetChat } from './interfaces/NtosNetChat'; -import { NtosNetDownloader } from './interfaces/NtosNetDownloader'; -import { NtosSupermatterMonitor } from './interfaces/NtosSupermatterMonitor'; -import { NtosWrapper } from './interfaces/NtosWrapper'; -import { NuclearBomb } from './interfaces/NuclearBomb'; -import { OperatingComputer } from './interfaces/OperatingComputer'; -import { OreBox } from './interfaces/OreBox'; -import { OreRedemptionMachine } from './interfaces/OreRedemptionMachine'; -import { Pandemic } from './interfaces/Pandemic'; -import { PortableGenerator } from './interfaces/PortableGenerator'; -import { PortablePump, PortableScrubber } from './interfaces/PortableAtmos'; -import { PowerMonitor } from './interfaces/PowerMonitor'; -import { Radio } from './interfaces/Radio'; -import { RapidPipeDispenser } from './interfaces/RapidPipeDispenser'; -import { SatelliteControl } from './interfaces/SatelliteControl'; -import { ScannerGate } from './interfaces/ScannerGate'; -import { ShuttleManipulator } from './interfaces/ShuttleManipulator'; -import { SkillPanel } from './interfaces/SkillPanel'; -import { Sleeper } from './interfaces/Sleeper'; -import { SlimeBodySwapper } from './interfaces/SlimeBodySwapper'; -import { Signaler } from './interfaces/Signaler'; -import { SmartVend } from './interfaces/SmartVend'; -import { Smes } from './interfaces/Smes'; -import { SmokeMachine } from './interfaces/SmokeMachine'; -import { SolarControl } from './interfaces/SolarControl'; -import { SpaceHeater } from './interfaces/SpaceHeater'; -import { SpawnersMenu } from './interfaces/SpawnersMenu'; -import { StationAlertConsole } from './interfaces/StationAlertConsole'; -import { SuitStorageUnit } from './interfaces/SuitStorageUnit'; -import { Tank } from './interfaces/Tank'; -import { TeleLogBrowser } from './interfaces/TelecommsLogBrowser'; -import { Telemonitor } from './interfaces/TelecommsMonitor'; -import { TelePDALog } from './interfaces/TelecommsPDALog'; -import { TeleInteract } from './interfaces/TelecommsInteraction'; -import { TankDispenser } from './interfaces/TankDispenser'; -import { Teleporter } from './interfaces/Teleporter'; -import { ThermoMachine } from './interfaces/ThermoMachine'; -import { TurbineComputer } from './interfaces/TurbineComputer'; -import { Uplink } from './interfaces/Uplink'; -import { VaultController } from './interfaces/VaultController'; -import { Vending } from './interfaces/Vending'; -import { Wires } from './interfaces/Wires'; -import { AtmosRelief } from './interfaces/AtmosRelief'; - -const ROUTES = { - achievements: { - component: () => Achievements, - scrollable: true, - }, - ai_airlock: { - component: () => AiAirlock, - scrollable: false, - }, - airalarm: { - component: () => AirAlarm, - scrollable: true, - }, - airlock_electronics: { - component: () => AirlockElectronics, - scrollable: false, - }, - apc: { - component: () => Apc, - scrollable: false, - }, - atmos_alert: { - component: () => AtmosAlertConsole, - scrollable: true, - }, - atmos_control: { - component: () => AtmosControlConsole, - scrollable: true, - }, - atmos_filter: { - component: () => AtmosFilter, - scrollable: false, - }, - atmos_mixer: { - component: () => AtmosMixer, - scrollable: false, - }, - atmos_pump: { - component: () => AtmosPump, - scrollable: false, - }, - atmos_relief: { - component: () => AtmosRelief, - scrollable: false, - }, - bepis: { - component: () => Bepis, - scrollable: false, - }, - bank_machine: { - component: () => BankMachine, - scrollable: false, - }, - borgopanel: { - component: () => BorgPanel, - scrollable: true, - }, - brig_timer: { - component: () => BrigTimer, - scrollable: false, - }, - bsa: { - component: () => BluespaceArtillery, - scrollable: false, - }, - canvas: { - component: () => Canvas, - scrollable: false, - }, - canister: { - component: () => Canister, - scrollable: false, - }, - cargo: { - component: () => Cargo, - scrollable: true, - }, - cargo_express: { - component: () => CargoExpress, - scrollable: true, - }, - cellular_emporium: { - component: () => CellularEmporium, - scrollable: true, - }, - centcom_podlauncher: { - component: () => CentcomPodLauncher, - scrollable: false, - }, - acclimator: { - component: () => ChemAcclimator, - scrollable: false, - }, - chem_dispenser: { - component: () => ChemDispenser, - scrollable: true, - }, - chemical_filter: { - component: () => ChemFilter, - scrollable: true, - }, - chem_heater: { - component: () => ChemHeater, - scrollable: true, - }, - chem_master: { - component: () => ChemMaster, - scrollable: true, - }, - chem_press: { - component: () => ChemPress, - scrollable: false, - }, - reaction_chamber: { - component: () => ChemReactionChamber, - scrollable: true, - }, - chem_splitter: { - component: () => ChemSplitter, - scrollable: false, - }, - chem_synthesizer: { - component: () => ChemDebugSynthesizer, - scrollable: false, - }, - synthesizer: { - component: () => ChemSynthesizer, - scrollable: false, - }, - codex_gigas: { - component: () => CodexGigas, - scrollable: false, - }, - computer_fabricator: { - component: () => ComputerFabricator, - scrollable: false, - }, - crayon: { - component: () => Crayon, - scrollable: true, - }, - crew: { - component: () => CrewConsole, - scrollable: true, - }, - cryo: { - component: () => Cryo, - scrollable: false, - }, - decal_painter: { - component: () => DecalPainter, - scrollable: false, - }, - disposal_unit: { - component: () => DisposalUnit, - scrollable: false, - }, - dna_vault: { - component: () => DnaVault, - scrollable: false, - }, - eightball: { - component: () => EightBallVote, - scrollable: false, - }, - emergency_shuttle_console: { - component: () => EmergencyShuttleConsole, - scrollable: false, - }, - engraved_message: { - component: () => EngravedMessage, - scrollable: false, - }, - gps: { - component: () => Gps, - scrollable: true, - }, - gravity_generator: { - component: () => GravityGenerator, - scrollable: false, - }, - gulag_console: { - component: () => GulagTeleporterConsole, - scrollable: false, - }, - gulag_item_reclaimer: { - component: () => GulagItemReclaimer, - scrollable: true, - }, - holodeck: { - component: () => Holodeck, - scrollable: true, - }, - hypnochair: { - component: () => HypnoChair, - scrollable: false, - }, - implantchair: { - component: () => ImplantChair, - scrollable: false, - }, - intellicard: { - component: () => Intellicard, - scrollable: true, - }, - keycard_auth: { - component: () => KeycardAuth, - scrollable: false, - }, - labor_claim_console: { - component: () => LaborClaimConsole, - scrollable: false, - }, - language_menu: { - component: () => LanguageMenu, - scrollable: true, - }, - launchpad_console: { - component: () => LaunchpadConsole, - scrollable: true, - }, - launchpad_remote: { - component: () => LaunchpadRemote, - scrollable: false, - theme: 'syndicate', - }, - mech_bay_power_console: { - component: () => MechBayPowerConsole, - scrollable: false, - }, - nanite_chamber_control: { - component: () => NaniteChamberControl, - scrollable: true, - }, - nanite_cloud_control: { - component: () => NaniteCloudControl, - scrollable: true, - }, - nanite_program_hub: { - component: () => NaniteProgramHub, - scrollable: true, - }, - nanite_programmer: { - component: () => NaniteProgrammer, - scrollable: true, - }, - nanite_remote: { - component: () => NaniteRemote, - scrollable: true, - }, - mulebot: { - component: () => Mule, - scrollable: false, - }, - notificationpanel: { - component: () => NotificationPreferences, - scrollable: true, - }, - ntnet_relay: { - component: () => NtnetRelay, - scrollable: false, - }, - ntos_arcade: { - component: () => NtosArcade, - wrapper: () => NtosWrapper, - scrollable: false, - theme: 'ntos', - }, - ntos_configuration: { - component: () => NtosConfiguration, - wrapper: () => NtosWrapper, - scrollable: true, - theme: 'ntos', - }, - ntos_main: { - component: () => NtosMain, - wrapper: () => NtosWrapper, - scrollable: true, - theme: 'ntos', - }, - ntos_net_chat: { - component: () => NtosNetChat, - wrapper: () => NtosWrapper, - scrollable: false, - theme: 'ntos', - }, - ntos_net_downloader: { - component: () => NtosNetDownloader, - wrapper: () => NtosWrapper, - scrollable: true, - theme: 'ntos', - }, - ntos_power_monitor: { - component: () => PowerMonitor, - wrapper: () => NtosWrapper, - scrollable: true, - theme: 'ntos', - }, - ntos_supermatter_monitor: { - component: () => NtosSupermatterMonitor, - wrapper: () => NtosWrapper, - scrollable: true, - theme: 'ntos', - }, - nuclear_bomb: { - component: () => NuclearBomb, - scrollable: false, - theme: 'retro', - }, - ore_redemption_machine: { - component: () => OreRedemptionMachine, - scrollable: true, - }, - ore_box: { - component: () => OreBox, - scrollable: true, - }, - operating_computer: { - component: () => OperatingComputer, - scrollable: true, - }, - pandemic: { - component: () => Pandemic, - scrollable: true, - }, - portable_generator: { - component: () => PortableGenerator, - scrollable: false, - }, - personal_crafting: { - component: () => PersonalCrafting, - scrollable: true, - }, - portable_pump: { - component: () => PortablePump, - scrollable: false, - }, - portable_scrubber: { - component: () => PortableScrubber, - scrollable: false, - }, - power_monitor: { - component: () => PowerMonitor, - scrollable: true, - }, - radio: { - component: () => Radio, - scrollable: false, - }, - rpd: { - component: () => RapidPipeDispenser, - scrollable: true, - }, - sat_control: { - component: () => SatelliteControl, - scrollable: false, - }, - scanner_gate: { - component: () => ScannerGate, - scrollable: true, - }, - shuttle_manipulator: { - component: () => ShuttleManipulator, - scrollable: true, - }, - skillpanel: { - component: () => SkillPanel, - scrollable: true, - }, - sleeper: { - component: () => Sleeper, - scrollable: false, - }, - slime_swap_body: { - component: () => SlimeBodySwapper, - scrollable: true, - }, - signaler: { - component: () => Signaler, - scrollable: false, - }, - smartvend: { - component: () => SmartVend, - scrollable: true, - }, - smes: { - component: () => Smes, - scrollable: false, - }, - smoke_machine: { - component: () => SmokeMachine, - scrollable: false, - }, - solar_control: { - component: () => SolarControl, - scrollable: false, - }, - space_heater: { - component: () => SpaceHeater, - scrollable: false, - }, - spawners_menu: { - component: () => SpawnersMenu, - scrollable: true, - }, - station_alert: { - component: () => StationAlertConsole, - scrollable: true, - }, - suit_storage_unit: { - component: () => SuitStorageUnit, - scrollable: false, - }, - tcommsserver: { - component: () => TeleLogBrowser, - scrollable: true, - theme: 'ntos', - }, - telemonitor: { - component: () => Telemonitor, - scrollable: true, - theme: 'ntos', - }, - telepdalog: { - component: () => TelePDALog, - scrollable: true, - theme: 'ntos', - }, - teleinteract: { - component: () => TeleInteract, - scrollable: true, - }, - tanks: { - component: () => Tank, - scrollable: false, - }, - tank_dispenser: { - component: () => TankDispenser, - scrollable: false, - }, - teleporter: { - component: () => Teleporter, - scrollable: false, - }, - thermomachine: { - component: () => ThermoMachine, - scrollable: false, - }, - turbine_computer: { - component: () => TurbineComputer, - scrollable: false, - }, - uplink: { - component: () => Uplink, - scrollable: true, - theme: 'syndicate', - }, - vault_controller: { - component: () => VaultController, - scrollable: false, - }, - vending: { - component: () => Vending, - scrollable: true, - }, - wires: { - component: () => Wires, - scrollable: false, - }, -}; - -export const getRoute = state => { - if (process.env.NODE_ENV !== 'production') { - // Show a kitchen sink - if (state.showKitchenSink) { - const { KitchenSink } = require('./interfaces/KitchenSink'); - return { - component: () => KitchenSink, - scrollable: true, - }; - } - } - // Refer to the routing table - return ROUTES[state.config && state.config.interface]; -}; diff --git a/tgui-next/packages/tgui/styles/components/Flex.scss b/tgui-next/packages/tgui/styles/components/Flex.scss deleted file mode 100644 index 49156bd9c6..0000000000 --- a/tgui-next/packages/tgui/styles/components/Flex.scss +++ /dev/null @@ -1,15 +0,0 @@ -.Flex { - display: -ms-flexbox; - display: flex; -} - -@for $i from 1 through 2 { - .Flex--spacing--#{$i} { - margin: -3px * $i; - margin-bottom: 3px * $i; - - & > .Flex__item { - margin: 3px * $i; - } - } -} diff --git a/tgui-next/packages/tgui/styles/components/NoticeBox.scss b/tgui-next/packages/tgui/styles/components/NoticeBox.scss deleted file mode 100644 index 048904ed75..0000000000 --- a/tgui-next/packages/tgui/styles/components/NoticeBox.scss +++ /dev/null @@ -1,28 +0,0 @@ -@use '../functions.scss' as *; - -// NoticeBox -$color-first: #bb9b68 !default; -$color-second: #b1905d !default; -$color-border: #272727 !default; - -.NoticeBox { - // Adapt text color to background luminance to ensure high contast - $luminance: luminance($color-first); - $text-color: if($luminance > 0.35, - rgba(0, 0, 0, 1), - rgba(255, 255, 255, 1)); - - padding: 4px 6px; - margin-bottom: 6px; - box-shadow: none; - font-weight: bold; - font-style: italic; - color: $text-color; - background-color: $color-first; - background-image: repeating-linear-gradient( - -45deg, - $color-first, - $color-first 10px, - $color-second 10px, - $color-second 20px); -} diff --git a/tgui-next/packages/tgui/styles/components/Tabs.scss b/tgui-next/packages/tgui/styles/components/Tabs.scss deleted file mode 100644 index d195b5ac58..0000000000 --- a/tgui-next/packages/tgui/styles/components/Tabs.scss +++ /dev/null @@ -1,39 +0,0 @@ -.Tabs__content { - padding-top: 6px; - border-top: 2px solid rgba(255, 255, 255, 0.1); -} - -.Tabs--vertical { - display: table-row; -} - -// NOTE: These selectors have to be specific in order to stop cascading -// from influencing nested tabs. -.Tabs--vertical > .Tabs__content { - display: table-cell; - width: 100%; - padding-top: 0; - padding-left: 9px; - border-top: 0; -} - -.Tabs--vertical > .Tabs__tabBox { - display: table-cell; - // padding-right: 2px; - border-right: 2px solid rgba(255, 255, 255, 0.1); - // Disable baseline alignment when doing vertical tabs - vertical-align: top; -} - -.Tabs--vertical > .Tabs__tabBox > .Tabs__tab { - // Force display block because Button theme overrides it via cascading. - display: block !important; - margin-right: 0; - margin-bottom: 0; - padding: 1px 9px 0px 6px; - border-bottom: 2px solid rgba(255, 255, 255, 0.1); - - &:last-child { - border-bottom: 0; - } -} diff --git a/tgui/.babelrc b/tgui/.babelrc deleted file mode 100644 index 3c078e9f99..0000000000 --- a/tgui/.babelrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "presets": [ - "es2015" - ] -} diff --git a/tgui-next/.editorconfig b/tgui/.editorconfig similarity index 100% rename from tgui-next/.editorconfig rename to tgui/.editorconfig diff --git a/tgui-next/.eslintignore b/tgui/.eslintignore similarity index 100% rename from tgui-next/.eslintignore rename to tgui/.eslintignore diff --git a/tgui-next/.eslintrc-harder.yml b/tgui/.eslintrc-harder.yml similarity index 100% rename from tgui-next/.eslintrc-harder.yml rename to tgui/.eslintrc-harder.yml diff --git a/tgui-next/.eslintrc.yml b/tgui/.eslintrc.yml similarity index 98% rename from tgui-next/.eslintrc.yml rename to tgui/.eslintrc.yml index 4bff333295..67e74085c7 100644 --- a/tgui-next/.eslintrc.yml +++ b/tgui/.eslintrc.yml @@ -305,7 +305,13 @@ rules: ## Enforce or disallow capitalization of the first letter of a comment # capitalized-comments: error ## Require or disallow trailing commas - comma-dangle: [error, always-multiline] + comma-dangle: [error, { + arrays: always-multiline, + objects: always-multiline, + imports: always-multiline, + exports: always-multiline, + functions: only-multiline, ## Optional on functions + }] ## Enforce consistent spacing before and after commas comma-spacing: [error, { before: false, after: true }] ## Enforce consistent comma style @@ -625,7 +631,7 @@ rules: ## Prevent invalid characters from appearing in markup react/no-unescaped-entities: error ## Prevent usage of unknown DOM property (fixable) - react/no-unknown-property: error + # react/no-unknown-property: error ## Prevent usage of unsafe lifecycle methods react/no-unsafe: error ## Prevent definitions of unused prop types @@ -705,7 +711,7 @@ rules: ## Validate JSX has key prop when in array or iterator react/jsx-key: error ## Validate JSX maximum depth - react/jsx-max-depth: [error, { max: 6 }] ## Generous + react/jsx-max-depth: [error, { max: 10 }] ## Generous ## Limit maximum of props on a single line in JSX (fixable) # react/jsx-max-props-per-line: error ## Prevent usage of .bind() and arrow functions in JSX props diff --git a/tgui/.gitattributes b/tgui/.gitattributes index 6da3dcfc2d..0016cc3bf6 100644 --- a/tgui/.gitattributes +++ b/tgui/.gitattributes @@ -1 +1,10 @@ -assets/* binary +* text=auto + +## Enforce text mode and LF line breaks +*.js text eol=lf +*.css text eol=lf +*.html text eol=lf +*.json text eol=lf + +## Treat bundles as binary and ignore them during conflicts +*.bundle.* binary merge=tgui-merge-bundle diff --git a/tgui/.gitignore b/tgui/.gitignore index 71b051e887..416ca3768d 100644 --- a/tgui/.gitignore +++ b/tgui/.gitignore @@ -1,2 +1,7 @@ -npm-debug.log -node_modules/ +node_modules +*.log +package-lock.json + +/packages/tgui/public/.tmp/**/* +/packages/tgui/public/**/*.hot-update.* +/packages/tgui/public/**/*.map diff --git a/tgui/LICENSE.md b/tgui/LICENSE.md deleted file mode 100644 index 0ddc16bf39..0000000000 --- a/tgui/LICENSE.md +++ /dev/null @@ -1,20 +0,0 @@ -MIT license - -Copyright (c) 2016 Bjorn Neergaard (neersighted), tgui contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the -Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tgui/README.md b/tgui/README.md index e3ed2a20ee..5ddeb18fdd 100644 --- a/tgui/README.md +++ b/tgui/README.md @@ -1,139 +1,187 @@ - - -- [tgui](#tgui) - - [Concepts](#concepts) - - [Using It](#using-it) - - [Copypasta](#copypasta) - - - # tgui -tgui is the user interface library of /tg/station. It is rendered clientside, based on JSON data sent from the server. Clicks are processed on the server, in a similar method to native BYOND `Topic()`. -Basic tgui consists of defining a few procs. In these procs you will handle a request to open or update a UI (typically by updating a UI if it exists or setting up and opening it if it does not), a request for data, in which you build a list to be passed as JSON to the UI, and an action handler, which handles any user input. In addition, you will write a HTML template file which renders your data and provides actionable inputs. +## Introduction -tgui is very different from most UIs you will encounter in BYOND programming, and is heavily reliant of Javascript and web technologies as opposed to DM. However, if you are familiar with NanoUI (a library which can be found on almost every other SS13 codebase), tgui should be fairly easy to pick up. +tgui is a robust user interface framework of /tg/station. -tgui is a fork of NanoUI. The server-side code (DM) is similar and derived from NanoUI, while the clientside is a wholly new project with no code in common. +tgui is very different from most UIs you will encounter in BYOND programming. +It is heavily reliant on Javascript and web technologies as opposed to DM. +If you are familiar with NanoUI (a library which can be found on almost +every other SS13 codebase), tgui should be fairly easy to pick up. -## Concepts -tgui is loosely based a MVVM architecture. MVVM stands for model, view, view model. -- A model is the object that a UI represents. This is the atom a UI corresponds to in the game world in most cases, and is known as the `src_object` in tgui. -- The view model is how data is represented in terms of the view. In tgui, this is the `ui_data` proc which munges whatever complex data your `src_object` has into a list. -- The view is how the data is rendered. This is the template, a HTML (plus mustaches and other goodies) file which is compiled into the tgui blob that the browser executes. +## Learn tgui -Not included in the MVVM model are other important concepts: -- The action/topic handler, `ui_act`, is what recieves input from the user and acts on it. -- The request/update proc, `ui_interact` is where you open your UI and set options like title, size, autoupdate, theme, and more. -- Finally, `ui_state`s (set in `ui_interact`) dictate under what conditions a UI may be interacted with. This may be the standard checks that check if you are in range and conscious, or more. +People come to tgui from different backgrounds and with different +learning styles. Whether you prefer a more theoretical or a practical +approach, we hope you’ll find this section helpful. -States are easy to write and extend, and what make tgui interactions so powerful. Because states can over overridden from other procs, you can build powerful interactions for embedded objects or remote access. +### Practical Tutorial -## Using It -All these examples and abstracts sound great, you might say. But you also might say, "How do I use it?" +If you are completely new to frontend and prefer to **learn by doing**, +start with our [practical tutorial](docs/tutorial-and-examples.md). -Examples can be as simple or as complex as you would like. Let's start with a very basic hello world. +### Guides -```DM -/obj/machinery/my_machine/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state) - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "my_machine", name, 300, 300, master_ui, state) - ui.open() +This project uses **Inferno** - a very fast UI rendering engine with a similar +API to React. Take your time to read these guides: + +- [React guide](https://reactjs.org/docs/hello-world.html) +- [Inferno documentation](https://infernojs.org/docs/guides/components) - +highlights differences with React. + +If you were already familiar with an older, Ractive-based tgui, and want +to translate concepts between old and new tgui, read this +[interface conversion guide](docs/converting-old-tgui-interfaces.md). + +## Pre-requisites + +You will need these programs to start developing in tgui: + +- [Node v12.13+](https://nodejs.org/en/download/) +- [Yarn v1.19+](https://yarnpkg.com/en/docs/install) +- [MSys2](https://www.msys2.org/) (optional) + +> MSys2 closely replicates a unix-like environment which is necessary for +> the `bin/tgui` script to run. It comes with a robust "mintty" terminal +> emulator which is better than any standard Windows shell, it supports +> "git" out of the box (almost like Git for Windows, but better), has +> a "pacman" package manager, and you can install a text editor like "vim" +> for a full boomer experience. + +## Usage + +**For MSys2, Git Bash, WSL, Linux or macOS users:** + +First and foremost, change your directory to `tgui`. + +Run `bin/tgui --install-git-hooks` (optional) to install merge drivers +which will assist you in conflict resolution when rebasing your branches. + +Run one of the following: + +- `bin/tgui` - build the project in production mode. +- `bin/tgui --dev` - launch a development server. + - tgui development server provides you with incremental compilation, + hot module replacement and logging facilities in all running instances + of tgui. In short, this means that you will instantly see changes in the + game as you code it. Very useful, highly recommended. + - In order to use it, you should start the game server first, connect to it + and wait until the world has been properly loaded and you are no longer + in the lobby. Start tgui dev server. You'll know that it's hooked correctly + if data gets dumped to the log when tgui windows are opened. +- `bin/tgui --dev --reload` - reload byond cache once. +- `bin/tgui --dev --debug` - run server with debug logging enabled. +- `bin/tgui --dev --no-hot` - disable hot module replacement (helps when +doing development on IE8). +- `bin/tgui --lint` - show problems with the code. +- `bin/tgui --lint --fix` - auto-fix problems with the code. +- `bin/tgui --analyze` - run a bundle analyzer. +- `bin/tgui --clean` - clean up project repo. +- `bin/tgui [webpack options]` - build the project with custom webpack +options. + +**For everyone else:** + +If you haven't opened the console already, you can do that by holding +Shift and right clicking on the `tgui` folder, then pressing +either `Open command window here` or `Open PowerShell window here`. + +Run `yarn install` to install npm dependencies, then one of the following: + +- `yarn run build` - build the project in production mode. +- `yarn run watch` - launch a development server. +- `yarn run lint` - show problems with the code. +- `yarn run lint --fix` - auto-fix problems with the code. +- `yarn run analyze` - run a bundle analyzer. + +We also got some batch files in store, for those who don't like fiddling +with the console: + +- `bin/tgui-build.bat` - build the project in production mode. +- `bin/tgui-dev-server.bat` - launch a development server. + +> Remember to always run a full build before submitting a PR. It creates +> a compressed javascript bundle which is then referenced from DM code. +> We prefer to keep it version controlled, so that people could build the +> game just by using Dream Maker. + +## Troubleshooting + +**Development server doesn't find my BYOND cache!** + +This happens if your Documents folder in Windows has a custom location, for +example in `E:\Libraries\Documents`. Development server has no knowledge +of these non-standard locations, therefore you have to run the dev server +with an additional environmental variable, with a full path to BYOND cache. + +``` +export BYOND_CACHE="E:/Libraries/Documents/BYOND/cache" +bin/tgui --dev ``` -This is the proc that defines our interface. There's a bit going on here, so let's break it down. First, we override the ui_interact proc on our object. This will be called by `interact` for you, which is in turn called by `attack_hand` (or `attack_self` for items). `ui_interact` is also called to update a UI (hence the `try_update_ui`), so we accept an existing UI to update. The `state` is a default argument so that a caller can overload it with named arguments (`ui_interact(state = overloaded_state)`) if needed. +Note that in Windows, you have to go through Advanced System Settings, +System Properties and then open Environment Variables window to do the +same thing. You may need to reboot after this. -Inside the `if(!ui)` block (which means we are creating a new UI), we choose our template, title, and size; we can also set various options like `style` (for themes), or autoupdate. These options will be elaborated on later (as will `ui_state`s). +## Developer Tools -After `ui_interact`, we need to define `ui_data`. This just returns a list of data for our object to use. Let's imagine our object has a few vars: +When developing with `tgui-dev-server`, you will have access to certain +development only features. -```DM -/obj/machinery/my_machine/ui_data(mob/user) - var/list/data = list() - data["health"] = health - data["color"] = color +**Debug Logs.** +When running server via `bin/tgui --dev --debug`, server will print debug +logs and time spent on rendering. Use this information to optimize your +code, and try to keep re-renders below 16ms. - return data -``` +**Kitchen Sink.** +Press `Ctrl+Alt+=` to open the KitchenSink interface. This interface is a +playground to test various tgui components. -The `ui_data` proc is what people often find the hardest about tgui, but its really quite simple! You just need to represent your object as numbers, strings, and lists, instead of atoms and datums. +**Layout Debugger.** +Press `Ctrl+Alt+-` to toggle the *layout debugger*. It will show outlines of +all tgui elements, which makes it easy to understand how everything comes +together, and can reveal certain layout bugs which are not normally visible. -Finally, the `ui_act` proc is called by the interface whenever the user used an input. The input's `action` and `params` are passed to the proc. +## Project Structure -```DM -/obj/machinery/my_machine/ui_act(action, params) - if(..()) - return - switch(action) - if("change_color") - var/new_color = params["color"] - if(!(color in allowed_coors)) - return - color = new_color - . = TRUE - update_icon() -``` +- `/packages` - Each folder here represents a self-contained Node module. +- `/packages/common` - Helper functions +- `/packages/tgui/index.js` - Application entry point. +- `/packages/tgui/components` - Basic UI building blocks. +- `/packages/tgui/interfaces` - Actual in-game interfaces. +Interface takes data via the `state` prop and outputs an html-like stucture, +which you can build using existing UI components. +- `/packages/tgui/layouts` - Root level UI components, that affect the final +look and feel of the browser window. They usually hold various window +elements, like the titlebar and resize handlers, and control the UI theme. +- `/packages/tgui/routes.js` - This is where tgui decides which interface to +pull and render. +- `/packages/tgui/layout.js` - A root-level component, holding the +window elements, like the titlebar, buttons, resize handlers. Calls +`routes.js` to decide which component to render. +- `/packages/tgui/styles/main.scss` - CSS entry point. +- `/packages/tgui/styles/functions.scss` - Useful SASS functions. +Stuff like `lighten`, `darken`, `luminance` are defined here. +- `/packages/tgui/styles/atomic` - Atomic CSS classes. +These are very simple, tiny, reusable CSS classes which you can use and +combine to change appearance of your elements. Keep them small. +- `/packages/tgui/styles/components` - CSS classes which are used +in UI components. These stylesheets closely follow the +[BEM](https://en.bem.info/methodology/) methodology. +- `/packages/tgui/styles/interfaces` - Custom stylesheets for your interfaces. +Add stylesheets here if you really need a fine control over your UI styles. +- `/packages/tgui/styles/layouts` - Layout-related styles. +- `/packages/tgui/styles/themes` - Contains all the various themes you can +use in tgui. Each theme must be registered in `webpack.config.js` file. -The `..()` (parent call) is very important here, as it is how we check that the user is allowed to use this interface (to avoid so-called href exploits). It is also very important to clamp and sanitize all input here. Always assume the user is attempting to exploit the game. +## Component Reference -Also note the use of `. = TRUE` (or `FALSE`), which is used to notify the UI that this input caused an update. This is especially important for UIs that do not auto-update, as otherwise the user will never see their change. +See: [Component Reference](docs/component-reference.md). -Finally, you have a template. This is also a source of confusion for many new users. Some basic HTML knowledge will get you a long way, however. +## License -A template is regular HTML, with mustache for logic and built-in components to quickly build UIs. Here's how we might show some data (components will be elaborated on later). +All code is licensed with the parent license of *tgstation*, **AGPL-3.0**. -In a template there are a few special values. `config` is always the same and is part of core tgui (it will be explained later), `data` is the data returned from `ui_data`, and `adata` is the same, but with certain values (numbers at this time) interpolated in order to allow animation. +See the main [README](../README.md) for more details. -```html - - - {{data.health}} - - - {{data.color}} - - -``` - -Templates can be very confusing at first, as ternary operators, computed properties, and iterators are used quite a bit in more complex interfaces. Start with the basics, and work your way up. Much of the complexity stems from performance concerns. If in doubt, take the simpler approach and refactor if performance becomes an issue. - -## Copypasta -We all do it, even the best of us. If you just want to make a tgui **fast**, here's what you need (note that you'll probably be forced to clean your shit up upon code review): - -```DM -/obj/copypasta/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state) // Remember to use the appropriate state. - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "copypasta", name, 300, 300, master_ui, state) - ui.open() - -/obj/copypasta/ui_data(mob/user) - var/list/data = list() - data["var"] = var - - return data - -/obj/copypasta/ui_act(action, params) - if(..()) - return - switch(action) - if("copypasta") - var/newvar = params["var"] - var = Clamp(newvar, min_val, max_val) // Just a demo of proper input sanitation. - . = TRUE - update_icon() // Not applicable to all objects. -``` - -And the template: - -```html - - - {{data.var}} - - - {{adata.var}} - - -``` +The Authors retain all copyright to their respective work here submitted. diff --git a/tgui/assets/tgui.css b/tgui/assets/tgui.css deleted file mode 100644 index f98e093ba2..0000000000 --- a/tgui/assets/tgui.css +++ /dev/null @@ -1 +0,0 @@ -@charset "utf-8";body,html{box-sizing:border-box;height:100%;margin:0}html{overflow:hidden;cursor:default}body{overflow:auto;font-family:Verdana,Geneva,sans-serif;font-size:12px;color:#fff;background-color:#2a2a2a;background-image:linear-gradient(180deg,#2a2a2a 0,#202020);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff2a2a2a",endColorstr="#ff202020",GradientType=0)}*,:after,:before{box-sizing:inherit}h1,h2,h3,h4{display:inline-block;margin:0;padding:6px 0}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}h4{font-size:12px}body.clockwork{background:linear-gradient(180deg,#b18b25 0,#5f380e);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ffb18b25",endColorstr="#ff5f380e",GradientType=0)}body.clockwork .normal{color:#b18b25}body.clockwork .good{color:#cfba47}body.clockwork .average{color:#896b19}body.clockwork .bad{color:#5f380e}body.clockwork .highlight{color:#b18b25}body.clockwork main{display:block;margin-top:32px;padding:2px 6px 0}body.clockwork hr{height:2px;background-color:#b18b25;border:none}body.clockwork .hidden{display:none}body.clockwork .bar .barText,body.clockwork span.button{color:#b18b25;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.clockwork .bold{font-weight:700}body.clockwork .italic{font-style:italic}body.clockwork [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.clockwork div[data-tooltip],body.clockwork span[data-tooltip]{position:relative}body.clockwork div[data-tooltip]:after,body.clockwork span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);pointer-events:none;visibility:hidden;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";opacity:0;white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #170800;background-color:#2d1400}body.clockwork div[data-tooltip]:hover:after,body.clockwork span[data-tooltip]:hover:after{pointer-events:none;visibility:visible;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";opacity:1}body.clockwork div[data-tooltip].tooltip-top:after,body.clockwork span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.clockwork div[data-tooltip].tooltip-top:hover:after,body.clockwork span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.clockwork div[data-tooltip].tooltip-bottom:after,body.clockwork span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.clockwork div[data-tooltip].tooltip-bottom:hover:after,body.clockwork span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.clockwork div[data-tooltip].tooltip-left:after,body.clockwork span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-left:hover:after,body.clockwork span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-right:after,body.clockwork span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-right:hover:after,body.clockwork span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.clockwork .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #170800;background:#2d1400}body.clockwork .bar .barText{position:absolute;top:0;right:3px}body.clockwork .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#b18b25}body.clockwork .bar .barFill.good{background-color:#cfba47}body.clockwork .bar .barFill.average{background-color:#896b19}body.clockwork .bar .barFill.bad{background-color:#5f380e}body.clockwork span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #170800}body.clockwork span.button .fa{padding-right:2px}body.clockwork span.button.normal{transition:background-color .5s;background-color:#5f380e}body.clockwork span.button.normal.active:focus,body.clockwork span.button.normal.active:hover{transition:background-color .25s;background-color:#704211;outline:0}body.clockwork span.button.normal:not(.active){background-image:repeating-linear-gradient(-45deg,#5f380e,#5f380e 1px,#2d1400 0,#2d1400 2px)}body.clockwork span.button.disabled{transition:background-color .5s;background-color:#2d1400}body.clockwork span.button.disabled.active:focus,body.clockwork span.button.disabled.active:hover{transition:background-color .25s;background-color:#441e00;outline:0}body.clockwork span.button.selected{transition:background-color .5s;background-color:#cfba47}body.clockwork span.button.selected.active:focus,body.clockwork span.button.selected.active:hover{transition:background-color .25s;background-color:#d1bd50;outline:0}body.clockwork span.button.selected:not(.active){background-image:repeating-linear-gradient(-45deg,#cfba47,#cfba47 1px,#2d1400 0,#2d1400 2px)}body.clockwork span.button.toggle{transition:background-color .5s;background-color:#cfba47}body.clockwork span.button.toggle.active:focus,body.clockwork span.button.toggle.active:hover{transition:background-color .25s;background-color:#d1bd50;outline:0}body.clockwork span.button.toggle:not(.active){background-image:repeating-linear-gradient(-45deg,#cfba47,#cfba47 1px,#2d1400 0,#2d1400 2px)}body.clockwork span.button.caution{transition:background-color .5s;background-color:#be6209}body.clockwork span.button.caution.active:focus,body.clockwork span.button.caution.active:hover{transition:background-color .25s;background-color:#cd6a0a;outline:0}body.clockwork span.button.caution:not(.active){background-image:repeating-linear-gradient(-45deg,#be6209,#be6209 1px,#2d1400 0,#2d1400 2px)}body.clockwork span.button.danger{transition:background-color .5s;background-color:#9a9d00}body.clockwork span.button.danger.active:focus,body.clockwork span.button.danger.active:hover{transition:background-color .25s;background-color:#abaf00;outline:0}body.clockwork span.button.danger:not(.active){background-image:repeating-linear-gradient(-45deg,#9a9d00,#9a9d00 1px,#2d1400 0,#2d1400 2px)}body.clockwork span.button.gridable{width:125px;margin:2px 0}body.clockwork span.button.gridable.center{text-align:center;width:75px}body.clockwork span.button+span:not(.button),body.clockwork span:not(.button)+span.button{margin-left:5px}body.clockwork div.display{width:100%;padding:4px;margin:6px 0;background-color:#2d1400;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#e62d1400,endColorStr=#e62d1400)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#e62d1400,endColorStr=#e62d1400);background-color:rgba(45,20,0,.9);box-shadow:inset 0 0 5px rgba(0,0,0,.3)}body.clockwork div.display.tabular{padding:0;margin:0}body.clockwork div.display header,body.clockwork div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#cfba47;border-bottom:2px solid #b18b25}body.clockwork div.display header .buttonRight,body.clockwork div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.clockwork div.display article,body.clockwork div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.clockwork input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#b18b25;background-color:#cfba47;border:1px solid #272727}body.clockwork input.number{width:35px}body.clockwork input:-ms-input-placeholder{color:#999}body.clockwork input::placeholder{color:#999}body.clockwork input::-ms-clear{display:none}body.clockwork svg.linegraph{overflow:hidden}body.clockwork div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#2d1400;font-weight:700;font-style:italic;background-color:#000;background-image:repeating-linear-gradient(-45deg,#000,#000 10px,#170800 0,#170800 20px)}body.clockwork div.notice .label{color:#2d1400}body.clockwork div.notice .content:only-of-type{padding:0}body.clockwork div.notice hr{background-color:#896b19}body.clockwork div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-color:transparent transparent #5f380e;border-style:solid;border-width:0 0 45px 45px;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.clockwork section .cell,body.clockwork section .content,body.clockwork section .label,body.clockwork section .line,body.nanotrasen section .cell,body.nanotrasen section .content,body.nanotrasen section .label,body.nanotrasen section .line,body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.clockwork section{display:table-row;width:100%}body.clockwork section:not(:first-child){padding-top:4px}body.clockwork section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.clockwork section .label{width:1%;padding-right:32px;white-space:nowrap;color:#b18b25}body.clockwork section .content:not(:last-child){padding-right:16px}body.clockwork section .line{width:100%}body.clockwork section .cell:not(:first-child){text-align:center;padding-top:0}body.clockwork section .cell span.button{width:75px}body.clockwork section:not(:last-child){padding-right:4px}body.clockwork div.subdisplay{width:100%;margin:0}body.clockwork header.titlebar .close,body.clockwork header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#cfba47}body.clockwork header.titlebar .close:hover,body.clockwork header.titlebar .minimize:hover{color:#d1bd50}body.clockwork header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#5f380e;border-bottom:1px solid #170800;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.clockwork header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.clockwork header.titlebar .title{position:absolute;top:6px;left:46px;color:#cfba47;font-size:16px;white-space:nowrap}body.clockwork header.titlebar .minimize{position:absolute;top:6px;right:46px}body.clockwork header.titlebar .close{position:absolute;top:4px;right:12px}body.clockwork header.titlebar .statusicon.no-icons{font-size:20px}body.clockwork header.titlebar .statusicon.no-icons:after{content:"O"}body.clockwork header.titlebar .minimize.no-icons{top:-2px;font-size:20px}body.clockwork header.titlebar .minimize.no-icons:after{content:"—"}body.clockwork header.titlebar .close.no-icons{font-size:20px}body.clockwork header.titlebar .close.no-icons:after{content:"X"}body.clockwork.airlock_electronics table{width:100%;border-spacing:2px}body.clockwork.airlock_electronics th{text-align:left}body.clockwork.airlock_electronics td{vertical-align:top}body.clockwork.airlock_electronics td .button{margin-top:4px}body.nanotrasen{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMCIgdmlld0JveD0iMCAwIDQyNSAyMDAiIG9wYWNpdHk9Ii4zMyI+PHBhdGggZD0iTTE3OC4wMDQuMDM5SDEwNi44YTYuNzYxIDYuMDI2IDAgMCAwLTYuNzYxIDYuMDI1djE4Ny44NzJhNi43NjEgNi4wMjYgMCAwIDAgNi43NjEgNi4wMjVoNTMuMTA3YTYuNzYxIDYuMDI2IDAgMCAwIDYuNzYyLTYuMDI1VjkyLjM5Mmw3Mi4yMTYgMTA0LjdhNi43NjEgNi4wMjYgMCAwIDAgNS43NiAyLjg3SDMxOC4yYTYuNzYxIDYuMDI2IDAgMCAwIDYuNzYxLTYuMDI2VjYuMDY0QTYuNzYxIDYuMDI2IDAgMCAwIDMxOC4yLjA0aC01NC43MTdhNi43NjEgNi4wMjYgMCAwIDAtNi43NiA2LjAyNXYxMDIuNjJMMTgzLjc2MyAyLjkwOWE2Ljc2MSA2LjAyNiAwIDAgMC01Ljc2LTIuODd6TTQuODQ1IDIyLjEwOUExMy40MTIgMTIuNTAyIDAgMCAxIDEzLjQ3OC4wMzloNjYuMTE4QTUuMzY1IDUgMCAwIDEgODQuOTYgNS4wNHY3OS44OHpNNDIwLjE1NSAxNzcuODkxYTEzLjQxMiAxMi41MDIgMCAwIDEtOC42MzMgMjIuMDdoLTY2LjExOGE1LjM2NSA1IDAgMCAxLTUuMzY1LTUuMDAxdi03OS44OHoiLz48L3N2Zz4=") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#2a2a2a 0,#202020);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff2a2a2a",endColorstr="#ff202020",GradientType=0)}body.nanotrasen .normal{color:#40628a}body.nanotrasen .good{color:#537d29}body.nanotrasen .average{color:#be6209}body.nanotrasen .bad{color:#b00e0e}body.nanotrasen .highlight{color:#8ba5c4}body.nanotrasen main{display:block;margin-top:32px;padding:2px 6px 0}body.nanotrasen hr{height:2px;background-color:#40628a;border:none}body.nanotrasen .hidden{display:none}body.nanotrasen .bar .barText,body.nanotrasen span.button{color:#fff;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.nanotrasen .bold{font-weight:700}body.nanotrasen .italic{font-style:italic}body.nanotrasen [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.nanotrasen div[data-tooltip],body.nanotrasen span[data-tooltip]{position:relative}body.nanotrasen div[data-tooltip]:after,body.nanotrasen span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);pointer-events:none;visibility:hidden;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";opacity:0;white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #272727;background-color:#363636}body.nanotrasen div[data-tooltip]:hover:after,body.nanotrasen span[data-tooltip]:hover:after{pointer-events:none;visibility:visible;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";opacity:1}body.nanotrasen div[data-tooltip].tooltip-top:after,body.nanotrasen span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.nanotrasen div[data-tooltip].tooltip-top:hover:after,body.nanotrasen span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.nanotrasen div[data-tooltip].tooltip-bottom:after,body.nanotrasen span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.nanotrasen div[data-tooltip].tooltip-bottom:hover:after,body.nanotrasen span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.nanotrasen div[data-tooltip].tooltip-left:after,body.nanotrasen span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-left:hover:after,body.nanotrasen span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-right:after,body.nanotrasen span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-right:hover:after,body.nanotrasen span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.nanotrasen .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #40628a;background:#272727}body.nanotrasen .bar .barText{position:absolute;top:0;right:3px}body.nanotrasen .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#40628a}body.nanotrasen .bar .barFill.good{background-color:#537d29}body.nanotrasen .bar .barFill.average{background-color:#be6209}body.nanotrasen .bar .barFill.bad{background-color:#b00e0e}body.nanotrasen span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #272727}body.nanotrasen span.button .fa{padding-right:2px}body.nanotrasen span.button.normal{transition:background-color .5s;background-color:#40628a}body.nanotrasen span.button.normal.active:focus,body.nanotrasen span.button.normal.active:hover{transition:background-color .25s;background-color:#4f78aa;outline:0}body.nanotrasen span.button.normal:not(.active){background-image:repeating-linear-gradient(-45deg,#40628a,#40628a 1px,#999 0,#999 2px)}body.nanotrasen span.button.disabled{transition:background-color .5s;background-color:#999}body.nanotrasen span.button.disabled.active:focus,body.nanotrasen span.button.disabled.active:hover{transition:background-color .25s;background-color:#a8a8a8;outline:0}body.nanotrasen span.button.selected{transition:background-color .5s;background-color:#2f943c}body.nanotrasen span.button.selected.active:focus,body.nanotrasen span.button.selected.active:hover{transition:background-color .25s;background-color:#3ab84b;outline:0}body.nanotrasen span.button.selected:not(.active){background-image:repeating-linear-gradient(-45deg,#2f943c,#2f943c 1px,#999 0,#999 2px)}body.nanotrasen span.button.toggle{transition:background-color .5s;background-color:#2f943c}body.nanotrasen span.button.toggle.active:focus,body.nanotrasen span.button.toggle.active:hover{transition:background-color .25s;background-color:#3ab84b;outline:0}body.nanotrasen span.button.toggle:not(.active){background-image:repeating-linear-gradient(-45deg,#2f943c,#2f943c 1px,#999 0,#999 2px)}body.nanotrasen span.button.caution{transition:background-color .5s;background-color:#9a9d00}body.nanotrasen span.button.caution.active:focus,body.nanotrasen span.button.caution.active:hover{transition:background-color .25s;background-color:#ced200;outline:0}body.nanotrasen span.button.caution:not(.active){background-image:repeating-linear-gradient(-45deg,#9a9d00,#9a9d00 1px,#999 0,#999 2px)}body.nanotrasen span.button.danger{transition:background-color .5s;background-color:#9d0808}body.nanotrasen span.button.danger.active:focus,body.nanotrasen span.button.danger.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.nanotrasen span.button.danger:not(.active){background-image:repeating-linear-gradient(-45deg,#9d0808,#9d0808 1px,#999 0,#999 2px)}body.nanotrasen span.button.gridable{width:125px;margin:2px 0}body.nanotrasen span.button.gridable.center{text-align:center;width:75px}body.nanotrasen span.button+span:not(.button),body.nanotrasen span:not(.button)+span.button{margin-left:5px}body.nanotrasen div.display{width:100%;padding:4px;margin:6px 0;background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000);background-color:rgba(0,0,0,.33);box-shadow:inset 0 0 5px rgba(0,0,0,.5)}body.nanotrasen div.display.tabular{padding:0;margin:0}body.nanotrasen div.display header,body.nanotrasen div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#fff;border-bottom:2px solid #40628a}body.nanotrasen div.display header .buttonRight,body.nanotrasen div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.nanotrasen div.display article,body.nanotrasen div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.nanotrasen input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#000;background-color:#fff;border:1px solid #272727}body.nanotrasen input.number{width:35px}body.nanotrasen input:-ms-input-placeholder{color:#999}body.nanotrasen input::placeholder{color:#999}body.nanotrasen input::-ms-clear{display:none}body.nanotrasen svg.linegraph{overflow:hidden}body.nanotrasen div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#000;font-weight:700;font-style:italic;background-color:#bb9b68;background-image:repeating-linear-gradient(-45deg,#bb9b68,#bb9b68 10px,#b1905d 0,#b1905d 20px)}body.nanotrasen div.notice .label{color:#000}body.nanotrasen div.notice .content:only-of-type{padding:0}body.nanotrasen div.notice hr{background-color:#272727}body.nanotrasen div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-color:transparent transparent #363636;border-style:solid;border-width:0 0 45px 45px;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.nanotrasen section .cell,body.nanotrasen section .content,body.nanotrasen section .label,body.nanotrasen section .line,body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.nanotrasen section{display:table-row;width:100%}body.nanotrasen section:not(:first-child){padding-top:4px}body.nanotrasen section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.nanotrasen section .label{width:1%;padding-right:32px;white-space:nowrap;color:#8ba5c4}body.nanotrasen section .content:not(:last-child){padding-right:16px}body.nanotrasen section .line{width:100%}body.nanotrasen section .cell:not(:first-child){text-align:center;padding-top:0}body.nanotrasen section .cell span.button{width:75px}body.nanotrasen section:not(:last-child){padding-right:4px}body.nanotrasen div.subdisplay{width:100%;margin:0}body.nanotrasen header.titlebar .close,body.nanotrasen header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#8ba5c4}body.nanotrasen header.titlebar .close:hover,body.nanotrasen header.titlebar .minimize:hover{color:#9cb2cd}body.nanotrasen header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#363636;border-bottom:1px solid #161616;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.nanotrasen header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.nanotrasen header.titlebar .title{position:absolute;top:6px;left:46px;color:#8ba5c4;font-size:16px;white-space:nowrap}body.nanotrasen header.titlebar .minimize{position:absolute;top:6px;right:46px}body.nanotrasen header.titlebar .close{position:absolute;top:4px;right:12px}body.nanotrasen header.titlebar .statusicon.no-icons{font-size:20px}body.nanotrasen header.titlebar .statusicon.no-icons:after{content:"O"}body.nanotrasen header.titlebar .minimize.no-icons{top:-2px;font-size:20px}body.nanotrasen header.titlebar .minimize.no-icons:after{content:"—"}body.nanotrasen header.titlebar .close.no-icons{font-size:20px}body.nanotrasen header.titlebar .close.no-icons:after{content:"X"}body.nanotrasen.airlock_electronics table{width:100%;border-spacing:2px}body.nanotrasen.airlock_electronics th{text-align:left}body.nanotrasen.airlock_electronics td{vertical-align:top}body.nanotrasen.airlock_electronics td .button{margin-top:4px}body.syndicate{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMCIgdmlld0JveD0iMCAwIDIwMCAyODkuNzQyIiBvcGFjaXR5PSIuMzMiPjxwYXRoIGQ9Ik05My41MzggMGMtMTguMTEzIDAtMzQuMjIgMy4xMTItNDguMzI0IDkuMzM0LTEzLjk2NSA2LjIyMi0yNC42MTIgMTUuMDcyLTMxLjk0IDI2LjU0N0M2LjA4NCA0Ny4yMiAyLjk3MiA2MC42MzEgMi45NzIgNzYuMTE2YzAgMTAuNjQ3IDIuNzI1IDIwLjQ2NSA4LjE3NSAyOS40NTMgNS42MTYgOC45ODcgMTQuMDM5IDE3LjM1MiAyNS4yNyAyNS4wOTQgMTEuMjMgNy42MDYgMjYuNTA3IDE1LjQxOSA0NS44MyAyMy40MzggMTkuOTg0IDguMjk2IDM0Ljg0OSAxNS41NTUgNDQuNTkzIDIxLjc3NiA5Ljc0NCA2LjIyMyAxNi43NjEgMTIuODU5IDIxLjA1NSAxOS45MSA0LjI5NSA3LjA1MiA2LjQ0MiAxNS43NjQgNi40NDIgMjYuMTM0IDAgMTYuMTc4LTUuMjAyIDI4LjQ4My0xNS42MDYgMzYuOTE3LTEwLjI0IDguNDM1LTI1LjAyMiAxMi42NTMtNDQuMzQ1IDEyLjY1My0xNC4wMzkgMC0yNS41MTYtMS42Ni0zNC40MzQtNC45NzgtOC45MTgtMy40NTctMTYuMTg2LTguNzExLTIxLjgtMTUuNzYzLTUuNjE2LTcuMDUyLTEwLjA3Ni0xNi42NjEtMTMuMzc5LTI4LjgyOUgwdjU2LjgyN2MzMy44NTcgNy4zMjggNjMuNzQ5IDEwLjk5NCA4OS42NzggMTAuOTk0IDE2LjAyIDAgMzAuNzItMS4zODMgNDQuMDk4LTQuMTQ4IDEzLjU0Mi0yLjkwNCAyNS4xMDQtNy40NjcgMzQuNjgzLTEzLjY5IDkuNzQ0LTYuMzU5IDE3LjM0LTE0LjUxOSAyMi43OS0yNC40NzQgNS40NS0xMC4wOTMgOC4xNzUtMjIuNCA4LjE3NS0zNi45MTcgMC0xMi45OTctMy4zMDItMjQuMzM1LTkuOTA4LTM0LjAxNC02LjQ0LTkuODE4LTE1LjUyNS0xOC41MjctMjcuMjUxLTI2LjEzMi0xMS41NjEtNy42MDQtMjcuOTExLTE1LjgzMS00OS4wNTEtMjQuNjgtMTcuNTA2LTcuMTktMzAuNzItMTMuNjktMzkuNjM4LTE5LjQ5N1M1NC45NjkgOTMuNzU2IDQ5LjQ3OSA4Ny4zMTZjLTUuNDI2LTYuMzY2LTkuNjU4LTE1LjA3LTkuNjU4LTI0Ljg4NyAwLTkuMjY0IDIuMDc1LTE3LjIxNCA2LjIyMy0yMy44NUM1Ny4xNDIgMjQuMTggODcuMzMxIDM2Ljc4MiA5MS4xMiA2Mi45MjVjNC44NCA2Ljc3NSA4Ljg1IDE2LjI0NyAxMi4wMyAyOC40MTVoMjAuNTMydi01NmMtNC40NzktNS45MjQtOS45NTUtMTAuNjMxLTE1LjkwOS0xNC4zNzMgMS42NC40NzkgMy4xOSAxLjAyMyA0LjYzOSAxLjY0IDYuNDk4IDIuNjI2IDEyLjE2OCA3LjMyNyAxNy4wMDcgMTQuMTAzIDQuODQgNi43NzUgOC44NSAxNi4yNDYgMTIuMDMgMjguNDE0IDAgMCA4LjQ4LS4xMjkgOC40OS0uMDAyLjQxNyA2LjQxNS0xLjc1NCA5LjQ1My00LjEyNCAxMi41NjEtMi40MTcgMy4xNy01LjE0NSA2Ljc5LTQuMDAzIDEzLjAwMyAxLjUwOCA4LjIwMyAxMC4xODQgMTAuNTk3IDE0LjYyMiA5LjMxMi0zLjMxOC0uNS01LjMxOC0xLjc1LTUuMzE4LTEuNzVzMS44NzYuOTk5IDUuNjUtMS4zNmMtMy4yNzYuOTU2LTEwLjcwNC0uNzk3LTExLjgtNi43NjMtLjk1OC01LjIwOC45NDYtNy4yOTUgMy40LTEwLjUxNCAyLjQ1NS0zLjIyIDUuMjg1LTYuOTU5IDQuNjg1LTE0LjQ4OWwuMDAzLjAwMmg4LjkyN3YtNTZjLTE1LjA3Mi0zLjg3MS0yNy42NTMtNi4zNi0zNy43NDctNy40NjVDMTE0LjI3OS41NTIgMTA0LjA0NiAwIDkzLjUzNyAwem03MC4zMjEgMTcuMzA5bC4yMzggNDAuMzA1YzEuMzE4IDEuMjI2IDIuNDQgMi4yNzggMy4zNDEgMy4xMDYgNC44NCA2Ljc3NSA4Ljg1IDE2LjI0NiAxMi4wMyAyOC40MTRIMjAwdi01NmMtNi42NzctNC41OTQtMTkuODM2LTEwLjQ3My0zNi4xNC0xNS44MjV6bS0yOC4xMiA1LjYwNWw4LjU2NSAxNy43MTdjLTExLjk3LTYuNDY3LTEzLjg0Ny05LjcxNy04LjU2NS0xNy43MTd6bTIyLjc5NyAwYzIuNzcxIDggMS43ODcgMTEuMjUtNC40OTQgMTcuNzE3bDQuNDk0LTE3LjcxN3ptMTUuMjIyIDI0LjAwOWw4LjU2NSAxNy43MTZjLTExLjk3LTYuNDY2LTEzLjg0Ny05LjcxNy04LjU2NS0xNy43MTZ6bTIyLjc5NyAwYzIuNzcxIDggMS43ODcgMTEuMjUtNC40OTQgMTcuNzE2bDQuNDk0LTE3LjcxNnpNOTcuNDQgNDkuMTNsOC41NjUgMTcuNzE2Yy0xMS45Ny02LjQ2Ny0xMy44NDctOS43MTctOC41NjUtMTcuNzE2em0yMi43OTUgMGMyLjc3MiA3Ljk5OSAxLjc4OCAxMS4yNS00LjQ5MyAxNy43MTZsNC40OTMtMTcuNzE2eiIvPjwvc3ZnPg==") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#750000 0,#340404);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff750000",endColorstr="#ff340404",GradientType=0)}body.syndicate .normal{color:#40628a}body.syndicate .good{color:#73e573}body.syndicate .average{color:#be6209}body.syndicate .bad{color:#b00e0e}body.syndicate .highlight{color:#000}body.syndicate main{display:block;margin-top:32px;padding:2px 6px 0}body.syndicate hr{height:2px;background-color:#272727;border:none}body.syndicate .hidden{display:none}body.syndicate .bar .barText,body.syndicate span.button{color:#fff;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.syndicate .bold{font-weight:700}body.syndicate .italic{font-style:italic}body.syndicate [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.syndicate div[data-tooltip],body.syndicate span[data-tooltip]{position:relative}body.syndicate div[data-tooltip]:after,body.syndicate span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);pointer-events:none;visibility:hidden;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";opacity:0;white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #272727;background-color:#363636}body.syndicate div[data-tooltip]:hover:after,body.syndicate span[data-tooltip]:hover:after{pointer-events:none;visibility:visible;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";opacity:1}body.syndicate div[data-tooltip].tooltip-top:after,body.syndicate span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.syndicate div[data-tooltip].tooltip-top:hover:after,body.syndicate span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.syndicate div[data-tooltip].tooltip-bottom:after,body.syndicate span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.syndicate div[data-tooltip].tooltip-bottom:hover:after,body.syndicate span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.syndicate div[data-tooltip].tooltip-left:after,body.syndicate span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-left:hover:after,body.syndicate span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-right:after,body.syndicate span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-right:hover:after,body.syndicate span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.syndicate .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #000;background:#272727}body.syndicate .bar .barText{position:absolute;top:0;right:3px}body.syndicate .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#000}body.syndicate .bar .barFill.good{background-color:#73e573}body.syndicate .bar .barFill.average{background-color:#be6209}body.syndicate .bar .barFill.bad{background-color:#b00e0e}body.syndicate span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #272727}body.syndicate span.button .fa{padding-right:2px}body.syndicate span.button.normal{transition:background-color .5s;background-color:#397439}body.syndicate span.button.normal.active:focus,body.syndicate span.button.normal.active:hover{transition:background-color .25s;background-color:#4a964a;outline:0}body.syndicate span.button.normal:not(.active){background-image:repeating-linear-gradient(-45deg,#397439,#397439 1px,#363636 0,#363636 2px)}body.syndicate span.button.disabled{transition:background-color .5s;background-color:#363636}body.syndicate span.button.disabled.active:focus,body.syndicate span.button.disabled.active:hover{transition:background-color .25s;background-color:#545454;outline:0}body.syndicate span.button.selected{transition:background-color .5s;background-color:#9d0808}body.syndicate span.button.selected.active:focus,body.syndicate span.button.selected.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.syndicate span.button.selected:not(.active){background-image:repeating-linear-gradient(-45deg,#9d0808,#9d0808 1px,#363636 0,#363636 2px)}body.syndicate span.button.toggle{transition:background-color .5s;background-color:#9d0808}body.syndicate span.button.toggle.active:focus,body.syndicate span.button.toggle.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.syndicate span.button.toggle:not(.active){background-image:repeating-linear-gradient(-45deg,#9d0808,#9d0808 1px,#363636 0,#363636 2px)}body.syndicate span.button.caution{transition:background-color .5s;background-color:#be6209}body.syndicate span.button.caution.active:focus,body.syndicate span.button.caution.active:hover{transition:background-color .25s;background-color:#eb790b;outline:0}body.syndicate span.button.caution:not(.active){background-image:repeating-linear-gradient(-45deg,#be6209,#be6209 1px,#363636 0,#363636 2px)}body.syndicate span.button.danger{transition:background-color .5s;background-color:#9a9d00}body.syndicate span.button.danger.active:focus,body.syndicate span.button.danger.active:hover{transition:background-color .25s;background-color:#ced200;outline:0}body.syndicate span.button.danger:not(.active){background-image:repeating-linear-gradient(-45deg,#9a9d00,#9a9d00 1px,#363636 0,#363636 2px)}body.syndicate span.button.gridable{width:125px;margin:2px 0}body.syndicate span.button.gridable.center{text-align:center;width:75px}body.syndicate span.button+span:not(.button),body.syndicate span:not(.button)+span.button{margin-left:5px}body.syndicate div.display{width:100%;padding:4px;margin:6px 0;background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000);background-color:rgba(0,0,0,.5);box-shadow:inset 0 0 5px rgba(0,0,0,.75)}body.syndicate div.display.tabular{padding:0;margin:0}body.syndicate div.display header,body.syndicate div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#fff;border-bottom:2px solid #272727}body.syndicate div.display header .buttonRight,body.syndicate div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.syndicate div.display article,body.syndicate div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.syndicate input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#fff;background-color:#9d0808;border:1px solid #272727}body.syndicate input.number{width:35px}body.syndicate input:-ms-input-placeholder{color:#999}body.syndicate input::placeholder{color:#999}body.syndicate input::-ms-clear{display:none}body.syndicate svg.linegraph{overflow:hidden}body.syndicate div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#000;font-weight:700;font-style:italic;background-color:#750000;background-image:repeating-linear-gradient(-45deg,#750000,#750000 10px,#910101 0,#910101 20px)}body.syndicate div.notice .label{color:#000}body.syndicate div.notice .content:only-of-type{padding:0}body.syndicate div.notice hr{background-color:#272727}body.syndicate div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-color:transparent transparent #363636;border-style:solid;border-width:0 0 45px 45px;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.syndicate section{display:table-row;width:100%}body.syndicate section:not(:first-child){padding-top:4px}body.syndicate section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.syndicate section .label{width:1%;padding-right:32px;white-space:nowrap;color:#fff}body.syndicate section .content:not(:last-child){padding-right:16px}body.syndicate section .line{width:100%}body.syndicate section .cell:not(:first-child){text-align:center;padding-top:0}body.syndicate section .cell span.button{width:75px}body.syndicate section:not(:last-child){padding-right:4px}body.syndicate div.subdisplay{width:100%;margin:0}body.syndicate header.titlebar .close,body.syndicate header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#e74242}body.syndicate header.titlebar .close:hover,body.syndicate header.titlebar .minimize:hover{color:#eb5e5e}body.syndicate header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#363636;border-bottom:1px solid #161616;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.syndicate header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.syndicate header.titlebar .title{position:absolute;top:6px;left:46px;color:#e74242;font-size:16px;white-space:nowrap}body.syndicate header.titlebar .minimize{position:absolute;top:6px;right:46px}body.syndicate header.titlebar .close{position:absolute;top:4px;right:12px}body.syndicate header.titlebar .statusicon.no-icons{font-size:20px}body.syndicate header.titlebar .statusicon.no-icons:after{content:"O"}body.syndicate header.titlebar .minimize.no-icons{top:-2px;font-size:20px}body.syndicate header.titlebar .minimize.no-icons:after{content:"—"}body.syndicate header.titlebar .close.no-icons{font-size:20px}body.syndicate header.titlebar .close.no-icons:after{content:"X"}body.syndicate.airlock_electronics table{width:100%;border-spacing:2px}body.syndicate.airlock_electronics th{text-align:left}body.syndicate.airlock_electronics td{vertical-align:top}body.syndicate.airlock_electronics td .button{margin-top:4px} \ No newline at end of file diff --git a/tgui/assets/tgui.js b/tgui/assets/tgui.js deleted file mode 100644 index a80e21a6ae..0000000000 --- a/tgui/assets/tgui.js +++ /dev/null @@ -1 +0,0 @@ -require=function a(o,s,p){function u(e,t){if(!s[e]){if(!o[e]){var n="function"==typeof require&&require;if(!t&&n)return n(e,!0);if(c)return c(e,!0);var r=new Error("Cannot find module '"+e+"'");throw r.code="MODULE_NOT_FOUND",r}var i=s[e]={exports:{}};o[e][0].call(i.exports,function(t){return u(o[e][1][t]||t)},i,i.exports,a,o,s,p)}return s[e].exports}for(var c="function"==typeof require&&require,t=0;to;)i.call(t,a=r[o++])&&e.push(a);return e}},{78:78,81:81,82:82}],34:[function(t,e,n){var m=t(41),g=t(24),b=t(43),v=t(92),y=t(26),_="prototype",x=function(t,e,n){var a,r,i,o,s=t&x.F,p=t&x.G,u=t&x.S,c=t&x.P,l=t&x.B,d=p?m:u?m[e]||(m[e]={}):(m[e]||{})[_],f=p?g:g[e]||(g[e]={}),h=f[_]||(f[_]={});for(a in p&&(n=e),n)i=((r=!s&&d&&d[a]!==undefined)?d:n)[a],o=l&&r?y(i,m):c&&"function"==typeof i?y(Function.call,i):i,d&&v(d,a,i,t&x.U),f[a]!=i&&b(f,a,o),c&&h[a]!=i&&(h[a]=i)};m.core=g,x.F=1,x.G=2,x.S=4,x.P=8,x.B=16,x.W=32,x.U=64,x.R=128,e.exports=x},{24:24,26:26,41:41,43:43,92:92}],35:[function(t,e,n){var r=t(127)("match");e.exports=function(t){var e=/./;try{"/./"[t](e)}catch(n){try{return e[r]=!1,!"/./"[t](e)}catch(a){}}return!0}},{127:127}],36:[function(t,e,n){e.exports=function(t){try{return!!t()}catch(e){return!0}}},{}],37:[function(t,e,n){"use strict";var s=t(43),p=t(92),u=t(36),c=t(29),l=t(127);e.exports=function(e,t,n){var a=l(e),r=n(c,a,""[e]),i=r[0],o=r[1];u(function(){var t={};return t[a]=function(){return 7},7!=""[e](t)})&&(p(String.prototype,e,i),s(RegExp.prototype,a,2==t?function(t,e){return o.call(t,this,e)}:function(t){return o.call(t,this)}))}},{127:127,29:29,36:36,43:43,92:92}],38:[function(t,e,n){"use strict";var a=t(8);e.exports=function(){var t=a(this),e="";return t.global&&(e+="g"),t.ignoreCase&&(e+="i"),t.multiline&&(e+="m"),t.unicode&&(e+="u"),t.sticky&&(e+="y"),e}},{8:8}],39:[function(t,e,n){"use strict";var f=t(50),h=t(52),m=t(116),g=t(26),b=t(127)("isConcatSpreadable");e.exports=function v(t,e,n,a,r,i,o,s){for(var p,u,c=r,l=0,d=!!o&&g(o,s,3);ldocument.F=Object<\/script>"),t.close(),c=t.F;n--;)delete c[u][s[n]];return c()};t.exports=Object.create||function(t,e){var n;return null!==t?(r[u]=i(t),n=new r,r[u]=null,n[p]=t):n=c(),e===undefined?n:o(n,e)}},{100:100,31:31,32:32,44:44,73:73,8:8}],72:[function(t,e,n){var r=t(8),i=t(45),o=t(118),s=Object.defineProperty;n.f=t(30)?Object.defineProperty:function(t,e,n){if(r(t),e=o(e,!0),r(n),i)try{return s(t,e,n)}catch(a){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(t[e]=n.value),t}},{118:118,30:30,45:45,8:8}],73:[function(t,e,n){var o=t(72),s=t(8),p=t(81);e.exports=t(30)?Object.defineProperties:function(t,e){s(t);for(var n,a=p(e),r=a.length,i=0;ir;)o(a,n=e[r++])&&(~p(i,n)||i.push(n));return i}},{100:100,115:115,12:12,42:42}],81:[function(t,e,n){var a=t(80),r=t(32);e.exports=Object.keys||function(t){return a(t,r)}},{32:32,80:80}],82:[function(t,e,n){n.f={}.propertyIsEnumerable},{}],83:[function(t,e,n){var r=t(34),i=t(24),o=t(36);e.exports=function(t,e){var n=(i.Object||{})[t]||Object[t],a={};a[t]=e(n),r(r.S+r.F*o(function(){n(1)}),"Object",a)}},{24:24,34:34,36:36}],84:[function(t,e,n){var p=t(81),u=t(115),c=t(82).f;e.exports=function(s){return function(t){for(var e,n=u(t),a=p(n),r=a.length,i=0,o=[];i>>0||(o.test(n)?16:10))}:a},{109:109,110:110,41:41}],88:[function(t,e,n){e.exports=function(t){try{return{e:!1,v:t()}}catch(e){return{e:!0,v:e}}}},{}],89:[function(t,e,n){var a=t(8),r=t(52),i=t(69);e.exports=function(t,e){if(a(t),r(e)&&e.constructor===t)return e;var n=i.f(t);return(0,n.resolve)(e),n.promise}},{52:52,69:69,8:8}],90:[function(t,e,n){e.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},{}],91:[function(t,e,n){var r=t(92);e.exports=function(t,e,n){for(var a in e)r(t,a,e[a],n);return t}},{92:92}],92:[function(t,e,n){var i=t(41),o=t(43),s=t(42),p=t(122)("src"),a="toString",r=Function[a],u=(""+r).split(a);t(24).inspectSource=function(t){return r.call(t)},(e.exports=function(t,e,n,a){var r="function"==typeof n;r&&(s(n,"name")||o(n,"name",e)),t[e]!==n&&(r&&(s(n,p)||o(n,p,t[e]?""+t[e]:u.join(String(e)))),t===i?t[e]=n:a?t[e]?t[e]=n:o(t,e,n):(delete t[e],o(t,e,n)))})(Function.prototype,a,function(){return"function"==typeof this&&this[p]||r.call(this)})},{122:122,24:24,41:41,42:42,43:43}],93:[function(t,e,n){e.exports=function(e,n){var a=n===Object(n)?function(t){return n[t]}:n;return function(t){return String(t).replace(e,a)}}},{}],94:[function(t,e,n){e.exports=Object.is||function(t,e){return t===e?0!==t||1/t==1/e:t!=t&&e!=e}},{}],95:[function(t,e,n){"use strict";var a=t(34),o=t(4),s=t(26),p=t(40);e.exports=function(t){a(a.S,t,{from:function(t){var e,n,a,r,i=arguments[1];return o(this),(e=i!==undefined)&&o(i),t==undefined?new this:(n=[],e?(a=0,r=s(i,arguments[2],2),p(t,!1,function(t){n.push(r(t,a++))})):p(t,!1,n.push,n),new this(n))}})}},{26:26,34:34,4:4,40:40}],96:[function(t,e,n){"use strict";var a=t(34);e.exports=function(t){a(a.S,t,{of:function(){for(var t=arguments.length,e=new Array(t);t--;)e[t]=arguments[t];return new this(e)}})}},{34:34}],97:[function(r,t,e){function i(t,e){if(a(t),!n(e)&&null!==e)throw TypeError(e+": can't set as prototype!")}var n=r(52),a=r(8);t.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(t,n,a){try{(a=r(26)(Function.call,r(75).f(Object.prototype,"__proto__").set,2))(t,[]),n=!(t instanceof Array)}catch(e){n=!0}return function(t,e){return i(t,e),n?t.__proto__=e:a(t,e),t}}({},!1):undefined),check:i}},{26:26,52:52,75:75,8:8}],98:[function(t,e,n){"use strict";var a=t(41),r=t(72),i=t(30),o=t(127)("species");e.exports=function(t){var e=a[t];i&&e&&!e[o]&&r.f(e,o,{configurable:!0,get:function(){return this}})}},{127:127,30:30,41:41,72:72}],99:[function(t,e,n){var a=t(72).f,r=t(42),i=t(127)("toStringTag");e.exports=function(t,e,n){t&&!r(t=n?t:t.prototype,i)&&a(t,i,{configurable:!0,value:e})}},{127:127,42:42,72:72}],100:[function(t,e,n){var a=t(101)("keys"),r=t(122);e.exports=function(t){return a[t]||(a[t]=r(t))}},{101:101,122:122}],101:[function(t,e,n){var a=t(24),r=t(41),i="__core-js_shared__",o=r[i]||(r[i]={});(e.exports=function(t,e){return o[t]||(o[t]=e!==undefined?e:{})})("versions",[]).push({version:a.version,mode:t(60)?"pure":"global",copyright:"© 2018 Denis Pushkarev (zloirock.ru)"})},{24:24,41:41,60:60}],102:[function(t,e,n){var r=t(8),i=t(4),o=t(127)("species");e.exports=function(t,e){var n,a=r(t).constructor;return a===undefined||(n=r(a)[o])==undefined?e:i(n)}},{127:127,4:4,8:8}],103:[function(t,e,n){"use strict";var a=t(36);e.exports=function(t,e){return!!t&&a(function(){e?t.call(null,function(){},1):t.call(null)})}},{36:36}],104:[function(t,e,n){var p=t(114),u=t(29);e.exports=function(s){return function(t,e){var n,a,r=String(u(t)),i=p(e),o=r.length;return i<0||o<=i?s?"":undefined:(n=r.charCodeAt(i))<55296||56319"+r+""}var r=t(34),i=t(36),o=t(29),s=/"/g;e.exports=function(e,t){var n={};n[e]=t(a),r(r.P+r.F*i(function(){var t=""[e]('"');return t!==t.toLowerCase()||3p&&(u=u.slice(0,p)),a?u+r:r+u}},{108:108,116:116,29:29}],108:[function(t,e,n){"use strict";var r=t(114),i=t(29);e.exports=function(t){var e=String(i(this)),n="",a=r(t);if(a<0||a==Infinity)throw RangeError("Count can't be negative");for(;0>>=1)&&(e+=e))1&a&&(n+=e);return n}},{114:114,29:29}],109:[function(t,e,n){function a(t,e,n){var a={},r=s(function(){return!!p[t]()||"​…"!="​…"[t]()}),i=a[t]=r?e(l):p[t];n&&(a[n]=i),o(o.P+o.F*r,"String",a)}var o=t(34),r=t(29),s=t(36),p=t(110),i="["+p+"]",u=RegExp("^"+i+i+"*"),c=RegExp(i+i+"*$"),l=a.trim=function(t,e){return t=String(r(t)),1&e&&(t=t.replace(u,"")),2&e&&(t=t.replace(c,"")),t};e.exports=a},{110:110,29:29,34:34,36:36}],110:[function(t,e,n){e.exports="\t\n\x0B\f\r   ᠎ â€â€‚         âŸã€€\u2028\u2029\ufeff"},{}],111:[function(t,e,n){function a(){var t=+this;if(y.hasOwnProperty(t)){var e=y[t];delete y[t],e()}}function r(t){a.call(t.data)}var i,o,s,p=t(26),u=t(47),c=t(44),l=t(31),d=t(41),f=d.process,h=d.setImmediate,m=d.clearImmediate,g=d.MessageChannel,b=d.Dispatch,v=0,y={},_="onreadystatechange";h&&m||(h=function(t){for(var e=[],n=1;n>1,c=23===e?O(2,-24)-O(2,-77):0,l=0,d=t<0||0===t&&1/t<0?1:0;for((t=A(t))!=t||t===C?(r=t!=t?1:0,a=p):(a=T(R(t)/M),t*(i=O(2,-a))<1&&(a--,i*=2),2<=(t+=1<=a+u?c/i:c*O(2,1-u))*i&&(a++,i/=2),p<=a+u?(r=0,a=p):1<=a+u?(r=(t*i-1)*O(2,e),a+=u):(r=t*O(2,u-1)*O(2,e),a=0));8<=e;o[l++]=255&r,r/=256,e-=8);for(a=a<>1,s=r-7,p=n-1,u=t[p--],c=127&u;for(u>>=7;0>=-s,s+=e;0>8&255]}function G(t){return[255&t,t>>8&255,t>>16&255,t>>24&255]}function z(t){return F(t,52,8)}function W(t){return F(t,23,4)}function H(t,e,n){m(t[_],e,{get:function(){return this[n]}})}function K(t,e,n,a){var r=f(+n);if(r+e>t[N])throw E(x);var i=t[D]._b,o=r+t[I],s=i.slice(o,o+e);return a?s:s.reverse()}function Q(t,e,n,a,r,i){var o=f(+n);if(o+e>t[N])throw E(x);for(var s=t[D]._b,p=o+t[I],u=a(+r),c=0;cJ;)(Y=X[J++])in w||s(w,Y,P[Y]);i||($.constructor=w)}var Z=new k(new w(2)),tt=k[_].setInt8;Z.setInt8(0,2147483648),Z.setInt8(1,2147483649),!Z.getInt8(0)&&Z.getInt8(1)||p(k[_],{setInt8:function(t,e){tt.call(this,t,e<<24>>24)},setUint8:function(t,e){tt.call(this,t,e<<24>>24)}},!0)}else w=function(t){c(this,w,v);var e=f(t);this._b=g.call(new Array(e),0),this[N]=e},k=function(t,e,n){c(this,k,y),c(t,w,y);var a=t[N],r=l(e);if(r<0||a>24},getUint8:function(t){return K(this,1,t)[0]},getInt16:function(t){var e=K(this,2,t,arguments[1]);return(e[1]<<8|e[0])<<16>>16},getUint16:function(t){var e=K(this,2,t,arguments[1]);return e[1]<<8|e[0]},getInt32:function(t){return q(K(this,4,t,arguments[1]))},getUint32:function(t){return q(K(this,4,t,arguments[1]))>>>0},getFloat32:function(t){return B(K(this,4,t,arguments[1]),23,4)},getFloat64:function(t){return B(K(this,8,t,arguments[1]),52,8)},setInt8:function(t,e){Q(this,1,t,V,e)},setUint8:function(t,e){Q(this,1,t,V,e)},setInt16:function(t,e){Q(this,2,t,U,e,arguments[2])},setUint16:function(t,e){Q(this,2,t,U,e,arguments[2])},setInt32:function(t,e){Q(this,4,t,G,e,arguments[2])},setUint32:function(t,e){Q(this,4,t,G,e,arguments[2])},setFloat32:function(t,e){Q(this,4,t,W,e,arguments[2])},setFloat64:function(t,e){Q(this,8,t,z,e,arguments[2])}});b(w,v),b(k,y),s(k[_],o.VIEW,!0),n[v]=w,n[y]=k},{10:10,113:113,114:114,116:116,121:121,30:30,36:36,41:41,43:43,60:60,7:7,72:72,77:77,91:91,99:99}],121:[function(t,e,n){for(var a,r=t(41),i=t(43),o=t(122),s=o("typed_array"),p=o("view"),u=!(!r.ArrayBuffer||!r.DataView),c=u,l=0,d="Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array".split(",");l<9;)(a=r[d[l++]])?(i(a.prototype,s,!0),i(a.prototype,p,!0)):c=!1;e.exports={ABV:u,CONSTR:c,TYPED:s,VIEW:p}},{122:122,41:41,43:43}],122:[function(t,e,n){var a=0,r=Math.random();e.exports=function(t){return"Symbol(".concat(t===undefined?"":t,")_",(++a+r).toString(36))}},{}],123:[function(t,e,n){var a=t(41).navigator;e.exports=a&&a.userAgent||""},{41:41}],124:[function(t,e,n){var a=t(52);e.exports=function(t,e){if(!a(t)||t._t!==e)throw TypeError("Incompatible receiver, "+e+" required!");return t}},{52:52}],125:[function(t,e,n){var a=t(41),r=t(24),i=t(60),o=t(126),s=t(72).f;e.exports=function(t){var e=r.Symbol||(r.Symbol=i?{}:a.Symbol||{});"_"==t.charAt(0)||t in e||s(e,t,{value:o.f(t)})}},{126:126,24:24,41:41,60:60,72:72}],126:[function(t,e,n){n.f=t(127)},{127:127}],127:[function(t,e,n){var a=t(101)("wks"),r=t(122),i=t(41).Symbol,o="function"==typeof i;(e.exports=function(t){return a[t]||(a[t]=o&&i[t]||(o?i:r)("Symbol."+t))}).store=a},{101:101,122:122,41:41}],128:[function(t,e,n){var a=t(18),r=t(127)("iterator"),i=t(59);e.exports=t(24).getIteratorMethod=function(t){if(t!=undefined)return t[r]||t["@@iterator"]||i[a(t)]}},{127:127,18:18,24:24,59:59}],129:[function(t,e,n){var a=t(34),r=t(93)(/[\\^$*+?.()|[\]{}]/g,"\\$&");a(a.S,"RegExp",{escape:function(t){return r(t)}})},{34:34,93:93}],130:[function(t,e,n){var a=t(34);a(a.P,"Array",{copyWithin:t(9)}),t(6)("copyWithin")},{34:34,6:6,9:9}],131:[function(t,e,n){"use strict";var a=t(34),r=t(13)(4);a(a.P+a.F*!t(103)([].every,!0),"Array",{every:function(t){return r(this,t,arguments[1])}})},{103:103,13:13,34:34}],132:[function(t,e,n){var a=t(34);a(a.P,"Array",{fill:t(10)}),t(6)("fill")},{10:10,34:34,6:6}],133:[function(t,e,n){"use strict";var a=t(34),r=t(13)(2);a(a.P+a.F*!t(103)([].filter,!0),"Array",{filter:function(t){return r(this,t,arguments[1])}})},{103:103,13:13,34:34}],134:[function(t,e,n){"use strict";var a=t(34),r=t(13)(6),i="findIndex",o=!0;i in[]&&Array(1)[i](function(){o=!1}),a(a.P+a.F*o,"Array",{findIndex:function(t){return r(this,t,1=t.length?(this._t=undefined,r(1)):r(0,"keys"==e?n:"values"==e?t[n]:[n,t[n]])},"values"),i.Arguments=i.Array,a("keys"),a("values"),a("entries")},{115:115,56:56,58:58,59:59,6:6}],141:[function(t,e,n){"use strict";var a=t(34),r=t(115),i=[].join;a(a.P+a.F*(t(48)!=Object||!t(103)(i)),"Array",{join:function(t){return i.call(r(this),t===undefined?",":t)}})},{103:103,115:115,34:34,48:48}],142:[function(t,e,n){"use strict";var a=t(34),r=t(115),i=t(114),o=t(116),s=[].lastIndexOf,p=!!s&&1/[1].lastIndexOf(1,-0)<0;a(a.P+a.F*(p||!t(103)(s)),"Array",{lastIndexOf:function(t){if(p)return s.apply(this,arguments)||0;var e=r(this),n=o(e.length),a=n-1;for(1>>=0)?31-Math.floor(Math.log(t+.5)*Math.LOG2E):32}})},{34:34}],165:[function(t,e,n){var a=t(34),r=Math.exp;a(a.S,"Math",{cosh:function(t){return(r(t=+t)+r(-t))/2}})},{34:34}],166:[function(t,e,n){var a=t(34),r=t(61);a(a.S+a.F*(r!=Math.expm1),"Math",{expm1:r})},{34:34,61:61}],167:[function(t,e,n){var a=t(34);a(a.S,"Math",{fround:t(62)})},{34:34,62:62}],168:[function(t,e,n){var a=t(34),p=Math.abs;a(a.S,"Math",{hypot:function(t,e){for(var n,a,r=0,i=0,o=arguments.length,s=0;i>>16)*o+i*(n&r>>>16)<<16>>>0)}})},{34:34,36:36}],170:[function(t,e,n){var a=t(34);a(a.S,"Math",{log10:function(t){return Math.log(t)*Math.LOG10E}})},{34:34}],171:[function(t,e,n){var a=t(34);a(a.S,"Math",{log1p:t(63)})},{34:34,63:63}],172:[function(t,e,n){var a=t(34);a(a.S,"Math",{log2:function(t){return Math.log(t)/Math.LN2}})},{34:34}],173:[function(t,e,n){var a=t(34);a(a.S,"Math",{sign:t(65)})},{34:34,65:65}],174:[function(t,e,n){var a=t(34),r=t(61),i=Math.exp;a(a.S+a.F*t(36)(function(){return-2e-17!=!Math.sinh(-2e-17)}),"Math",{sinh:function(t){return Math.abs(t=+t)<1?(r(t)-r(-t))/2:(i(t-1)-i(-t-1))*(Math.E/2)}})},{34:34,36:36,61:61}],175:[function(t,e,n){var a=t(34),r=t(61),i=Math.exp;a(a.S,"Math",{tanh:function(t){var e=r(t=+t),n=r(-t);return e==Infinity?1:n==Infinity?-1:(e-n)/(i(t)+i(-t))}})},{34:34,61:61}],176:[function(t,e,n){var a=t(34);a(a.S,"Math",{trunc:function(t){return(0w;w++)i(g,_=x[w])&&!i(m,_)&&d(m,_,l(g,_));(m.prototype=b).constructor=m,t(92)(r,h,m)}},{109:109,118:118,19:19,30:30,36:36,41:41,42:42,46:46,71:71,72:72,75:75,77:77,92:92}],178:[function(t,e,n){var a=t(34);a(a.S,"Number",{EPSILON:Math.pow(2,-52)})},{34:34}],179:[function(t,e,n){var a=t(34),r=t(41).isFinite;a(a.S,"Number",{isFinite:function(t){return"number"==typeof t&&r(t)}})},{34:34,41:41}],180:[function(t,e,n){var a=t(34);a(a.S,"Number",{isInteger:t(51)})},{34:34,51:51}],181:[function(t,e,n){var a=t(34);a(a.S,"Number",{isNaN:function(t){return t!=t}})},{34:34}],182:[function(t,e,n){var a=t(34),r=t(51),i=Math.abs;a(a.S,"Number",{isSafeInteger:function(t){return r(t)&&i(t)<=9007199254740991}})},{34:34,51:51}],183:[function(t,e,n){var a=t(34);a(a.S,"Number",{MAX_SAFE_INTEGER:9007199254740991})},{34:34}],184:[function(t,e,n){var a=t(34);a(a.S,"Number",{MIN_SAFE_INTEGER:-9007199254740991})},{34:34}],185:[function(t,e,n){var a=t(34),r=t(86);a(a.S+a.F*(Number.parseFloat!=r),"Number",{parseFloat:r})},{34:34,86:86}],186:[function(t,e,n){var a=t(34),r=t(87);a(a.S+a.F*(Number.parseInt!=r),"Number",{parseInt:r})},{34:34,87:87}],187:[function(t,e,n){"use strict";function u(t,e){for(var n=-1,a=e;++n<6;)a+=t*o[n],o[n]=a%1e7,a=i(a/1e7)}function c(t){for(var e=6,n=0;0<=--e;)n+=o[e],o[e]=i(n/t),n=n%t*1e7}function l(){for(var t=6,e="";0<=--t;)if(""!==e||0===t||0!==o[t]){var n=String(o[t]);e=""===e?n:e+h.call("0",7-n.length)+n}return e}var a=t(34),d=t(114),f=t(5),h=t(108),r=1..toFixed,i=Math.floor,o=[0,0,0,0,0,0],m="Number.toFixed: incorrect invocation!",g=function(t,e,n){return 0===e?n:e%2==1?g(t,e-1,n*t):g(t*t,e/2,n)};a(a.P+a.F*(!!r&&("0.000"!==8e-5.toFixed(3)||"1"!==.9.toFixed(0)||"1.25"!==1.255.toFixed(2)||"1000000000000000128"!==(0xde0b6b3a7640080).toFixed(0))||!t(36)(function(){r.call({})})),"Number",{toFixed:function(t){var e,n,a,r,i=f(this,m),o=d(t),s="",p="0";if(o<0||20t;)e(a[t++]);l._c=[],l._n=!1,n&&!l._h&&N(l)})}}function o(t){var e=this;e._d||(e._d=!0,(e=e._w||e)._v=t,e._s=2,e._a||(e._a=e._c.slice()),i(e,!0))}var n,s,p,u,c=a(60),l=a(41),f=a(26),h=a(18),m=a(34),g=a(52),b=a(4),v=a(7),y=a(40),_=a(102),x=a(111).set,w=a(68)(),k=a(69),S=a(88),E=a(123),C=a(89),P="Promise",A=l.TypeError,O=l.process,T=O&&O.versions,R=T&&T.v8||"",M=l[P],L="process"==h(O),j=s=k.f,D=!!function(){try{var t=M.resolve(1),e=(t.constructor={})[a(127)("species")]=function(t){t(r,r)};return(L||"function"==typeof PromiseRejectionEvent)&&t.then(r)instanceof e&&0!==R.indexOf("6.6")&&-1===E.indexOf("Chrome/66")}catch(n){}}(),N=function(i){x.call(l,function(){var t,e,n,a=i._v,r=I(i);if(r&&(t=S(function(){L?O.emit("unhandledRejection",a,i):(e=l.onunhandledrejection)?e({promise:i,reason:a}):(n=l.console)&&n.error&&n.error("Unhandled promise rejection",a)}),i._h=L||I(i)?2:1),i._a=undefined,r&&t.e)throw t.v})},I=function(t){return 1!==t._h&&0===(t._a||t._c).length},F=function(e){x.call(l,function(){var t;L?O.emit("rejectionHandled",e):(t=l.onrejectionhandled)&&t({promise:e,reason:e._v})})},B=function(n){var a,r=this;if(!r._d){r._d=!0,r=r._w||r;try{if(r===n)throw A("Promise can't be resolved itself");(a=d(n))?w(function(){var t={_w:r,_d:!1};try{a.call(n,f(B,t,1),f(o,t,1))}catch(e){o.call(t,e)}}):(r._v=n,r._s=1,i(r,!1))}catch(t){o.call({_w:r,_d:!1},t)}}};D||(M=function(t){v(this,M,P,"_h"),b(t),n.call(this);try{t(f(B,this,1),f(o,this,1))}catch(e){o.call(this,e)}},(n=function(t){this._c=[],this._a=undefined,this._s=0,this._d=!1,this._v=undefined,this._h=0,this._n=!1}).prototype=a(91)(M.prototype,{then:function(t,e){var n=j(_(this,M));return n.ok="function"!=typeof t||t,n.fail="function"==typeof e&&e,n.domain=L?O.domain:undefined,this._c.push(n),this._a&&this._a.push(n),this._s&&i(this,!1),n.promise},"catch":function(t){return this.then(undefined,t)}}),p=function(){var t=new n;this.promise=t,this.resolve=f(B,t,1),this.reject=f(o,t,1)},k.f=j=function(t){return t===M||t===u?new p(t):s(t)}),m(m.G+m.W+m.F*!D,{Promise:M}),a(99)(M,P),a(98)(P),u=a(24)[P],m(m.S+m.F*!D,P,{reject:function(t){var e=j(this);return(0,e.reject)(t),e.promise}}),m(m.S+m.F*(c||!D),P,{resolve:function(t){return C(c&&this===u?M:this,t)}}),m(m.S+m.F*!(D&&a(57)(function(t){M.all(t)["catch"](r)})),P,{all:function(t){var o=this,e=j(o),s=e.resolve,p=e.reject,n=S(function(){var a=[],r=0,i=1;y(t,!1,function(t){var e=r++,n=!1;a.push(undefined),i++,o.resolve(t).then(function(t){n||(n=!0,a[e]=t,--i||s(a))},p)}),--i||s(a)});return n.e&&p(n.v),e.promise},race:function(t){var e=this,n=j(e),a=n.reject,r=S(function(){y(t,!1,function(t){e.resolve(t).then(n.resolve,a)})});return r.e&&a(r.v),n.promise}})},{102:102,111:111,123:123,127:127,18:18,24:24,26:26,34:34,4:4,40:40,41:41,52:52,57:57,60:60,68:68,69:69,7:7,88:88,89:89,91:91,98:98,99:99}],209:[function(t,e,n){var a=t(34),i=t(4),o=t(8),s=(t(41).Reflect||{}).apply,p=Function.apply;a(a.S+a.F*!t(36)(function(){s(function(){})}),"Reflect",{apply:function(t,e,n){var a=i(t),r=o(n);return s?s(a,e,r):p.call(a,e,r)}})},{34:34,36:36,4:4,41:41,8:8}],210:[function(t,e,n){var a=t(34),s=t(71),p=t(4),u=t(8),c=t(52),r=t(36),l=t(17),d=(t(41).Reflect||{}).construct,f=r(function(){function t(){}return!(d(function(){},[],t)instanceof t)}),h=!r(function(){d(function(){})});a(a.S+a.F*(f||h),"Reflect",{construct:function(t,e){p(t),u(e);var n=arguments.length<3?t:p(arguments[2]);if(h&&!f)return d(t,e,n);if(t==n){switch(e.length){case 0:return new t;case 1:return new t(e[0]);case 2:return new t(e[0],e[1]);case 3:return new t(e[0],e[1],e[2]);case 4:return new t(e[0],e[1],e[2],e[3])}var a=[null];return a.push.apply(a,e),new(l.apply(t,a))}var r=n.prototype,i=s(c(r)?r:Object.prototype),o=Function.apply.call(t,i,e);return c(o)?o:i}})},{17:17,34:34,36:36,4:4,41:41,52:52,71:71,8:8}],211:[function(t,e,n){var r=t(72),a=t(34),i=t(8),o=t(118);a(a.S+a.F*t(36)(function(){Reflect.defineProperty(r.f({},1,{value:1}),1,{value:2})}),"Reflect",{defineProperty:function(t,e,n){i(t),e=o(e,!0),i(n);try{return r.f(t,e,n),!0}catch(a){return!1}}})},{118:118,34:34,36:36,72:72,8:8}],212:[function(t,e,n){var a=t(34),r=t(75).f,i=t(8);a(a.S,"Reflect",{deleteProperty:function(t,e){var n=r(i(t),e);return!(n&&!n.configurable)&&delete t[e]}})},{34:34,75:75,8:8}],213:[function(t,e,n){"use strict";function a(t){this._t=i(t),this._i=0;var e,n=this._k=[];for(e in t)n.push(e)}var r=t(34),i=t(8);t(55)(a,"Object",function(){var t,e=this._k;do{if(this._i>=e.length)return{value:undefined,done:!0}}while(!((t=e[this._i++])in this._t));return{value:t,done:!1}}),r(r.S,"Reflect",{enumerate:function(t){return new a(t)}})},{34:34,55:55,8:8}],214:[function(t,e,n){var a=t(75),r=t(34),i=t(8);r(r.S,"Reflect",{getOwnPropertyDescriptor:function(t,e){return a.f(i(t),e)}})},{34:34,75:75,8:8}],215:[function(t,e,n){var a=t(34),r=t(79),i=t(8);a(a.S,"Reflect",{getPrototypeOf:function(t){return r(i(t))}})},{34:34,79:79,8:8}],216:[function(t,e,n){var i=t(75),o=t(79),s=t(42),a=t(34),p=t(52),u=t(8);a(a.S,"Reflect",{get:function c(t,e){var n,a,r=arguments.length<3?t:arguments[2];return u(t)===r?t[e]:(n=i.f(t,e))?s(n,"value")?n.value:n.get!==undefined?n.get.call(r):undefined:p(a=o(t))?c(a,e,r):void 0}})},{34:34,42:42,52:52,75:75,79:79,8:8}],217:[function(t,e,n){var a=t(34);a(a.S,"Reflect",{has:function(t,e){return e in t}})},{34:34}],218:[function(t,e,n){var a=t(34),r=t(8),i=Object.isExtensible;a(a.S,"Reflect",{isExtensible:function(t){return r(t),!i||i(t)}})},{34:34,8:8}],219:[function(t,e,n){var a=t(34);a(a.S,"Reflect",{ownKeys:t(85)})},{34:34,85:85}],220:[function(t,e,n){var a=t(34),r=t(8),i=Object.preventExtensions;a(a.S,"Reflect",{preventExtensions:function(t){r(t);try{return i&&i(t),!0}catch(e){return!1}}})},{34:34,8:8}],221:[function(t,e,n){var a=t(34),r=t(97);r&&a(a.S,"Reflect",{setPrototypeOf:function(t,e){r.check(t,e);try{return r.set(t,e),!0}catch(n){return!1}}})},{34:34,97:97}],222:[function(t,e,n){var s=t(72),p=t(75),u=t(79),c=t(42),a=t(34),l=t(90),d=t(8),f=t(52);a(a.S,"Reflect",{set:function h(t,e,n){var a,r,i=arguments.length<4?t:arguments[3],o=p.f(d(t),e);if(!o){if(f(r=u(t)))return h(r,e,n,i);o=l(0)}if(c(o,"value")){if(!1===o.writable||!f(i))return!1;if(a=p.f(i,e)){if(a.get||a.set||!1===a.writable)return!1;a.value=n,s.f(i,e,a)}else s.f(i,e,l(0,n));return!0}return o.set!==undefined&&(o.set.call(i,n),!0)}})},{34:34,42:42,52:52,72:72,75:75,79:79,8:8,90:90}],223:[function(t,e,n){var a=t(41),i=t(46),r=t(72).f,o=t(77).f,s=t(53),p=t(38),u=a.RegExp,c=u,l=u.prototype,d=/a/g,f=/a/g,h=new u(d)!==d;if(t(30)&&(!h||t(36)(function(){return f[t(127)("match")]=!1,u(d)!=d||u(f)==f||"/a/i"!=u(d,"i")}))){u=function(t,e){var n=this instanceof u,a=s(t),r=e===undefined;return!n&&a&&t.constructor===u&&r?t:i(h?new c(a&&!r?t.source:t,e):c((a=t instanceof u)?t.source:t,a&&r?p.call(t):e),n?this:l,u)};function m(e){e in u||r(u,e,{configurable:!0,get:function(){return c[e]},set:function(t){c[e]=t}})}for(var g=o(c),b=0;g.length>b;)m(g[b++]);(l.constructor=u).prototype=l,t(92)(a,"RegExp",u)}t(98)("RegExp")},{127:127,30:30,36:36,38:38,41:41,46:46,53:53,72:72,77:77,92:92,98:98}],224:[function(t,e,n){t(30)&&"g"!=/./g.flags&&t(72).f(RegExp.prototype,"flags",{configurable:!0,get:t(38)})},{30:30,38:38,72:72}],225:[function(t,e,n){t(37)("match",1,function(a,r,t){return[function(t){"use strict";var e=a(this),n=t==undefined?undefined:t[r];return n!==undefined?n.call(t,e):new RegExp(t)[r](String(e))},t]})},{37:37}],226:[function(t,e,n){t(37)("replace",2,function(r,i,o){return[function(t,e){"use strict";var n=r(this),a=t==undefined?undefined:t[i];return a!==undefined?a.call(t,n,e):o.call(String(n),t,e)},o]})},{37:37}],227:[function(t,e,n){t(37)("search",1,function(a,r,t){return[function(t){"use strict";var e=a(this),n=t==undefined?undefined:t[r];return n!==undefined?n.call(t,e):new RegExp(t)[r](String(e))},t]})},{37:37}],228:[function(e,t,n){e(37)("split",2,function(r,i,o){"use strict";var f=e(53),h=o,m=[].push,t="split",g="length",b="lastIndex";if("c"=="abbc"[t](/(b)*/)[1]||4!="test"[t](/(?:)/,-1)[g]||2!="ab"[t](/(?:ab)*/)[g]||4!="."[t](/(.?)(.?)/)[g]||1<"."[t](/()()/)[g]||""[t](/.?/)[g]){var v=/()??/.exec("")[1]===undefined;o=function(t,e){var n=String(this);if(t===undefined&&0===e)return[];if(!f(t))return h.call(n,t,e);var a,r,i,o,s,p=[],u=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),c=0,l=e===undefined?4294967295:e>>>0,d=new RegExp(t.source,u+"g");for(v||(a=new RegExp("^"+d.source+"$(?!\\s)",u));(r=d.exec(n))&&!(c<(i=r.index+r[0][g])&&(p.push(n.slice(c,r.index)),!v&&1=l));)d[b]===r.index&&d[b]++;return c===n[g]?!o&&d.test("")||p.push(""):p.push(n.slice(c)),p[g]>l?p.slice(0,l):p}}else"0"[t](undefined,0)[g]&&(o=function(t,e){return t===undefined&&0===e?[]:h.call(this,t,e)});return[function(t,e){var n=r(this),a=t==undefined?undefined:t[i];return a!==undefined?a.call(t,n,e):o.call(String(n),t,e)},o]})},{37:37,53:53}],229:[function(e,t,n){"use strict";e(224);function a(t){e(92)(RegExp.prototype,s,t,!0)}var r=e(8),i=e(38),o=e(30),s="toString",p=/./[s];e(36)(function(){return"/a/b"!=p.call({source:"a",flags:"b"})})?a(function(){var t=r(this);return"/".concat(t.source,"/","flags"in t?t.flags:!o&&t instanceof RegExp?i.call(t):undefined)}):p.name!=s&&a(function(){return p.call(this)})},{224:224,30:30,36:36,38:38,8:8,92:92}],230:[function(t,e,n){"use strict";var a=t(20),r=t(124);e.exports=t(23)("Set",function(t){return function(){return t(this,0>10),e%1024+56320))}return n.join("")}})},{112:112,34:34}],241:[function(t,e,n){"use strict";var a=t(34),r=t(105),i="includes";a(a.P+a.F*t(35)(i),"String",{includes:function(t){return!!~r(this,t,i).indexOf(t,1=e.length?{value:undefined,done:!0}:(t=a(e,n),this._i+=t.length,{value:t,done:!1})})},{104:104,56:56}],244:[function(t,e,n){"use strict";t(106)("link",function(e){return function(t){return e(this,"a","href",t)}})},{106:106}],245:[function(t,e,n){var a=t(34),o=t(115),s=t(116);a(a.S,"String",{raw:function(t){for(var e=o(t.raw),n=s(e.length),a=arguments.length,r=[],i=0;ir;)c(W,e=n[r++])||e==V||e==h||a.push(e);return a}function p(t){for(var e,n=t===K,a=N(n?H:C(t)),r=[],i=0;a.length>i;)!c(W,e=a[i++])||n&&!c(K,e)||r.push(W[e]);return r}var u=t(41),c=t(42),l=t(30),d=t(34),f=t(92),h=t(66).KEY,m=t(36),g=t(101),b=t(99),v=t(122),y=t(127),_=t(126),x=t(125),w=t(33),k=t(50),S=t(8),E=t(52),C=t(115),P=t(118),A=t(90),O=t(71),T=t(76),R=t(75),M=t(72),L=t(81),j=R.f,D=M.f,N=T.f,I=u.Symbol,F=u.JSON,B=F&&F.stringify,q="prototype",V=y("_hidden"),U=y("toPrimitive"),G={}.propertyIsEnumerable,z=g("symbol-registry"),W=g("symbols"),H=g("op-symbols"),K=Object[q],Q="function"==typeof I,Y=u.QObject,$=!Y||!Y[q]||!Y[q].findChild,X=l&&m(function(){return 7!=O(D({},"a",{get:function(){return D(this,"a",{value:7}).a}})).a})?function(t,e,n){var a=j(K,e);a&&delete K[e],D(t,e,n),a&&t!==K&&D(K,e,a)}:D,J=Q&&"symbol"==typeof I.iterator?function(t){return"symbol"==typeof t}:function(t){return t instanceof I},Z=function(t,e,n){return t===K&&Z(H,e,n),S(t),e=P(e,!0),S(n),c(W,e)?(n.enumerable?(c(t,V)&&t[V][e]&&(t[V][e]=!1),n=O(n,{enumerable:A(0,!1)})):(c(t,V)||D(t,V,A(1,{})),t[V][e]=!0),X(t,e,n)):D(t,e,n)};Q||(f((I=function(){if(this instanceof I)throw TypeError("Symbol is not a constructor!");var e=v(0et;)y(tt[et++]);for(var nt=L(y.store),at=0;nt.length>at;)x(nt[at++]);d(d.S+d.F*!Q,"Symbol",{"for":function(t){return c(z,t+="")?z[t]:z[t]=I(t)},keyFor:function(t){if(!J(t))throw TypeError(t+" is not a symbol!");for(var e in z)if(z[e]===t)return e},useSetter:function(){$=!0},useSimple:function(){$=!1}}),d(d.S+d.F*!Q,"Object",{create:function(t,e){return e===undefined?O(t):r(O(t),e)},defineProperty:Z,defineProperties:r,getOwnPropertyDescriptor:o,getOwnPropertyNames:s,getOwnPropertySymbols:p}),F&&d(d.S+d.F*(!Q||m(function(){var t=I();return"[null]"!=B([t])||"{}"!=B({a:t})||"{}"!=B(Object(t))})),"JSON",{stringify:function(t){for(var e,n,a=[t],r=1;r>>0,i=n>>>0;return(e>>>0)+(a>>>0)+((r&i|(r|i)&~(r+i>>>0))>>>31)|0}})},{34:34}],281:[function(t,e,n){var a=t(34);a(a.S,"Math",{imulh:function(t,e){var n=+t,a=+e,r=65535&n,i=65535&a,o=n>>16,s=a>>16,p=(o*i>>>0)+(r*i>>>16);return o*s+(p>>16)+((r*s>>>0)+(65535&p)>>16)}})},{34:34}],282:[function(t,e,n){var a=t(34);a(a.S,"Math",{isubh:function(t,e,n,a){var r=t>>>0,i=n>>>0;return(e>>>0)-(a>>>0)-((~r&i|~(r^i)&r-i>>>0)>>>31)|0}})},{34:34}],283:[function(t,e,n){var a=t(34);a(a.S,"Math",{RAD_PER_DEG:180/Math.PI})},{34:34}],284:[function(t,e,n){var a=t(34),r=Math.PI/180;a(a.S,"Math",{radians:function(t){return t*r}})},{34:34}],285:[function(t,e,n){var a=t(34);a(a.S,"Math",{scale:t(64)})},{34:34,64:64}],286:[function(t,e,n){var a=t(34);a(a.S,"Math",{signbit:function(t){return(t=+t)!=t?t:0==t?1/t==Infinity:0>>16,s=a>>>16,p=(o*i>>>0)+(r*i>>>16);return o*s+(p>>>16)+((r*s>>>0)+(65535&p)>>>16)}})},{34:34}],288:[function(t,e,n){"use strict";var a=t(34),r=t(117),i=t(4),o=t(72);t(30)&&a(a.P+t(74),"Object",{__defineGetter__:function(t,e){o.f(r(this),t,{get:i(e),enumerable:!0,configurable:!0})}})},{117:117,30:30,34:34,4:4,72:72,74:74}],289:[function(t,e,n){"use strict";var a=t(34),r=t(117),i=t(4),o=t(72);t(30)&&a(a.P+t(74),"Object",{__defineSetter__:function(t,e){o.f(r(this),t,{set:i(e),enumerable:!0,configurable:!0})}})},{117:117,30:30,34:34,4:4,72:72,74:74}],290:[function(t,e,n){var a=t(34),r=t(84)(!0);a(a.S,"Object",{entries:function(t){return r(t)}})},{34:34,84:84}],291:[function(t,e,n){var a=t(34),p=t(85),u=t(115),c=t(75),l=t(25);a(a.S,"Object",{getOwnPropertyDescriptors:function(t){for(var e,n,a=u(t),r=c.f,i=p(a),o={},s=0;i.length>s;)(n=r(a,e=i[s++]))!==undefined&&l(o,e,n);return o}})},{115:115,25:25,34:34,75:75,85:85}],292:[function(t,e,n){"use strict";var a=t(34),r=t(117),i=t(118),o=t(79),s=t(75).f;t(30)&&a(a.P+t(74),"Object",{__lookupGetter__:function(t){var e,n=r(this),a=i(t,!0);do{if(e=s(n,a))return e.get}while(n=o(n))}})},{117:117,118:118,30:30,34:34,74:74,75:75,79:79}],293:[function(t,e,n){"use strict";var a=t(34),r=t(117),i=t(118),o=t(79),s=t(75).f;t(30)&&a(a.P+t(74),"Object",{__lookupSetter__:function(t){var e,n=r(this),a=i(t,!0);do{if(e=s(n,a))return e.set}while(n=o(n))}})},{117:117,118:118,30:30,34:34,74:74,75:75,79:79}],294:[function(t,e,n){var a=t(34),r=t(84)(!1);a(a.S,"Object",{values:function(t){return r(t)}})},{34:34,84:84}],295:[function(t,e,n){"use strict";function i(t){return null==t?undefined:f(t)}function o(t){var e=t._c;e&&(t._c=undefined,e())}function s(t){return t._o===undefined}function p(t){s(t)||(t._o=undefined,o(t))}function a(t,e){h(t),this._c=undefined,this._o=t,t=new _(this);try{var n=e(t),a=n;null!=n&&("function"==typeof n.unsubscribe?n=function(){a.unsubscribe()}:f(n),this._c=n)}catch(r){return void t.error(r)}s(this)&&o(this)}var r=t(34),u=t(41),c=t(24),l=t(68)(),d=t(127)("observable"),f=t(4),h=t(8),m=t(7),g=t(91),b=t(43),v=t(40),y=v.RETURN;a.prototype=g({},{unsubscribe:function(){p(this)}});var _=function(t){this._s=t};_.prototype=g({},{next:function(t){var e=this._s;if(!s(e)){var n=e._o;try{var a=i(n.next);if(a)return a.call(n,t)}catch(r){try{p(e)}finally{throw r}}}},error:function(t){var e=this._s;if(s(e))throw t;var n=e._o;e._o=undefined;try{var a=i(n.error);if(!a)throw t;t=a.call(n,t)}catch(r){try{o(e)}finally{throw r}}return o(e),t},complete:function(t){var e=this._s;if(!s(e)){var n=e._o;e._o=undefined;try{var a=i(n.complete);t=a?a.call(n,t):undefined}catch(r){try{o(e)}finally{throw r}}return o(e),t}}});var x=function(t){m(this,x,"Observable","_f")._f=f(t)};g(x.prototype,{subscribe:function(t){return new a(t,this._f)},forEach:function(r){var e=this;return new(c.Promise||u.Promise)(function(t,n){f(r);var a=e.subscribe({next:function(t){try{return r(t)}catch(e){n(e),a.unsubscribe()}},error:n,complete:t})})}}),g(x,{from:function(a){var t="function"==typeof this?this:x,e=i(h(a)[d]);if(e){var n=h(e.call(a));return n.constructor===t?n:new t(function(t){return n.subscribe(t)})}return new t(function(e){var n=!1;return l(function(){if(!n){try{if(v(a,!1,function(t){if(e.next(t),n)return y})===y)return}catch(t){if(n)throw t;return void e.error(t)}e.complete()}}),function(){n=!0}})},of:function(){for(var t=0,e=arguments.length,a=new Array(e);t",a.insertBefore(n.lastChild,a.firstChild)}(t,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),s||function a(e,n){n.cache||(n.cache={},n.createElem=e.createElement,n.createFrag=e.createDocumentFragment,n.frag=n.createFrag()),e.createElement=function(t){return h.shivMethods?d(t,e,n):n.createElem(t)},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+c().join().replace(/[\w\-:]+/g,function(t){return n.createElem(t),n.frag.createElement(t),'c("'+t+'")'})+");return n}")(h,n.frag)}(t,e),t}!function(){try{var t=o.createElement("a");t.innerHTML="",n="hidden"in t,s=1==t.childNodes.length||function(){o.createElement("a");var t=o.createDocumentFragment();return"undefined"==typeof t.cloneNode||"undefined"==typeof t.createDocumentFragment||"undefined"==typeof t.createElement}()}catch(e){s=n=!0}}();var h={elements:e.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:"3.7.3-pre",shivCSS:!1!==e.shivCSS,supportsUnknownElements:s,shivMethods:!1!==e.shivMethods,type:"default",shivDocument:f,createElement:d,createDocumentFragment:function m(t,e){if(t=t||o,s)return t.createDocumentFragment();for(var n=(e=e||l(t)).frag.cloneNode(),a=0,r=c(),i=r.length;a=-n&&t.vec[0]*a>=-n;var i=e.vec[0]*t.vec[1]-e.vec[1]*t.vec[0];if(0==i)return!1;var o=(r*e.vec[0]-a*e.vec[1])/i,s=(r*t.vec[0]-a*t.vec[1])/i;return-n<=o&&n<=s||n<=o&&-n<=s},o=function o(t,e){return t.map(function(t){return{x:t.x*e[0]+t.y*e[2]+e[4],y:t.x*e[1]+t.y*e[3]+e[5]}})},v=function v(t,e,n,a){var r=Math.PI/180,i=Math.cos(n*r),o=Math.sin(n*r),s=[t*(a[0]*i+a[2]*o),t*(a[1]*i+a[3]*o),e*(-a[0]*o+a[2]*i),e*(-a[1]*o+a[3]*i)],p=s[0]*s[0]+s[2]*s[2],u=s[1]*s[1]+s[3]*s[3],c=((s[0]-s[3])*(s[0]-s[3])+(s[2]+s[1])*(s[2]+s[1]))*((s[0]+s[3])*(s[0]+s[3])+(s[2]-s[1])*(s[2]-s[1])),l=(p+u)/2;if(c<1e-10*l)return{rx:Math.sqrt(l),ry:Math.sqrt(l),ax:0,isDegenerate:!1};var d=s[0]*s[1]+s[2]*s[3],f=l+(c=Math.sqrt(c))/2,h=l-c/2,m=undefined,g=undefined,b=undefined;return b=0<=(m=Math.abs(d)<1e-10&&Math.abs(f-u)<1e-10?90:180*Math.atan(Math.abs(d)>Math.abs(f-u)?(f-p)/d:d/(f-u))/Math.PI)?(g=Math.sqrt(f),Math.sqrt(h)):(m+=90,g=Math.sqrt(h),Math.sqrt(f)),{rx:g,ry:b,ax:m,isDegenerate:g<1e-10*b||b<1e-10*g}};n["default"]={distPointToPoint:c,distPointToParabol:a,circumCenter:r,parabolsCrossX:i,doHalflinesCross:l,matrixTransform:o,transformEllipse:v},e.exports=n["default"]},{}],333:[function(t,e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var x=function(t,e){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return function u(t,e){var n=[],a=!0,r=!1,i=undefined;try{for(var o,s=t[Symbol.iterator]();!(a=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);a=!0);}catch(p){r=!0,i=p}finally{try{!a&&s["return"]&&s["return"]()}finally{if(r)throw i}}return n}(t,e);throw new TypeError("Invalid attempt to destructure non-iterable instance")};var w=function a(t){return t&&t.__esModule?t:{"default":t}}(t(334)),k=t(335),S=function S(t,e,n){var a=t.map(e),r=n?a.sort(function(t,e){var n=x(t,2),a=n[0],r=(n[1],x(e,2)),i=r[0];r[1];return a-i}):a,i=r.length,o=r[0][0],s=r[i-1][0],p=(0,k.minBy)(r,function(t){return t[1]}),u=(0,k.maxBy)(r,function(t){return t[1]});return o==s&&(s+=1e-5),p==u&&(u+=1e-5),{points:r,xmin:o,xmax:s,ymin:p,ymax:u}};n["default"]=function(t){var e=t.data,n=t.xaccessor,a=t.yaccessor,r=t.width,i=t.height,o=t.closed,s=t.min,p=t.max,u=t.sort,c=u===undefined||u;n=n||function(t){var e=x(t,2),n=e[0];e[1];return n},a=a||function(t){var e=x(t,2);e[0];return e[1]};var l=function l(t){return[n(t),a(t)]},d=e.map(function(t){return S(t,l,c)}),f=(0,k.minBy)(d,function(t){return t.xmin}),h=(0,k.maxBy)(d,function(t){return t.xmax}),m=null==s?(0,k.minBy)(d,function(t){return t.ymin}):s,g=null==p?(0,k.maxBy)(d,function(t){return t.ymax}):p;o&&(m=Math.min(m,0),g=Math.max(g,0));var b=o?0:m,v=(0,w["default"])([f,h],[0,r]),y=(0,w["default"])([m,g],[i,0]);return{arranged:d,scale:function _(t){var e=x(t,2),n=e[0],a=e[1];return[v(n),y(a)]},xscale:v,yscale:y,base:b}},e.exports=n["default"]},{334:334,335:335}],334:[function(t,e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var u=function(t,e){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return function u(t,e){var n=[],a=!0,r=!1,i=undefined;try{for(var o,s=t[Symbol.iterator]();!(a=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);a=!0);}catch(p){r=!0,i=p}finally{try{!a&&s["return"]&&s["return"]()}finally{if(r)throw i}}return n}(t,e);throw new TypeError("Invalid attempt to destructure non-iterable instance")},c=function c(t,e){var n=u(t,2),a=n[0],r=n[1],i=u(e,2),o=i[0],s=i[1],p=function p(t){return o+(s-o)*(t-a)/(r-a)};return p.inverse=function(){return c([o,s],[a,r])},p};n["default"]=c,e.exports=n["default"]},{}],335:[function(t,e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var o=function(t,e){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return function u(t,e){var n=[],a=!0,r=!1,i=undefined;try{for(var o,s=t[Symbol.iterator]();!(a=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);a=!0);}catch(p){r=!0,i=p}finally{try{!a&&s["return"]&&s["return"]()}finally{if(r)throw i}}return n}(t,e);throw new TypeError("Invalid attempt to destructure non-iterable instance")},a=function a(t){return t.reduce(function(t,e){return t+e},0)},r=function r(t){return t.reduce(function(t,e){return Math.min(t,e)})},i=function i(t){return t.reduce(function(t,e){return Math.max(t,e)})},s=function s(t,n){return t.reduce(function(t,e){return t+n(e)},0)},p=function p(t,n){return t.reduce(function(t,e){return Math.min(t,n(e))},Infinity)},u=function u(t,n){return t.reduce(function(t,e){return Math.max(t,n(e))},-Infinity)},c=function c(t,e){var n=o(t,2),a=n[0],r=n[1],i=o(e,2);return[a+i[0],r+i[1]]},l=function l(t,e){var n=o(t,2),a=n[0],r=n[1],i=o(e,2);return[a-i[0],r-i[1]]},d=function d(t,e){var n=o(e,2);return[t*n[0],t*n[1]]},f=function f(t){var e=o(t,2),n=e[0],a=e[1];return Math.sqrt(n*n+a*a)},h=function h(t){return t.reduce(c,[0,0])},m=function m(t){return d(1/t.length,t.reduce(c))},g=function g(t,e){return d(t,[Math.sin(e),-Math.cos(e)])},b=function b(t,e){var n=t||{};for(var a in n){var r=n[a];e[a]=r(e.index,e.item,e.group)}return e},v=function v(t,e,n){for(var a=[],r=t;r>>0,"function"!=typeof t)throw new TypeError;for(r=0;r "+t);var i=undefined;(i=n.node||a.fragment&&a.fragment.rendered&&a.find("*"))&&e.push(i)}}console.warn.apply(console,["%cRactive.js: %c"+t,"color: rgb(114, 157, 52);","color: rgb(85, 85, 85);"].concat(e))},nt=function(){console.log.apply(console,arguments)}):at=nt=rt=B;var ft='A function was specified for "%s" %s, but no %s was returned',ht=function(t,e){return'Missing "'+t+'" '+e+" plugin. You may need to download a plugin via http://docs.ractivejs.org/latest/plugins#"+e+"s"};function mt(t,e,n){var a=gt(t,e,n);return a?a[t][n]:null}function gt(t,e,n){for(;e;){if(n in e[t])return e;if(e.isolated)return null;e=e.parent}}var bt=function(t,e,n,a){if(t===e)return vt(e);if(a){var r=mt("interpolators",n,a);if(r)return r(t,e)||vt(e);pt(ht(a,"interpolator"))}return yt.number(t,e)||yt.array(t,e)||yt.object(t,e)||vt(e)};function vt(t){return function(){return t}}var yt={number:function(e,t){var n;return tt(e)&&tt(t)?(n=(t=+t)-(e=+e))?function(t){return e+t*n}:function(){return e}:null},array:function(t,e){var n,a,r,i;if(!X(t)||!X(e))return null;for(n=[],a=[],i=r=Math.min(t.length,e.length);i--;)a[i]=bt(t[i],e[i]);for(i=r;i=this.duration?(null!==r&&(ge.start(this.root),this.root.viewmodel.set(r,this.to),ge.end()),this.step&&this.step(1,this.to),this.complete(this.to),-1===(a=this.root._animations.indexOf(this))&<("Animation was not found"),this.root._animations.splice(a,1),this.running=!1):(e=this.easing?this.easing(t/this.duration):t/this.duration,null!==r&&(n=this.interpolator(e),ge.start(this.root),this.root.viewmodel.set(r,n),ge.end()),this.step&&this.step(e,n),!0))},stop:function(){var t;this.running=!1,-1===(t=this.root._animations.indexOf(this))&<("Animation was not found"),this.root._animations.splice(t,1)}};function ke(t,e,n){var a,r,i,o,s,p,u,c,l,d,f,h,m,g;if(a=new Xt(function(t){return r=t}),"object"!=typeof t)return(n=n||{}).complete&&a.then(n.complete),n.complete=r,o=Ce(this,t,e,n),a.stop=function(){return o.stop()},a;for(i in p=(n=e||{}).easing,u=n.duration,s=[],c=n.step,l=n.complete,(c||l)&&(f={},n.step=null,n.complete=null,d=function(n){return function(t,e){f[n]=e}}),t)t.hasOwnProperty(i)&&((c||l)&&(h=d(i),n={easing:p,duration:u},c&&(n.step=h)),n.complete=l?h:B,s.push(Ce(this,i,t[i],n)));return g={easing:p,duration:u},c&&(g.step=function(t){return c(t,f)}),l&&a.then(function(t){return l(t,f)}),g.complete=r,m=Ce(this,null,null,g),s.push(m),a.stop=function(){for(var t;t=s.pop();)t.stop();m&&m.stop()},a}var Se=ye,Ee={stop:B};function Ce(t,e,n,a){var r,i,o,s;return null!==(e=e&&Pt(Tt(e)))&&(s=t.viewmodel.get(e)),we.abort(e,t),Z(s,n)?(a.complete&&a.complete(a.to),Ee):(a.easing&&"function"!=typeof(r="function"==typeof a.easing?a.easing:t.easing[a.easing])&&(r=null),i=a.duration===undefined?400:a.duration,o=new Se({keypath:e,from:s,to:n,root:t,duration:i,easing:r,interpolator:a.interpolator,step:a.step,complete:a.complete}),we.add(o),t._animations.push(o),o)}function Pe(){return this.detached||(this.el&&Wt(this.el.__ractive_instances__,this),this.detached=this.fragment.detach(),Ae.fire(this)),this.detached}var Ae=new Bt("detach");function Oe(t){return this.el?this.fragment.find(t):null}function Te(t,e){if(this._isComponentQuery?!this.selector||t.name===this.selector:t.node?p(t.node,this.selector):null)return this.push(t.node||t.instance),e||this._makeDirty(),!0}function Re(){var t,e,n;t=this._root[this._isComponentQuery?"liveComponentQueries":"liveQueries"],e=this.selector,-1!==(n=t.indexOf(e))&&(t.splice(n,1),t[e]=null)}function Me(t,e){var n,a,r,i,o,s,p,u;for(n=je(t.component||t._ractive.proxy),a=je(e.component||e._ractive.proxy),r=zt(n),i=zt(a);r&&r===i;)n.pop(),a.pop(),o=r,r=zt(n),i=zt(a);if(r=r.component||r,i=i.component||i,(p=r.parentFragment)===(u=i.parentFragment))return p.items.indexOf(r)-u.items.indexOf(i)||n.length-a.length;if(s=o.fragments)return s.indexOf(p)-s.indexOf(u)||n.length-a.length;throw new Error("An unexpected condition was met while comparing the position of two components. Please file an issue at https://github.com/RactiveJS/Ractive/issues - thanks!")}function Le(t){var e;return(e=t.parentFragment)?e.owner:t.component&&(e=t.component.parentFragment)?e.owner:void 0}function je(t){var e,n;for(e=[t],n=Le(t);n;)e.push(n),n=Le(n);return e}function De(t,e){return t.compareDocumentPosition?2&t.compareDocumentPosition(e)?1:-1:Me(t,e)}function Ne(){this.sort(this._isComponentQuery?Me:De),this._dirty=!1}function Ie(){var t=this;this._dirty||(this._dirty=!0,ge.scheduleTask(function(){t._sort()}))}function Fe(t){var e=this.indexOf(this._isComponentQuery?t.instance:t);-1!==e&&this.splice(e,1)}var Be=function Cc(t,e,n,a){var r=[];return W(r,{selector:{value:e},live:{value:n},_isComponentQuery:{value:a},_test:{value:Te}}),n&&W(r,{cancel:{value:Re},_root:{value:t},_sort:{value:Ne},_makeDirty:{value:Ie},_remove:{value:Fe},_dirty:{value:!1,writable:!0}}),r};function qe(t,e){var n,a;return this.el?(e=e||{},n=this._liveQueries,(a=n[t])?e&&e.live?a:a.slice():((a=Be(this,t,!!e.live,!1)).live&&(n.push(t),n["_"+t]=a),this.fragment.findAll(t,a),a)):[]}function Ve(t,e){var n,a;return e=e||{},n=this._liveComponentQueries,(a=n[t])?e&&e.live?a:a.slice():((a=Be(this,t,!!e.live,!0)).live&&(n.push(t),n["_"+t]=a),this.fragment.findAllComponents(t,a),a)}function Ue(t){return this.fragment.findComponent(t)}function Ge(t){return this.container?this.container.component&&this.container.component.name===t?this.container:this.container.findContainer(t):null}function ze(t){return this.parent?this.parent.component&&this.parent.component.name===t?this.parent:this.parent.findParent(t):null}var We={enqueue:function(t,e){t.event&&(t._eventQueue=t._eventQueue||[],t._eventQueue.push(t.event)),t.event=e},dequeue:function(t){t._eventQueue&&t._eventQueue.length?t.event=t._eventQueue.pop():delete t.event}},He=function Pc(t,e){var n=arguments[2]===undefined?{}:arguments[2];if(!e)return;n.event?n.event.name=e:n.event={name:e,_noArg:!0};var a=Pt(e).wildcardMatches();!function u(t,e,n,a){var r=arguments[4]!==undefined&&arguments[4];var i,o,s=!0;We.enqueue(t,n);for(o=e.length;0<=o;o--)(i=t._subs[e[o]])&&(s=Ke(t,i,n,a)&&s);We.dequeue(t);if(t.parent&&s){if(r&&t.component){var p=t.component.name+"."+e[e.length-1];e=Pt(p).wildcardMatches(),n&&(n.component=t)}u(t.parent,e,n,a)}}(t,a,n.event,n.args,!0)};function Ke(t,e,n,a){var r=null,i=!1;n&&!n._noArg&&(a=[n].concat(a));for(var o=0,s=(e=e.slice()).length;o\~:]))+)((?::[^\s\+\>\~\(]+(?:\([^\)]+\))?)?\s*[\s\+\>\~]?)\s*/g,In=/^@media/,Fn=/\[data-ractive-css~="\{[a-z0-9-]+\}"]/g;function Bn(t){return t.trim?t.trim():t.replace(/^\s+/,"").replace(/\s+$/,"")}function qn(t){return t.str}var Vn=1,Un={name:"css",extend:function(t,e,n){if(n.css){var a=Vn++,r=n.noCssTransform?n.css:Ln(n.css,a);e.cssId=a,On.add({id:a,styles:r})}},init:function(){}};var Gn={name:"data",extend:function(t,e,n){var a=undefined,r=undefined;if(n.data&&et(n.data))for(a in n.data)(r=n.data[a])&&"object"==typeof r&&(et(r)||X(r))&<("Passing a `data` option with object and array properties to Ractive.extend() is discouraged, as mutating them is likely to cause bugs. Consider using a data function instead:\n\n // this...\n data: function () {\n return {\n myObject: {}\n };\n })\n\n // instead of this:\n data: {\n myObject: {}\n }");e.data=zn(e.data,n.data)},init:function(t,e,n){var a=zn(t.prototype.data,n.data);return"function"==typeof a&&(a=a.call(e)),a||{}},reset:function(t){var e=this.init(t.constructor,t,t.viewmodel);return t.viewmodel.reset(e),!0}};function zn(t,e){!function r(t){t&&t.constructor!==Object&&("function"==typeof t||("object"!=typeof t?pt("data option must be an object or a function, `"+t+"` is not valid"):lt("If supplied, options.data should be a plain JavaScript object - using a non-POJO as the root object may work, but is discouraged")))}(e);var n="function"==typeof t,a="function"==typeof e;return e||n||(e={}),n||a?function(){return Hn(a?Wn(e,this):e,n?Wn(t,this):t)}:Hn(e,t)}function Wn(t,e){var n=t.call(e);if(n)return"object"!=typeof n&&pt("Data function must return an object"),n.constructor!==Object&&dt("Data function returned something other than a plain JavaScript object. This might work, but is strongly discouraged"),n}function Hn(t,e){if(t&&e){for(var n in e)n in t||(t[n]=e[n]);return t}return t||e}var Kn=null,Qn=["preserveWhitespace","sanitize","stripComments","delimiters","tripleDelimiters","interpolate"],Yn={fromId:function Mc(t,e){var n;if(!a){if(e&&e.noThrow)return;throw new Error("Cannot retrieve template #"+t+" as Ractive is not running in a browser.")}Xn(t)&&(t=t.substring(1));if(!(n=document.getElementById(t))){if(e&&e.noThrow)return;throw new Error("Could not find template element with id #"+t)}if("SCRIPT"===n.tagName.toUpperCase())return"textContent"in n?n.textContent:n.innerHTML;if(e&&e.noThrow)return;throw new Error("Template element with id #"+t+", must be a @@ -63,10 +123,6 @@ location.href = 'byond://?src=' + window.__ref__ - - - - @@ -75,9 +131,6 @@ location.href = 'byond://?src=' + window.__ref__
        - -
        -