diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml
index e9dd9bd5f3f7..b758c4d58a62 100644
--- a/.github/workflows/ci_suite.yml
+++ b/.github/workflows/ci_suite.yml
@@ -189,31 +189,20 @@ jobs:
name: Integration Tests
needs: collect_data
- strategy:
- fail-fast: false
- matrix:
- map: ${{ fromJSON(needs.collect_data.outputs.maps).paths }}
-
- uses: ./.github/workflows/run_integration_tests.yml
+ uses: ./.github/workflows/perform_regular_version_tests.yml
with:
- map: ${{ matrix.map }}
+ maps: ${{ needs.collect_data.outputs.maps }}
max_required_byond_client: ${{needs.collect_data.outputs.max_required_byond_client}}
run_alternate_tests:
if: needs.collect_data.outputs.alternate_tests != '[]'
name: Alternate Tests
needs: collect_data
- strategy:
- fail-fast: false
- matrix:
- setup: ${{ fromJSON(needs.collect_data.outputs.alternate_tests) }}
- uses: ./.github/workflows/run_integration_tests.yml
+ uses: ./.github/workflows/perform_alternate_version_tests.yml
with:
- map: ${{ matrix.setup.map }}
- major: ${{ matrix.setup.major }}
- minor: ${{ matrix.setup.minor }}
- max_required_byond_client: ${{ matrix.setup.max_client_version || needs.collect_data.outputs.max_required_byond_client }}
+ alternate_tests: ${{ needs.collect_data.outputs.alternate_tests }}
+ default_max_required_byond_client: ${{ needs.collect_data.outputs.max_required_byond_client }}
compare_screenshots:
if: needs.collect_data.outputs.alternate_tests == '[]' || needs.run_alternate_tests.result == 'success'
diff --git a/.github/workflows/perform_alternate_version_tests.yml b/.github/workflows/perform_alternate_version_tests.yml
new file mode 100644
index 000000000000..de2abfe3e81e
--- /dev/null
+++ b/.github/workflows/perform_alternate_version_tests.yml
@@ -0,0 +1,25 @@
+name: Run Alternate BYOND Version Tests
+on:
+ workflow_call:
+ inputs:
+ alternate_tests:
+ required: true
+ type: string
+ default_max_required_byond_client:
+ required: true
+ type: string
+
+jobs:
+ run:
+ uses: ./.github/workflows/run_integration_tests.yml
+
+ strategy:
+ fail-fast: false
+ matrix:
+ setup: ${{ fromJSON(inputs.alternate_tests) }}
+
+ with:
+ map: ${{ matrix.setup.map }}
+ major: ${{ matrix.setup.major }}
+ minor: ${{ matrix.setup.minor }}
+ max_required_byond_client: ${{ matrix.setup.max_client_version || inputs.default_max_required_byond_client }}
diff --git a/.github/workflows/perform_regular_version_tests.yml b/.github/workflows/perform_regular_version_tests.yml
new file mode 100644
index 000000000000..bc515d850025
--- /dev/null
+++ b/.github/workflows/perform_regular_version_tests.yml
@@ -0,0 +1,23 @@
+name: Run Regular BYOND Version Tests
+on:
+ workflow_call:
+ inputs:
+ maps:
+ required: true
+ type: string
+ max_required_byond_client:
+ required: true
+ type: string
+
+jobs:
+ run:
+ uses: ./.github/workflows/run_integration_tests.yml
+
+ strategy:
+ fail-fast: false
+ matrix:
+ map: ${{ fromJSON(inputs.maps).paths }}
+
+ with:
+ map: ${{ matrix.map }}
+ max_required_byond_client: ${{ inputs.max_required_byond_client }}
diff --git a/.github/workflows/run_integration_tests.yml b/.github/workflows/run_integration_tests.yml
index e5d75f303b39..70af0eeadd0e 100644
--- a/.github/workflows/run_integration_tests.yml
+++ b/.github/workflows/run_integration_tests.yml
@@ -19,6 +19,12 @@ on:
jobs:
run_integration_tests:
+ # If `inputs.major` is specified, this will output `Run Tests (major.minor; map; max)`.
+ # For example, `Run Tests (515.1627; runtimestation; 515)`.
+ #
+ # Otherwise, it will output `Run Tests (map; max)`.
+ # For example, `Run Tests (runtimestation; 515)`.
+ name: Run Tests (${{ inputs.major && format('{0}.{1}; ', inputs.major, inputs.minor) || '' }}${{ inputs.map }}; ${{ inputs.max_required_byond_client }})
runs-on: ubuntu-latest
timeout-minutes: 30 # Monkestation edit: Our CI takes nearly twice as long, so the timeout is twice as long
services:
diff --git a/_maps/RandomRuins/SpaceRuins/deepstorage.dmm b/_maps/RandomRuins/SpaceRuins/deepstorage.dmm
index ba03c88fc2e8..f4104f9f4305 100644
--- a/_maps/RandomRuins/SpaceRuins/deepstorage.dmm
+++ b/_maps/RandomRuins/SpaceRuins/deepstorage.dmm
@@ -2259,6 +2259,7 @@
/obj/item/clothing/head/bio_hood/interdyne,
/obj/item/clothing/head/bio_hood/interdyne,
/obj/item/clothing/head/bio_hood/interdyne,
+/obj/item/construction/plumbing/research,
/turf/open/floor/iron/white/textured,
/area/ruin/space/has_grav/deepstorage/xenobiology)
"gu" = (
@@ -2637,7 +2638,6 @@
/obj/effect/turf_decal/stripes{
dir = 8
},
-/obj/machinery/duct,
/turf/open/floor/iron/white/textured,
/area/ruin/space/has_grav/deepstorage/xenobiology)
"kB" = (
@@ -2646,6 +2646,7 @@
},
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/light/directional/south,
+/obj/machinery/duct,
/turf/open/floor/iron/white/textured,
/area/ruin/space/has_grav/deepstorage/xenobiology)
"kE" = (
@@ -2795,6 +2796,7 @@
},
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/structure/cable,
+/obj/machinery/duct,
/turf/open/floor/iron/white/textured,
/area/ruin/space/has_grav/deepstorage/xenobiology)
"sy" = (
@@ -2852,7 +2854,6 @@
/obj/effect/turf_decal/stripes{
dir = 4
},
-/obj/machinery/duct,
/turf/open/floor/iron/white/textured,
/area/ruin/space/has_grav/deepstorage/xenobiology)
"vs" = (
@@ -2908,8 +2909,8 @@
/obj/item/stack/sheet/mineral/plasma/twenty,
/obj/item/stack/sheet/mineral/plasma/twenty,
/obj/item/stack/sheet/mineral/plasma/twenty,
-/obj/item/disk/vacuum_upgrade,
-/obj/item/disk/vacuum_upgrade,
+/obj/item/disk/vacuum_upgrade/biomass,
+/obj/item/disk/vacuum_upgrade/biomass,
/turf/open/floor/iron/white/textured,
/area/ruin/space/has_grav/deepstorage/xenobiology)
"wI" = (
@@ -2988,6 +2989,7 @@
/area/ruin/space/has_grav/deepstorage/xenobiology)
"An" = (
/obj/structure/extinguisher_cabinet/directional/south,
+/obj/machinery/duct,
/turf/open/floor/iron/white/textured,
/area/ruin/space/has_grav/deepstorage/xenobiology)
"Az" = (
diff --git a/_maps/map_files/Blueshift/Blueshift.dmm b/_maps/map_files/Blueshift/Blueshift.dmm
index a95cb5b9546a..1497beddc1b5 100644
--- a/_maps/map_files/Blueshift/Blueshift.dmm
+++ b/_maps/map_files/Blueshift/Blueshift.dmm
@@ -525,6 +525,9 @@
/obj/effect/turf_decal/tile/brown/half/contrasted{
dir = 4
},
+/obj/structure/table/reinforced,
+/obj/machinery/recharger,
+/obj/item/restraints/handcuffs/cable/orange,
/turf/open/floor/iron/dark/side{
dir = 8
},
@@ -20925,7 +20928,7 @@
/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{
cycle_id = "tcomms-internal"
},
-/obj/effect/mapping_helpers/airlock/access/all/engineering/construction,
+/obj/effect/mapping_helpers/airlock/access/all/engineering/tcoms,
/turf/open/floor/iron,
/area/station/tcommsat/computer)
"dYM" = (
@@ -21416,11 +21419,11 @@
/obj/machinery/door/airlock/engineering/glass{
name = "Shared Engineering Storage"
},
-/obj/effect/mapping_helpers/airlock/access/all/engineering/general,
/obj/structure/disposalpipe/segment,
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/effect/mapping_helpers/airlock/access/all/engineering/construction,
/turf/open/floor/iron,
/area/station/engineering/storage_shared)
"eeY" = (
@@ -34005,7 +34008,6 @@
/obj/machinery/door/airlock/engineering/glass{
name = "Engineering Break Room"
},
-/obj/effect/mapping_helpers/airlock/access/all/engineering/general,
/obj/effect/mapping_helpers/airlock/cyclelink_helper{
dir = 1
},
@@ -34013,6 +34015,7 @@
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/effect/mapping_helpers/airlock/access/all/engineering/construction,
/turf/open/floor/iron,
/area/station/engineering/lobby)
"gBa" = (
@@ -34417,10 +34420,9 @@
cycle_id = "tcomms-internal"
},
/obj/machinery/door/firedoor/heavy,
-/obj/effect/mapping_helpers/airlock/access/any/engineering/tcoms,
-/obj/effect/mapping_helpers/airlock/access/any/command/general,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/effect/mapping_helpers/airlock/access/all/engineering/tcoms,
/turf/open/floor/iron,
/area/station/tcommsat/computer)
"gFA" = (
@@ -36719,11 +36721,11 @@
/obj/machinery/door/airlock/engineering/glass{
name = "Shared Engineering Storage"
},
-/obj/effect/mapping_helpers/airlock/access/all/engineering/general,
/obj/structure/disposalpipe/segment,
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/effect/mapping_helpers/airlock/access/all/engineering/construction,
/turf/open/floor/iron,
/area/station/engineering/storage_shared)
"hdL" = (
@@ -43966,7 +43968,6 @@
/obj/machinery/door/airlock/command/glass{
name = "Secure Tools Storage"
},
-/obj/effect/mapping_helpers/airlock/access/all/command/general,
/obj/machinery/door/firedoor,
/obj/machinery/door/poddoor/preopen{
id = "Secure Tool";
@@ -43975,6 +43976,7 @@
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/effect/mapping_helpers/airlock/access/all/command/minisat,
/turf/open/floor/iron,
/area/station/engineering/transit_tube)
"iyE" = (
@@ -49746,13 +49748,13 @@
/obj/machinery/door/airlock/engineering/glass{
name = "Engineering Foyer"
},
-/obj/effect/mapping_helpers/airlock/access/all/engineering/general,
/obj/effect/mapping_helpers/airlock/cyclelink_helper,
/obj/structure/disposalpipe/segment,
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/effect/landmark/navigate_destination,
+/obj/effect/mapping_helpers/airlock/access/all/engineering/construction,
/turf/open/floor/iron,
/area/station/engineering/lobby)
"jGA" = (
@@ -55673,11 +55675,10 @@
/obj/machinery/door/airlock/hatch{
name = "MiniSat Space Access Airlock"
},
-/obj/effect/mapping_helpers/airlock/access/any/command/general,
-/obj/effect/mapping_helpers/airlock/access/any/engineering/construction,
/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{
cycle_id = "AIsatAirlock"
},
+/obj/effect/mapping_helpers/airlock/access/all/command/minisat,
/turf/open/floor/plating,
/area/station/ai_monitored/aisat/exterior)
"kKN" = (
@@ -61507,9 +61508,9 @@
name = "Telecoms Cooling"
},
/obj/machinery/door/firedoor,
-/obj/effect/mapping_helpers/airlock/access/all/engineering/construction,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/effect/mapping_helpers/airlock/access/all/engineering/tcoms,
/turf/open/floor/iron/dark,
/area/station/tcommsat/computer)
"lTC" = (
@@ -61528,6 +61529,11 @@
/area/station/engineering/atmos)
"lTH" = (
/obj/effect/turf_decal/bot,
+/mob/living/basic/pet/poppy,
+/obj/structure/bed/dogbed{
+ anchored = 1;
+ name = "Poppy's bed"
+ },
/turf/open/floor/iron/dark,
/area/station/engineering/supermatter/room)
"lTN" = (
@@ -65234,7 +65240,7 @@
/obj/effect/turf_decal/tile/purple{
dir = 8
},
-/obj/structure/table/reinforced,
+/obj/machinery/computer/security,
/turf/open/floor/iron/dark/side{
dir = 1
},
@@ -66574,7 +66580,6 @@
/obj/structure/extinguisher_cabinet/directional/west,
/mob/living/basic/pet/potty,
/obj/structure/sink/directional/east,
-/obj/machinery/duct,
/turf/open/floor/iron,
/area/station/common/night_club/changing_room)
"mTN" = (
@@ -70043,6 +70048,19 @@
/obj/machinery/airalarm/directional/east,
/turf/open/floor/iron/white,
/area/station/medical/coldroom)
+"nEX" = (
+/obj/machinery/door/airlock/hatch{
+ name = "MiniSat Space Access Airlock"
+ },
+/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{
+ cycle_id = "AIsatAirlock"
+ },
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/effect/mapping_helpers/airlock/access/all/command/minisat,
+/turf/open/floor/plating,
+/area/station/ai_monitored/aisat/exterior)
"nFc" = (
/obj/machinery/door/firedoor/border_only{
dir = 4
@@ -72741,9 +72759,9 @@
/area/station/maintenance/department/crew_quarters/bar)
"ofN" = (
/obj/machinery/newscaster/directional/west,
-/obj/structure/table/reinforced,
-/obj/machinery/recharger,
-/obj/item/restraints/handcuffs/cable/orange,
+/obj/machinery/computer/security{
+ dir = 1
+ },
/turf/open/floor/iron/dark,
/area/station/security/checkpoint/supply)
"ofS" = (
@@ -78236,9 +78254,11 @@
/turf/open/floor/iron,
/area/station/security/prison/workout)
"phZ" = (
-/obj/structure/filingcabinet,
/obj/effect/turf_decal/bot,
/obj/item/radio/intercom/directional/west,
+/obj/machinery/computer/security{
+ dir = 4
+ },
/turf/open/floor/iron/dark,
/area/station/security/checkpoint/engineering)
"pic" = (
@@ -85416,7 +85436,9 @@
/area/station/service/forge)
"qCz" = (
/obj/machinery/firealarm/directional/west,
-/obj/structure/table/reinforced,
+/obj/machinery/computer/security{
+ dir = 4
+ },
/turf/open/floor/iron/dark,
/area/station/security/checkpoint/medical)
"qCC" = (
@@ -89063,8 +89085,7 @@
name = "MiniSat Antechamber"
},
/obj/structure/cable,
-/obj/effect/mapping_helpers/airlock/access/any/command/general,
-/obj/effect/mapping_helpers/airlock/access/any/engineering/construction,
+/obj/effect/mapping_helpers/airlock/access/all/command/minisat,
/turf/open/floor/iron/dark,
/area/station/ai_monitored/turret_protected/aisat_interior)
"rml" = (
@@ -95798,7 +95819,6 @@
/turf/open/floor/plating,
/area/station/engineering/atmos/upper)
"sCJ" = (
-/obj/structure/table/reinforced,
/obj/item/book/manual/wiki/security_space_law,
/obj/item/radio,
/obj/structure/cable,
@@ -95806,6 +95826,7 @@
/obj/effect/turf_decal/tile/brown/half/contrasted{
dir = 4
},
+/obj/structure/table/reinforced,
/turf/open/floor/iron/dark/side{
dir = 8
},
@@ -97095,7 +97116,6 @@
/turf/open/floor/plating/airless,
/area/space/nearstation)
"sOT" = (
-/obj/effect/mapping_helpers/airlock/access/any/engineering/construction,
/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{
cycle_id = "AISATFOYER"
},
@@ -97105,6 +97125,7 @@
},
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/effect/mapping_helpers/airlock/access/all/engineering/construction,
/turf/open/floor/plating,
/area/station/engineering/transit_tube)
"sOV" = (
@@ -102934,8 +102955,7 @@
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/obj/effect/mapping_helpers/airlock/access/any/command/general,
-/obj/effect/mapping_helpers/airlock/access/any/engineering/construction,
+/obj/effect/mapping_helpers/airlock/access/all/command/minisat,
/turf/open/floor/iron/dark,
/area/station/ai_monitored/turret_protected/aisat_interior)
"tTy" = (
@@ -106243,8 +106263,7 @@
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
-/obj/effect/mapping_helpers/airlock/access/any/command/general,
-/obj/effect/mapping_helpers/airlock/access/any/engineering/construction,
+/obj/effect/mapping_helpers/airlock/access/all/command/minisat,
/turf/open/floor/iron/dark,
/area/station/ai_monitored/turret_protected/aisat_interior)
"uAR" = (
@@ -107573,20 +107592,6 @@
/obj/machinery/ntnet_relay,
/turf/open/floor/circuit/telecomms/mainframe,
/area/station/tcommsat/server)
-"uOa" = (
-/obj/machinery/door/airlock/hatch{
- name = "MiniSat Space Access Airlock"
- },
-/obj/effect/mapping_helpers/airlock/access/any/command/general,
-/obj/effect/mapping_helpers/airlock/access/any/engineering/construction,
-/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{
- cycle_id = "AIsatAirlock"
- },
-/obj/structure/cable,
-/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
-/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/turf/open/floor/plating,
-/area/station/ai_monitored/aisat/exterior)
"uOh" = (
/obj/structure/cable,
/turf/open/floor/iron/dark/side,
@@ -107744,10 +107749,10 @@
/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{
cycle_id = "tcomms-internal"
},
-/obj/effect/mapping_helpers/airlock/access/all/engineering/construction,
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/effect/mapping_helpers/airlock/access/all/engineering/tcoms,
/turf/open/floor/iron,
/area/station/tcommsat/computer)
"uQb" = (
@@ -109309,8 +109314,7 @@
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/obj/effect/mapping_helpers/airlock/access/any/command/general,
-/obj/effect/mapping_helpers/airlock/access/any/engineering/construction,
+/obj/effect/mapping_helpers/airlock/access/all/command/ai_upload,
/turf/open/floor/engine,
/area/station/ai_monitored/turret_protected/aisat_interior)
"vfS" = (
@@ -109880,10 +109884,10 @@
name = "MiniSat Transit Tube Access"
},
/obj/structure/cable,
-/obj/effect/mapping_helpers/airlock/access/all/command/minisat,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/effect/landmark/navigate_destination,
+/obj/effect/mapping_helpers/airlock/access/all/command/minisat,
/turf/open/floor/iron,
/area/station/engineering/transit_tube)
"vkG" = (
@@ -117184,9 +117188,7 @@
},
/area/station/security/execution/transfer)
"wCw" = (
-/obj/machinery/camera/directional/south{
- c_tag = "Courtroom - Holding Cell"
- },
+/obj/machinery/camera/directional/north,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/iron/dark,
/area/station/security/courtroom)
@@ -119931,8 +119933,7 @@
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/obj/effect/mapping_helpers/airlock/access/any/command/general,
-/obj/effect/mapping_helpers/airlock/access/any/engineering/construction,
+/obj/effect/mapping_helpers/airlock/access/all/command/minisat,
/turf/open/floor/iron/dark,
/area/station/ai_monitored/turret_protected/aisat_interior)
"xeY" = (
@@ -120119,9 +120120,9 @@
name = "MiniSat Access"
},
/obj/structure/cable,
-/obj/effect/mapping_helpers/airlock/access/all/command/minisat,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/effect/mapping_helpers/airlock/access/all/engineering/construction,
/turf/open/floor/iron,
/area/station/engineering/transit_tube)
"xgS" = (
@@ -120989,11 +120990,11 @@
},
/obj/machinery/door/firedoor,
/obj/effect/landmark/navigate_destination,
-/obj/effect/mapping_helpers/airlock/access/all/engineering/construction,
/obj/structure/disposalpipe/segment,
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/effect/mapping_helpers/airlock/access/all/engineering/tcoms,
/turf/open/floor/iron,
/area/station/tcommsat/computer)
"xqe" = (
@@ -121528,8 +121529,8 @@
/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{
cycle_id = "tcomms-internal"
},
-/obj/effect/mapping_helpers/airlock/access/all/engineering/construction,
/obj/structure/cable,
+/obj/effect/mapping_helpers/airlock/access/all/engineering/tcoms,
/turf/open/floor/iron,
/area/station/tcommsat/computer)
"xuJ" = (
@@ -220903,7 +220904,7 @@ gLc
gLc
gLc
tQB
-uOa
+nEX
mcW
kKI
xya
@@ -221417,7 +221418,7 @@ gLc
gLc
gLc
tQB
-uOa
+nEX
mPm
kKI
hKn
diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index 68e4b5935c3f..5a1300bf4906 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -1650,6 +1650,7 @@
/obj/structure/cable,
/obj/machinery/holopad,
/obj/machinery/duct,
+/mob/living/basic/bot/cleanbot/medbay,
/turf/open/floor/iron/white/smooth_large,
/area/station/medical/storage)
"aBj" = (
@@ -60852,14 +60853,12 @@
/area/station/engineering/break_room)
"tQC" = (
/obj/effect/turf_decal/trimline/yellow/filled/warning,
-/obj/structure/disposalpipe/sorting/mail/flip{
- dir = 1
- },
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/structure/cable,
/obj/machinery/duct,
/obj/effect/mapping_helpers/mail_sorting/engineering/general,
+/obj/structure/disposalpipe/sorting/mail,
/turf/open/floor/iron/dark/side,
/area/station/engineering/break_room)
"tQD" = (
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index b231ec1a3dd2..b472196814c8 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -17763,6 +17763,7 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/effect/spawner/random/engineering/tracking_beacon,
/obj/effect/turf_decal/tile/blue/fourcorners,
+/mob/living/basic/bot/cleanbot/medbay,
/turf/open/floor/iron,
/area/station/medical/storage)
"eiK" = (
@@ -34948,6 +34949,11 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/effect/decal/cleanable/dirt,
/obj/machinery/light/small/directional/north,
+/obj/structure/bed/dogbed{
+ anchored = 1;
+ name = "Poppy's bed"
+ },
+/mob/living/basic/pet/poppy,
/turf/open/floor/iron,
/area/station/engineering/supermatter/room)
"ikx" = (
diff --git a/_maps/map_files/Graveyard/Graveyard.dmm b/_maps/map_files/Graveyard/Graveyard.dmm
index 656dc0e33c9a..0846e2c50b33 100644
--- a/_maps/map_files/Graveyard/Graveyard.dmm
+++ b/_maps/map_files/Graveyard/Graveyard.dmm
@@ -17052,7 +17052,6 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{
dir = 1
},
-/obj/machinery/duct,
/turf/open/floor/iron/grimy,
/area/ruin/syndicate_lava_base)
"gEx" = (
@@ -25736,8 +25735,6 @@
/obj/structure/cable/multilayer/connected,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
-/obj/structure/cable/layer3,
-/obj/structure/cable,
/turf/open/floor/plating,
/area/station/maintenance/port/fore)
"kbt" = (
@@ -27229,6 +27226,11 @@
/obj/effect/spawner/random/trash/cigbutt,
/turf/open/floor/plating,
/area/station/maintenance/starboard/central)
+"kFj" = (
+/obj/machinery/duct,
+/obj/machinery/light/floor/has_bulb,
+/turf/open/floor/iron/white,
+/area/station/science/xenobiology)
"kFp" = (
/obj/machinery/atmospherics/pipe/smart/manifold/purple/visible{
dir = 1
@@ -27805,7 +27807,6 @@
/area/station/maintenance/aft)
"kQn" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/obj/machinery/duct,
/obj/structure/sink/directional/east,
/turf/open/floor/iron/white,
/area/graveyard/bunker/medical)
@@ -50815,7 +50816,6 @@
req_access = list("xenobiology");
pixel_x = -24
},
-/obj/machinery/light/floor/has_bulb,
/turf/open/floor/iron/white,
/area/station/science/xenobiology)
"tNd" = (
@@ -122384,7 +122384,7 @@ dKV
emY
raD
jvq
-lLz
+kFj
lLz
pmj
sQT
diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
index 9553433c5639..88eb84cb29eb 100644
--- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm
+++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
@@ -44232,6 +44232,11 @@
/area/station/security/prison/safe)
"nXl" = (
/obj/effect/turf_decal/bot,
+/mob/living/basic/pet/poppy,
+/obj/structure/bed/dogbed{
+ anchored = 1;
+ name = "Poppy's bed"
+ },
/turf/open/floor/iron/dark,
/area/station/engineering/supermatter/room)
"nXn" = (
@@ -68339,6 +68344,7 @@
dir = 8
},
/obj/effect/landmark/event_spawn,
+/mob/living/basic/bot/cleanbot/medbay,
/turf/open/floor/iron/white,
/area/station/medical/storage)
"vQQ" = (
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index f8ceb07fca11..bf56aa214935 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -975,7 +975,7 @@
/turf/open/floor/iron/grimy,
/area/station/tcommsat/computer)
"arW" = (
-/obj/machinery/light/floor,
+/obj/machinery/light/floor/has_bulb,
/turf/open/floor/wood,
/area/station/commons/lounge)
"ase" = (
@@ -10067,7 +10067,7 @@
/obj/effect/turf_decal/siding/wood{
dir = 1
},
-/obj/machinery/light/floor,
+/obj/machinery/light/floor/has_bulb,
/turf/open/floor/wood/large,
/area/station/commons/lounge)
"dJK" = (
@@ -16326,7 +16326,7 @@
/obj/effect/turf_decal/siding/wood{
dir = 1
},
-/obj/machinery/light/floor,
+/obj/machinery/light/floor/has_bulb,
/turf/open/floor/wood/large,
/area/station/commons/lounge)
"fTE" = (
@@ -34062,7 +34062,6 @@
req_access = list("xenobiology");
pixel_x = -24
},
-/obj/machinery/light/floor/has_bulb,
/turf/open/floor/iron/white,
/area/station/science/xenobiology)
"lOZ" = (
@@ -38402,7 +38401,7 @@
/area/station/security/office)
"nlu" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
-/obj/machinery/light/floor,
+/obj/machinery/light/floor/has_bulb,
/turf/open/floor/wood,
/area/station/commons/lounge)
"nlL" = (
@@ -38933,7 +38932,7 @@
/obj/effect/turf_decal/siding/wood{
dir = 1
},
-/obj/machinery/light/floor,
+/obj/machinery/light/floor/has_bulb,
/turf/open/floor/wood,
/area/station/commons/lounge)
"ntk" = (
@@ -43662,6 +43661,11 @@
},
/turf/open/floor/iron/white,
/area/station/medical/chemistry)
+"pbB" = (
+/obj/machinery/duct,
+/obj/machinery/light/floor/has_bulb,
+/turf/open/floor/iron/white,
+/area/station/science/xenobiology)
"pbL" = (
/obj/machinery/door/firedoor,
/turf/open/floor/iron/white/side,
@@ -58794,7 +58798,7 @@
/area/station/security/prison/mess)
"umP" = (
/obj/structure/window/spawner/directional/west,
-/obj/machinery/light/floor,
+/obj/machinery/light/floor/has_bulb,
/turf/open/floor/carpet,
/area/station/service/theater)
"umS" = (
@@ -118451,7 +118455,7 @@ mtu
vHm
fHs
ycv
-kCw
+pbB
kCw
gRY
xCA
diff --git a/_maps/map_files/Theseus/Theseus.dmm b/_maps/map_files/Theseus/Theseus.dmm
index 903ce6488894..fc976b3b6858 100644
--- a/_maps/map_files/Theseus/Theseus.dmm
+++ b/_maps/map_files/Theseus/Theseus.dmm
@@ -459,7 +459,6 @@
/obj/item/radio/radio_mic{
pixel_y = 7
},
-/obj/machinery/light/floor/has_bulb/warm,
/obj/structure/cable,
/turf/open/floor/carpet/green,
/area/station/service/library/upper)
@@ -2325,6 +2324,7 @@
},
/obj/structure/sink/directional/south,
/obj/effect/turf_decal/bot,
+/obj/machinery/light/floor/has_bulb,
/turf/open/floor/iron/white/textured_edge{
dir = 1
},
@@ -4253,7 +4253,6 @@
/obj/effect/mapping_helpers/airlock/cyclelink_helper,
/obj/effect/mapping_helpers/airlock/access/all/service/theatre,
/obj/structure/cable,
-/obj/machinery/light/floor/has_bulb,
/obj/machinery/door/firedoor,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -4428,7 +4427,6 @@
"bqt" = (
/obj/structure/table/reinforced,
/obj/effect/turf_decal/tile/gray/fourcorners,
-/obj/machinery/light/floor/red,
/obj/item/storage/pill_bottle/lsdpsych{
pixel_y = 12;
name = "Emesis Diazepam"
@@ -8301,6 +8299,7 @@
"cxX" = (
/obj/effect/landmark/event_spawn,
/obj/structure/disposalpipe/segment,
+/obj/machinery/light/floor/has_bulb,
/turf/open/floor/iron/grimy,
/area/station/service/library)
"cya" = (
@@ -8591,7 +8590,6 @@
/area/station/engineering/break_room)
"cBi" = (
/obj/structure/bookcase/random/reference,
-/obj/machinery/light/floor/has_bulb,
/turf/open/floor/wood,
/area/station/service/library)
"cBm" = (
@@ -12365,6 +12363,7 @@
/area/station/hallway/primary/starboard)
"dIf" = (
/obj/structure/cable,
+/obj/machinery/light/floor/has_bulb,
/turf/open/floor/carpet,
/area/station/service/cafeteria)
"dIl" = (
@@ -13003,7 +13002,6 @@
/obj/item/reagent_containers/condiment/saltshaker{
pixel_x = -3
},
-/obj/machinery/light/floor/has_bulb,
/obj/machinery/door/firedoor,
/turf/open/floor/carpet,
/area/station/service/bar)
@@ -19913,7 +19911,6 @@
dir = 1
},
/obj/effect/mapping_helpers/airlock/access/all/security/brig,
-/obj/machinery/light/floor/has_bulb,
/turf/open/floor/plating,
/area/station/security/processing)
"fXf" = (
@@ -20226,6 +20223,11 @@
},
/turf/open/floor/engine,
/area/station/science/xenobiology)
+"gbR" = (
+/obj/structure/cable,
+/obj/machinery/light/floor/has_bulb/warm,
+/turf/open/floor/carpet/green,
+/area/station/service/library/upper)
"gbV" = (
/obj/effect/turf_decal/tile/yellow/half{
dir = 1
@@ -22330,11 +22332,6 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron,
/area/station/hallway/primary/central/fore)
-"gJm" = (
-/obj/structure/bookcase/random/nonfiction,
-/obj/machinery/light/floor/has_bulb,
-/turf/open/floor/iron/grimy,
-/area/station/service/library)
"gJn" = (
/obj/structure/lattice/catwalk,
/obj/item/bodypart/arm/right,
@@ -23812,7 +23809,6 @@
/turf/open/floor/plating,
/area/station/command/heads_quarters/hos)
"heQ" = (
-/obj/machinery/duct,
/obj/structure/reagent_dispensers/plumbed,
/turf/open/floor/plating,
/area/station/maintenance/solars/port/fore)
@@ -25223,6 +25219,7 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/structure/disposalpipe/segment,
+/obj/machinery/light/floor/has_bulb,
/turf/open/floor/carpet,
/area/station/service/cafeteria)
"hAQ" = (
@@ -26240,7 +26237,6 @@
/obj/structure/mirror/directional/north{
pixel_y = 30
},
-/obj/machinery/duct,
/turf/open/floor/iron/showroomfloor,
/area/station/commons/dorms)
"hRr" = (
@@ -26309,7 +26305,6 @@
/obj/effect/mapping_helpers/airlock/access/all/service/theatre,
/obj/structure/cable,
/obj/effect/landmark/navigate_destination/common/theatrebackstage,
-/obj/machinery/light/floor/has_bulb,
/obj/machinery/door/firedoor,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -32981,7 +32976,6 @@
/obj/item/surgical_drapes,
/obj/effect/decal/cleanable/blood,
/obj/effect/landmark/start/hangover,
-/obj/machinery/light/floor/has_bulb,
/obj/structure/drain/big,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
@@ -34007,7 +34001,6 @@
/obj/structure/table/optable,
/obj/item/surgical_drapes,
/obj/effect/landmark/start/hangover,
-/obj/machinery/light/floor/has_bulb,
/obj/structure/drain/big,
/turf/open/floor/iron/dark,
/area/station/medical/treatment_center)
@@ -38707,6 +38700,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 8
},
+/obj/machinery/light/floor/has_bulb,
/turf/open/floor/plating,
/area/station/security/processing)
"ltX" = (
@@ -47030,6 +47024,10 @@
"nTC" = (
/turf/open/floor/iron,
/area/station/security/office)
+"nTD" = (
+/obj/machinery/light/floor/has_bulb,
+/turf/open/floor/iron/grimy,
+/area/station/service/library)
"nTE" = (
/obj/machinery/computer/warrant,
/obj/effect/turf_decal/bot,
@@ -51853,7 +51851,6 @@
/area/station/security/checkpoint/escape)
"prO" = (
/obj/structure/bookcase/random/nonfiction,
-/obj/machinery/light/floor/has_bulb,
/obj/structure/disposalpipe/segment{
dir = 4
},
@@ -54540,7 +54537,6 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{
dir = 8
},
-/obj/machinery/duct,
/turf/open/floor/iron/showroomfloor,
/area/station/commons)
"qhb" = (
@@ -55981,6 +55977,13 @@
/obj/machinery/door/firedoor,
/turf/open/floor/carpet,
/area/station/service/bar)
+"qBj" = (
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/machinery/light/floor/has_bulb,
+/turf/open/floor/iron/dark,
+/area/station/service/theater)
"qBx" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/structure/cable,
@@ -58824,6 +58827,7 @@
/obj/effect/turf_decal/caution/stand_clear{
dir = 4
},
+/obj/machinery/light/floor/has_bulb,
/turf/open/floor/plating,
/area/station/security/processing)
"rrO" = (
@@ -58889,6 +58893,7 @@
/area/station/service/library)
"rsF" = (
/obj/machinery/iv_drip,
+/obj/machinery/light/floor/has_bulb,
/turf/open/floor/iron/dark,
/area/station/medical/treatment_center)
"rsL" = (
@@ -66348,7 +66353,6 @@
dir = 8
},
/obj/structure/sink/directional/south,
-/obj/machinery/duct,
/turf/open/floor/iron/white/textured,
/area/station/security/medical)
"tAh" = (
@@ -68831,6 +68835,7 @@
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/machinery/light/floor/has_bulb,
/turf/open/floor/wood,
/area/station/service/theater)
"ukt" = (
@@ -78112,7 +78117,6 @@
/obj/machinery/door/airlock/external{
name = "Gulag Shuttle Airlock"
},
-/obj/machinery/light/floor/has_bulb,
/turf/open/floor/plating,
/area/station/security/processing)
"wTF" = (
@@ -81835,6 +81839,7 @@
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/machinery/light/floor/has_bulb,
/turf/open/floor/eighties/red{
icon = 'goon/icons/turf/floors.dmi';
icon_state = "clown_carpet"
@@ -88742,7 +88747,7 @@ fel
mux
saq
ikP
-iRD
+gbR
azt
agO
mux
@@ -109408,7 +109413,7 @@ uGY
gck
prO
bwX
-gJm
+bwX
gck
umk
tyv
@@ -110178,7 +110183,7 @@ svf
ifR
iMW
fwA
-iLO
+nTD
aaT
ttd
vnu
@@ -121446,10 +121451,10 @@ bTD
ofY
ukm
bli
+qBj
rJj
rJj
-rJj
-rJj
+qBj
hSn
xYR
vjd
diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm
index e3e238f4627c..0eb60baf8bab 100644
--- a/_maps/map_files/tramstation/tramstation.dmm
+++ b/_maps/map_files/tramstation/tramstation.dmm
@@ -13742,6 +13742,10 @@
"dkO" = (
/turf/open/floor/iron,
/area/station/security/brig)
+"dkU" = (
+/mob/living/basic/bot/cleanbot/medbay,
+/turf/open/floor/iron/dark,
+/area/station/medical/treatment_center)
"dlb" = (
/obj/machinery/bluespace_beacon,
/obj/effect/turf_decal/trimline/yellow/filled/warning,
@@ -44027,6 +44031,15 @@
/obj/effect/turf_decal/sand/plating,
/turf/open/floor/catwalk_floor,
/area/station/solars/starboard/fore)
+"mJO" = (
+/obj/structure/table,
+/obj/machinery/duct,
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/item/radio/intercom/prison,
+/turf/open/floor/iron,
+/area/station/security/prison)
"mKe" = (
/obj/machinery/door/airlock/external{
name = "Solar Maintenance"
@@ -70907,7 +70920,6 @@
/area/station/maintenance/starboard/central)
"vcp" = (
/obj/structure/curtain,
-/obj/machinery/shower/directional/north,
/obj/machinery/duct,
/turf/open/floor/iron/freezer,
/area/station/commons/toilet)
@@ -80671,12 +80683,13 @@
/area/station/commons/fitness/recreation)
"yho" = (
/obj/structure/table,
-/obj/item/radio/intercom/prison,
/obj/machinery/duct,
-/obj/machinery/light/floor/has_bulb,
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/item/flashlight/lamp{
+ pixel_y = 7
+ },
/turf/open/floor/iron,
/area/station/security/prison)
"yhN" = (
@@ -99413,7 +99426,7 @@ cVl
fdr
tPb
yho
-oiF
+mJO
fdr
fdr
cCD
@@ -178627,7 +178640,7 @@ ecW
dXo
lTc
lrQ
-xOn
+dkU
gHp
dHv
xSZ
diff --git a/_maps/~monkestation/RandomEngines/BoxStation/supermatter.dmm b/_maps/~monkestation/RandomEngines/BoxStation/supermatter.dmm
index ef45726f6dc0..dfeff3080f4f 100644
--- a/_maps/~monkestation/RandomEngines/BoxStation/supermatter.dmm
+++ b/_maps/~monkestation/RandomEngines/BoxStation/supermatter.dmm
@@ -173,6 +173,15 @@
/obj/machinery/firealarm/directional/south,
/turf/open/floor/engine,
/area/station/engineering/supermatter/room)
+"eO" = (
+/obj/effect/turf_decal/bot,
+/mob/living/basic/pet/poppy,
+/obj/structure/bed/dogbed{
+ anchored = 1;
+ name = "Poppy's bed"
+ },
+/turf/open/floor/iron/dark/smooth_large,
+/area/station/engineering/supermatter/room)
"fc" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/green/visible,
/turf/closed/wall/r_wall,
@@ -1992,7 +2001,7 @@ Qi
TL
IC
hr
-YW
+eO
HS
ze
EI
diff --git a/_maps/~monkestation/RandomEngines/MetaStation/supermatter.dmm b/_maps/~monkestation/RandomEngines/MetaStation/supermatter.dmm
index 709c3188563d..8090eab80404 100644
--- a/_maps/~monkestation/RandomEngines/MetaStation/supermatter.dmm
+++ b/_maps/~monkestation/RandomEngines/MetaStation/supermatter.dmm
@@ -818,6 +818,17 @@
/obj/effect/spawner/structure/window/reinforced/plasma,
/turf/open/floor/plating,
/area/station/engineering/supermatter)
+"NK" = (
+/obj/effect/turf_decal/bot{
+ dir = 1
+ },
+/mob/living/basic/pet/poppy,
+/obj/structure/bed/dogbed{
+ anchored = 1;
+ name = "Poppy's bed"
+ },
+/turf/open/floor/iron/dark,
+/area/station/engineering/supermatter/room)
"NN" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/visible,
@@ -1205,7 +1216,7 @@ wE
yn
SK
Qn
-nu
+NK
nu
UI
GH
diff --git a/_maps/~monkestation/RandomEngines/TramStation/supermatter.dmm b/_maps/~monkestation/RandomEngines/TramStation/supermatter.dmm
index 1ee0b187e9ad..479d17a6e334 100644
--- a/_maps/~monkestation/RandomEngines/TramStation/supermatter.dmm
+++ b/_maps/~monkestation/RandomEngines/TramStation/supermatter.dmm
@@ -93,7 +93,6 @@
dir = 10;
network = list("ss13","engine","engineering")
},
-/obj/machinery/incident_display/delam/directional/south,
/turf/open/floor/engine,
/area/station/engineering/supermatter)
"fo" = (
@@ -314,6 +313,7 @@
/obj/machinery/atmospherics/components/binary/pump{
name = "Gas to Chamber"
},
+/obj/machinery/incident_display/delam/directional/south,
/turf/open/floor/engine,
/area/station/engineering/supermatter)
"lv" = (
@@ -806,6 +806,11 @@
/area/station/engineering/supermatter/room)
"Fs" = (
/obj/effect/turf_decal/bot,
+/obj/structure/bed/dogbed{
+ anchored = 1;
+ name = "Poppy's bed"
+ },
+/mob/living/basic/pet/poppy,
/turf/open/floor/engine,
/area/station/engineering/supermatter/room)
"FF" = (
diff --git a/code/__DEFINES/~monkestation/dcs/signals/signals_global.dm b/code/__DEFINES/~monkestation/dcs/signals/signals_global.dm
index d090af76972c..7505478a365c 100644
--- a/code/__DEFINES/~monkestation/dcs/signals/signals_global.dm
+++ b/code/__DEFINES/~monkestation/dcs/signals/signals_global.dm
@@ -1,2 +1,4 @@
/// Sent whenever a new goldeneye key is spawned: (obj/item/goldeneye_key)
#define COMSIG_GLOB_GOLDENEYE_KEY_CREATED "!goldeneye_key_created"
+/// Sent whenever a camera network broadcast is started/stopped/updated: (camera_net, is_show_active, announcement)
+#define COMSIG_GLOB_NETWORK_BROADCAST_UPDATED "!network_broadcast_updated"
diff --git a/code/__DEFINES/~monkestation/hud.dm b/code/__DEFINES/~monkestation/hud.dm
new file mode 100644
index 000000000000..d423dd120691
--- /dev/null
+++ b/code/__DEFINES/~monkestation/hud.dm
@@ -0,0 +1 @@
+#define ui_more_under_health_and_to_the_left "EAST-2:14,CENTER-5:29"
diff --git a/code/controllers/configuration/entries/monkestation.dm b/code/controllers/configuration/entries/monkestation.dm
index c49237131fec..988fae0853c4 100644
--- a/code/controllers/configuration/entries/monkestation.dm
+++ b/code/controllers/configuration/entries/monkestation.dm
@@ -62,3 +62,13 @@
. = ..()
if(.)
config_entry_value *= 600 // documented as minutes
+
+/datum/config_entry/flag/plexora_enabled
+
+/datum/config_entry/string/plexora_url
+ default = "http://127.0.0.1:1330"
+
+/datum/config_entry/string/plexora_url/ValidateAndSet(str_val)
+ if(!findtext(str_val, GLOB.is_http_protocol))
+ return FALSE
+ return ..()
diff --git a/code/datums/martial/cqc.dm b/code/datums/martial/cqc.dm
index e982f6488de0..bd81b07a38e5 100644
--- a/code/datums/martial/cqc.dm
+++ b/code/datums/martial/cqc.dm
@@ -32,17 +32,16 @@
return
// monkestation edit: improved messaging
cqc_user.visible_message(
- span_danger("[cqc_user] twists [attacker]'s arm, sending their [attack_weapon] back towards them!"),
- span_userdanger("Making sure to avoid [attacker]'s [attack_weapon], you twist their arm to send it right back at them!"),
+ span_danger("[cqc_user] twists [attacker]'s arm, sending [attacker.p_their()] [attack_weapon] back towards [attacker.p_them()]!"),
+ span_userdanger("Making sure to avoid [attacker]'s [attack_weapon], you twist [attacker.p_their()] arm to send it right back at [attacker.p_them()]!"),
ignored_mobs = list(attacker),
)
to_chat(attacker, span_userdanger("[cqc_user] swiftly grabs and twists your arm, hitting you with your own [attack_weapon]!"), type = MESSAGE_TYPE_COMBAT)
// monkestation end
var/obj/item/melee/touch_attack/touch_weapon = attack_weapon
var/datum/action/cooldown/spell/touch/touch_spell = touch_weapon.spell_which_made_us?.resolve()
- if(!touch_spell)
- return
- INVOKE_ASYNC(touch_spell, TYPE_PROC_REF(/datum/action/cooldown/spell/touch, do_hand_hit), touch_weapon, attacker, attacker)
+ if(touch_spell)
+ INVOKE_ASYNC(touch_spell, TYPE_PROC_REF(/datum/action/cooldown/spell/touch, do_hand_hit), touch_weapon, attacker, attacker)
return COMPONENT_NO_AFTERATTACK
/datum/martial_art/cqc/reset_streak(mob/living/new_target)
@@ -242,7 +241,7 @@
if(prob(65))
if(!defender.stat || !defender.IsParalyzed() || !restraining_mob)
held_item = defender.get_active_held_item()
- defender.visible_message(span_danger("[attacker] strikes [defender]'s jaw with their hand!"), \
+ defender.visible_message(span_danger("[attacker] strikes [defender]'s jaw with [attacker.p_their()] hand!"), \
span_userdanger("Your jaw is struck by [attacker], you feel disoriented!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker)
to_chat(attacker, span_danger("You strike [defender]'s jaw, leaving [defender.p_them()] disoriented!"))
playsound(get_turf(defender), 'sound/weapons/cqchit1.ogg', 50, TRUE, -1)
diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm
index 56bd900fdf8d..4279e8d08dc4 100644
--- a/code/datums/martial/sleeping_carp.dm
+++ b/code/datums/martial/sleeping_carp.dm
@@ -13,7 +13,7 @@
var/deflect_cooldown = 3 SECONDS //monke edit start
var/deflect_stamcost = 15 //how much stamina it costs per bullet deflected
var/log_name = "Sleeping Carp"
- var/damage = 0
+ var/damage = 20
var/kick_speed = 0 //how fast you get punted into the stratosphere on launchkick
var/wounding = 0 //whether or not you get wounded by the attack
var/zone_message = "" //string for where the attack is targetting
@@ -52,31 +52,41 @@
return FALSE
///Gnashing Teeth: Harm Harm, consistent 20 force punch on every second harm punch
-/datum/martial_art/the_sleeping_carp/proc/strongPunch(mob/living/attacker, mob/living/defender)
- damage = 20
- wounding = 0
+/datum/martial_art/the_sleeping_carp/proc/strongPunch(mob/living/attacker, mob/living/defender, set_damage = TRUE)
+ if(set_damage)
+ damage = 20
+ wounding = 0
///this var is so that the strong punch is always aiming for the body part the user is targeting and not trying to apply to the chest before deviating
var/obj/item/bodypart/affecting = defender.get_bodypart(defender.get_random_valid_zone(attacker.zone_selected))
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
var/atk_verb = pick("precisely kick", "brutally chop", "cleanly hit", "viciously slam")
- defender.visible_message(span_danger("[attacker] [atk_verb]s [defender]!"), \
- span_userdanger("[attacker] [atk_verb]s you!"), null, null, attacker)
+ defender.visible_message(
+ span_danger("[attacker] [atk_verb]s [defender]!"),
+ span_userdanger("[attacker] [atk_verb]s you!"),
+ ignored_mobs = attacker
+ )
to_chat(attacker, span_danger("You [atk_verb] [defender]!"))
playsound(defender, 'sound/weapons/punch1.ogg', vol = 25, vary = TRUE, extrarange = -1)
log_combat(attacker, defender, "strong punched ([log_name])") //monke edit
defender.apply_damage(damage, attacker.get_attack_type(), affecting, wound_bonus = wounding)
- return
///Crashing Wave Kick: Harm Disarm combo, throws people seven tiles backwards
-/datum/martial_art/the_sleeping_carp/proc/launchKick(mob/living/attacker, mob/living/defender)
- damage = 15 //monke edit start
- kick_speed = 4
- wounding = CANT_WOUND
- zone_message = "chest"
- zone = BODY_ZONE_CHEST
+/datum/martial_art/the_sleeping_carp/proc/launchKick(mob/living/attacker, mob/living/defender, set_damage = TRUE)
+ //monke edit start
+ if(set_damage)
+ damage = 15
+ kick_speed = 4
+ wounding = CANT_WOUND
+ zone_message = "chest"
+ zone = BODY_ZONE_CHEST
attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK)
- defender.visible_message(span_warning("[attacker] kicks [defender] square in the [zone_message], sending them flying!"), \
- span_userdanger("You are kicked square in the [zone_message] by [attacker], sending you flying!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker)
+ defender.visible_message(
+ span_warning("[attacker] kicks [defender] square in the [zone_message], sending [defender.p_them()] flying!"),
+ span_userdanger("You are kicked square in the [zone_message] by [attacker], sending you flying!"),
+ span_hear("You hear a sickening sound of flesh hitting flesh!"),
+ vision_distance = COMBAT_MESSAGE_RANGE,
+ ignored_mobs = attacker,
+ )
playsound(get_turf(attacker), 'sound/effects/hit_kick.ogg', vol = 50, vary = TRUE, extrarange = -1)
var/atom/throw_target = get_edge_target_turf(defender, attacker.dir)
defender.throw_at(throw_target, 7, kick_speed, attacker)
@@ -85,24 +95,30 @@
return
///Keelhaul: Disarm Disarm combo, knocks people down and deals substantial stamina damage, and also discombobulates them. Knocks objects out of their hands if they're already on the ground.
-/datum/martial_art/the_sleeping_carp/proc/dropKick(mob/living/attacker, mob/living/defender)
- stamina_damage = 100 //monke edit start
+/datum/martial_art/the_sleeping_carp/proc/dropKick(mob/living/attacker, mob/living/defender, set_damage = TRUE)
+ //monke edit start
+ if(set_damage)
+ stamina_damage = 100
attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK)
playsound(get_turf(attacker), 'sound/effects/hit_kick.ogg', vol = 50, vary = TRUE, extrarange = -1)
if(defender.body_position == STANDING_UP)
defender.Knockdown(2 SECONDS)
defender.visible_message(
- span_warning("[attacker] kicks [defender] in the head, sending them face first into the floor!"),
+ span_warning("[attacker] kicks [defender] in the head, sending [defender.p_them()] face first into the floor!"),
span_userdanger("You are kicked in the head by [attacker], sending you crashing to the floor!"),
- span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker
- )
+ span_hear("You hear a sickening sound of flesh hitting flesh!"),
+ vision_distance = COMBAT_MESSAGE_RANGE,
+ ignored_mobs = attacker,
+ )
else
defender.drop_all_held_items()
defender.visible_message(
span_warning("[attacker] kicks [defender] in the head!"),
span_userdanger("You are kicked in the head by [attacker]!"),
- span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker
- )
+ span_hear("You hear a sickening sound of flesh hitting flesh!"),
+ vision_distance = COMBAT_MESSAGE_RANGE,
+ ignored_mobs = attacker,
+ )
defender.stamina.adjust(stamina_damage)
defender.adjust_dizzy_up_to(10 SECONDS, 10 SECONDS)
defender.adjust_temp_blindness_up_to(2 SECONDS, 10 SECONDS)
@@ -121,7 +137,7 @@
playsound(defender, 'sound/weapons/punch1.ogg', vol = 25, vary = TRUE, extrarange = -1)
if(defender.stat != DEAD && !defender.IsUnconscious() && defender.stamina.current <= 50) //We put our target to sleep.
defender.visible_message(
- span_danger("[attacker] carefully pinch a nerve in [defender]'s neck, knocking them out cold"),
+ span_danger("[attacker] carefully pinch a nerve in [defender]'s neck, knocking [defender.p_them()] out cold"),
span_userdanger("[attacker] pinches something in your neck, and you fall unconscious!"),
)
grab_log_description = "grabbed and nerve pinched"
@@ -143,9 +159,9 @@
span_danger("[attacker] snaps the neck of [defender]!"),
span_userdanger("Your neck is snapped by [attacker]!"),
span_hear("You hear a sickening snap!"),
- ignored_mobs = attacker
+ ignored_mobs = attacker,
)
- to_chat(attacker, span_danger("In a swift motion, you snap the neck of [defender]!"))
+ to_chat(attacker, span_danger("In a swift motion, you snap the neck of [defender]!"), type = MESSAGE_TYPE_COMBAT)
log_combat(attacker, defender, "snapped neck")
defender.apply_damage(100, BRUTE, BODY_ZONE_HEAD, wound_bonus=CANT_WOUND)
if(!HAS_TRAIT(defender, TRAIT_NODEATH))
@@ -164,7 +180,7 @@
span_danger("[attacker] [atk_verb]s [defender]!"),
span_userdanger("[attacker] [atk_verb]s you!"), null, null, attacker
)
- to_chat(attacker, span_danger("You [atk_verb] [defender]!"))
+ to_chat(attacker, span_danger("You [atk_verb] [defender]!"), type = MESSAGE_TYPE_COMBAT)
defender.apply_damage(rand(10,15), attacker.get_attack_type(), affecting, wound_bonus = CANT_WOUND)
playsound(defender, 'sound/weapons/punch1.ogg', 25, TRUE, -1)
@@ -186,12 +202,12 @@
return ..()
-/datum/martial_art/the_sleeping_carp/proc/can_deflect(mob/living/carp_user)
+/datum/martial_art/the_sleeping_carp/proc/can_deflect(mob/living/carp_user, check_intent = TRUE)
if(!COOLDOWN_FINISHED(src, block_cooldown)) //monke edit
return FALSE
if(!can_use(carp_user))
return FALSE
- if(!(carp_user.istate & ISTATE_HARM)) // monke edit: istates/intents
+ if(check_intent && !(carp_user.istate & ISTATE_HARM)) // monke edit: istates/intents
return FALSE
if(carp_user.incapacitated(IGNORE_GRAB)) //NO STUN
return FALSE
@@ -222,10 +238,11 @@
return COMPONENT_BULLET_PIERCED
///Signal from getting attacked with an item, for a special interaction with touch spells
-/datum/martial_art/the_sleeping_carp/proc/on_attackby(mob/living/carbon/human/carp_user, obj/item/attack_weapon, mob/attacker, params) //no signal handler or this proc will explode
- if(!istype(attack_weapon, /obj/item/melee/touch_attack) || !can_deflect(carp_user))
+/datum/martial_art/the_sleeping_carp/proc/on_attackby(mob/living/carbon/human/carp_user, obj/item/melee/touch_attack/touch_weapon, mob/attacker, params)
+ SIGNAL_HANDLER
+
+ if(!istype(touch_weapon) || !can_deflect(carp_user, check_intent = !touch_weapon.dangerous))
return
- var/obj/item/melee/touch_attack/touch_weapon = attack_weapon
var/datum/action/cooldown/spell/touch/touch_spell = touch_weapon.spell_which_made_us?.resolve()
// monkestation edit: flavor tweaks
if(!counter)
@@ -239,15 +256,15 @@
playsound(carp_user, 'monkestation/sound/effects/miss.ogg', vol = 50, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE)
else
carp_user.visible_message(
- span_danger("[carp_user] twists [attacker]'s arm, sending their [attack_weapon] back towards them!"),
- span_userdanger("Making sure to avoid [attacker]'s [attack_weapon], you twist their arm to send it right back at them!"),
- ignored_mobs = list(attacker),
- )
- to_chat(attacker, span_userdanger("[carp_user] swiftly grabs and twists your arm, hitting you with your own [attack_weapon]!"), type = MESSAGE_TYPE_COMBAT)
- carp_user.say(message = "PATHETIC!", language = /datum/language/common, ignore_spam = TRUE, forced = src)
- if(!touch_spell)
- return
- INVOKE_ASYNC(touch_spell, TYPE_PROC_REF(/datum/action/cooldown/spell/touch, do_hand_hit), touch_weapon, attacker, attacker)
+ span_danger("[carp_user] twists [attacker]'s arm, sending [attacker.p_their()] [touch_weapon] back towards [attacker.p_them()]!"),
+ span_userdanger("Making sure to avoid [attacker]'s [touch_weapon], you twist [attacker.p_their()] arm to send it right back at [attacker.p_them()]!"),
+ ignored_mobs = list(attacker),
+ )
+ to_chat(attacker, span_userdanger("[carp_user] swiftly grabs and twists your arm, hitting you with your own [touch_weapon]!"), type = MESSAGE_TYPE_COMBAT)
+ INVOKE_ASYNC(carp_user, TYPE_PROC_REF(/atom/movable, say), message = "PATHETIC!", language = /datum/language/common, ignore_spam = TRUE, forced = src)
+ if(touch_spell)
+ INVOKE_ASYNC(touch_spell, TYPE_PROC_REF(/datum/action/cooldown/spell/touch, do_hand_hit), touch_weapon, attacker, attacker)
+ attacker.changeNext_move(CLICK_CD_MELEE)
// monkestation end
return COMPONENT_NO_AFTERATTACK
diff --git a/code/datums/quirks/_quirk.dm b/code/datums/quirks/_quirk.dm
index b470ad4d4f48..e685c0236934 100644
--- a/code/datums/quirks/_quirk.dm
+++ b/code/datums/quirks/_quirk.dm
@@ -33,10 +33,18 @@
/// The base weight for the each quirk's mail goodies list to be selected is 5
/// then the item selected is determined by pick(selected_quirk.mail_goodies)
var/list/mail_goodies = list() //Monkestation Edit BLOOD_DATUM: Why? this is already a list all this does is mess confuse us.
- /// The minimum stat where this quirk can process (if it has QUIRK_PROCESSES)
- var/minimum_process_stat = HARD_CRIT
+ /// The maximum stat below which this quirk can process (if it has QUIRK_PROCESSES), and above which it stops.
+ var/maximum_process_stat = HARD_CRIT
/// A list of additional signals to register with update_process()
var/list/process_update_signals
+ /// A list of traits that should stop this quirk from processing.
+ /// Signals for adding and removing this trait will automatically be added to `process_update_signals`.
+ var/list/no_process_traits
+
+/datum/quirk/New()
+ . = ..()
+ for(var/trait in no_process_traits)
+ LAZYADD(process_update_signals, list(SIGNAL_ADDTRAIT(trait), SIGNAL_REMOVETRAIT(trait)))
/datum/quirk/Destroy()
if(quirk_holder)
@@ -81,7 +89,8 @@
add(client_source)
if(quirk_flags & QUIRK_PROCESSES)
- RegisterSignal(quirk_holder, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_changed))
+ if(!isnull(maximum_process_stat))
+ RegisterSignal(quirk_holder, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_changed))
if(process_update_signals)
RegisterSignals(quirk_holder, process_update_signals, PROC_REF(update_process))
if(should_process())
@@ -161,7 +170,16 @@
/datum/quirk/proc/should_process()
SHOULD_CALL_PARENT(TRUE)
SHOULD_BE_PURE(TRUE)
- return (quirk_flags & QUIRK_PROCESSES) && !QDELETED(quirk_holder) && quirk_holder.stat <= minimum_process_stat
+ if(QDELETED(quirk_holder))
+ return FALSE
+ if(!(quirk_flags & QUIRK_PROCESSES))
+ return FALSE
+ if(!isnull(maximum_process_stat) && quirk_holder.stat >= maximum_process_stat)
+ return FALSE
+ for(var/trait in no_process_traits)
+ if(HAS_TRAIT(quirk_holder, trait))
+ return FALSE
+ return TRUE
/// Checks to see if the quirk should be processing, and starts/stops it.
/datum/quirk/proc/update_process()
diff --git a/code/datums/quirks/negative_quirks/allergic.dm b/code/datums/quirks/negative_quirks/allergic.dm
index 371c5d691c38..86999706ba8f 100644
--- a/code/datums/quirks/negative_quirks/allergic.dm
+++ b/code/datums/quirks/negative_quirks/allergic.dm
@@ -9,10 +9,7 @@
hardcore_value = 3
quirk_flags = QUIRK_HUMAN_ONLY | QUIRK_PROCESSES
mail_goodies = list(/obj/item/reagent_containers/hypospray/medipen) // epinephrine medipen stops allergic reactions
- process_update_signals = list(
- SIGNAL_ADDTRAIT(TRAIT_STASIS),
- SIGNAL_REMOVETRAIT(TRAIT_STASIS),
- )
+ no_process_traits = list(TRAIT_STASIS)
var/list/allergies = list()
var/list/blacklist = list(
/datum/reagent/medicine/c2,
@@ -64,6 +61,3 @@
if(SPT_PROB(10, seconds_per_tick))
carbon_quirk_holder.vomit()
carbon_quirk_holder.adjustOrganLoss(pick(ORGAN_SLOT_BRAIN,ORGAN_SLOT_APPENDIX,ORGAN_SLOT_LUNGS,ORGAN_SLOT_HEART,ORGAN_SLOT_LIVER,ORGAN_SLOT_STOMACH),10)
-
-/datum/quirk/item_quirk/allergic/should_process()
- return iscarbon(quirk_holder) && ..() && !HAS_TRAIT(quirk_holder, TRAIT_STASIS)
diff --git a/code/datums/quirks/negative_quirks/brain_problems.dm b/code/datums/quirks/negative_quirks/brain_problems.dm
index 2f9165f20961..2f6d24c461a2 100644
--- a/code/datums/quirks/negative_quirks/brain_problems.dm
+++ b/code/datums/quirks/negative_quirks/brain_problems.dm
@@ -14,10 +14,7 @@
hardcore_value = 12
quirk_flags = QUIRK_HUMAN_ONLY | QUIRK_PROCESSES | QUIRK_DONT_CLONE // monkestation edit: QUIRK_DONT_CLONE (the cloner isn't gonna clone ur tumor lol)
mail_goodies = list(/obj/item/storage/pill_bottle/mannitol/braintumor)
- process_update_signals = list(
- SIGNAL_ADDTRAIT(TRAIT_TUMOR_SUPPRESSED),
- SIGNAL_REMOVETRAIT(TRAIT_TUMOR_SUPPRESSED),
- )
+ no_process_traits = list(TRAIT_TUMOR_SUPPRESSED)
/datum/quirk/item_quirk/brainproblems/add_unique(client/client_source)
give_item_to_holder(
@@ -33,6 +30,3 @@
/datum/quirk/item_quirk/brainproblems/process(seconds_per_tick)
quirk_holder.adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.2 * seconds_per_tick)
-
-/datum/quirk/item_quirk/brainproblems/should_process()
- return ..() && !HAS_TRAIT(quirk_holder, TRAIT_TUMOR_SUPPRESSED)
diff --git a/code/datums/quirks/negative_quirks/claustrophobia.dm b/code/datums/quirks/negative_quirks/claustrophobia.dm
index c84b8770bbbf..1861abf8ec4e 100644
--- a/code/datums/quirks/negative_quirks/claustrophobia.dm
+++ b/code/datums/quirks/negative_quirks/claustrophobia.dm
@@ -6,12 +6,9 @@
medical_record_text = "Patient demonstrates a fear of tight spaces."
hardcore_value = 5
quirk_flags = QUIRK_HUMAN_ONLY | QUIRK_PROCESSES
- minimum_process_stat = CONSCIOUS
+ maximum_process_stat = SOFT_CRIT
mail_goodies = list(/obj/item/reagent_containers/syringe/convermol) // to help breathing
- process_update_signals = list(
- SIGNAL_ADDTRAIT(TRAIT_FEARLESS),
- SIGNAL_REMOVETRAIT(TRAIT_FEARLESS),
- )
+ no_process_traits = list(TRAIT_FEARLESS)
/datum/quirk/claustrophobia/remove()
quirk_holder.clear_mood_event("claustrophobia")
@@ -36,9 +33,6 @@
else
to_chat(quirk_holder, span_warning("You feel trapped! Must escape... can't breathe..."))
-/datum/quirk/claustrophobia/should_process()
- return ..() && !HAS_TRAIT(quirk_holder, TRAIT_FEARLESS)
-
///investigates whether possible_saint_nick possesses a high level of christmas cheer
/datum/quirk/claustrophobia/proc/evaluate_jolly_levels(mob/living/carbon/human/possible_saint_nick)
if(!istype(possible_saint_nick))
diff --git a/code/datums/quirks/negative_quirks/junkie.dm b/code/datums/quirks/negative_quirks/junkie.dm
index 539cd953c516..6ac9ac705011 100644
--- a/code/datums/quirks/negative_quirks/junkie.dm
+++ b/code/datums/quirks/negative_quirks/junkie.dm
@@ -8,10 +8,7 @@
hardcore_value = 4
quirk_flags = QUIRK_HUMAN_ONLY | QUIRK_PROCESSES | QUIRK_DONT_CLONE
mail_goodies = list(/obj/effect/spawner/random/contraband/narcotics)
- process_update_signals = list(
- SIGNAL_ADDTRAIT(TRAIT_LIVERLESS_METABOLISM),
- SIGNAL_REMOVETRAIT(TRAIT_LIVERLESS_METABOLISM),
- )
+ no_process_traits = list(TRAIT_LIVERLESS_METABOLISM)
var/drug_list = list(/datum/reagent/drug/blastoff, /datum/reagent/drug/krokodil, /datum/reagent/medicine/painkiller/morphine, /datum/reagent/drug/happiness, /datum/reagent/drug/methamphetamine) //List of possible IDs
var/datum/reagent/reagent_type //!If this is defined, reagent_id will be unused and the defined reagent type will be instead.
var/datum/reagent/reagent_instance //! actual instanced version of the reagent
@@ -86,9 +83,6 @@
for(var/addiction in reagent_instance.addiction_types)
human_holder.last_mind?.add_addiction_points(addiction, 1000) ///Max that shit out
-/datum/quirk/item_quirk/junkie/should_process()
- return ..() && !HAS_TRAIT(quirk_holder, TRAIT_LIVERLESS_METABOLISM)
-
/datum/quirk/item_quirk/junkie/smoker
name = "Smoker"
desc = "Sometimes you just really want a smoke. Probably not great for your lungs."
diff --git a/code/datums/quirks/positive_quirks/drunk_healing.dm b/code/datums/quirks/positive_quirks/drunk_healing.dm
index cb9572896cb1..a565c78cc9b4 100644
--- a/code/datums/quirks/positive_quirks/drunk_healing.dm
+++ b/code/datums/quirks/positive_quirks/drunk_healing.dm
@@ -7,7 +7,7 @@
lose_text = span_danger("You no longer feel like drinking would ease your pain.")
medical_record_text = "Patient has unusually efficient liver metabolism and can slowly regenerate wounds by drinking alcoholic beverages."
quirk_flags = QUIRK_HUMAN_ONLY | QUIRK_PROCESSES
- minimum_process_stat = DEAD // it processed before while dead, so I'm keeping it that way
+ maximum_process_stat = DEAD // it processed before while dead, so I'm keeping it that way
mail_goodies = list(/obj/effect/spawner/random/food_or_drink/booze)
/datum/quirk/drunkhealing/process(seconds_per_tick)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 4c14051481c3..939115953f8b 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -213,7 +213,7 @@
move_packet = null
if(spatial_grid_key)
- SSspatial_grid.force_remove_from_cell(src)
+ SSspatial_grid.force_remove_from_grid(src)
LAZYNULL(client_mobs_in_contents)
diff --git a/code/game/machinery/computer/telescreen.dm b/code/game/machinery/computer/telescreen.dm
index ac49361fa2da..21531e8f5295 100644
--- a/code/game/machinery/computer/telescreen.dm
+++ b/code/game/machinery/computer/telescreen.dm
@@ -58,17 +58,19 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/security/telescreen/entertai
/obj/machinery/computer/security/telescreen/entertainment/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_CLICK, PROC_REF(BigClick))
+ RegisterSignal(SSdcs, COMSIG_GLOB_NETWORK_BROADCAST_UPDATED, PROC_REF(on_network_broadcast_updated)) // monkestation edit: convert to signal handler
speakers = new(src)
/obj/machinery/computer/security/telescreen/entertainment/Destroy()
- . = ..()
+ UnregisterSignal(SSdcs, COMSIG_GLOB_NETWORK_BROADCAST_UPDATED) // monkestation edit: convert to signal handler
QDEL_NULL(speakers)
+ return ..()
// Bypass clickchain to allow humans to use the telescreen from a distance
/obj/machinery/computer/security/telescreen/entertainment/proc/BigClick()
SIGNAL_HANDLER
- if(!network.len)
+ if(!length(network))
balloon_alert(usr, "nothing on TV!")
return
@@ -84,7 +86,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/security/telescreen/entertai
say(announcement)
/// Adds a camera network ID to the entertainment monitor, and turns off the monitor if network list is empty
-/obj/machinery/computer/security/telescreen/entertainment/proc/update_shows(is_show_active, tv_show_id, announcement)
+/obj/machinery/computer/security/telescreen/entertainment/proc/on_network_broadcast_updated(datum/source, tv_show_id, is_show_active, announcement) // monkestation edit: convert to signal handler
+ SIGNAL_HANDLER
if(!network)
return
@@ -93,7 +96,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/security/telescreen/entertai
else
network -= tv_show_id
- notify(network.len, announcement)
+ INVOKE_ASYNC(src, TYPE_PROC_REF(/datum, update_static_data_for_all_viewers)) // monkestation edit: ensure static data is always updated
+ notify(length(network), announcement)
/**
* Adds a camera network to all entertainment monitors.
@@ -102,12 +106,15 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/security/telescreen/entertai
* * announcement - Optional, what announcement to make when the show starts.
*/
/proc/start_broadcasting_network(camera_net, announcement)
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NETWORK_BROADCAST_UPDATED, camera_net, TRUE, announcement)
+/* monkestation edit: convert to global signal
for(var/obj/machinery/computer/security/telescreen/entertainment/tv as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/computer/security/telescreen/entertainment))
tv.update_shows(
is_show_active = TRUE,
tv_show_id = camera_net,
announcement = announcement,
)
+monkestation end */
/**
* Removes a camera network from all entertainment monitors.
@@ -116,12 +123,15 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/security/telescreen/entertai
* * announcement - Optional, what announcement to make when the show ends.
*/
/proc/stop_broadcasting_network(camera_net, announcement)
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NETWORK_BROADCAST_UPDATED, camera_net, FALSE, announcement)
+/* monkestation edit: convert to global signal
for(var/obj/machinery/computer/security/telescreen/entertainment/tv as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/computer/security/telescreen/entertainment))
tv.update_shows(
is_show_active = FALSE,
tv_show_id = camera_net,
announcement = announcement,
)
+monkestation end */
/**
* Sets the camera network status on all entertainment monitors.
@@ -135,12 +145,15 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/security/telescreen/entertai
* Likewise, there's no way to differentiate off -> on and on -> off, unless you handle that yourself.
*/
/proc/set_network_broadcast_status(camera_net, is_show_active, announcement)
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NETWORK_BROADCAST_UPDATED, camera_net, is_show_active, announcement)
+/* monkestation edit: convert to global signal
for(var/obj/machinery/computer/security/telescreen/entertainment/tv as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/computer/security/telescreen/entertainment))
tv.update_shows(
is_show_active = is_show_active,
tv_show_id = camera_net,
announcement = announcement,
)
+monkestation end */
/obj/machinery/computer/security/telescreen/rd
name = "\improper Research Director's telescreen"
diff --git a/code/game/objects/items/devices/broadcast_camera.dm b/code/game/objects/items/devices/broadcast_camera.dm
index 83dbfe7c1559..488450e8ad8b 100644
--- a/code/game/objects/items/devices/broadcast_camera.dm
+++ b/code/game/objects/items/devices/broadcast_camera.dm
@@ -35,7 +35,6 @@
/obj/item/broadcast_camera/Initialize(mapload)
. = ..()
-
AddElement(/datum/element/empprotection, EMP_PROTECT_ALL)
/obj/item/broadcast_camera/Destroy(force)
@@ -47,21 +46,22 @@
icon_state = "[base_icon_state][active]"
return ..()
-/obj/item/broadcast_camera/attack_self(mob/user, modifiers)
+/obj/item/broadcast_camera/attack_self(mob/living/user, modifiers)
. = ..()
active = !active
if(active)
on_activating()
else
+ user.remove_status_effect(/datum/status_effect/streamer, internal_camera)
on_deactivating()
/obj/item/broadcast_camera/attack_self_secondary(mob/user, modifiers)
. = ..()
- broadcast_name = tgui_input_text(user = user, title = "Broadcast Name", message = "What will be the name of your broadcast?", default = "[broadcast_name]", max_length = MAX_CHARTER_LEN)
+ broadcast_name = tgui_input_text(user = user, title = "Broadcast Name", message = "What will be the name of your broadcast?", default = "[broadcast_name]", max_length = MAX_CHARTER_LEN, encode = FALSE)
/obj/item/broadcast_camera/examine(mob/user)
. = ..()
- . += span_notice("Broadcast name is [broadcast_name]")
+ . += span_notice("Broadcast name is [html_encode(broadcast_name)]")
. += span_notice("The microphone is [active_microphone ? "On" : "Off"]")
/obj/item/broadcast_camera/on_enter_storage(datum/storage/master_storage)
@@ -69,25 +69,29 @@
if(active)
on_deactivating()
-/obj/item/broadcast_camera/dropped(mob/user, silent)
+/obj/item/broadcast_camera/dropped(mob/living/user, silent)
. = ..()
if(active)
+ user?.remove_status_effect(/datum/status_effect/streamer, internal_camera)
on_deactivating()
/// When activating the camera
/obj/item/broadcast_camera/proc/on_activating()
- if(!iscarbon(loc))
+ if(!isliving(loc))
+ return
+ /// The mob who wielded the camera, allegedly
+ var/mob/living/wielder = loc
+ if(!wielder.is_holding(src))
return
active = TRUE
update_icon_state()
- /// The carbon who wielded the camera, allegedly
- var/mob/living/carbon/wielding_carbon = loc
// INTERNAL CAMERA
- internal_camera = new(wielding_carbon) // Cameras for some reason do not work inside of obj's
+ internal_camera = new(wielder) // Cameras for some reason do not work inside of obj's
internal_camera.internal_light = FALSE
internal_camera.network = camera_networks
internal_camera.c_tag = "LIVE: [broadcast_name]"
+ wielder.apply_status_effect(/datum/status_effect/streamer, internal_camera, CALLBACK(src, PROC_REF(ensure_still_active)))
start_broadcasting_network(camera_networks, "[broadcast_name] is now LIVE!")
// INTERNAL RADIO
@@ -112,6 +116,16 @@
playsound(source = src, soundin = 'sound/machines/terminal_prompt_deny.ogg', vol = 20, vary = FALSE, ignore_walls = FALSE)
balloon_alert_to_viewers("offline")
+/obj/item/broadcast_camera/proc/ensure_still_active()
+ if(!active)
+ return FALSE
+ if(!isliving(loc))
+ return FALSE
+ var/mob/living/wielder = loc
+ if(!wielder.is_holding(src))
+ return FALSE
+ return TRUE
+
/obj/item/broadcast_camera/AltClick(mob/user)
if(!user.can_perform_action(src, NEED_DEXTERITY|FORBID_TELEKINESIS_REACH))
return
diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm
index 94fde875336c..dd2fcc1fea98 100644
--- a/code/modules/admin/holder2.dm
+++ b/code/modules/admin/holder2.dm
@@ -75,7 +75,6 @@ GLOBAL_PROTECT(href_token)
activate()
else
deactivate()
- plane_debug = new(src)
/datum/admins/Destroy()
if(IsAdminAdvancedProcCall())
@@ -96,7 +95,7 @@ GLOBAL_PROTECT(href_token)
deadmined = FALSE
if(owner)
rementor(owner)
- QDEL_NULL(plane_debug)
+ plane_debug = new(src)
if (GLOB.directory[target])
associate(GLOB.directory[target]) //find the client for a ckey if they are connected and associate them with us
@@ -109,6 +108,7 @@ GLOBAL_PROTECT(href_token)
return
GLOB.deadmins[target] = src
GLOB.admin_datums -= target
+ QDEL_NULL(plane_debug)
if(owner)
dementor(owner)
diff --git a/code/modules/food_and_drinks/machinery/smartfridge.dm b/code/modules/food_and_drinks/machinery/smartfridge.dm
index eacf09e02f6b..80c5ca3fc694 100644
--- a/code/modules/food_and_drinks/machinery/smartfridge.dm
+++ b/code/modules/food_and_drinks/machinery/smartfridge.dm
@@ -521,8 +521,8 @@
/obj/machinery/smartfridge/chemistry/virology/preloaded
initial_contents = list(
/obj/item/reagent_containers/syringe/antiviral = 4,
- /obj/item/reagent_containers/cup/bottle/cold = 1,
- /obj/item/reagent_containers/cup/bottle/flu_virion = 1,
+ // /obj/item/reagent_containers/cup/bottle/cold = 1,
+ // /obj/item/reagent_containers/cup/bottle/flu_virion = 1, Monkestation removal, Old viro code
/obj/item/reagent_containers/cup/bottle/mutagen = 1,
/obj/item/reagent_containers/cup/bottle/sugar = 1,
/obj/item/reagent_containers/cup/bottle/plasma = 1,
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index e665c4bf3ee8..9b69ce808959 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -192,7 +192,7 @@
if (!bulky && prob(50))
return
visible_message(span_danger("[src] looses [src.p_their()] balance."), \
- span_danger("You loose your balance."))
+ span_danger("You lose your balance."))
Knockdown(2 SECONDS)
//MONKESTATION EDIT END
diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm
index 45fc9ba947da..18f0ab2c210b 100644
--- a/code/modules/mob/living/carbon/death.dm
+++ b/code/modules/mob/living/carbon/death.dm
@@ -51,7 +51,7 @@
var/org_zone = check_zone(organ.zone) //both groin and chest organs.
if(org_zone != BODY_ZONE_CHEST)
continue
- organs.Remove(organ)
+ organ.Remove(src)
organ.forceMove(Tsec)
organ.fly_away(Tsec, horizontal_multiplier = 2, vertical_multiplier = 1.2)
else
@@ -62,7 +62,7 @@
if(no_organs && !istype(organ, /obj/item/organ/internal/brain))
qdel(organ)
continue
- organs.Remove(organ)
+ organ.Remove(src)
organ.forceMove(Tsec)
organ.fly_away(Tsec, horizontal_multiplier = 2, vertical_multiplier = 1.2)
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index d3b2bb374ff6..274a1c708248 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -51,6 +51,8 @@
///The department the secbot will deposit collected money into
var/payment_department = ACCOUNT_SEC
+ var/stamina_damage = 95 //3 hit stam crit from full, but they most likely wont be due to running a bit
+
/mob/living/simple_animal/bot/secbot/beepsky
name = "Commander Beep O'sky"
desc = "It's Commander Beep O'sky! Officially the superior officer of all bots on station, Beepsky remains as humble and dedicated to the law as the day he was first fabricated."
@@ -321,7 +323,7 @@
back_to_idle()
/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/current_target, harm = FALSE)
- var/judgement_criteria = judgement_criteria()
+ //var/judgement_criteria = judgement_criteria()
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
icon_state = "[initial(icon_state)]-c"
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_appearance)), 0.2 SECONDS)
@@ -329,15 +331,17 @@
if(harm)
weapon.attack(current_target, src)
+
+ // monkestation start: check shields and baton resistance, deal stamina damage
if(ishuman(current_target))
- current_target.set_stutter(10 SECONDS)
- current_target.Paralyze(100)
var/mob/living/carbon/human/human_target = current_target
- threat = human_target.assess_threat(judgement_criteria, weaponcheck = CALLBACK(src, PROC_REF(check_for_weapons)))
+ if(human_target.check_shields(src, 0, "\the [name]", MELEE_ATTACK))
+ return
+ if(HAS_TRAIT(current_target, TRAIT_BATON_RESISTANCE))
+ current_target.stamina.adjust_to(-stamina_damage, current_target.stamina.maximum * 0.29)
else
- current_target.Paralyze(100)
- current_target.set_stutter(10 SECONDS)
- threat = current_target.assess_threat(judgement_criteria, weaponcheck = CALLBACK(src, PROC_REF(check_for_weapons)))
+ current_target.stamina.adjust(-stamina_damage)
+ // monkestation end
log_combat(src, current_target, "stunned")
if(security_mode_flags & SECBOT_DECLARE_ARRESTS)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
index c9c55baabd26..6218c46124bd 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
@@ -183,7 +183,7 @@
return FALSE
return ..()
-/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE)
+/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE, atom/push_appearance)
if(swooping & SWOOP_INVULNERABLE) //to suppress attack messages without overriding every single proc that could send a message saying we got hit
return
return ..()
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 978be4255fca..131cac527030 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -265,12 +265,16 @@
* * blind_message (optional) is what blind people will hear e.g. "You hear something!"
* * vision_distance (optional) define how many tiles away the message can be seen.
* * ignored_mob (optional) doesn't show any message to a given mob if TRUE.
+ * * push_appearance(optional) pushes an atom's appearance to all viewing mobs, for use with
*/
-/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE)
+/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE, atom/push_appearance)
var/turf/T = get_turf(src)
if(!T)
return
+ if(!isnull(push_appearance) && !isatom(push_appearance))
+ stack_trace("push_appearance must be an atom, but got [push_appearance] instead")
+
if(!islist(ignored_mobs))
ignored_mobs = list(ignored_mobs)
var/list/hearers = get_hearers_in_view(vision_distance, src) //caches the hearers and then removes ignored mobs.
@@ -304,6 +308,9 @@
if(!msg)
continue
+ if(push_appearance)
+ M << output(push_appearance, "push_appearance_placeholder_id")
+
if(visible_message_flags & EMOTE_MESSAGE && runechat_prefs_check(M, visible_message_flags) && !M.is_blind())
M.create_chat_message(src, raw_message = raw_msg, runechat_flags = visible_message_flags)
@@ -311,7 +318,7 @@
///Adds the functionality to self_message.
-/mob/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE)
+/mob/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE, atom/push_appearance)
. = ..()
if(self_message)
show_message(self_message, MSG_VISUAL, blind_message, MSG_AUDIBLE)
diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm
index 01ede1c17be9..c4750484ea2f 100644
--- a/code/modules/modular_computers/computers/item/computer.dm
+++ b/code/modules/modular_computers/computers/item/computer.dm
@@ -496,11 +496,11 @@
* The program calling this proc.
* The message that the program wishes to display.
*/
-/obj/item/modular_computer/proc/alert_call(datum/computer_file/program/origin, alerttext, sound = 'sound/machines/twobeep_high.ogg')
- if(!origin || !origin.alert_able || origin.alert_silenced || !alerttext) //Yeah, we're checking alert_able. No, you don't get to make alerts that the user can't silence.
+/obj/item/modular_computer/proc/alert_call(datum/computer_file/program/origin, alerttext, sound = 'sound/machines/twobeep_high.ogg', vision_distance = DEFAULT_MESSAGE_RANGE)
+ if(QDELETED(loc) || QDELETED(origin) || !origin.alert_able || origin.alert_silenced || !alerttext) //Yeah, we're checking alert_able. No, you don't get to make alerts that the user can't silence.
return FALSE
playsound(src, sound, 50, TRUE)
- loc.visible_message(span_notice("[icon2html(src)] [span_notice("The [src] displays a [origin.filedesc] notification: [alerttext]")]"))
+ loc.visible_message(span_notice("
\The [src] displays a [origin.filedesc] notification: [alerttext]"), vision_distance = vision_distance, push_appearance = src)
/obj/item/modular_computer/proc/ring(ringtone, list/balloon_alertees) // bring bring
if(HAS_TRAIT(SSstation, STATION_TRAIT_PDA_GLITCHED))
diff --git a/code/modules/modular_computers/computers/item/computer_ui.dm b/code/modules/modular_computers/computers/item/computer_ui.dm
index 4146588d7d93..8ea9c28dc699 100644
--- a/code/modules/modular_computers/computers/item/computer_ui.dm
+++ b/code/modules/modular_computers/computers/item/computer_ui.dm
@@ -39,14 +39,12 @@
// Operates TGUI
/obj/item/modular_computer/ui_interact(mob/user, datum/tgui/ui)
if(!enabled || !user.can_read(src, READING_CHECK_LITERACY) || !use_power())
- if(ui)
- ui.close()
+ ui?.close()
return
// Robots don't really need to see the screen, their wireless connection works as long as computer is on.
if(!screen_on && !issilicon(user))
- if(ui)
- ui.close()
+ ui?.close()
return
if(honkvirus_amount > 0) // EXTRA annoying, huh!
@@ -56,6 +54,8 @@
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
update_tablet_open_uis(user)
+ else if(active_program?.always_update_ui)
+ active_program.ui_interact(user, ui)
/obj/item/modular_computer/ui_assets(mob/user)
var/list/data = list()
diff --git a/code/modules/modular_computers/computers/item/pda.dm b/code/modules/modular_computers/computers/item/pda.dm
index 9560738ecafd..e6d731213aa1 100644
--- a/code/modules/modular_computers/computers/item/pda.dm
+++ b/code/modules/modular_computers/computers/item/pda.dm
@@ -36,7 +36,10 @@
/datum/computer_file/program/messenger,
/datum/computer_file/program/nt_pay,
/datum/computer_file/program/notepad,
- /datum/computer_file/program/crew_manifest // monke edit: install crew manifest by default
+ // monkestation edit: install crew manifest and spess.tv by default
+ /datum/computer_file/program/crew_manifest,
+ /datum/computer_file/program/secureye/spesstv,
+ // monkestation end
)
///List of items that can be stored in a PDA
var/static/list/contained_item = list(
diff --git a/code/modules/modular_computers/computers/item/role_tablet_presets.dm b/code/modules/modular_computers/computers/item/role_tablet_presets.dm
index 0e1ddcc72b2e..c45f41998800 100644
--- a/code/modules/modular_computers/computers/item/role_tablet_presets.dm
+++ b/code/modules/modular_computers/computers/item/role_tablet_presets.dm
@@ -102,6 +102,7 @@
/datum/computer_file/program/robocontrol,
/datum/computer_file/program/budgetorders,
/datum/computer_file/program/signal_commander,
+ /datum/computer_file/program/scipaper_program,
)
/obj/item/modular_computer/pda/heads/quartermaster
@@ -187,6 +188,8 @@
starting_programs = list(
/datum/computer_file/program/atmosscan,
/datum/computer_file/program/signal_commander,
+ /datum/computer_file/program/science,
+ /datum/computer_file/program/scipaper_program,
)
/obj/item/modular_computer/pda/roboticist
diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm
index 59ef183f6d66..65336cf0e43b 100644
--- a/code/modules/modular_computers/file_system/program.dm
+++ b/code/modules/modular_computers/file_system/program.dm
@@ -43,6 +43,8 @@
var/detomatix_resistance = NONE
///Boolean on whether or not only one copy of the app can exist. This means it deletes itself when cloned elsewhere.
var/unique_copy = FALSE
+ ///Boolean on whether the UI should *always* be updated while active.
+ var/always_update_ui = FALSE
/datum/computer_file/program/clone()
var/datum/computer_file/program/temp = ..()
diff --git a/code/modules/modular_computers/file_system/programs/secureye.dm b/code/modules/modular_computers/file_system/programs/secureye.dm
index 1fd00e163345..14e50869aa75 100644
--- a/code/modules/modular_computers/file_system/programs/secureye.dm
+++ b/code/modules/modular_computers/file_system/programs/secureye.dm
@@ -13,6 +13,7 @@
size = 5
tgui_id = "NtosSecurEye"
program_icon = "eye"
+ always_update_ui = TRUE
///Boolean on whether or not the app will make noise when flipping around the channels.
var/spying = FALSE
diff --git a/code/modules/pai/card.dm b/code/modules/pai/card.dm
index 3e11c0b7bcb8..91f2222641dd 100644
--- a/code/modules/pai/card.dm
+++ b/code/modules/pai/card.dm
@@ -14,8 +14,8 @@
/// Spam alert prevention
var/alert_cooldown
- /// The emotion icon displayed.
- var/emotion_icon = "off"
+ /// The icon displayed on the card's screen.
+ var/datum/pai_screen_image/screen_image = /datum/pai_screen_image/off
/// Any pAI personalities inserted
var/mob/living/silicon/pai/pai
/// Prevents a crew member from hitting "request pAI" repeatedly
@@ -60,7 +60,7 @@
/obj/item/pai_card/handle_atom_del(atom/thing)
if(thing == pai) //double check /mob/living/silicon/pai/Destroy() if you change these.
pai = null
- emotion_icon = initial(emotion_icon)
+ screen_image = initial(screen_image)
update_appearance()
return ..()
@@ -76,13 +76,13 @@
/obj/item/pai_card/update_overlays()
. = ..()
- . += "pai-[emotion_icon]"
+ . += image(icon = screen_image.icon, icon_state = screen_image.icon_state)
if(pai?.hacking_cable)
. += "[initial(icon_state)]-connector"
/obj/item/pai_card/vv_edit_var(vname, vval)
. = ..()
- if(vname == NAMEOF(src, emotion_icon))
+ if(vname == NAMEOF(src, screen_image))
update_appearance()
/obj/item/pai_card/ui_interact(mob/user, datum/tgui/ui)
@@ -268,7 +268,7 @@
if(pai)
return FALSE
pai = downloaded
- emotion_icon = "null"
+ screen_image = /datum/pai_screen_image/neutral
update_appearance()
playsound(src, 'sound/effects/pai_boot.ogg', 50, TRUE, -1)
audible_message("[src] plays a cheerful startup noise!")
diff --git a/code/modules/pai/datums/screen_icon.dm b/code/modules/pai/datums/screen_icon.dm
new file mode 100644
index 000000000000..2115b8ea0d61
--- /dev/null
+++ b/code/modules/pai/datums/screen_icon.dm
@@ -0,0 +1,67 @@
+// Datums describing an icon that is overlaid on a pAI card, to make its screen show something. The
+// player can select between any of these at any time. These are usually faces, but can
+// realistically be anything (similar to an AI's display).
+
+/datum/pai_screen_image
+ // The name to show in the radial menu.
+ var/name
+ // The icon and icon state that is applied to the pAI device when this screen image is selected.
+ var/icon/icon = 'icons/obj/aicards.dmi'
+ var/icon_state
+ // The FontAwesome icon to use next to the "Display" button in the pAI's tgui interface window.
+ var/interface_icon
+
+/datum/pai_screen_image/angry
+ name = "Angry"
+ icon_state = "pai-angry"
+ interface_icon = "angry"
+
+/datum/pai_screen_image/cat
+ name = "Cat"
+ icon_state = "pai-cat"
+ interface_icon = "cat"
+
+/datum/pai_screen_image/extremely_happy
+ name = "Extremely Happy"
+ icon_state = "pai-extremely-happy"
+ interface_icon = "grin-beam"
+
+/datum/pai_screen_image/face
+ name = "Face"
+ icon_state = "pai-face"
+ interface_icon = "grin-alt"
+
+/datum/pai_screen_image/happy
+ name = "Happy"
+ icon_state = "pai-happy"
+ interface_icon = "smile"
+
+/datum/pai_screen_image/laugh
+ name = "Laugh"
+ icon_state = "pai-laugh"
+ interface_icon = "grin-tears"
+
+/datum/pai_screen_image/neutral
+ name = "Neutral"
+ icon_state = "pai-null"
+ interface_icon = "meh"
+
+/datum/pai_screen_image/off
+ name = "None"
+ icon_state = "pai-off"
+ interface_icon = "meh-blank"
+
+/datum/pai_screen_image/sad
+ name = "Sad"
+ icon_state = "pai-sad"
+ interface_icon = "sad-cry"
+
+/datum/pai_screen_image/sunglasses
+ name = "Sunglasses"
+ icon_state = "pai-sunglasses"
+ interface_icon = "sun"
+
+/datum/pai_screen_image/what
+ name = "What"
+ icon_state = "pai-what"
+ interface_icon = "frown-open"
diff --git a/code/modules/pai/death.dm b/code/modules/pai/death.dm
index 469f1757d47a..b819e16bfce8 100644
--- a/code/modules/pai/death.dm
+++ b/code/modules/pai/death.dm
@@ -13,7 +13,7 @@
if (!QDELETED(card) && loc != card)
card.forceMove(drop_location())
card.pai = null
- card.emotion_icon = initial(card.emotion_icon)
+ card.screen_image = initial(card.screen_image)
card.update_appearance()
qdel(src)
diff --git a/code/modules/pai/pai.dm b/code/modules/pai/pai.dm
index 35229887c86b..278d642b6ae8 100644
--- a/code/modules/pai/pai.dm
+++ b/code/modules/pai/pai.dm
@@ -124,20 +124,6 @@
"puppy" = FALSE,
"spider" = FALSE,
)
- /// List of all available card overlays.
- var/static/list/possible_overlays = list(
- "null",
- "angry",
- "cat",
- "extremely-happy",
- "face",
- "happy",
- "laugh",
- "off",
- "sad",
- "sunglasses",
- "what"
- )
/mob/living/silicon/pai/add_sensors() //pAIs have to buy their HUDs
return
diff --git a/code/modules/pai/software.dm b/code/modules/pai/software.dm
index f5b69dd03264..a8c34ca60b89 100644
--- a/code/modules/pai/software.dm
+++ b/code/modules/pai/software.dm
@@ -8,7 +8,7 @@
/mob/living/silicon/pai/ui_data(mob/user)
var/list/data = list()
data["door_jack"] = hacking_cable
- data["image"] = card.emotion_icon
+ data["screen_image_interface_icon"] = card.screen_image.interface_icon
data["installed"] = installed_software
data["ram"] = ram
return data
@@ -135,16 +135,16 @@
*/
/mob/living/silicon/pai/proc/change_image()
var/list/possible_choices = list()
- for(var/face_option in possible_overlays)
+ for(var/datum/pai_screen_image/screen_option as anything in subtypesof(/datum/pai_screen_image))
var/datum/radial_menu_choice/choice = new
- choice.name = face_option
- choice.image = image(icon = card.icon, icon_state = "pai-[face_option]")
- possible_choices[face_option] += choice
+ choice.name = screen_option.name
+ choice.image = image(icon = screen_option.icon, icon_state = screen_option.icon_state)
+ possible_choices[screen_option] += choice
var/atom/anchor = get_atom_on_turf(src)
var/new_image = show_radial_menu(src, anchor, possible_choices, custom_check = CALLBACK(src, PROC_REF(check_menu), anchor), radius = 40, require_near = TRUE)
if(isnull(new_image))
return FALSE
- card.emotion_icon = new_image
+ card.screen_image = new_image
card.update_appearance()
return TRUE
diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm
index 214ad78425be..c6e3fbe78d72 100644
--- a/code/modules/unit_tests/_unit_tests.dm
+++ b/code/modules/unit_tests/_unit_tests.dm
@@ -121,6 +121,7 @@
#include "egg_glands.dm"
#include "emoting.dm"
#include "fish_unit_tests.dm"
+#include "floor_lights.dm"
#include "focus_only_tests.dm"
#include "food_edibility_check.dm"
#include "full_heal.dm"
diff --git a/code/modules/unit_tests/floor_lights.dm b/code/modules/unit_tests/floor_lights.dm
new file mode 100644
index 000000000000..1caa5fdce08b
--- /dev/null
+++ b/code/modules/unit_tests/floor_lights.dm
@@ -0,0 +1,21 @@
+/// This test ensures that floor lights aren't mapped underneath any sort of solid object that would obscure it.
+/datum/unit_test/floor_lights
+
+/datum/unit_test/floor_lights/Run()
+ var/static/list/obscuring_typecache = typecacheof(list(
+ /obj/structure/table,
+ /obj/structure/bookcase,
+ /obj/machinery/computer,
+ /obj/machinery/vending,
+ ))
+
+ for(var/obj/machinery/light/floor/light as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/light/floor))
+ var/turf/light_turf = light.loc
+ if(!isturf(light_turf) || !is_station_level(light_turf.z)) // only check lights on-station
+ continue
+ if(!istype(light, /obj/machinery/light/floor/has_bulb))
+ TEST_FAIL("[light] ([light.type]) does not start with a bulb at [AREACOORD(light_turf)], this is likely a mistake")
+ continue
+ for(var/obj/thing in light_turf)
+ if(thing.density && (is_type_in_typecache(thing, obscuring_typecache) || ((thing.flags_1 & PREVENT_CLICK_UNDER_1) && thing.layer > light.layer)))
+ TEST_FAIL("[light] ([light.type]) obscured by [thing] ([thing.type]) at [AREACOORD(light_turf)]")
diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm
index 2f7bcf439cb8..1877abe8ddf5 100644
--- a/code/modules/unit_tests/unit_test.dm
+++ b/code/modules/unit_tests/unit_test.dm
@@ -256,6 +256,7 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
/turf/closed/mineral/random/regrowth,
/obj/effect/abstract/signboard_holder, // monkestation addition: shouldn't exist outside of signboards
/obj/effect/transmission_beam, // monkestation addition: relies on the existence of a PTL
+ /obj/item/radio/entertainment/speakers/pda, // monkestation addition: should never exist outside of a modular computer
)
//Say it with me now, type template
ignore += typesof(/obj/effect/mapping_helpers)
@@ -353,9 +354,12 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
var/list/test_results = list()
+ //Hell code, we're bound to end the round somehow so let's stop if from ending while we work
+ SSticker.delay_end = TRUE
for(var/unit_path in tests_to_run)
CHECK_TICK //We check tick first because the unit test we run last may be so expensive that checking tick will lock up this loop forever
RunUnitTest(unit_path, test_results)
+ SSticker.delay_end = FALSE
var/file_name = "data/unit_tests.json"
fdel(file_name)
diff --git a/config/config.txt b/config/config.txt
index 464b95aa5078..1078e1d6e593 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -8,6 +8,7 @@ $include resources.txt
$include interviews.txt
$include lua.txt
$include auxtools.txt
+$include plexora.txt
# You can use the @ character at the beginning of a config option to lock it from being edited in-game
# Example usage:
diff --git a/config/plexora.json b/config/plexora.json
deleted file mode 100644
index cac6b9114fca..000000000000
--- a/config/plexora.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "enabled": true,
- "ip": "127.0.0.1",
- "port": 1330
-}
diff --git a/config/plexora.txt b/config/plexora.txt
new file mode 100644
index 000000000000..b7ceb1904d69
--- /dev/null
+++ b/config/plexora.txt
@@ -0,0 +1,5 @@
+# Uncomment this to enable Plexora. You probably won't need this, this is really only used by the main Monkestation server.
+#PLEXORA_ENABLED
+
+# The base URL for the Plexora instance.
+PLEXORA_URL http://127.0.0.1:1330
diff --git a/html/changelogs/AutoChangeLog-pr-5134.yml b/html/changelogs/AutoChangeLog-pr-5134.yml
deleted file mode 100644
index b47eec56d913..000000000000
--- a/html/changelogs/AutoChangeLog-pr-5134.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Absolucy"
-delete-after: True
-changes:
- - bugfix: "Fixed various minor errors."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-5142.yml b/html/changelogs/AutoChangeLog-pr-5142.yml
deleted file mode 100644
index f4a02ca4e6b8..000000000000
--- a/html/changelogs/AutoChangeLog-pr-5142.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Absolucy"
-delete-after: True
-changes:
- - bugfix: "Scrollbars are now properly themed on BYOND 516."
- - bugfix: "Fixed not being able to scroll properly through techfabs/lathes on BYOND 516."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-5152.yml b/html/changelogs/AutoChangeLog-pr-5152.yml
new file mode 100644
index 000000000000..2de52e72a17e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-5152.yml
@@ -0,0 +1,4 @@
+author: "Ancient_Engineer, Killermankey, Camroid"
+delete-after: True
+changes:
+ - rscadd: "New and improved mentor cloak I'd advise against trying to steal it (:"
\ No newline at end of file
diff --git a/html/changelogs/archive/2025-01.yml b/html/changelogs/archive/2025-01.yml
index ea07313dc880..42c165832845 100644
--- a/html/changelogs/archive/2025-01.yml
+++ b/html/changelogs/archive/2025-01.yml
@@ -627,6 +627,12 @@
- qol: The corrupt appendix and lungs now have a cooldown, to prevent stunlocks
or rapidly filling entire rooms with plasma if you're super unlucky.
- bugfix: Fixed some minor map issues.
+ - bugfix: Fixed a few floor lights that were obscured by dense objects.
+ - bugfix: Fixed crew transfer votes being spammed if nobody votes on them.
+ - bugfix: Scrollbars are now properly themed on BYOND 516.
+ - bugfix: Fixed not being able to scroll properly through techfabs/lathes on BYOND
+ 516.
+ - bugfix: Fixed various minor errors.
BingusSS13:
- qol: Updates The Derelict / KS13 / Drone Station / Russian Station's engineering
to look like it's original map's engineering.
@@ -651,6 +657,9 @@
- balance: Minimum players required for a Disease/plague outbreak are all increased
- balance: 'Fake virus''s will now share starting conditions with Disease: Classic
rather than Plague rats.'
+ - bugfix: Engineering is properly accessed by Construction access.
+ - bugfix: Tcomms is properly accessed with TComms access.
+ - bugfix: AI sat is properly accessed by minisat access
MrBagHead:
- qol: Renamed "Midround Heretics" event to "Forbidden Calling (Heretics)" for consistency.
Shoddd:
@@ -662,3 +671,23 @@
- bugfix: fixed donator tokens being buggy (hopefully)
- rscadd: Syndicate Depot's Operatives are reminded of escalation requirements when
faxing or teleporting stuff to the station.
+ - bugfix: Donator Tokens.
+ - bugfix: Tokens now backup appropriately after being spent.
+2025-01-31:
+ Gw0sty:
+ - rscadd: Added security camera consoles to blueshift outposts.
+ - rscadd: Rockroach disks finally lost their copyright and are now purchasable on
+ the slime market.
+ - rscdel: Removed old rhinovirus and cold bottles from viro fridges
+ - bugfix: Boxstation no longer has ooze suckers that link to its neighbour pens
+ - bugfix: Deepstation engineers stopped cutting corners, and completed the ooze
+ network, and gave proper upgrade disks, and a plumbing device
+ - bugfix: Colour mutation syringes no longer pretend to be No Ooze syringes in the
+ market
+ - bugfix: Tram station's super matter will no longer have a delam counter hanging
+ off the wall.
+ - bugfix: Blueshift no longer has a dedicated camera for looking at a wall.
+ - bugfix: Xenobiology has finally figured out what the hell a possum is. Thus are
+ printable by vacuum backpacks
+ - bugfix: Semi-organic bugs will be unlocked on red slimes, instead of dark purple
+ slimes
diff --git a/html/changelogs/archive/2025-02.yml b/html/changelogs/archive/2025-02.yml
new file mode 100644
index 000000000000..a8bbb2dd5e07
--- /dev/null
+++ b/html/changelogs/archive/2025-02.yml
@@ -0,0 +1,47 @@
+2025-02-01:
+ Absolucy:
+ - bugfix: Awakened Dragon's attacks now do the intended amount of damage.
+ - bugfix: Awakened Dragon and Tunnel Arts now have fully consistent counter/dodge
+ effects with the blood cult stun hand.
+ - bugfix: When a touch attack gets dodged by a martial arts user, the attacker will
+ properly have their click cooldown set.
+ - balance: Sleeping Carp, Awakened Dragon, and Tunnel Arts will now dodge/counter
+ touch attacks regardless of combat mode if they're considered a "dangerous"
+ attack (pretty much everything except genetics shock touch)
+ - balance: Tunnel Arts' illusionary warriors now move at the same speed as normal
+ humans, rather than the typical slower rate than most simplemobs do.
+ - qol: Categorized many martial arts-related chat messages as being combat-related
+ in chat tabs.
+ - rscadd: PDAs can now tune into the broadcast camera's streams, with the pre-installed
+ Spess.tv app!
+ - refactor: Refactored some stuff about how camera broadcasts work.
+ - bugfix: Mark of Rust can no longer damage indestructible items.
+ - bugfix: Fixed the chat reliability subsystem being completely useless (hopefully).
+ - balance: Securitrons/Beepsky now only deal stamina damage instead of instantly
+ hardstunning someone.
+ - balance: Having baton resistance now also provides resistance against beepsky.
+ - balance: Beepsky can now be blocked/parried with shields and such.
+ Absolucy, SyncIt21:
+ - bugfix: Quirks now properly process again.
+ Gw0sty:
+ - rscadd: Added cures to the various transformation diseases
+ - balance: Lowered the maximum trigger chance of transformation symptoms.
+ - bugfix: Boxstation engineering disposals will no longer explode.
+ RikuTheKiller:
+ - spellcheck: You no longer loosen your balance, instead you lose it when throwing
+ a bulky item.
+ TheColorCyan:
+ - rscadd: Added NT frontier and NT Science Hub to Scientist PDAs
+ - rscadd: Added NT frontier to RD PDAs
+ ThePooba:
+ - bugfix: Fixed ships being unabled to be recalled after completing your first ship
+ on blueshift
+ - bugfix: box station shipbreaker hut wont run out of power now
+2025-02-03:
+ Gw0sty:
+ - rscadd: Added Dr. Scrubs to remaining maps
+ - rscadd: Added Poppy the safety inspector into the remaining SM maps
+ - bugfix: Fixed a missing airlock helping on minisat.
+ Wernerses:
+ - balance: reduced minimum apid honey require to make beehives from 150 to 70
+ - balance: reduced beehive cooldown from 25 minutes to 5 minutes.
diff --git a/monkestation/code/controllers/subsystem/autotransfer.dm b/monkestation/code/controllers/subsystem/autotransfer.dm
index e136b3aca303..cbe8968a2f81 100644
--- a/monkestation/code/controllers/subsystem/autotransfer.dm
+++ b/monkestation/code/controllers/subsystem/autotransfer.dm
@@ -14,9 +14,20 @@ SUBSYSTEM_DEF(autotransfer)
SSticker.OnRoundstart(CALLBACK(src, PROC_REF(crew_transfer_setup)))
return SS_INIT_SUCCESS
+/datum/controller/subsystem/autotransfer/Recover()
+ next_transfer_vote = SSautotransfer.next_transfer_vote
+
/datum/controller/subsystem/autotransfer/fire()
if(can_run_transfer_vote())
SSvote.initiate_vote(/datum/vote/shuttle_call, "automatic shuttle vote", forced = TRUE)
+ start_subsequent_vote_cooldown()
+
+/datum/controller/subsystem/autotransfer/proc/start_subsequent_vote_cooldown()
+ var/subsequent_transfer_vote_time = CONFIG_GET(number/subsequent_transfer_vote_time)
+ if(subsequent_transfer_vote_time)
+ COOLDOWN_START(src, next_transfer_vote, subsequent_transfer_vote_time + CONFIG_GET(number/vote_period))
+ else
+ next_transfer_vote = 0
/datum/controller/subsystem/autotransfer/proc/can_run_transfer_vote()
. = TRUE
@@ -50,8 +61,3 @@ SUBSYSTEM_DEF(autotransfer)
/datum/controller/subsystem/autotransfer/proc/crew_transfer_continue()
SSgamemode.point_gain_multipliers[EVENT_TRACK_ROLESET]++
- var/subsequent_transfer_vote_time = CONFIG_GET(number/subsequent_transfer_vote_time)
- if(!subsequent_transfer_vote_time)
- next_transfer_vote = 0
- return
- COOLDOWN_START(src, next_transfer_vote, subsequent_transfer_vote_time)
diff --git a/monkestation/code/controllers/subsystem/plexora.dm b/monkestation/code/controllers/subsystem/plexora.dm
index 38c9f7ae9219..72f2d993c50a 100644
--- a/monkestation/code/controllers/subsystem/plexora.dm
+++ b/monkestation/code/controllers/subsystem/plexora.dm
@@ -20,8 +20,8 @@
INVOKE_ASYNC(SSplexora, TYPE_PROC_REF(/datum/controller/subsystem/plexora, topic_listener_response), input["emitter_token"], returning); \
return; \
};
-
#define AUTH_HEADER ("Basic " + CONFIG_GET(string/comms_key))
+#define OLD_PLEXORA_CONFIG "config/plexora.json"
SUBSYSTEM_DEF(plexora)
name = "Plexora"
@@ -36,11 +36,9 @@ SUBSYSTEM_DEF(plexora)
// MUST INCREMENT BY ONE FOR EVERY CHANGE MADE TO PLEXORA
var/version_increment_counter = 2
- var/configuration_path = "config/plexora.json"
var/plexora_is_alive = FALSE
var/vanderlin_available = FALSE
- var/http_root = ""
- var/http_port = 0
+ var/base_url = ""
var/enabled = TRUE
var/tripped_bad_version = FALSE
var/list/default_headers
@@ -49,16 +47,7 @@ SUBSYSTEM_DEF(plexora)
var/hrp_available = FALSE
/datum/controller/subsystem/plexora/Initialize()
- if (!aneri_file_read(configuration_path))
- stack_trace("SSplexora has no configuration file! (missing: [configuration_path])")
- enabled = FALSE
- flags |= SS_NO_FIRE
- return SS_INIT_FAILURE
-
- // Get config
- var/list/config = json_decode(aneri_file_read(configuration_path))
-
- if (!config["enabled"])
+ if(!CONFIG_GET(flag/plexora_enabled) && !load_old_plexora_config())
enabled = FALSE
flags |= SS_NO_FIRE
return SS_INIT_NO_NEED
@@ -70,8 +59,7 @@ SUBSYSTEM_DEF(plexora)
flags |= SS_NO_FIRE
return SS_INIT_FAILURE
- http_root = config["ip"]
- http_port = config["port"]
+ base_url = CONFIG_GET(string/plexora_url)
default_headers = list(
"Content-Type" = "application/json",
@@ -92,19 +80,30 @@ SUBSYSTEM_DEF(plexora)
flags |= SS_NO_INIT // Make extra sure we don't initialize twice.
initialized = SSplexora.initialized
plexora_is_alive = SSplexora.plexora_is_alive
- http_root = SSplexora.http_root
- http_port = SSplexora.http_port
+ base_url = SSplexora.base_url
enabled = SSplexora.enabled
tripped_bad_version = SSplexora.tripped_bad_version
default_headers = SSplexora.default_headers
if(initialized && !enabled)
flags |= SS_NO_FIRE
+// compat thing so that it'll load plexora.json if it's still used
+/datum/controller/subsystem/plexora/proc/load_old_plexora_config()
+ if(!aneri_file_exists(OLD_PLEXORA_CONFIG))
+ return FALSE
+ var/list/old_config = json_decode(aneri_file_read(OLD_PLEXORA_CONFIG))
+ if(!old_config["enabled"])
+ return FALSE
+ stack_trace("Falling back to [OLD_PLEXORA_CONFIG], you should really migrate to the PLEXORA_ENABLED and PLEXORA_URL config entries!")
+ CONFIG_SET(flag/plexora_enabled, TRUE)
+ CONFIG_SET(string/plexora_url, "http://[old_config["ip"]]:[old_config["port"]]")
+ return TRUE
+
/datum/controller/subsystem/plexora/proc/is_plexora_alive()
. = FALSE
if(!enabled) return
- var/datum/http_request/request = new(RUSTG_HTTP_METHOD_GET, "http://[http_root]:[http_port]/alive")
+ var/datum/http_request/request = new(RUSTG_HTTP_METHOD_GET, "[base_url]/alive")
request.begin_async()
UNTIL_OR_TIMEOUT(request.is_complete(), 10 SECONDS)
var/datum/http_response/response = request.into_response()
@@ -134,7 +133,7 @@ SUBSYSTEM_DEF(plexora)
http_request(
RUSTG_HTTP_METHOD_POST,
- "http://[http_root]:[http_port]/status",
+ "[base_url]/status",
json_encode(status),
default_headers
).begin_async()
@@ -211,7 +210,7 @@ SUBSYSTEM_DEF(plexora)
"id" = id
)
- var/datum/http_request/request = new(RUSTG_HTTP_METHOD_GET, "http://[http_root]:[http_port]/byondserver_alive", json_encode(body), default_headers)
+ var/datum/http_request/request = new(RUSTG_HTTP_METHOD_GET, "[base_url]/byondserver_alive", json_encode(body), default_headers)
request.begin_async()
UNTIL_OR_TIMEOUT(request.is_complete(), 5 SECONDS)
var/datum/http_response/response = request.into_response()
@@ -362,7 +361,7 @@ SUBSYSTEM_DEF(plexora)
var/datum/http_request/request = new(
RUSTG_HTTP_METHOD_POST,
- "http://[http_root]:[http_port]/[path]",
+ "[base_url]/[path]",
json_encode(body),
default_headers,
"tmp/response.json"
@@ -979,5 +978,6 @@ SUBSYSTEM_DEF(plexora)
html = "Mentor PM: [key_name_mentor(sender, honked_client, FALSE, FALSE)]->[key_name_mentor(recipient, honked_client, FALSE, FALSE)]: ",
confidential = TRUE)
+#undef OLD_PLEXORA_CONFIG
#undef AUTH_HEADER
#undef TOPIC_EMITTER
diff --git a/monkestation/code/datums/meta_tokens.dm b/monkestation/code/datums/meta_tokens.dm
index 7f91794f9a07..a3180b6c3fd9 100644
--- a/monkestation/code/datums/meta_tokens.dm
+++ b/monkestation/code/datums/meta_tokens.dm
@@ -44,6 +44,8 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list(
var/antag_timeout
/// The timer for the event token timeout
var/event_timeout
+ /// The month we last used a donator token on
+ var/token_month = 0
/datum/meta_token_holder/New(client/creator)
. = ..()
@@ -72,6 +74,7 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list(
event_tokens = saved_tokens["event_tokens"]
event_token_month = saved_tokens["event_token_month"]
donator_token = saved_tokens["donator"]
+ token_month = saved_tokens["donator_token_month"]
total_antag_tokens = total_low_threat_tokens + total_medium_threat_tokens + total_high_threat_tokens
@@ -90,6 +93,7 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list(
"event_tokens" = event_tokens,
"event_token_month" = event_token_month,
"donator" = donator_token,
+ "donator_token_month" = token_month,
)
backup_tokens()
owner.prefs.save_preferences()
@@ -101,20 +105,18 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list(
return FALSE
var/month_number = text2num(time2text(world.time, "MM"))
- if(owner.prefs.token_month == 0)
- owner.prefs.token_month = month_number
- if(owner.prefs.token_month != month_number)
+ if(token_month != month_number)
if(patreon.has_access(ACCESS_NUKIE_RANK)) ///if nukie rank, get coins AND token
owner.prefs.adjust_metacoins(owner?.ckey, 10000, "Monthly Monkecoin rations.", TRUE, FALSE, FALSE)
donator_token++
- owner.prefs.token_month = month_number ///update per-person month counter
+ token_month = month_number ///update per-person month counter
convert_tokens_to_list()
return TRUE
else
- owner.prefs.token_month = month_number
+ token_month = month_number
convert_tokens_to_list()
return FALSE
@@ -122,8 +124,8 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list(
if(use_donor)
if(donator_token)
donator_token--
- logger.Log(LOG_CATEGORY_META, "[owner], used donator token on [owner.prefs.token_month].")
- owner.prefs.save_preferences()
+ logger.Log(LOG_CATEGORY_META, "[owner], used donator token on [token_month].")
+ convert_tokens_to_list()
return
switch(tier)
diff --git a/monkestation/code/game/machinery/computer/camera.dm b/monkestation/code/game/machinery/computer/camera.dm
new file mode 100644
index 000000000000..4df9a6f64ead
--- /dev/null
+++ b/monkestation/code/game/machinery/computer/camera.dm
@@ -0,0 +1,6 @@
+/obj/machinery/camera/proc/count_spesstv_viewers()
+ . = 0
+ var/list/spesstv_viewers = GLOB.spesstv_viewers // just in case this ends up being a hot proc
+ for(var/key in spesstv_viewers)
+ if(spesstv_viewers[key] == c_tag)
+ .++
diff --git a/monkestation/code/game/machinery/computer/telescreen.dm b/monkestation/code/game/machinery/computer/telescreen.dm
new file mode 100644
index 000000000000..c44fe9e435ff
--- /dev/null
+++ b/monkestation/code/game/machinery/computer/telescreen.dm
@@ -0,0 +1,17 @@
+/obj/machinery/computer/security/telescreen/entertainment/update_active_camera_screen()
+ . = ..()
+ update_spesstv_watcher_list(REF(src), active_camera)
+
+/obj/machinery/computer/security/telescreen/entertainment/Destroy()
+ LAZYREMOVE(GLOB.spesstv_viewers, REF(src))
+ return ..()
+
+/obj/machinery/computer/security/telescreen/entertainment/atom_break(damage_flag)
+ . = ..()
+ if(.)
+ LAZYREMOVE(GLOB.spesstv_viewers, REF(src))
+
+/obj/machinery/computer/security/telescreen/entertainment/power_change()
+ . = ..()
+ if(!powered())
+ LAZYREMOVE(GLOB.spesstv_viewers, REF(src))
diff --git a/monkestation/code/game/objects/items/devices/broadcast_camera.dm b/monkestation/code/game/objects/items/devices/broadcast_camera.dm
new file mode 100644
index 000000000000..eca97528a612
--- /dev/null
+++ b/monkestation/code/game/objects/items/devices/broadcast_camera.dm
@@ -0,0 +1,79 @@
+/datum/status_effect/streamer
+ id = "streamer"
+ alert_type = null
+ processing_speed = STATUS_EFFECT_NORMAL_PROCESS
+ /// How many people are currently watching the stream.
+ var/viewers = 0
+ /// The camera being used to stream.
+ var/obj/machinery/camera/camera
+ /// Simple screen element used to hold the maptext for the viewer counter.
+ var/atom/movable/screen/stream_viewers/viewer_display
+ /// Callback to see if the stream is still valid.
+ var/datum/callback/extra_checks
+
+/datum/status_effect/streamer/Destroy()
+ extra_checks = null
+ camera = null
+ QDEL_NULL(viewer_display)
+ return ..()
+
+/datum/status_effect/streamer/on_creation(mob/living/new_owner, obj/machinery/camera/camera, datum/callback/extra_checks)
+ src.camera = camera
+ src.extra_checks = extra_checks
+ return ..()
+
+/datum/status_effect/streamer/on_apply()
+ if(QDELETED(camera))
+ return FALSE
+ else if(!istype(camera))
+ CRASH("Invalid camera ([camera]) passed to [type] (expected an /obj/machinery/camera)")
+ if(extra_checks && !extra_checks.Invoke(src))
+ return FALSE
+ give_hud()
+ RegisterSignal(owner, COMSIG_MOB_LOGIN, PROC_REF(give_hud))
+ RegisterSignal(owner, COMSIG_MOB_GET_STATUS_TAB_ITEMS, PROC_REF(get_status_tab_item))
+ RegisterSignal(camera, COMSIG_QDELETING, PROC_REF(hamburger_time))
+ return TRUE
+
+/datum/status_effect/streamer/on_remove()
+ . = ..()
+ UnregisterSignal(owner, list(COMSIG_MOB_LOGIN, COMSIG_MOB_GET_STATUS_TAB_ITEMS))
+ UnregisterSignal(camera, COMSIG_QDELETING)
+ if(!isnull(viewer_display))
+ owner.client?.screen -= viewer_display
+
+/datum/status_effect/streamer/before_remove(source)
+ if(!isnull(source) && !QDELETED(camera) && source == camera)
+ return FALSE
+ return ..()
+
+/datum/status_effect/streamer/tick(seconds_per_tick, times_fired)
+ if(extra_checks && !extra_checks.Invoke(src))
+ qdel(src)
+ return
+ viewers = camera.count_spesstv_viewers()
+ viewer_display?.update_maptext(camera.count_spesstv_viewers())
+
+/datum/status_effect/streamer/proc/give_hud()
+ SIGNAL_HANDLER
+ if(QDELETED(viewer_display))
+ viewer_display = new
+ viewers = camera.count_spesstv_viewers()
+ viewer_display.update_maptext(viewers)
+ owner.client?.screen |= viewer_display
+
+/datum/status_effect/streamer/proc/get_status_tab_item(mob/living/source, list/items)
+ SIGNAL_HANDLER
+ items += "Stream Viewers: [viewers]"
+
+/datum/status_effect/streamer/proc/hamburger_time()
+ SIGNAL_HANDLER
+ qdel(src)
+
+/atom/movable/screen/stream_viewers
+ screen_loc = ui_more_under_health_and_to_the_left
+ maptext_width = 84
+ maptext_height = 24
+
+/atom/movable/screen/stream_viewers/proc/update_maptext(amt)
+ maptext = "